我一直在用指针做一些测试,并遇到了以下两种情况。谁能向我解释发生了什么?
void t ();
void wrong_t ();
void t () {
int i;
for (i=0;i<1;i++) {
int *p;
int a = 54;
p = &a;
printf("%d\n", *p);
}
}
void wrong_t() {
int i;
for (i=0;i<1;i++) {
int *p;
*p = 54;
printf("%d\n", *p);
}
}
考虑这两个版本的main:
int main () {
t();
wrong_t();
}
打印: 54 \ n54 \ n,正如预期的那样
int main () {
wrong_t();
}
收率: 分段错误:11
我认为这个问题源于“wrong_t()”中的“int * p”是一个“坏指针”,因为它未正确初始化(cfr。:cslibrary.stanford.edu/102/PointersAndMemory.pdf ,第8页)。但我不明白为什么在某些情况下会出现这样的问题(例如:如果我在wrong_t()之前调用t()或者我在wrong_t()中删除了代码周围的for循环,则不会发生这种情况。
答案 0 :(得分:4)
因为取消引用未初始化的指针(正如您猜测的那样)会调用未定义的行为。任何事情都可能发生。
如果您想了解您正在观察的精确行为,那么唯一的方法是查看编译器生成的汇编代码。但这通常效率不高。
答案 1 :(得分:3)
几乎可以肯定会发生什么:
在t
和wrong_t
中,定义int *p
在堆栈上为p
分配空间。当您只调用wrong_t
时,此空间包含以前活动遗留的数据(例如,来自在调用main
之前设置环境的代码)。它恰好是一些无效的指针值,因此使用它来访问内存会导致段错误。
当您致电t
时,t
会为p
初始化此空间,以包含指向a
的指针。在此之后调用wrong_t
时,wrong_t
无法初始化p
的空间,但它已经包含从a
执行时t
的指针,因此使用它访问内存导致访问a
。
这显然不是您可能依赖的行为。您可能会发现启用优化的编译(例如,-O3
与GCC)会改变行为。
答案 2 :(得分:1)
在wrong_t
函数中,此语句*p = 54;
很有意思。您正在尝试将值存储到指针p
中,而您尚未分配内存,因此错误。