目录
1、为什么可以返回局部变量
int test() {
int a = 10;
return a;
}
int main() {
int b = test();
printf("%d\n", b);
return 0;
}
每调用一次函数,编译器就会为这个函数在栈上开辟一块空间,在main函数中声明的局部变量也都在这块空间里,因此在调用main函数的时候,其实也会开辟一块空间。
调用test函数的时候,也会分配一块空间,test函数中的局部变量 a 放在 test函数所在栈空间里。
函数执行完毕或者函数返回的时候,这块空间就会被销毁,test函数返回了 a 的值,其实在返回之前,a 的值先会被保存到一个寄存器中,然后再销毁test函数的栈。
这里说的销毁并不是真的销毁,栈空间是否被使用,其实是通过一对指针 ebp 和 esp 来维护的,ebp 指向起始位置,esp 指向末尾位置,这两者之间的空间是当前程序可以使用的。栈空间的销毁也只是指针的移动而已。
实际上函数所返回的变量的值,其实是原变量的拷贝,因此,我们可以返回局部变量。
2、为什么不能返回局部变量的地址
(1) 提出问题
======================= 第一种情况 =======================
int* test() {
int a = 10;
return &a;
}
int main() {
int* b = test(); //error,编译器不会报错
printf("%d\n", *b);
return 0;
}
打印结果如下,打印的结果依然是10,因为保存了 a 的地址,就可以定位到内存上的任意位置,即便是不在 ebp 和 esp 划定的范围内,依然可以访问到。
======================= 第二种情况 =======================
在原本的基础上,新增一句话
int* test() {
int a = 10;
return &a;
}
int main() {
int* b = test(); //error,编译器不会报错
printf("hello\n");
printf("%d\n", *b);
return 0;
}
打印结果如下,我们发现打印的结果不是10 了,这是为什么?
(2) 分析问题
在 test函数调用以后,内存中的情况如下
第一种情况下,此时已经保存了变量 a的地址,虽然无法使用变量名直接访问,但是使用地址访问是不受限制的。因此,打印出来的结果是 10
第二种情况下,在打印之前,先调用了printf("hello\n"),printf也是函数,调用时会被分配一块空间,此时旧的test函数的空间会被新的 printf函数的空间 覆盖,后面就无法再访问 变量 a了,因为原本的 空间已经被覆盖了。
因此,函数返回的时候,不能返回局部变量的地址,因为原本的局部变量很可能会被新的空间覆盖导致无法访问到。