在编译下面的代码时出现警告背后可能的原因是什么?

时间:2011-05-25 06:31:30

标签: c

这是一段简单的代码,我编写这些代码来检查返回局部变量的地址是否合法,编译器证明我的假设是正确的,并给出了相同的警告:

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;
}

6 个答案:

答案 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;
}