Pointers 指针对指针 #包括 无效设置全部(int*iPtr、int**p、int***pp、int****ppp){ *p=iPtr; **pp=iPtr; ***ppp=iPtr; printf(“hi\n”); } int main(){ 国际贸易指数=42,*p,**pp,***购买力平价; SetupAll(&i,&p,&pp,&ppp); printf(“%u%u%u%u\n”,***购买力平价,**购买力平价,*购买力平价,i); }

Pointers 指针对指针 #包括 无效设置全部(int*iPtr、int**p、int***pp、int****ppp){ *p=iPtr; **pp=iPtr; ***ppp=iPtr; printf(“hi\n”); } int main(){ 国际贸易指数=42,*p,**pp,***购买力平价; SetupAll(&i,&p,&pp,&ppp); printf(“%u%u%u%u\n”,***购买力平价,**购买力平价,*购买力平价,i); },pointers,Pointers,为什么当我在没有ppp的情况下运行这段代码时,它运行得非常好,并且打印了42个三次。但是,当我包含三个指针时,SetupAll函数中会出现seg故障。在我看来,ppp遵循与其他两个指针相同的格式来获取i。帮助?它崩溃,因为您在初始化指针之前取消了对它们的引用。即使你没有ppp,你也有同样的问题——你很幸运,它没有崩溃 您打算做的是: #include <stdio.h> void SetupAll(int *iPtr, int **p, int ***pp, int ****ppp)

为什么当我在没有ppp的情况下运行这段代码时,它运行得非常好,并且打印了42个三次。但是,当我包含三个指针时,SetupAll函数中会出现seg故障。在我看来,ppp遵循与其他两个指针相同的格式来获取i。帮助?

它崩溃,因为您在初始化指针之前取消了对它们的引用。即使你没有ppp,你也有同样的问题——你很幸运,它没有崩溃

您打算做的是:

#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);
}
#包括
无效设置全部(int*iPtr、int**p、int***pp、int****ppp){
*p=iPtr;
*pp=p;
*购买力平价=购买力平价;
printf(“hi\n”);
}
int main(){
国际贸易指数=42,*p,**pp,***购买力平价;
SetupAll(&i,&p,&pp,&ppp);
printf(“%u%u%u%u\n”,***购买力平价,**购买力平价,*购买力平价,i);
}
请注意SetupAll中的差异——每个指针只解引用一次,以便可以设置其值。声明中其余的“星”告诉您指针指向的是什么类型的对象


编辑:详细说明一下,当你做
**pp
时,你实际上是在做
*(*pp)
——换句话说,(a)首先找到
*pp
的值,它本身就是指向一个int的指针,然后(b)尝试找到
*pp
指向的int的值。但是在您的原始代码中,您还没有初始化
*pp
,所以它指向了某个随机的地方。因此,在(b)处,当您尝试查找int的值时,如果
*pp
返回的随机值不是有效的内存地址,则很容易崩溃。

它崩溃是因为您在初始化指针之前取消了对指针的引用。即使你没有ppp,你也有同样的问题——你很幸运,它没有崩溃

您打算做的是:

#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);
}
#包括
无效设置全部(int*iPtr、int**p、int***pp、int****ppp){
*p=iPtr;
*pp=p;
*购买力平价=购买力平价;
printf(“hi\n”);
}
int main(){
国际贸易指数=42,*p,**pp,***购买力平价;
SetupAll(&i,&p,&pp,&ppp);
printf(“%u%u%u%u\n”,***购买力平价,**购买力平价,*购买力平价,i);
}
请注意SetupAll中的差异——每个指针只解引用一次,以便可以设置其值。声明中其余的“星”告诉您指针指向的是什么类型的对象


编辑:详细说明一下,当你做
**pp
时,你实际上是在做
*(*pp)
——换句话说,(a)首先找到
*pp
的值,它本身就是指向一个int的指针,然后(b)尝试找到
*pp
指向的int的值。但是在您的原始代码中,您还没有初始化
*pp
,所以它指向了某个随机的地方。因此,在(b)处,当您尝试查找int的值时,如果
*pp
返回的随机值不是有效的内存地址,则很容易崩溃。

使用valgrind(一种用于解除内存错误屏蔽的工具)调试此问题可能会有所帮助

使用调试符号编译并在valgrind下运行:

#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);
}
第四行是:

$ 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

因此,您可以看到,当您尝试取消引用未初始化的值
*p
时,valgrind终止了程序。

使用valgrind调试此问题可能会有所帮助,valgrind是一种用于解除内存错误屏蔽的工具

使用调试符号编译并在valgrind下运行:

#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);
}
第四行是:

$ 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

因此,您可以看到valgrind在尝试取消引用未初始化的值
*p
时终止了程序。

调试时,
p
pp
ppp
的原始指针值是多少?当输入
SetupAll
时,
p
的原始指针值是多少,
pp
ppp
何时进入
SetupAll
?回答得很好。作为补充,我建议您在声明指针时将其初始化为null,这样可以避免“幸运”但实际上是“不幸”的情况:总是崩溃可能比不知道何时崩溃要好。啊,很好的一点,@duskast。总是撞车肯定比随机撞车好!我可以在答案中添加这一点,但如果与原始代码的唯一区别在于去引用,可能会更清楚。答案很好。作为补充,我建议您在声明指针时将其初始化为null,这样可以避免“幸运”但实际上是“不幸”的情况:总是崩溃可能比不知道何时崩溃要好。啊,很好的一点,@duskast。总是撞车肯定比随机撞车好!我可以在答案中添加这一点,但如果与原始代码的唯一区别在于取消引用,可能会更清楚。