3

这是关于假设变量范围的一个非常基本的问题。我有以下代码:

int main()
{
    int *p;
    p=func();
    printf("%d",*p);
    return 0;
}

int *func()
{
   int i;
   i=5;
   return &i;
}

我的问题

  • i 的范围已完成,func()但是,由于我要返回的地址,i我可以访问print5 inmain()吗?
  • 如果不是,为什么?编译器是否在该地址空间中放置了一个垃圾值(我认为这还没有完成)。
  • 它实际上是什么意思the scope of a variable is ended?分配给的内存i是否在其范围结束时被释放?
4

5 回答 5

4

变量的范围是可以访问它的区域。
变量的生命周期是保证变量存在的时间。

在您的情况下,生命周期i功能范围内而不是超出功能范围内。这意味着i不保证在功能之外存在。访问函数之外的局部变量不是必需的,而且是未定义的行为。

的范围i已完成,func()但是,由于我要返回的地址,我i可以访问和打印吗?5main()

你可能会,但它是未定义的行为。所以不要这样做。

如果不是,为什么?编译器是否在该地址空间中放置了一个垃圾值(我认为这还没有完成)

编译器可以将它选择的任何内容放在该位置,一旦函数返回地址位置保存一个Indeterminate值。

变量的范围结束实际上意味着什么?分配给的内存i是否在其范围结束时被释放?

i是一个自动/局部变量,一旦声明它们的范围结束{,所有自动变量都会被释放。}因此名称自动。

于 2012-11-06T08:57:39.567 回答
2

超出范围后访问变量是未定义的行为。这意味着不可能说肯定会发生什么。在发布的代码中,5可能会打印一些其他值,或者可能会发生一些其他行为(例如访问冲突)。

于 2012-11-06T08:57:51.690 回答
2

您示例中的行为未定义。您printf可能会输出 5 但这取决于运气而不是良好的设计。

在这种情况下,当变量的作用域结束时,进一步的函数调用可能会重用堆栈地址&i来更改p变量指向的值。

于 2012-11-06T08:58:01.987 回答
2

不,访问超出范围的变量会导致未定义的行为。v 变量曾经所在的存储空间已被回收,因此您可能会覆盖其他可能导致崩溃或无法预测的行为的内容。

于 2012-11-06T08:58:22.420 回答
2

您的函数可能会打印 5,但您永远不应该这样做。这是未定义的行为,因为您的程序不再拥有返回的指针所指向的位置(换句话说,您的程序不再拥有i)。

基本上每次调用函数时,堆栈指针都会被下推以容纳新的堆栈帧。当函数调用结束时,堆栈指针会重新升起。这意味着如果要调用不同的函数,它将与前一个函数调用重叠相同的堆栈空间。

为了更好地说明这一点,请考虑以下内容:

int main()
{
    int *p;
    p=func();
    printf("%d\n",*p);
    func2();
    printf("%d\n",*p);
    return 0;
}

int *func()
{
   int i;
   i=5;
   return &i;
}

void func2()
{
    int i = 1;
}

输出很可能是 5 1。这是因为第二次调用将重用相同的堆栈空间。

(请注意,上面的代码片段很糟糕——你永远不应该做这样的事情——它是未定义的行为并且高度依赖于实现。)


直接回答您的问题:

i 的范围在 func() 中完成,但是,由于我返回 i 的地址,我是否能够在 main() 中访问和 print5?

不,你可以,但你不应该。这就是 C 的美妙之处。根据编译器/操作系统/等,它可能输出 5,或者它可能输出随机车库。

如果不是,为什么?编译器是否在该地址空间中放置了一个垃圾值(我认为这还没有完成)。

用于局部变量的空间被重用。希望答案的前半部分说明了这是如何工作的。(嗯,它通常是如何工作的。)

变量的范围结束实际上意味着什么?分配给 i 的内存是否在其范围结束时被释放?

基于堆栈的内存分配是幕后发生的事情。

于 2012-11-06T08:58:32.337 回答