首页 > C语言栈区变量和返回变量疑问?返回变量在系统内部是怎样的流程?

C语言栈区变量和返回变量疑问?返回变量在系统内部是怎样的流程?

比如程序1:

int* getIntArr()
{
    int ans[3] = {1,2,3};
    return ans;
}

int main()
{
    int* p = getIntArr();
    for(int i = 0;i < 3;i ++)
        printf("%d\n", *(p+i));
}

比如程序2:

int getInt()
{
    int ans = 3;
    return ans;
}

int main()
{
    int p = getInt();
    printf("%d\n",p);
}

可以知道第一个程序会打印乱码的,第二个会正常打印。返回变量在系统中具体是怎么样一个流程?栈在退出时,会申请一块地址,把返回值存储起来返回,还是直接返回我们指定的地址,比如上面的ans。

附一个完整的程序吧:

#include
#include
#include
#include
using namespace std;

int* f()
{
    int tmp[12];
    for (int i = 0;i < 12;i ++)
        tmp[i] = i;

    return tmp;
}

vector testVector()
{
    vector tmp;
    tmp.push_back(1);
    tmp.push_back(2);
    tmp.push_back(3);
    return tmp;
}
string testString()
{
    string tmp;
    tmp = "123";
    return tmp;
}
const char* testCharArr()
{
    return "123";
}

int main()
{
    int* p;
    p = f();
    for (int i = 0;i < 12;i ++)
        printf("%d\n", *p+i);
    vector t_vec = testVector();
    for ( int i = 0;i < t_vec.size();i ++)
        printf("%d\n", t_vec[i]);
    printf("%s\n",testString().c_str());
    printf("%s\n",testCharArr());
    return 0;
}

在栈上申请的内存会在函数返回后自动销毁

int* getIntArr()
{
    int ans[3] = {1,2,3};
    return ans;
}

函数返回只是将数组的首地址复制返回。
而在

int getInt()
{
    int ans = 3;
    return ans;
}

中,函数返回时,相当于拷贝了一个int类型的ans。
如果要返回一个连续的内存区域可以动态申请。

int* getIntArr()
{
    int *ans = malloc(sizeof(int) * 3);
    return ans;
}

PS: 如果是C++也适用,当然C++申请内存也可以用new


简单地说,从栈返回值时该值会被复制,不管它是整数、浮点数、字符、结构体还是指针。返回数组时,实际上返回的是数组的首地址(即一个指针)。

当返回的实际是一个指针时,这里的意思是说这个地址被返回了。如果它指向堆上的内存还好,你没主动释放那片内存就没问题。如果它指向栈上的内存(如你的程序一),那么在返回之后这个值就没有意义了(你只能知道曾经有那么一个数据在那片内存出现过)。

至于具体实现参考 @Jex 的答案。


提问者竟然更新上去了一段 C++ 代码……

声明:本答案只适用于 C。C++ 本人不会亦从未试图作答。


不同的编译器、不同的平台,实现的方式会有差别。理解这些至少需要一些前置知识:CPU Register(学过汇编的都知道)和Function call convention。

简单地讲,C函数只能返回array的指针。函数返回整型值和地址是使用的EAX寄存器(浮点型使用st0),
由于局部变量数据是分配在栈上,函数返回后,栈会被清掉,原来局部变量指针指向的内存区域的数据就不再有保证了。要实现返回array指针后,仍然读取到原来array的数据,则需要使用malloc。

这东西解释起来还有好多概念,
你需要补的知识是这些:

更新

我了个去,提问者竟然将代码又改成C++,还问返回string结果是怎样?题主你不会是看的谭浩强的C语言被误导了吧?

C中只不过有一个string literal,这个string literal的数据,是在编译时写到data section中的,这部分在运行时其实是全局的,函数返回后,这部分数据仍然存在。而普通的array,是直接分配在栈上的。同理,变通的方案,如果你将函数局部变量标记成static,则它在函数返回后仍然存在,返回static变量的指针是work的。

char * return_str() {
    char* s = "hello";
    return s;
}

上面的代码工作OK。因为"hello"是被分配到`.section .rodata`中的(如果只是static char array,则是`.section .data`),你也许注意到了rodata,说明这个string是不能被修改的,一修改就真的要上提问题了。(标准C禁止修改字符串字面量)

你要补的这方面的知识是这个:Data segment

如果还要寻根究底,则建议直接去看《Professional Assembly Language — Richard Blum》或《Computer Systems: A Programmer's Perspective》

【热门文章】
【热门文章】