(1)c程序编译知识小科普:
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
(1)为什么要把堆和栈分开?
为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?
第一,从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。
这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。
第二,堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。
第三,栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
第四,面向对象就是堆和栈的完美结合。其实,面向对象方式的程序与以前结构化的程序在执行上没有任何区别。但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。不得不承认,面向对象的设计,确实很美。
测试程序如下:
#include "stdint.h"
#include "stdio.h"
#include "string.h"
int main(void)
{
uint8_t a = 0;
uint8_t b = 0;
char c = '1';
char d[3] = {0};
char e = '2';
printf("a[%p][%d]\n",&a, a);
printf("b[%p][%d]\n",&b, b);
printf("c[%p][%d]\n",&c, c);
printf("d[%p][%d], d1[%p][%d]\n",&d[0], d[0],&d[1],d[1]);
printf("e[%p][%d]\n", &e, e);
printf("stack overflow\n");
sscanf("user", "%s", d);
printf("a[%p][%d]\n",&a, a);
printf("b[%p][%d]\n",&b, b);
printf("c[%p][%d]\n",&c, c);
printf("d[%p][%d], d1[%p][%d]\n",&d[0], d[0],&d[1],d[1]);
printf("e[%p][%d]\n", &e, e);
}
测试结果如下:
测试结论:栈的生长方向是从上往下。但是,在栈中的数组,其生长方向是从下往上的