シナリオ1
int *nums = {5, 2, 1, 4};
printf("%d\n", nums[0]);
なぜこれがセグメンテーション違反なのですか?
あなたはnums
intへのポインタとして宣言しました-それはメモリ内nums
の1つの整数のアドレスを保持することになっています。
次にnums
、複数の値の配列に初期化しようとしました。したがって、詳細を掘り下げることなく、これは概念的に正しくありません。1つの値を保持することになっている変数に複数の値を割り当てることは意味がありません。この点で、これを行うとまったく同じ効果が見られます。
int nums = {5, 2, 1, 4};
printf("%d\n", nums);
いずれの場合も(ポインターまたはint変数に複数の値を割り当てる)、その後、変数は最初の値であるを取得し、5
残りの値は無視されます。このコードは準拠していますが、割り当てに含まれていないはずの追加の値ごとに警告が表示されます。
warning: excess elements in scalar initializer
。
ポインタ変数に複数の値を割り当てる場合、にアクセスするとプログラムはセグメンテーション違反になりますnums[0]
。つまり、アドレス5に文字通り格納されているものはすべて延期されます。nums
この場合、ポインタに有効なメモリを割り当てていません。
int変数に複数の値を割り当てる場合のセグメンテーション違反はないことに注意してください(ここでは無効なポインターを逆参照していません)。
シナリオ2
int nums[] = {5, 2, 1, 4};
スタックに4つのintの配列を合法的に割り当てているため、これはセグメンテーション違反ではありません。
シナリオ3
int *nums = {5, 2, 1, 4};
printf("%d\n", nums);
これは、ポインタ自体の値を出力しているため、期待どおりにセグメンテーション違反を起こしません-逆参照しているものではありません(これは無効なメモリアクセスです)。
その他
このようにポインタの値をハードコーディングすると、ほとんどの場合、セグメンテーション違反が発生する運命にあります(どのプロセスがどのメモリ位置にアクセスできるかを判断するのはオペレーティングシステムのタスクであるため)。
int *nums = 5;
したがって、経験則では、次のような割り当てられた変数のアドレスへのポインタを常に初期化します。
int a;
int *nums = &a;
または、
int a[] = {5, 2, 1, 4};
int *nums = a;