比如程序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。
这东西解释起来还有好多概念,
你需要补的知识是这些:
- Calling convention
- 通常我们都是使用x86平台,可以直接看这个:x86 calling conventions
更新
我了个去,提问者竟然将代码又改成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》