for
ループでポインターを使用すると問題が発生します。私のfor
ループ初期化子で、int
ポインターを逆参照し、それに「0」の値を与えます。ループでこの逆参照されたポインターを使用すると、セグメンテーション違反が発生し、その理由がわかりません。私は Code :: Blocks およびC GNU GCCコンパイラを使用しています。
ウォッチウィンドウを見ると、for
ループ中に変数に乱数が含まれていることがわかります。
逆参照されたポインターは、for
ループ中にスコープを失うようです。
コード:
#include <stdio.h>
int main(void)
{
int val = 0;
int *p = NULL;
int answer = 0;
p = &val;
*p = 1; // This dereferences and sets to one successfully
for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
{
printf("do stuff");
(*p) += 1; // Here it causes a segmentation fault
}
answer = *p;
}
私のようにポインターを使っても問題ないと思いました。
ここをよく見てください:
for (int i=3, (*p)=0 ; i>=0; i--)
for
の最初の部分では、前に定義したp
をシャドウし、NULLに初期化するp
という名前のnewポインター変数を定義しています。 。次に、segfaultの原因となるループでNULLポインターを逆参照します。
このように、変数の定義と既存の変数への割り当ての両方を同時に持つことはできないため、*p
の割り当てをループの前に移動します。
*p = 0;
for (int i=3; i>=0; i--)
または、ループの外でi
を定義できます。
int i;
for (i=3, (*p)=0 ; i>=0; i--)
あなたcouldは、コンマ演算子を悪用することにより、これらを一緒に絞ります:
for (int i=(*p=0,3) ; i>=0; i--)
ここで、p
への割り当てはi
の初期化子の一部として行われるため、新しい変数は宣言されません。ただし、コードの読み取りと理解が難しくなるため、これはお勧めしません。
p
という完全に新しい変数を宣言しています。
for (int i=3, (*p)=0 ; i>=0; i--)
これは次と同じです:
for (int i=3, *p=0 ; i>=0; i--)
だからあなたはint i
と int *p
、アドレス0を指します。これは、以前に定義されたものと同じp
ではありません。それはただそれを覆っています。したがって、それを逆参照すると、segfaultが発生します。
ヒント:-Wshadow
変数が別の変数をシャドウするときに警告を表示します。
[] $ gcc main.c -Wshadow
main.c: In function ‘main’:
main.c:13:21: warning: declaration of ‘p’ shadows a previous local [-Wshadow]
13 | for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
| ^
main.c:6:10: note: shadowed declaration is here
6 | int *p = NULL;
| ^