我用C语言编写了一个悬挂指针的程序。
#include<stdio.h>
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 。
有人可以解释一下上述两项产出的原因吗?
答案 0 :(得分:16)
未定义的行为意味着任何事情都可能发生,包括它会像您期望的那样。在这种情况下,您的堆栈变量不会被覆盖。
void func3() {
int a=0, b=1, c=2;
}
如果您在func3()
和func1
之间加入printf
来电,则会得到不同的结果。
编辑:某些平台上实际发生的事情。
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
答案 1 :(得分:4)
这是因为内存的分配方式。
在调用func
并返回悬空指针后,存储num
的堆栈部分仍然具有值100
(这是您之后看到的)。我们可以根据观察到的行为得出这个结论。
在更改之后,看起来会发生的事情是func1
调用覆盖了a
指向的内存位置以及func1
内的添加结果(之前的堆栈空间)用于func
的{{1}}现在由func1
重复使用,这就是为什么你会看到200。
当然,所有这些都是未定义的行为所以虽然这可能是一个很好的哲学问题,但回答它并不能真正为你买任何东西。
答案 2 :(得分:2)
这是未定义的行为。它现在可以在您的计算机上正常工作,从现在开始20分钟,可能在一小时内崩溃等等。一旦另一个对象在堆栈中占据同一个位置num
,您将注定!
答案 3 :(得分:1)
悬空指针(指向已解除关联的位置的指针)会导致未定义的行为,即任何事情都可能发生。
特别是,func1
中的偶然 *会重复使用内存位置。结果取决于堆栈布局,编译器优化,体系结构,调用约定和堆栈安全机制。
答案 4 :(得分:1)
使用悬空指针,程序的结果是未定义的。这取决于堆栈和寄存器的使用方式。使用不同的编译器,不同的编译器版本和不同的优化设置,您将获得不同的行为。
答案 5 :(得分:1)
返回指向局部变量的指针会产生未定义的行为,这意味着程序所做的任何事情(任何事物)都是有效的。如果你得到了预期的结果,那就是运气不好。
答案 6 :(得分:-1)
请从基本的C学习函数。你的概念有缺陷...... main
应该是
int main(void)
{
int *a = func();
int b;
b = func1();
printf("%d\n%d",*a,func1());
return 0;
}
这将输出100 200