内存四区的模型如下图1所示
内存四区模型是初学者进行C语言学习的一个重点同时也是一个难点,许多的C语言程序员在编写代码时往往只注重代码的逻辑功能的实现而不注重编写的代码在执行中所进行的内存的变化而导致程序隐藏一些问题,甚至导致程序失控崩溃。C语言的内存区分
根据功能的不同可以将内存分为四个区域,分别为堆区,栈区,全局区和代码区。
- 代码区:程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。
- 静态区:所有的全局变量以及程序中的静态变量,以及字符串都存储到静态区, C编译器对于相同的字符串会自动进行优化分配为统一的地址。
- 栈区:栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。
- 堆区:堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
C语言内存分析
下面对这四个区域进行代码分析,栈区最重要的特性是先进后出的内存结构,当函数运行完成后便会自动释放开辟给函数以及该函数的变量的内存,正是因为因为栈的这种特性使得变量有作用域,main函数一般规定为程序的入口,可以理解为它是最先入栈的函数,所以根据栈的先进后出的原理,main函数也是最后被释放。栈的方向(编译器给函数分配的地址)不一定是向上的(地址递增)也可能是向下(地址递减)。
1.1 内存四区
1.1.1 代码区
代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。
1.1.2 静态区
所有的全局变量以及程序中的静态变量,以及字符串都存储到静态区, C编译器对于相同的字符串会自动进行优化分配为统一的地址。
1.1.3 栈区
栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。
1.1.4 堆区
堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。
堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
2.C语言的内存分析
1,下面对这这几区域进行分析。栈区 最重要的特性是先进后出的内存结构,当函数运行完成后,自动释放开辟给函数以及该函数的变量的内存,正是因为栈的这种特性使得变量有作用域的说法,main是程序的入口,可以理解为他是最先入栈的函数,所以他最后被释放。栈的方向(编译器给函数分配的地址)不一定是向上的(地址递增)也可能是向下(地址递减)。
2静态区的理解:
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdio.h> 5 6 char * getStr1() 7 { 8 char *p1 = "abcdefg2"; 9 return p1; 10 } 11 char *getStr2() 12 { 13 char *p2 = "abcdefg2"; 14 return p2; 15 } 16 17 void main55() 18 { 19 char *p1 = NULL; 20 char *p2 = NULL; 21 p1 = getStr1(); 22 p2 = getStr2(); 23 24 //打印p1 p2 所指向内存空间的数据 25 printf("p1:%s , p2:%s \n", p1, p2); 26 27 //打印p1 p2 的值 28 printf("p1:%d , p2:%d \n", p1, p2); 29 30 printf("hello...\n"); 31 system("pause"); 32 return ; 33 }
分析以上代码发现指针所指的地址是一样,原因在于字符串是储存在静态区的,相同字符串,系统并不会重新开辟空间。这样做可以减少代码所占有的内存。
3 堆(heap)与栈(stack)的区别
//堆区开辟内存
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h>//堆
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数据
printf("hello..tmp:%s.\n", tmp);
system("pause");
return ;
}
//栈区开辟内存
define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h>char *getMem1()
{
char buf[64]; //临时变量 栈区存放
strcpy(buf, "123456789");
return buf;
}void main()
{
char *tmp = NULL;
tmp = getMem1();
if (tmp == NULL)
{
return ;
}
strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据
printf("hello..tmp:%s.\n", tmp);
system("pause");
return ;
}
堆区和栈区的不同在于函数运行后会不会自动的释放内存空间。栈会自动释放,所以代码2输出时乱码,因为buf地址中的内容在getnum1()运行完毕之后被释放了,所以buf地址的内容是乱码。而代码1开辟的空间是在堆区,所以不会自动释放内容。注意一般使用molloc()和free()这两个函数来开辟堆区的内存。
当开辟空间,不需要后要对内存进行释放。
内存空间的概念十分重要,影响了对指针的理解。而指针又是C语言的精髓。所以十分重要。