このコードが出力として4を出力するのはなぜですか?
この種の行動をよりよく理解するのに役立つ詳細も教えてください。
int main(){
int *p=NULL;
printf("%d" ,p+1);
return 0;
}
ポインタを0(NULL)に設定してから、それに1を追加しています。次に、結果をに変換して結果をint
印刷します。ここで必要な重要な知識は、ポインターをインクリメント(1を追加)するときに、実際にポイント先のオブジェクトのサイズを追加することです。ポインターは、次int
のオブジェクトを指すように進められます。は(明らかに)プラットフォーム上で4バイトなので、開始位置から4バイト先のアドレスを指すようにインクリメントされます。 int
int
p
Cでのサイズint
は(通常)4バイトです。したがって、ポインタを1単位増やすことは、その値を。だけ増やすことを意味しますsizeof(int)
。
また、(これは確かにプログラムをクラッシュさせるので)ポインターが向けている値を出力するのではなく、ポインター自体の値を出力します。C(または一般)のポインタチュートリアルを必ず確認してください。
これはp + 1
無効なポインタ(つまり、NULL
有効なオブジェクトでも、配列オブジェクトの1つ先でもないポインタ)であり、その使用は未定義の動作であることに注意してください。
printf("%d" ,p+1);
または(より正確):
printf("%p", (void *) (p + 1));
未定義の動作です。
ATアドレスpに格納されている値ではなく、pのアドレスを出力しています。p = NULLは、pをゼロに設定します。これは整数へのポインタであるため、1ずつインクリメントすると、実際には整数のサイズ(通常は4バイトまたは8バイト)だけポインタがインクリメントされます。
* pを介してアドレス0(または4)に格納されているものを印刷しようとすると、メモリのその領域が保護されているため、通常、ほとんどのシステムでプログラムが終了します。
未定義の動作が発生しています。ポインターが配列の要素または配列の終わりを超えた要素を指し、整数で示される位置の数だけポインターを移動した結果が次の要素も指す場合にのみ、ポインターに整数を追加することが有効です。同じ配列、または終わりを超えた配列。(非配列オブジェクトは、これらの目的のために1つの要素配列の唯一の要素として扱うことができます。)
nullポインターは配列の要素を指していないため、配列に追加することはできません。(C ++では、nullポインター値に0を追加し、結果としてnullポインター値を取得することが明示的に許可されています(Dr.DobbのAndrewKoenigによるこのブログエントリを参照してください)。
対応するフォーマット指定子が期待する場所にポインタ値を渡すことにより、さらに未定義の動作が得られます。はの正しいフォーマット指定子です。ポインタをwithとして出力する場合は、明示的なキャストが必要です。printf
%d
int
%p
void*
int
%d
プログラムの動作が未定義の場合、発生する可能性のあることについての保証はありません。結果を観察することから言語について何も推測することはできません。そのような動作から実装のプロパティを推測しようとするメリットは、そうでないプログラムからの観察可能な結果の形でのさらなる証拠なしに、議論の余地があります。未定義の動作またはコンパイラベンダーからの保証がある場合、観察された動作が変化する原因となる可能性のある状況がわかりません。