C ++を学んでいて、nullを理解するのに苦労しています。特に、私が読んだチュートリアルでは、「nullチェック」の実行について言及していますが、それが何を意味するのか、なぜそれが必要なのかわかりません。
- nullとは正確には何ですか?
- 「nullをチェックする」とはどういう意味ですか?
- 常にnullをチェックする必要がありますか?
コード例をいただければ幸いです。
コメント
- いつ: programmers.stackexchange.com/questions/186036/ …
- 読んだすべてのチュートリアルで、説明やサンプルコードを提供せずに、nullチェックについて説明している場合は、より良いチュートリアルを入手することをお勧めします…
回答
CおよびC ++では、ポインターは本質的に安全ではありません。つまり、ポインターを逆参照すると、それがどこか有効な場所を指していることを確認するのはあなた自身の責任です。これは「手動メモリ管理」の一部です(Javaのような言語で実装された自動メモリ管理スキームとは対照的です) 、PHP、または.NETランタイム。かなりの労力をかけずに無効な参照を作成することはできません。
多くのエラーをキャッチする一般的な解決策は、何も指さないすべてのポインタを設定することです。 NULL
(または、正しいC ++では0
)として、ポインターにアクセスする前にそれを確認します。具体的には、すべてのポインタをNULLに初期化し(宣言時にポインタを指すものがすでにある場合を除く)、delete
または
それら(直後にスコープから外れない限り)。例(Cで、有効なC ++でも):
void fill_foo(int* foo) { *foo = 23; // this will crash and burn if foo is NULL }
より良いバージョン:
void fill_foo(int* foo) { if (!foo) { // this is the NULL check printf("This is wrong\n"); return; } *foo = 23; }
nullチェックがないと、この関数にNULLポインターを渡すと、セグメンテーション違反が発生し、実行できることは何もありません。OSはプロセスを強制終了し、コアダンプするか、クラッシュレポートダイアログをポップアップします。ヌルチェックを実行すると、適切なエラー処理を実行し、適切に回復できます。問題を自分で修正し、現在の操作を中止し、ログエントリを書き込み、ユーザーに通知します。
コメント
- @MrListerどういう意味ですか、nullチェックはC ++では機能しません'ポインタを宣言するときに、ポインタをnullに初期化する必要があります。
- つまり、ポインタをNULLに設定することを忘れないでください。そうしないと、ポインタがnullになります'仕事。また、覚えている場合、つまり、ポインタがNULLであることを知っている場合は、'とにかくfill_fooを呼び出す必要はありません。 fill_fooは、ポインターに有効な値があるかどうかではなく、ポインターに値があるかどうかをチェックします。 C ++では、ポインタがNULLであるか、有効な値を持つことが保証されていません。
- ここでは、assert()の方が優れたソリューションです。 '安全に"しようとしても意味がありません"。 NULLが渡された場合、'は明らかに間違っているので、プログラマーに完全に認識させるために明示的にクラッシュしないのはなぜですか? (本番環境では、'は重要ではありません。'誰もfill_fooを呼び出さないことが証明されているからです。 ()NULLの場合、そうですか?本当に、'それほど難しくはありません。)
- '忘れないでくださいこの関数のさらに優れたバージョンでは、ポインタの代わりに参照を使用して、NULLチェックを廃止する必要があることに言及してください。
- これは手動のメモリ管理の目的ではなく、管理対象プログラムも爆発します((または、少なくとも、ほとんどの言語でネイティブプログラムが行うように、例外を発生させます)null参照を逆参照しようとした場合。
回答
他の回答は、あなたの正確な質問をほぼカバーしていました。受け取ったポインタが実際に型の有効なインスタンス(オブジェクト、プリミティブなど)を指していることを確認するために、nullチェックが行われます。
ここに独自のアドバイスを追加します。ただし、nullチェックは避けてください。:) nullチェック(および他の形式の防御プログラミング)はコードを乱雑にし、実際には他のエラー処理手法よりもエラーが発生しやすくなります。
私のお気に入りの手法です。オブジェクトポインタは、 Nullオブジェクトパターンを使用することです。つまり、nullの代わりに(ポインタ、またはさらに良いのは、への参照)空の配列またはリストを返すことを意味します。 nullの代わりに空の文字列( “”)を返すか、整数に解析されると予想される文字列 “0”(またはコンテキスト内の “nothing”に相当するもの)を返します。
おまけとして、ここに「1965年にCAR HoareによってAlgolW言語用に(最初に正式に)実装されたnullポインタについて知らなかったかもしれない小さなことがあります。
私はそれを10億ドルの間違いと呼んでいます。これは、1965年のnull参照の発明でした。当時、私はオブジェクト内の参照用の最初の包括的な型システムを設計していました。指向言語(ALGOL W)。私の目標は、参照のすべての使用が完全に安全であり、チェックがコンパイラによって自動的に実行されるようにすることでした。しかし、null参照を入力したいという誘惑に抵抗できませんでした。実装が簡単です。これにより、無数のエラー、脆弱性、システムクラッシュが発生し、過去40年間でおそらく10億ドルの痛みと損害が発生しました。
コメント
- Nullオブジェクトは、単にnullポインタを持つよりもさらに悪いです。アルゴリズムXがあなたが持っていないデータYを必要とする場合、それはプログラムのバグであり、あなたが持っているふりをして単に隠しているだけです。
- それはコンテキスト、およびどちらの方法でも、"データの存在"のテストは私の本のnullのテストよりも優れています。私の経験から、アルゴリズムがたとえばリストで機能し、リストが空の場合、アルゴリズムは何もする必要がなく、for / foreachなどの標準の制御ステートメントを使用するだけでそれを実現します。
- アルゴリズムが何の関係もないのなら、なぜあなたはそれを呼んでいるのですか?そして、そもそもそれを呼びたかったのは、何か重要なことをするからです。
- @DeadMGプログラムは入力に関するものであり、現実の世界では、宿題の割り当て、入力は無関係である可能性があります(例:空)。コードはどちらの方法でも呼び出されます。 2つのオプションがあります。関連性(または空)をチェックするか、条件ステートメントを使用して関連性を明示的にチェックせずに読み取りて適切に機能するようにアルゴリズムを設計します。
- 私はほとんど同じコメントなので、代わりに私の投票をしました。ただし、これはゾンビオブジェクトのより大きな問題を表していることも付け加えておきます。多段階の初期化(または破壊)があり、完全には機能していないが完全には死んでいないオブジェクトがある場合はいつでも。 " safe "コードが確定的確定のない言語で表示され、オブジェクトが破棄されたかどうかを確認するためにすべての関数にチェックが追加されている場合、 'の頭を育てるのはこの一般的な問題です。 nullの場合は絶対に使用しないでください。存続期間に必要なオブジェクトがある状態で作業する必要があります。
回答
nullポインター値は、明確に定義された「どこにも」を表します。これは無効なポインタ値であり、他のポインタ値と等しくないことが保証されています。 nullポインターを逆参照しようとすると、未定義の動作が発生し、通常はランタイムエラーが発生するため、逆参照を試みる前に、ポインターがNULLでないことを確認する必要があります。多くのCおよびC ++ライブラリ関数は、エラー状態を示すnullポインタを返します。たとえば、ライブラリ関数malloc
は、要求されたバイト数を割り当てることができない場合、nullポインタ値を返し、そのポインタを介してメモリにアクセスしようとすると(通常)ランタイムエラーへ:
int *p = malloc(sizeof *p * N); p[0] = ...; // this will (usually) blow up if malloc returned NULL
したがって、malloc
呼び出しが成功したことを確認するために、 p
NULLに対して:
int *p = malloc(sizeof *p * N); if (p != NULL) // or just if (p) p[0] = ...;
さて、ちょっと待ってください。これで少しでこぼこです。
nullポインタ value とnullポインタ constant があり、2つは必ずしも同じではありません。ヌルポインタ value は、基盤となるアーキテクチャが「どこにも」を表すために使用する値です。この値は、0x00000000、0xFFFFFFFF、0xDEADBEEF、またはまったく異なるものである可能性があります。ヌルポインタの値が常に0であると想定しないでください。
ヌルポインタの定数であるOTOHは、常に0値の整数式です。 ソースコードに関する限り、0(または0と評価される任意の整数式)はnullポインタを表します。 CとC ++はどちらも、NULLマクロをNULLポインター定数として定義しています。コードがコンパイルされると、生成されたマシンコードでnullポインタ定数が適切なnullポインタ値に置き換えられます。
また、NULLは多くの無効なポインタ値の1つにすぎないことに注意してください。明示的に初期化せずに自動ポインタ変数を宣言した場合(
int *p;
変数に最初に格納された値は不確定)、有効またはアクセス可能なメモリアドレスに対応していない可能性があります。残念ながら、NULL以外のポインタ値を使用する前に、それが有効かどうかを判断する(移植可能な)方法はありません。したがって、ポインタを扱う場合は、通常、ポインタを明示的に初期化することをお勧めします。それらを宣言するときはNULLであり、アクティブに何も指していないときはNULLに設定します。
これはC ++よりもCの方が問題であることに注意してください。慣用的なC ++は、ポインタをそれほど使用するべきではありません。
回答
いくつかのメソッドがあり、すべて基本的に同じです。
int *foo = NULL; //sometimes set to 0x00 or 0 or 0L instead of NULL
nullチェック(ポインタがnullかどうかをチェック)、バージョンA
if( foo == NULL)
nullチェック、バージョンB
if( !foo ) //since NULL is defined as 0, !foo will return a value from a null pointer
nullチェック、バージョンC
if( foo == 0 )
3つのうち、最初のチェックを使用することをお勧めします。これは、将来の開発者に何をチェックしようとしているかを明示的に示し、fooがポインターであると期待していたことを明確にするためです。
回答
あなたはしません。 C ++でポインターを使用する唯一の理由は、nullポインターの存在を明示的に必要とするためです。それ以外の場合は、参照を取得できます。これは、意味的に使いやすく、null以外を保証します。
コメント
- @James:
new '?
- @James:C ++の大多数の機能を表すC ++の実装コーダーは楽しんでいます。これには、すべての C ++ 03言語機能(
export
を除く)とすべてのC ++ 03ライブラリ機能および TR1 そして C ++ 11のかなりの部分。 - 私は 人々が'と言わないことを望みます
div id = “d2489b1d21″>
参照はnull以外を保証します。"参照は' tではありません。 nullポインタと同じようにnull参照を生成するのは簡単で、同じように伝播します。
回答
NULL値をチェックしない場合、特にそれが構造体へのポインタである場合は、セキュリティの脆弱性(NULLポインタの逆参照)に遭遇した可能性があります。NULLポインタの逆参照は、バッファオーバーフローなどの他の重大なセキュリティの脆弱性につながる可能性があります。レース条件…攻撃者があなたのコンピュータを制御できるようにする可能性があります。
Microsoft、Oracle、Adobe、Appleなどの多くのソフトウェアベンダーは、これらのセキュリティの脆弱性を修正するためのソフトウェアパッチをリリースしています。各ポインタのNULL値を確認してください:)