目录
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语言底层是非常有帮助的。
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虽然也是地址,但是不是指针变量,不能直接赋值
栈区
由编译器自动分配释放,由操作系统自动管理,无须手动管理。
栈区上的内容只在函数范围内存在,当函数运行结束,这些内容也会自动被销毁。
#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左右,所以别定义太大的数组。
堆区
由程序员分配内存和释放。若程序员不释放,程序结束时可能由操作系统回收。
#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释放。
代码区的话就是用来存放代码的,转化为二进制存放。
通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量
和静态变量
。
全局区有 .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段
.data段
通俗来说:
全局区比较特殊,里面还分成了全局变量区,静态变量区,常量区。全局变量区用来存放全局变量,静态变量区用来存放带有static修饰的变量(包括静态局部变量和静态全局变量),只要含有static就存在这个区。常量区是用来存放字符常量的,还有const修饰的全局变量的,const 修饰的局部变量不存在这里,别搞混了。全局区存放的一切都是由操作系统管理,等程序结束由操作系统释放。常量区里存放的数据不可更改,就算你用指针也不行,你可能会说const修饰的局部变量都可以用指针改,但是局部变量可不是存放在常量区,这点搞清楚。
字符串
、数字
等常量存放在常量区。const
修饰的全局变量存放在常量区。
程序运行期间,常量区的内容不可以被修改。
程序执行代码
存放在代码区,其值不能修改(若修改则会出现错误)。字符串常量
和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函数释放。