直接看这个例子
void test()
{
char b[25];
printf("%s\n",b);
b[0]= 'a';
b[1] = 'b';
b[2] = 'c';
b[3]= '\0';
printf("%s\n",b);
}
对于上面的test函数, 如果连续调用两次, 会得到什么样的输出
答案是:
???
abc
abc
abc
这是我实际测出的值, 我当时很迷惑, 为什么b是局部数组, 当函数结束时这部分内存就被释放了, 而第二次调用test时, b数组的值仍然是abc.
可能有人说局部数组是存放在静态存储区的..., 对吗?
好, 下面就来解答这个问题,
编译时程序分为3段:text段,data段,bss段
text段:就是放程序代码的,编译时确定,只读,
data段:存放在编译阶段(而非运行时)就能确定的数据,可读可写,就是通常所说的静态存储区,赋了初值的全局变量和静态变量存放在这个区域,常量也存放在这个区域
bss段:定义而没有赋初值的全局变量和静态变量,放在这个区域
运行时程序还需要的区域
堆栈 (stack): stack就是存放局部变量, 临时变量的, 如调用函数时, 存放函数的局部变量
堆 (heap):heap就是用来存放动态分配的内存的, 即是通过malloc或是new分配的
明确一点, 局部变量一定是存放在堆栈的, 不可能放在静态区, 除非你加上static, 那么为什么会出现上面的现象?
透过现象看本质...
首先要理解堆栈的实现, 对于我们说的堆栈压入, 抛出操作, 并不是象我们想的那样实现的, 抛出后内容就不存在了
堆栈的操作就是通过移动栈顶指针实现的, 栈顶指针和栈底指针之间就是当前堆栈的大小
所以第一次调用test时, 分配了25字节的堆栈空间, 此时栈顶指针加25, 你对前4个字节赋值, 当函数结束时, 进行抛出操作, 即栈顶指针减25
但要注意, 此时系统并不会自动清空这25字节, 即他们仍然保留原来的内容.
第二次调用test时, 仍然分配了25字节的堆栈空间, 此时栈顶指针再加25, 其实这只是巧合, 分配了和第一次调用相同的空间, 并且内容都一样.
这就解释了我们上面说的那个问题.
想要验证很容易, 只需要在两次test调用中, 调用一次其他函数, 如果该函数修改了那段堆栈, 那么在第二次test中,就不会看到abc的初始值了. 这里绝对不要误认为局部数组是放在静态存储区的......千万不能被现象所迷惑...
总结
1. 通过malloc, 或局部数组分配的堆空间或堆栈空间, 首先用memset清0, 这是很多新手会忽视的, 这个很重要, 刚分配的空间的内容是不可预知的, 不清空很容易会影响程序的逻辑.
2. 在函数中不应该直接创建大的数组, 因为局部变量是分配在堆栈上的, 这样做, 不但效率不高, 而且会导致堆栈溢出, 堆栈空间是有限的.
对于大的数组, 应该通过malloc分配堆空间来解决.
本文章摘自博客园,原文发布日期:2011-07-05