对于一个C语言程序,内存空间主要由5个部分组成:代码段(.text),数据段(.data),BSS区,堆,栈
代码段:代码区(text segment)。存放CPU执行的机器指令(machine instructions)。通常,代码区是可共享的(即另外的执行程序可以调用它),因为对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指令。另外,代码区还规划了局部变量的相关信息。
数据段:存放已初始化全局变量,静态变量(包括全局静态变量和局部静态变量),和常量数据(例如常量字符串)
BSS:未初始化数据区,Uninitialized data segment,存入的是未初始化全局变量,未初始化静态变量,初始化为0的全局变量,初始化为0的静态变量。例如不在任何函数内的声明:int a;BSS 是英文Block Started by Symbol 的简称。BSS 段属于静态内存分配,即程序一开始就将其清零了。一般在初始化时BSS段部分将会清零。
堆:用于动态内存分配,程序员自己分配和释放
栈:编译器自动分配和释放,存放局部变量,函数参数,返回数据等。
栈是向下增长的,堆是向上增长的,最大化了可用空间。
下面是详细一点的图(照着https://blog.csdn.net/second60/article/details/79946310)
这几篇博客的图画的不错
https://www.cnblogs.com/beixiaobei/p/10507462.html
https://blog.csdn.net/rdgfdd/article/details/79190557
我看有的把data区包括了bss区,有的分开的,我觉得不影响。
整形常量占内存问题:
https://m.imooc.com/wenda/detail/538760
例如 int a = 1;
a占4个字节内存,常量1也占4个字节。
整型常量也是要占用内存的,但占用的内存位置有所不同。一般来说,基本类型(整型、字符型等)常量会在编译阶段被编译成立即数,占的是代码段的内存,而字符串常量或基本类型的常量数组占用的是数据段内存。当然,占代码段的内存一般不在我们常说的“占内存”范围中。
关于静态存储区与动态存储区
https://msd.misuland.com/pd/2884250137616452012?page=1#4__145
静态存储区:
1. 静态存储区是随着程序的运行而分配空间
2. 静态存储区的生命周期直到程序运行而结束
3. 在程序的编译期间,静态存储区的大小就已经确定
4. 静态存储区主要用于保存全局变量和静态局部变量以及类似于字符串字面量样式的字面量
动态存储区:栈、堆
初始化为0的全局变量和初始化为0的静态变量存储位置
我们知道未初始化的全局变量和未初始化的静态变量是存储在BSS区的,而初始化为0的全局变量和初始化为0的静态变量同样存储在BSS区,而不是存储在数据区
看一段程序运行结果: 摘自https://bbs.csdn.net/topics/390386973?list=9788915
#include <stdio.h>
int a = 0;
int b;
int c = 1;
int main()
{
static int d = 0;
static int e;
static int f = 2;
printf("%p\n", &a);
printf("%p\n", &b);
printf("%p\n", &c);
printf("%p\n", &d);
printf("%p\n", &e);
printf("%p\n", &f);
return 0;
}
这么不明显,我都不知道结论是不是对的了。下面把这几个变量都初始化看看运行结果:
#include <stdio.h>
int a = 1;
int b = 1;
int c = 1;
int main()
{
static int d = 1;
static int e = 1;
static int f = 2;
printf("%p\n", &a);
printf("%p\n", &b);
printf("%p\n", &c);
printf("%p\n", &d);
printf("%p\n", &e);
printf("%p\n", &f);
return 0;
}
这个结果很明显,都是顺序存的,和上面一个程序比较,可以看出还是有差别的。
const修饰的变量的存储位置
const修饰的局部变量存储在栈上,const修饰的全局变量存储在数据区。
#include <stdio.h>
int main(int argc, char const *argv[])
{
const int a = 1;
int *p = &a;
*p = 10;
printf("a=%d\n",a);
return 0;
}
这里程序编译会报一个警告,意思是说int* p前面应该加上const,我们不管它,运行后,a的值更改了,变成了10,说明a存储在栈。
再来看,const定义全局变量的存储位置:
#include <stdio.h>
const int a = 1;
int main(int argc, char const *argv[])
{
int *p = &a;
*p = 10;
printf("a=%d\n",a);
return 0;
}
编译报警,运行时发生段错误,说明a的值不能更改,a存储在数据区。
数据段合并:
在链接的时候,代码段和常量区会合并,BSS和初始化全局变量/静态变量区会合并
修改字符串常量值问题
#include <stdio.h>
char *s = "hello";//报错
int main()
{
char *s = "hello";
*(s+1)='H';//报错
printf("%s\n", s);
return 0;
}
*/
无论常量定义在哪都报错。VS和GCC中都不行,通过指针也不行。
参考:
https://www.cnblogs.com/tuhooo/p/7221136.html
https://blog.csdn.net/second60/article/details/79946310
https://blog.csdn.net/zhy557/article/details/80832268