【问题标题】:Call Stack - while a function returns reference of local variable to the calling function which is followed by the call to another function调用堆栈 - 函数将局部变量的引用返回给调用函数,然后调用另一个函数
【发布时间】:2012-07-27 19:45:57
【问题描述】:
#include<stdio.h>

int *fun();
int main()    
{
   int *ptr;
   ptr=fun();
   printf("%d",*ptr);
   printf("%d",*ptr);
}
int * fun()
{
   int k=4;//If auto then cannot print it two times.....stack will be changed
   return(&k);
}

O/P: 4
    -2

第一次调用 printf() 会打印正确的值。

在调用 fun() 之后立即调用任何函数(甚至 printf())。这次 printf( ) 打印一个垃圾值。为什么会发生这种情况?为什么我们在第一个打印语句本身期间没有得到垃圾值????

【问题讨论】:

    标签: c callstack


    【解决方案1】:

    这不是您可以依赖的行为;在不同的系统,甚至不同版本的编译器或不同的编译器开关上,它可能并且很可能会有所不同。

    鉴于此,可能发生的情况是:fun 返回一个指向它存储 k 的位置的指针。堆栈的那部分不再可靠,因为分配它的函数已经退出。尽管如此,还没有人写过它,所以 4 仍然是它写的地方。然后 main 准备调用 printf。为此,它获取第一个参数 *ptr。为此,它从 ptr 点的位置加载,这是 k 的(前)地址,因此加载得到那里的 4。这 4 存储在要传递给 printf 的寄存器或堆栈位置中。然后存储格式字符串的地址“%d”以传递给 printf。然后调用 printf。此时,printf 使用了大量的堆栈,并在 k 以前的位置写入新数据。但是,作为参数传递的 4 是在一个安全的地方, printf 的参数应该是,所以 printf 打印它。然后 printf 返回。然后主程序准备再次调用 printf。这一次,当它从 ptr 指向的位置加载时,4 不再存在;这是在第一次调用 printf 时写入的一些值。因此,该值就是传递给 printf 的值并被打印出来。

    永远不要编写使用这种行为的代码。它不可靠,也不是正确的代码。

    【讨论】:

      【解决方案2】:

      为什么会让你大吃一惊?行为未定义,但观察您观察到的情况并没有什么异常。

      所有变量都存在于内存中的某处。当一个变量被正式销毁时(如函数退出时的局部变量),它曾经占用的内存仍然存在,并且很可能仍然保存最后写入的值。该内存现在正式空闲,但它将继续保持最后一个值,直到其他代码将该内存用于其他目的并覆盖它。

      这是您在实验中观察到的。即使变量k 不再存在,指针ptr 仍然指向它以前的位置。而那个以前的位置仍然恰好保存k 的最后一个值,即4

      第一个printf“成功”接收到该值的副本以进行打印。而第一个printf 实际上是重用旧内存位置并覆盖k 以前值的那个。所有进一步取消引用ptr 的尝试都将显示4 不再存在,这就是为什么您的第二个printf 会打印其他内容。

      【讨论】:

        【解决方案3】:

        变量kfun() 的局部变量,意味着它会在函数返回时被销毁。这是一种非常糟糕的编码技术,总是会导致问题。

        以及第一个printf返回正确值的原因:

        首先它可能会也可能不会返回值。假设k 写在堆栈内存的某个地方。第一次函数返回时 printf 可能会得到正确的值,因为这部分内存可能存在一段时间。但这不能保证。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-26
          • 1970-01-01
          • 2018-06-14
          • 1970-01-01
          • 2014-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多