5C语言内存分区
1)代码区:可执行程序代码存放区,这个我们不用关心;
2)全局区:
1全局与静态变量区:存放全局变量与静态变量,又可以区分为已经初始化的全局变量和静态变量区以及为初始化的全局变量和静态变量区;
2常量区:字符串常量与const修饰的常量存放在常量区;
3)堆区:用户动态申请的内存区,需要用户进行释放,否则有可能会造成内存泄漏;
4)栈区:该区内存由系统自动分配和释放,存放局部变量以函数实参等。
1全局区分析
看一段代码:
char *get_str() { char *p="abcd";//文字常量区 return p; } char *get_str1() { char *q="abcd";//文字常量区 return q; } int main() { char *p=NULL; char *q=NULL; p=get_str(); q=get_str1(); //%s,打印指针指向内存区域的内容 //%d打印p本身的值 printf("p=%s,p=%d\n",p,p); printf("q=%s,q=%d\n",q,q); return 0; }
运行结果:
原因:
看图,从主函数main开始,在栈区定义了两个指针变量p、q为空,占4个字节;
下面调用get_str();函数返回地址,在get_str();函数中又定义了一个p这个p给主函数中的p目前没有关系,在get_str();函数中把字符串abcd赋值给p,而abcd是在文字常量区定义的,假如地址为oxaabb,只有程序结束,才会被释放。
有get_str();返回的是地址oxaabb给主函数中的p,指针指向谁,就把谁的地址赋给谁,所以当get_str();释放后,主函数的p已经指向了文字常量区的abcd,同样的原理,由于get_str1()也是把相同的字符串abcd赋值给q,q也是指向文字常量区的0xaabb,所以他们两个地址是相同的,当然如是在赋值的字符串不同,那地址一定不同。
赋值字符串不同时:
char *get_str() { char *p="abcd1";//文字常量区 return p; } char *get_str1() { char *q="abcd2";//文字常量区 return q; } int main() { char *p=NULL; char *q=NULL; p=get_str(); q=get_str1(); //%s,打印指针指向内存区域的内容 //%d打印p本身的值 printf("p=%s,p=%d\n",p,p); printf("q=%s,q=%d\n",q,q); return 0; }
运行结果:
2栈区分析
char *get_str2() { char str[]="abcd"; printf("str=%s\n",str); return str;//返回str数组的地址 } int main() { char buf[100]={0}; strcpy(buf,get_str2()); printf("buf = %s\n",buf); return 0; }
运行出错。
char *get_str2() { char str[]="abcd"; printf("str=%s\n",str); return str;//返回str数组的地址 } int main() { //char buf[100]={0}; //strcpy(buf,get_str2()); char *p=NULL; p=get_str2(); // printf("buf = %s\n",buf); printf("p= %s\n",p); return 0; }
运行结果:
为什么p为空那?
看图,有于get_str2()函数调用完被释放,str空间被回收,str空间的内容就未知,p指向就没有了,p没有指向会报错或乱码或为NULL。注意这里的char str[]="abcd";是赋值,并不是指针的指向。
3堆区分析
char *get_str3() { //堆区手动分配空间 char *str=(char *)malloc(sizeof (char)*100); if(str==NULL)//分配失败 { return NULL;//返回空 } //分配成功 strcpy(str,"abcd"); return str;//返回地址 } int main() { //char buf[100]={0}; //strcpy(buf,get_str2()); char *p=NULL; p=get_str3(); if(p!=NULL)//p不为空 { printf("p= %s\n",p);//打印 free(p);//手动释放 p=NULL;//赋值为空 } // printf("buf = %s\n",buf); return 0; }
运行结果:
4函数调用模型
注:main函数在栈区开辟的内存,所有子函数都可以使用
main函数在堆区开辟的内存,所有子函数都可以使用
子函数开辟的栈区内存,只有其内部子函数才能使用
子函数在堆区开辟的内存,主函数与子函数内部的子函数都可以使用
子函数在全局区开辟的内存,主函数与子函数内部的子函数都可以使用
5栈的生长方向和内存存放的方向
int main() { int a; int b; printf("&a=%d,&a=%d\n",&a,&b);//栈区生长方向是向下的 char *p=(char *)malloc(10); char *q=(char *)malloc(10); printf("p=%d,q=%d\n",p,q); //堆区生长方向是向上的 int buf[4]; printf("&buf[0]=%d,&buf[1]=%d\n",&buf[0],&buf[1]); //数组生长方向是向上的 return 0; }
运行结果:
- C语言基础知识之(十七):内存的分区:栈区,堆区,静态区(全局区),常量区,代码区
- C 语言的内存分区
- C 语言的内存分区
- c++语言--五大内存分区
- C 语言内存对齐详解
- C语言模型:内存四区模型和函数调用模型
- C语言内存分配问题和C语言中的内存
- C/C++中的内存分区及堆栈相关知识
- C++程序设计语言练习5.2 内存对齐
- 实时监控本机内存和硬盘剩余空间,剩余内存小于 500M、根分区剩余空间小于 1000M 时,发送报警
- [汇编语言]sub命令得到的结果,在送入内存之前,是否保存在某个寄存器中
- java堆栈、对象存储、内存分区
- C语言内存分布(BSS段、数据段、代码段、堆与栈
- C++内存分区(学习笔记)
- 五大内存分区
- 汇编语言(王爽)第三章 寄存器(内存访问)
- 操作系统内存管理---连续内存分区
- 关于Go语言共享内存操作的小实例
- 一起talk C栗子吧(第九十五回:C语言实例--使用共享内存进行进程间通信一)
- 五大内存分区,堆与栈的区别(转)