2
#include <stdio.h>
void SetupAll(int *iPtr, int **p, int ***pp, int ****ppp){
   *p = iPtr;
   **pp =iPtr;
   ***ppp = iPtr;
   printf("hi\n");
}

int main() {
   int i = 42, *p, **pp, ***ppp;
   SetupAll(&i, &p, &pp, &ppp);
   printf("%u %u %u %u\n", ***ppp, **pp, *p, i);
}

このコードを ppp (トリプル ポインター) なしで実行すると、問題なく実行され、42 が 3 回出力されるのはなぜですか。しかし、トリプル ポインターを含めると、SetupAll 関数内からセグ フォールトが発生します。私の考えでは、ppp は i を取得するための他の 2 つのポインターと同じ形式に従います。ヘルプ?

4

2 に答える 2

4

ポインターを初期化する前に逆参照しているため、クラッシュします。持っていなくても同じ問題がありますppp-運が良かっただけで、どういうわけかクラッシュしませんでした。

あなたがやろうとしていることは次のとおりです。

#include <stdio.h>
void SetupAll(int *iPtr, int **p, int ***pp, int ****ppp){
   *p = iPtr;
   *pp = p;
   *ppp = pp;
   printf("hi\n");
}

int main() {
   int i = 42, *p, **pp, ***ppp;
   SetupAll(&i, &p, &pp, &ppp);
   printf("%u %u %u %u\n", ***ppp, **pp, *p, i);
}

SetupAll の違いに注意してください。値を設定できるように、各ポインターを 1 回だけ逆参照しています。宣言内の残りの「星」は、ポインターが指すもののタイプを示します。

編集:詳しく説明すると**pp、実際に実行しています*(*pp)-つまり、(a)最初にそれ自体がintへのポインターである値を見つけ、次に(b)を指す*ppintの値を見つけようとします*pp. しかし、元のコードでは*ppまだ初期化していないため、ランダムな場所を指していました。そのため、(b) で int の値を見つけようとすると、返されたランダムな値が*pp有効なメモリ アドレスでない場合、簡単にクラッシュする可能性があります。

于 2013-05-10T01:49:11.603 に答える
0

この問題は、メモリ エラーをマスク解除するためのツールである valgrind を使用してデバッグすると役立つ場合があります。

デバッグ シンボルを使用してコンパイルし、valgrind で実行します。

$ cc test.c -o test -g 
$ valgrind ./test 
[...]
Use of uninitialised value of size 8
   at 0x100000E85: SetupAll (test.c:4)
   by 0x100000ED3: main (test.c:11)
Invalid write of size 8
   at 0x100000E85: SetupAll (test.c:4)
   by 0x100000ED3: main (test.c:11)
Address 0x0 is not stack'd, malloc'd or (recently) free'd

4 行目は次のとおりです。

   **pp =iPtr;

したがって、初期化されていない値である を逆参照しようとすると、valgrind がプログラムを終了したことがわかり*pます。

于 2013-05-10T02:17:51.950 に答える