一个朋友有次跟我探讨一段代码,其中涉及了局部变量被释放的问题,但是意外发现定义的局部指针变量在释放时候会有些奇怪的现象,借此我查找一些资料,写了测试佐证代码得出结论。不太清楚的朋友可以了解一下。
1.问题代码
#include "stdio.h"
#include "string.h"
int* get(int a ,int b)
{
int c = 0;
c = a + b;
printf("%p\n",&c);
return &c;
}
int main(void)
{
int *p = get(4,5);
printf("%p\n",p);
return 0;
}
gcc 编译时警告已经显示
Waning:函数返回了一个局部变量的地址
- 运行结果:
2.一次改动
这里我对返回的地址用指针存放,返回这个指针地址
#include "stdio.h"
#include "string.h"
int* get(int a ,int b)
{
int c = 0;
c = a + b;
int *d = &c;
printf("%p\n",&c);
return d;
}
int main(void)
{
int *p = get(4,5);
printf("%p\n",p);
printf("%d\n",*p);
return 0;
}
- 运行结果:
》》》发现没有警告,而且地址相同,甚至值也对的
但是经过测试发现,这个指针跟指向的值,其实都被回收了,只是没有人用而已,所以值才没有改变。
3.理论
-------------引用赵四老师:
a) : 栈中的变量通常包括函数参数和函数里声明的临时变量。
b) : 栈中的基本变量退出其作用域时,没有谁执行一段代码去释放/销毁/析构它所占用的内存,仅仅是没人再去理会的留在当前栈顶上方的若干遗留下来可被后续压栈操作覆盖的无用数据而已。
c) : 而栈中的类变量退出其作用域时,会自动执行其析构函数
4.佐证测试代码
#include <stdio.h>
int *global = NULL;
int *f(int c)
{
int b = c;
int *p1 = &b;
global = &b;
return p1;
}
int main()
{
int *p = f(6);
printf("p_addr : %p\n",p);
printf("p_num : %d\n",*p);
printf("global_addr : %p\n",global);
printf("global_num : %d\n",*global);
printf("*f(7) return : %d\n",*f(7));
printf("p_addr : %p\n",p);
printf("p_num : %d\n",*p);
printf("global_addr : %p\n",global);
printf("global_num : %d\n",*global);
}
- 运行结果:
5.总结
结果会发现,同一个地址,又被分配一次。
其实就是说,再一次执行这个函数时,你上次用这个函数返回的地址跟指向的内存地址,又被分配使用了,所以那样的使用是不安全的,那个对的数据,只是遗留下来可被后续压栈操作覆盖的无用数据
所以你访问一个被释放的局部变量,都是一个不安全的行为。返回可以返回数值,但是不能返回一个局部变量的地址