【问题标题】:returning a local variable from function in C [duplicate]从C中的函数返回局部变量[重复]
【发布时间】:2011-06-16 23:55:52
【问题描述】:
#include <stdio.h>

int foo1(void)
{
    int p;
    p = 99;
    return p;
}

char *foo2(void)
{
    char buffer[] = "test_123";
    return buffer;
}

int *foo3(void)
{
    int t[3] = {1,2,3};
    return t;
}

int main(void)
{
    int *p;
    char *s;

    printf("foo1: %d\n", foo1());
    printf("foo2: %s\n", foo2());
    printf("foo3: %d, %d, %d\n", p[0], p[1], p[2]);
    return 0;
}

当我用 gcc -ansi -pedantic -W -Wall 编译它时,编译器会发出 foo2() 和 foo3() 的警告消息:

warning: function returns address of local variable

我认为不允许返回局部变量,但是 foo1() 工作正常,返回指向局部对象的指针和对象本身之间似乎存在巨大差异。

有人能解释一下这个问题吗?提前致谢!

【问题讨论】:

    标签: c pointers local-variables


    【解决方案1】:

    这里的问题是,当您创建局部变量时,它被分配在堆栈上,因此一旦函数完成执行就无法使用(此处的实现有所不同)。最好的方法是使用malloc() 来保留非本地内存。这里的危险是您必须释放 (free()) 使用 malloc() 分配的所有内容,如果您忘记了,则会造成内存泄漏。

    【讨论】:

    • 另一个危险是如果你不重置(例如memset)分配的内存,它可能会从堆栈中泄漏信息。
    • @jweyrich 这时候calloc 就派上用场了,当然是连续分配。
    • @kelloti 如果我将局部变量声明为静态并返回它,它仍然不可用吗?
    • @AbdelAleem 那时它处于静态生命周期领域,所以它应该可用。
    【解决方案2】:

    对于foo1(),您返回局部变量的副本,而不是局部变量本身。

    对于其他函数,您返回一个指向局部变量的指针的副本。但是,当函数完成时,该局部变量会被释放,因此如果您在之后尝试引用它,最终会遇到令人讨厌的问题。

    【讨论】:

      【解决方案3】:

      任何变量在内存中都有一些空间。指针引用该空间。局部变量占用的空间在函数调用返回时被释放,这意味着它可以并且将被重用于其他事情。因此,对那个空间的引用最终会指向完全不相关的东西。 C 中的数组被实现为指针,所以这最终适用于它们。并且在函数中声明的常量数组也算作本地的。

      如果要在创建它的函数范围之外使用数组或其他指针,则需要使用 malloc 为其预留空间。使用 malloc 保留的空间在通过调用 free 显式释放之前不会被重新分配或重用。

      【讨论】:

      • +1。实际上,这意味着您需要在堆上而不是在堆栈上分配返回值。您需要在要返回的“数组”上使用 malloc 或 similair。或者更好的是,将指向缓冲区的指针 + 缓冲区长度作为参数。
      • @stefan:是的,这是一个很好的观点。我在答案中添加了更多关于如何解决这个问题的建议。
      • 'C 中的数组被实现为指针'过于简单化了;它是上下文可接受的边界线,但数组和指针之间存在重大差异(以及许多相似之处)。
      • @Jonathan Leffler:我不知道有什么不同。类型系统对它们的处理方式相同,并且引用和取消引用编译到同一个程序集,无论它是数组引用还是指针。如果你有 int *ip,那么 *ip 和 ip[0] 是可以互换的。 *(ip+1) 和 ip[1] 也是如此。这可能只是我不知道的事情,但是 C 中的数组和指针有何不同?
      • 考虑:char *a = "a"; char b[] = "b"; char *c; char d[] = "d";。可以写:c = a;c = b;,但是不能写b = a;或者b = d;,这是数组和指针的一个重要区别。
      【解决方案4】:

      是的,您正在返回一个数组,它实际上是一个在幕后的指针,指向存储您已初始化的变量内容的内存位置的地址。因此,它警告您,返回这样的结果可能没有那么有用,而您可能真的指的是数组值之一。

      【讨论】:

        猜你喜欢
        • 2015-08-11
        • 2023-04-09
        • 2021-04-03
        • 1970-01-01
        • 2013-01-30
        • 1970-01-01
        • 1970-01-01
        • 2013-08-16
        • 2016-01-19
        相关资源
        最近更新 更多