内存四区
1栈区
由编译器自动分配释放 ,存放函数的参数值,局部变量的值等
2.堆区
一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
3.静态全局数据区
主要包括静态全局区和常量区
- char *s = "HelloWorld";//该字符串 HelloWorld 即存放于文字常量区,不可修改。但指针s存放于栈区。
若在程序中尝试对其修改(例如尝试修改第一个字符 *s = 'h';),将出现编译可通过,运行报错的情况。
- 同时因注意它与const修饰的变量之间的区别:
char aa = 'A';//aa存放于栈区
const char bb = 'B'; //bb同样存放于栈区
const修饰的变量仅仅用于告诉编译器bb是一个常量,如果后续的程序中有出现尝试修改bb的操作时,编译将报错。
这种写法主要是为了防止程序员在后续的代码中误操作bb变量而添加的一个约束条件,并不会影响它存放的位置。
4.代码区
存放函数体的二进制代码。用于存储程序编译连接后生成的二进制机器码指令的内存区域
区别
-
能否产生碎片
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题。 -
生长方向不同
对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长。 -
分配方式不同
堆都是动态分配的;栈有静态和动态两种分配方式。静态分配由编译器完成,比如局部变量的分配。动态分配由alloca函数进行、但栈的动态分配和堆是不同的,它的动态分配由编译器进行释放,无需我们手工实现。 -
分配效率不同
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是c/c++库函数提供的,机制很复杂。库函数会按照一定的算法进行分配。显然,堆的效率比栈要低得多。 -
Buf的生长方向
如数组生长方向都是由低地址到高地址生长,和栈的生长方向无关
实验
代码
int add(int x, int y);
int sub(int x, int y);
int main() {
int c = 30;
int d[10];
int *p=malloc(sizeof(int)*2);
int *p1=malloc(sizeof(int));
printf("-----static--------\n");
printf("%x\n", &a);
printf("%x\n", &b);
printf("------stack-------\n");
printf("%x\n", &c);
printf("%x\n", &d);
printf("%x\n", &p);
printf("%x\n", &p1);
add(a,b);
sub(b,c);
printf("------heap-------\n");
printf("%x\n", p);
printf("%x\n", p1);
printf("------code-------\n");
printf("%x\n", add);
printf("%x\n", sub);
}
int add(int x, int y) {
printf("%x\n", &x);
printf("%x\n", &y);
return x + y;
}
int sub(int x, int y) {
printf("%x\n", &x);
printf("%x\n", &y);
return x - y;
}
结果
-----static--------
405008
40500c
------stack-------
28ff3c
28ff14
28ff10
28ff0c
28fef0
28fef4
28fef0
28fef4
------heap-------
4629f0
462a00
------code-------
401933
401969
- 栈地址的增长方向是由高->低
- 堆地址的增长方向是由低->高
- 静态全局数据区的增长方向是由低->高