我们平常写的程序,要想运行必须是要借助真实的物理空间(内存),每一个程序至少是有一个进程,因为操作系统中进程是资源分配的基本单位,程序的中的各种变量,还有代码段,在我们内存中按照指定的方式进程存储可以分为堆,栈,bss,data,text,rodata,常量段。
存储段 | 作用 | 性质 |
---|---|---|
栈 | 存放程序运行时,临时创建的局部变量,在函数被调用时,函数的参数和函数内部变量压栈,调用结束后,出栈。 | RW |
堆 | 存放程序运行时,动态分配的内存段,malloc.free函数 | RW |
bss | 存放程序中未初始化的全局变量,只是一个占位符并不占据内存空间 | RW |
data | 存放程序中已经初始化的全局变量和静态变量(static修饰) | RW |
text | 存放程序执行代码和一些常量,如字符串常量,define定义 | R |
size 查看文件大小
text和data段的内容存在与磁盘中;
bass段存放的是变量的名字和大小,变量并不实际存在于磁盘中;
堆和栈由程序运行时分配。
1.关于bss和data存放的数据的思考(原文)
有两段代码:
程序A
int ar[30000];
void main()
{
}
程序B
int ar[300000] = {1, 2, 3, 4, 5, 6 };
void main()
{
......
}
会发现程序B编译后得到的exe运行文件,比程序A大。
因为:A中的arr变量未初始化,存在bss段中,B中的arr初始化了存在与data段中, .bss是不占用.exe文件空间的,具体体现为一个占位符data却需要占用,其内容由程序初始化。
bss段并不给该段的数据分配空间,只是记录数据所需空间的大小, BSS段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含DATA和BSS段的整个区段此时通常称为数据区。
2.关于字符串常量的思考(原文)
字符串常量位于text段,只能读,对于以数组定义字符串和指针定义字符串就有了区别。
//数组定义
char str[] = "hello, world";
str[1] = 'a'; //可以
str++; //不可以
//指针定义
char *str = "hello, world";
str[1] = 'a'; //不可以
str++; //可以
原因是:
使用数组名时,数组名是隐式被const修饰的指针,一个常量指针,其指向的地址不能修改。
使用指针时 “hello, world” 是一个字符串常量,str 的确指向其地址,但该地址存在于在进程的 text 段,不可以改变其中的内容。
同时对于char * 与char[] (链接)
1.char指向的区域有时可写,有时只读。
2.char * a=”string1”;是实现了3个操作:
1声明一个char变量(也就是声明了一个指向char的指针变量)。
2在内存中的文字常量区中开辟了一个空间存储字符串常量”string1”。
3返回这个区域的地址,作为值,赋给这个字符指针变量a
最终的结果:指针变量a指向了这一个字符串常量“string1”
******如果这时候再执行:char * c=”string1”;则,c==a,
******只会执行上述步骤的1和3,因为这个常量已经在内存中创建
3.char b[]=”string2”;则是实现了2个操作:
1声明一个char 的数组,
2为该数组“赋值”,将”string2”的每一个字符分别赋值给数组的每一个元素,存储在栈上。
最终的结果:“数组的值”(注意不是b的值)等于”string2”,而不是b指向一个字符串常量
4.函数形参中,数组退化成指针,所以传递的形参数组大小可以不为实参的大小
(sizeof()占用字节的多少,strlen()字符串从开头到‘\0’的长度)
/*
char * a=”string1”; 的写法是不规范的
*/
char * a="string";
char b[]="string2";
strcpy(a,"string2"); //错误 因为a指向的是text段的内存,只能读
a = b;
strcpy(a,"string2"); //可以 因为a指向的是栈区的内存,可读可写
/*
"Hello World"字符串常量,位于text段
char *a ;char b[]位于栈区
a指向的地址是text段的地址,a本身的地址是栈区地址
b指向的地址是栈区的地址 = b本身的地址是栈区地址
*/
char *a="Hello World";
char b[]="Hello World";
printf("%s, %d\n","Hello World", "Hello World"); //Hello World 13457308
printf(“%s, %d %d\n”, a, a, &a);//Hello World 13457308 2030336
printf(“%s, %d %d\n”, b, b, &b);//Hello World 2030316 2030316
void Foo(char strOutSide[128])
{
void* p = malloc(256);
char strInside[128];
int output = sizeof(p) + sizeof(strOutSide) + sizeof(strInside);
print(output);
}
/*
函数里面的数组名退化成指针(所以传递的形参数组可以不为128),最后是8+8+128
*/
3.局部变量被static修饰后,寿命周期改变
原因式static修饰的变量存储在data段,不会和函数中其它变量一样,函数退出后出栈。