目录
1 C语言的内存分区
1.1 内存五大分区
1.2 内存分区简介
1.2.1 栈区(stack)
1.2.2 堆区(heap)
1.2.3 (全局)静态区
1.2.4 常量区
1.2.5 代码区
创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。
C语言已经持续学习一段时间了,今天特此总结一下关于C语言内存的五大区。它是我们深入理解C语言非常有必要了解的知识点。通过了解五大区,对于进一步学习C语言底层是非常有帮助的。
1 C语言的内存分区
1.1 内存五大分区
C语言内存可大致分为5个区域,图和表如下:
内存影像区 | 内容 | 权限 |
栈区 | 函数中的普通变量 | 可读可写 |
堆区 | 动态申请的内存 | 可读可写 |
(全局)静态变量区 | static修饰的变量 | 可读可写 |
常量区 | 用于初始化变量的常量 | 只读 |
代码区 | 代码指令 | 只读 |
nt k=1; void main() { int i=1; char *j; static int m=1; char *n="hello"; printf("栈区地址为:0X%x\n",&i); j = (char*)malloc(2); //一般不确定需要多大空间的时候用 free(j);//及时释放 printf("堆区地址为:0X%x\n",j); printf("全局变量地址为:0X%x\n",&k); printf("静态变量地址为:0X%x\n",&m); printf("文字常量区地址为:0X%x\n",n); printf("程序区地址为:0X%x\n",&main); } char *i="hello"; char j[10]="hello"; printf("0X%x\n",i); //存放在文字常量区 printf("0X%x\n",j); //存放在栈区 j[1]='*';//可以直接赋值 //*(i+1)='*'; //等价于i[1]='*'; //不可以这样赋值, 因为i是指针,指向的是文字常量区,里面的内容是不能修改的 i=j; //这样可以 printf("%s\n",i); printf("%x\n",i); j=i;//这样不可以,因为j虽然也是地址,但是不是指针变量,不能直接赋值
1.2 内存分区简介
1.2.1 栈区(stack)
栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理。
栈区上的内容只在函数范围内存在,当函数运行结束,这些内容也会自动被销毁。
#include char *getMem() { char buf[64]; //局部变量 栈区存放 strcpy(buf, "123456789");//向buf所代表的内存中写入内容 //printf("buf:%s\n", buf); return buf;//返回所分配内存区域的第一个元素的地址 } void main() { char *tmp = NULL; tmp = getMem(10); if (tmp == NULL) { return ; } printf("tmp:%s\n", tmp);//输出tmp: system("pause"); return ; }
内存分析:
- 栈区按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
- 栈区是先进后出原则,即先进去的被堵在屋里的最里面,后进去的在门口,释放的时候门口的先出去。
栈区存放内容
- 临时创建的局部变量和const定义的局部变量存放在栈区。
- 函数调用和返回时,其入口参数和返回值存放在栈区。
通俗来说:
栈区是用来存放局部变量的,比如函数内部定义的int a,int b,const int a,char p,char arr[ ],还有函数的形参等等都是存放在栈区。栈区的数据由编译器管理,调用完之后就自动释放,压栈,出栈。先进后出的原则,比如当你执行到函数调用的时候,编译器会先把下一条代码的地址压入栈中,再把你调用的那个函数里的一些局部变量啊,形参啊等等压入栈中,等你函数调用执行完毕。栈就会把你调用的这个函数之前压入栈的变量和形参全部清除出栈,之后根据下一条代码的地址,接着执行程序,以后的程序也都是这么执行。栈区是有大小的,一般是1M左右,所以别定义太大的数组。
1.2.2 堆区(heap)
堆区由程序员分配内存和释放。若程序员不释放,程序结束时可能由操作系统回收。
#include char *getMem(int num) { char *p1 = NULL; p1 = (char *)malloc(sizeof(char) * num); if (p1 == NULL) { return NULL; } return p1; } void main() { char *tmp = NULL; tmp = getMem(10); if (tmp == NULL) { return ; } strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据,注意不是向指针变量tmp中 printf("tmp:%s\n", tmp);//输出tmp:111222 system("pause"); return ; }
内存分析:
- 堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
堆区动态申请与释放内存
用malloc(),free()等函数实现动态分布内存。
void *malloc(size_t);
- 参数size_t是分配的字节大小;
- 返回值是一个void*型的指针,该指针指向分配空间的首地址;
(void *型指针可以任意转换为其他类型的指针)
用free()函数进行内存释放,否则会造成内存泄漏。
void free(void * /*ptr*/);
- 参数ptr是开辟的内存的首地址。
- 无返回值;
通俗来说:
由程序员手动申请和释放
比如:int p=(int )malloc(sizeof(int)10),表示申请了一块40个字节的堆区空间,然后申请完记得用free释放。
代码区的话就是用来存放代码的,转化为二进制存放。
1.2.3 (全局)静态区
通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。
全局区有 .bss段 和 .data段组成,可读可写。
#include char * getStr1() { char *p1 = "abcd"; return p1; } char *getStr2() { char *p2 = "abcd"; return p2; } void main() { char *p1 = NULL; char *p2 = NULL; p1 = getStr1(); p2 = getStr2(); //打印p1 p2 所指向内存空间的数据,不是p1 p2中的数据 printf("p1:%s , p2:%s \n", p1, p2);//输出p1:abcd , p2:abcd //打印p1 p2 的值 printf("p1:%d , p2:%d \n", p1, p2);//输出p1:19184372 , p2:19184372 system("pause"); return; }
内存分析:
- .bss段
未初始化的全局变量和未初始化的静态变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容由操作系统初始化。
- .data段
已初始化的全局变量存放在.data段。
已初始化的静态变量存放在.data段。
.data段占用可执行文件空间,其内容有程序初始化。
通俗来说:
全局区比较特殊,里面还分成了全局变量区,静态变量区,常量区。全局变量区用来存放全局变量,静态变量区用来存放带有static修饰的变量(包括静态局部变量和静态全局变量),只要含有static就存在这个区。常量区是用来存放字符常量的,还有const修饰的全局变量的,const 修饰的局部变量不存在这里,别搞混了。全局区存放的一切都是由操作系统管理,等程序结束由操作系统释放。常量区里存放的数据不可更改,就算你用指针也不行,你可能会说const修饰的局部变量都可以用指针改,但是局部变量可不是存放在常量区,这点搞清楚。
1.2.4 常量区
字符串、数字等常量存放在常量区。
const修饰的全局变量存放在常量区。程序运行期间,常量区的内容不可以被修改。
1.2.5 代码区
程序执行代码存放在代码区,其值不能修改(若修改则会出现错误)。
字符串常量和define定义的常量也有可能存放在代码区。以上五区,代码区和全局区是在生成.exe文件之后就有了,双击.exe文件运行程序才会生成栈区和堆区。
下面直接上图:
#include #include int a = 10; static int b = 20; void fun(int x) { char *p = "Hello"; printf("形参x的地址=%d\n\n", &x); printf("Hello的地址=%d\n\n", "Hello"); printf("指针变量p的地址=%d\n\n", &p); return; } int main(int argc,const char *argv[]) { int c = 10; int d = 20; static int e = 30; char *p = "Hello"; printf("\n全局变量a的地址=%d\n\n", &a); printf("静态全局变量b的地址=%d\n\n", &b); printf("静态局部变量e的地址=%d\n\n", &e); printf("字符串\"Hello\"的地址=%d\n\n", "Hello"); printf("局部变量c的地址=%d\n\n", &c); printf("局部变量d的地址=%d\n\n", &d); printf("指针变量p的地址=%d\n\n", &p); fun(5); system("pause"); return 0; }
简单的用图表示了一下,总结:
全局区存放的是全局变量,静态变量,字符常量,const 修饰的全局变量。栈区存放的是局部变量和函数的形参,以及一些代码的地址,栈区的内容是可以修改的
堆区是由程序员手动申请和释放,用malloc函数申请,用free函数释放。
创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。
- .bss段
- 堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
还没有评论,来说两句吧...