C中的悬空指针
我在C中编写了一个悬挂指针的程序。
#include int *func(void) { int num; num = 100; return # } int func1(void) { int x,y,z; scanf("%d %d",&y,&z); x=y+z; return x; } int main(void) { int *a = func(); int b; b = func1(); printf("%d\n",*a); return 0; }
即使指针悬空,我也将输出设为100 。
我在上面的函数func1()
做了一个更改。 现在我在编译时分配值,而不是像上面的程序那样从标准输入中获取y
和z
的值。
我重新定义了func1()
,如下所示:
int func1(void) { int x,y,z; y=100; z=100; x=y+z; return x; }
现在输出是200 。
有人可以解释一下上述两项产出的原因吗?
未定义的行为意味着任何事情都可能发生,包括它会像你期望的那样。 在这种情况下,您的堆栈变量不会被覆盖。
void func3() { int a=0, b=1, c=2; }
如果在func1
和printf
之间包含对func3()
的调用,则会得到不同的结果。
编辑:在某些平台上实际发生了什么。
int *func(void) { int num; num = 100; return # }
为简单起见,假设在调用此函数之前堆栈指针为10,并且堆栈向上增长。
当您调用该函数时,返回地址被压入堆栈(位置10)并且堆栈指针递增到14(是的,非常简化)。 然后在位置14的堆栈上创建变量num,并且堆栈指针递增到18。
返回时,返回指向地址14的指针 – 从堆栈中弹出返回地址,堆栈指针返回10。
void func2() { int y = 1; }
在这里,同样的事情发生了。 在位置推送的返回地址,在位置14创建的y,为y分配1(写入地址14),返回并将指针堆叠回到位置10。
现在,你的旧int *
从func
返回到地址14,对该地址的最后修改是func2的局部变量赋值。 所以,你有一个悬空指针(堆栈中位置10以上没有任何内容有效)指向调用func2
的剩余值
这是因为内存的分配方式。
在调用func
并返回一个悬空指针后,堆栈中存储num
的部分仍然具有值100
(这是您之后看到的)。 我们可以根据观察到的行为得出这个结论。
在更改之后,看起来发生的事情是func1
调用覆盖a
指向func1
内部的添加结果的内存位置(之前用于func
的堆栈空间现在由func1
重用),所以这就是你看到的原因200。
当然, 所有这些都是未定义的行为,所以虽然这可能是一个很好的哲学问题,回答它并不能真正为你买任何东西。
这是未定义的行为。 它现在可以在您的计算机上正常工作,从现在开始20分钟,可能会在一小时内崩溃,等等。一旦另一个对象在堆栈上占据相同的位置,就会出现num
,您将注定失败 !
悬空指针(指向已被解除关联的位置的指针)会导致未定义的行为 ,即任何事情都可能发生。
特别是,内存位置在func1
偶然重用*。 结果取决于堆栈布局,编译器优化,体系结构,调用约定和堆栈安全机制。
使用悬空指针,程序的结果是不确定的。 这取决于堆栈和寄存器的使用方式。 使用不同的编译器,不同的编译器版本和不同的优化设置,您将获得不同的行为。
返回指向局部变量的指针会产生未定义的行为,这意味着程序执行的任何操作(任何内容)都是有效的。 如果你得到了预期的结果,那就是运气不好。
请从基础C学习function。你的概念是有缺陷的… main
应该是
int main(void) { int *a = func(); int b; b = func1(); printf("%d\n%d",*a,func1()); return 0; }
这将输出100 200