関数を書いているときに、パラメータにポインタが付いていることがありますが、このときは注意が必要です。以下は注意事項を説明する例です。
プロトタイプの例
次のように、単純なC ++クラス(Cの原理は似ています)があるとします。
class Test
{
public:
Test()
{
m_ptr = nullptr;
}
void setPtr(int *ptr)
{
m_ptr = ptr;
}
int *getPtr(void)
{
return m_ptr;
}
private:
int * m_ptr;
};
このクラスには、2つのメソッドを持つプライベートポインタ変数m_ptrがあります。setPtr()はm_ptrを設定するために使用され、getPtr()はm_ptrを取得するために使用されます。
テストコードは次のとおりです。
int main(void)
{
Test test;
int data = 100;
test.setPtr(&data);
int *retPtr = test.getPtr();
if (retPtr != nullptr)
std::cout << *retPtr << "\n";
return 0;
}
印刷は次のとおりです。
エラーが発生しやすい2つの状況
getPtr()の戻り値を使用してポインタが有効かどうかを判断する場合は、次の形式に書き換えることができます。
bool getPtr(int * ptr)
{
if (m_ptr == nullptr)
{
return false;
}
else
{
ptr = m_ptr;
return true;
}
}
テストコードは次のとおりです。
int main(void)
{
Test test;
int data = 100;
test.setPtr(&data);
int *retPtr = nullptr;
if (test.getPtr(retPtr) == true)
{
std::cout << *retPtr << "\n";
}
return 0;
}
印刷は空です!これは予想と同じではありません。getPtr()の戻り値はtrueであり、テストのm_ptrがnullptrではないことを示しています。それでは、なぜ正しいポインター値を取得しなかったのでしょうか。
これは、C / C ++関数のパラメーターが値で渡されるためです。以前は、関連する概念を学習するときに、ポインターについての発言がありました。本質は値で渡すことです。retPtrをgetPtr()に渡すと、実際には次のようになります。この文を実行し、
int *ptr = retPtr;
ポインタ変数ptrが再生成され、retPtrの値がptrにコピーされます。ptrに対する後続の操作はretPtrの値に影響を与えないため、正しいポインタ値が取得されません。
3つの解決策
2つの方法があります、
1.セカンダリポインタを使用します
ターゲット変数は第1レベルのポインターであるため、第2レベルのポインターを使用して解決できます。
bool getPtr(int ** pptr)
{
if (m_ptr == nullptr)
{
return false;
}
else
{
(*pptr) = m_ptr; // key
return true;
}
}
コードで最も重要なことは、(*pptr) = m_ptr;
間違いを犯しやすいことです。これは、第2レベルのポインターを逆参照してから割り当てることです。記述しないでくださいpptr = &m_ptr;
。これは、前の値の受け渡しの問題になり、正しいポインターになります。値を取得できません。
テストコードは次のとおりです。
int main(void)
{
Test test;
int data = 100;
test.setPtr(&data);
int *retPtr = nullptr;
if (test.getPtr(&retPtr) == true) // 要取retPtr的地址传过去
{
std::cout << *retPtr << "\n";
}
return 0;
}
2. C ++参照を使用する
第2レベルのポインタは確かに問題を解決できますが、脳は1次元のものを扱うのが好きで、2次元が発生すると失神しやすいため、人を混乱させやすいという欠点があります。
C ++参照を使用すると、次のようにセカンダリポインタの使用を回避できます。
bool getPtr(int *& ptr)
{
if (m_ptr == nullptr)
{
return false;
}
else
{
ptr = m_ptr;
return true;
}
}
それでもパラメータが少し複雑だと感じる場合int*
は、次のようにtypedefを使用してエイリアスを指定できます。
typedef int * newType;
bool getPtr(newType& ptr)
{
if (m_ptr == nullptr)
{
return false;
}
else
{
ptr = m_ptr;
return true;
}
}
これにより、理解しやすくなります。
テストコードは次のとおりです。
int main(void)
{
Test test;
int data = 100;
test.setPtr(&data);
int *retPtr = nullptr;
if (test.getPtr(retPtr) == true)
{
std::cout << *retPtr << "\n";
}
return 0;
}
次のように印刷し、[
OK]を確認します
4つの要約
この記事では、主に関数パラメーターがポインターの場合の注意事項について説明します。ポインターパラメーターを使用して値を取得する場合は、特に注意が必要です。第2レベルのポインターまたはC ++参照を使用して問題を解決できます。
文章に何か問題がありましたら、訂正するためのメッセージを残したいと思います。読んでいただきありがとうございます。