在学指针这块的知识时,比如我们定义了一个指针:’char *str=”hello_world”’,我们都知道是计算机为指针str分配了内存空间,那么”hello_world”这个字符串是不是也被分配了内存空间呢,是不是指针和”hello_world”都在同一个内存空间呢?
当时,我坚定的认为这个答案是肯定的,但当我尝试用’printf(“%s”,str)’输出时,就出现问题了(程序会终止),又想通过sizeof操作符看一下它所占的字节数时,它的答案居然是char 指针的大小。这件事苦恼了我几天,直到知道了C的内存分配时,我的世界又一次明朗了起来。
废话说的有点多了,下面就开始切入正题吧,先来段代码,大家先思考一下机器是如何分配内存给各个变量吧。
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
int a = 0;
char *p1;
int main(void)
{
int b;
char s[] = "abc";
char *p2;
char *p3 = "123456";
static int c =0;
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
strcpy(p1, "123456");
return 0;
}
通过以下内容的介绍,希望大家都能有所收获吧。
一般来说,我们都将C语言中内存分为五个区:
1.栈(stack):用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放,。
2.堆(heap):用来存放由动态分配函数(如malloc)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直占着不放,导致内存泄露。
3.全局区/静态区:用来存放全局变量和静态变量。程序结束时由系统释放,分为全局初始化区和全局未初始化区;存在于程序的整个运行期间,是由编译器分配和释放的。
4.文字常量区:常量字符串放于此,程序结束时由系统释放。例如char *str=”hello_world”;则”hello_world”为文字常量,存放于文字常量区。也由编译器控制分配和释放。
5.程序代码区:用来存放程序的二进制代码。
下面就让我们将C语言各变量的分配区域注释出来吧。
#include <stdlib.h>
#include <string.h>
int a = 0; //全局初始化区
char *p1; //全局未初始化区
int main()
{
int b; //栈
char s[] = "abc"; //s在栈,"abc\0"在文字常量区
char *p2; //栈
char *p3 = "123456"; //"123456\0"在常量区,p3在栈上
static int c =0; //全局区
p1 = (char *)malloc(10); //p1在栈,分配的10字节在堆
p2 = (char *)malloc(20); //p2在栈,分配的20字节在堆
strcpy(p1, "123456"); //"123456"放在常量区,编译器可能会优化为和p3的指向同一块区域
return 0;
}
至于其他的分配方式,比较来比较去,个人感觉都是大同小异,像《Unix环境高级编程》(著名的APUE)中提出,C程序的内存布局为Text,Data,BSS,Stack, Heap:
1.Text是程序的代码段。
2.Data是程序中初始化了的全局、静态数据变量。
3.BSS是程序中未初始化的全局、静态数据变量。即使全局、静态数据变量初始化为0仍然是属于BSS段。(未初始化的数据段)
4.Stack是程序中的局部变量,由高地址到低地址向下增长。
5.Heap是malloc调用动态分配的内存,由低地址到高地址向上增长。
总之,关于C语言的内存分配大概就这么多了。希望大家都能有收获吧。