【问题标题】:scope rules in CC中的范围规则
【发布时间】:2011-12-10 03:43:16
【问题描述】:

我最近阅读了 C 中的作用域规则。它说局部变量或自动变量仅在声明它的函数块内可用。一旦在函数之外,它就不再可见。此外,它的生命周期只到函数体的最后一个右大括号结束。

现在问题来了。当局部变量的地址从函数返回给调用函数时会发生什么?

例如:-

 main()
 {
     int *p=fun();
 }

 int * fun()
 { 
     int  localvar=0;
     return (&localvar);
 }

一旦控制从函数 fun 返回,变量 localvar 就不再存在。那么 main 怎么才能访问到这个地址的内容呢?

【问题讨论】:

  • 对所有函数使用显式返回类型,包括main。因此:int main(void).
  • 挠头。务实地说,您不会返回地址。您将返回 localvar 中的值,在这种情况下,该函数声明是错误的(因为它需要返回 int 而不是 int *)。
  • 查看我标记为重复的问题。措辞略有不同,但代码相同,并且 Eric Lippert 给出了出色的答案。
  • @user980153 您无需将相同的评论复制并粘贴到每个人的答案中。

标签: c


【解决方案1】:

可以返回地址,但无法可靠地读取存储在该地址处的值。事实上,甚至不清楚您是否可以安全地分配它,尽管在大多数机器上可能不会有问题。

您通常可以读取地址,但行为未定义(读取“糟糕:不惜一切代价避免!”)。特别是该地址可能用于其他函数中的其他变量,所以如果你在调用其他函数后访问它,你肯定不太可能看到返回指向它的指针的函数最后存储在变量中的值。


那么为什么需要一个返回指针的函数呢?

一个原因通常是“动态内存”。 malloc() 系列函数返回一个指向新(非堆栈)内存的指针。

另一个原因是“在传递给我的值中在这个位置找到了一些东西”。考虑strchr()strstr()

另一个原因是“返回指向静态对象的指针,该对象隐藏在函数中或包含函数源的文件中”。考虑asctime() 等人(并担心线程安全)。

可能还有其他一些,但这些可能是最常见的。

请注意,这些都不会返回指向本地(基于堆栈)变量的指针。

【讨论】:

  • 是的,这正是我的猜测。但是,您能否详细说明为什么需要返回指针的函数?我的意思是它有什么用,因为每次我们尝试从函数返回局部变量的引用或地址到调用函数时,都是一样的,上面的解释是正确的。 ——
【解决方案2】:

变量已消失,但内存位置仍然存在,甚至可能仍包含您设置的值。然而,随着更多函数被调用并且内存地址被另一个函数的局部变量重用,它可能会很快被覆盖。您可以通过阅读 Call Stack 了解更多信息,这里存储了函数的局部变量。

【讨论】:

  • 是的,这正是我的猜测。但是,您能否详细说明为什么需要返回指针的函数?我的意思是它有什么用,因为每次我们尝试从函数返回局部变量的引用或地址到调用函数时,都是一样的,上面的解释是正确的。 ——
  • 在处理大型数据结构时,返回指针很有用,您不希望一直按值传递,因为它效率低下。这些大型结构通常使用 malloc() 在堆上分配,然后将指向数据的指针传入和传出函数。
【解决方案3】:

在函数返回后引用内存中的那个位置是危险的。当然该位置仍然存在(并且它可能仍然包含您的值),但是您不再对该内存区域有任何要求,并且随着程序的继续并且在堆栈上分配新的局部变量,它可能会被新数据覆盖。

gcc 给了我以下警告:

t.c: In function ‘test’:
t.c:3:2: warning: function returns address of local variable [enabled by default]

考虑这个测试程序:

int * test(int p) {
    int loc = p;
    return &loc;
}

int main(void) {
    int *c = test(4);
    test(5);
    printf("%d\n", *c);
    return 0;
}

你觉得这会打印什么?

【讨论】:

  • 是的,这正是我的猜测。但是,您能否详细说明为什么需要返回指针的函数?我的意思是它有什么用,因为每次我们尝试返回一个局部变量的引用或地址,从函数到调用函数,都是一样的,上面的解释成立。
  • @user980153 - 回答这个问题需要了解在堆栈上分配与在堆上分配之间的区别。
猜你喜欢
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
  • 2015-06-02
  • 1970-01-01
  • 2013-02-14
相关资源
最近更新 更多