这是一段简单的代码,我编写这些代码来检查返回局部变量的地址是否合法,编译器证明我的假设是正确的,并给出了相同的警告:
warning: function returns address of local variable
但是执行时会打印正确的地址......看起来很奇怪!
#include<stdio.h>
char * returnAddress();
main()
{
char *ptr;
ptr = returnAddress();
printf("%p\n",ptr);
}
char * returnAddress()
{
int x;
printf("%p\n",&x);
return &x;
}
答案 0 :(得分:5)
行为未定义。
当您调用未定义的行为时,允许发生任何事情 - 包括半理性行为。
返回局部变量的地址。它仍然是一个地址;如果你幸运的话,它甚至可能是一个有效的地址。如果您访问它指向的数据,您得到的是任何人的猜测 - 尽管您最好不知道。如果您调用另一个函数,则指向的空间可能会被新数据覆盖。
您应该收到有关int
指针和char
指针之间转换的警告,以及有关返回局部变量地址的警告。
答案 1 :(得分:4)
你要做的事情通常是危险的:
在returnAddress()
中,您在堆栈上声明了一个本地非静态变量i
。然后,一旦函数返回,您将返回其无效的地址。
此外,您尝试在实际拥有char *
时返回int *
。
要删除返回指向本地var的指针所引起的警告,可以使用以下代码:
void *p = &x;
return p;
当然打印它是完全无害的,但解除引用(例如int x = *ptr;
)它可能会导致程序崩溃。
但是,你正在做的是打破事情的好方法 - 其他人可能不知道你返回一个永远不能被解除引用的无效指针。
答案 2 :(得分:3)
是的,两次打印相同的地址。除此之外,当地址以main()
打印时,它不再指向任何有效的内存地址。 (变量x
是在returnAddress()
的堆栈框架中创建的,该函数在函数返回时被废弃。)
这就是产生警告的原因:因为你现在有一个你不能使用的地址。
答案 3 :(得分:1)
因为你可以访问局部变量的内存,并不意味着它是正确的事情。在函数调用结束后,堆栈指针回溯到它在内存中的先前位置,因此您可以访问函数的局部变量,因为它们不会被删除。但是没有保证这样的事情不会失败(比如分段错误),或者你不会阅读垃圾。
答案 4 :(得分:1)
哪个警告?我得到一个类型错误(你返回一个int *但类型说char *)和一个关于返回局部变量地址的警告。
类型错误是因为您为函数声明的类型是谎言(或统计?)。
第二个是因为这是一个疯狂的事情。该地址将在堆栈的中间(或者更确切地说,靠近顶部)发出。如果您使用它,您将踩踏数据(或通过后续函数调用让您的数据被踩踏)。
答案 5 :(得分:1)
这并不奇怪。函数的局部变量在该函数的堆栈中分配。一旦控件退出函数,局部变量就无效。您可以引用该地址,但可以用其他一些值替换相同的内存空间。这就是行为未定义的原因。如果要在整个程序中引用内存,请使用malloc进行分配。这将在堆中而不是堆栈中分配内存。您可以安全地引用它,直到您明确释放内存。
#include<stdio.h>
#include<stdlib.h>
char * returnAddress();
main()
{
char *ptr;
ptr = returnAddress();
printf("%p\n",ptr);
}
char * returnAddress()
{
char *x = malloc(sizeof(char));
printf("%p\n",x);
return x;
}