C语言中的内存空间,内存分配malloc
简介:
现代计算机操作系统中,重要的一个功能就是内存管理。在Linux系统中,提供了malloc函数来进行内存的分配。对应的,内存释放函数式free。
在C语言中,可以用printf函数输出变量的值,包括变量被分配的地址,%d用于输出整形,%s用于输出字符串,而%p就用于输出变量的地址值。
C语言程序的内存空间:
C语言程序包括以下几部分:
正文段:存放由CPU执行的机器指令,通常为只读;
初始化数据段:通常将此段称为数据段,它包含了程序中需赋初值的变量。
例如,C程序中任何函数之外的说明:
float PI= 3.14f;
使此变量以初值存放在初始化数据段中;
非初始化数据段:通常将此段称为b s s段,这一名称来源于早期汇编程序的一个操作符,意思是“block started by symbol(由符号开始的块)”。在程序开始执行之前,内核将此段初始化为0。
例如,函数外的说明:
long sum[1000] ;
使此变量存放在非初始化数据段中。
栈:自动变量以及每次函数调用时所需保存的信息都存放在此段中。
每次函数调用时,其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调用的函数在栈上为其自动和临时变量分配存储空间。
通过以这种方式使用栈,C函数可以递归调用。
例如,
int main() {
int x =10; // 栈存储
int y = 20; // 栈存储
return 0;
}
堆:通常在堆中进行动态存储分配,例如用malloc函数分配的地址空间。由于历史上形成的惯例,堆位于非初始化数据段顶和栈底之间。
例如,
int main() {
int x =10; // 栈分配
int y = 20; // 栈分配
char *p = (char*)malloc(256); //堆分配
return 0;
}
用malloc在堆中分配了一块内存空间,用p保存这个内存空间的首地址,用于后续访问这块内存。但p这个变量本身是在栈中分配的。
下图,是一个典型的C语言程序内存空间分布图:
内存地址的测试:
1.栈上分配的地址测试:
malloc_p.c,用于打印内存地址值。
#include <stdio.h>
#include <stdlib.h>
int test1() {
/*栈上分配,猜测,x和y的地址相邻*/
int x = 10;
int y = 20;
/*预想: p = x的地址; &p =p的地址(而且,和y的地址相邻); 实际结果:和预想的一样*/
int *p = &x;
printf("x=%d, &x=%p\n",x,&x);
printf("y=%d, &y=%p\n",y,&y);
printf("p=%p, &p=%p\n",p,&p);
printf("\n");
return 0;
}
int main() {
test1();
}
编译:用gcc命令进行编译:
gcc malloc_p.c
运行结果:
x=10, &x=0x7ffeed1df88c
y=20, &y=0x7ffeed1df888
p=0x7ffeed1df88c, &p=0x7ffeed1df880
可以看到,
一,p的值就是x的地址,而p也有自己的地址;
二,x,y,p三个变量的地址都挨着。其实都是系统在堆栈上给分配的。
2.malloc地址测试:
再看一个复杂的例子,我们加上malloc函数,再进行对比:
/*预想:q的值和p的值离的很远,因为,q的值是在堆中分配的,q本身的地址在栈中分配*/
char *q = (char*)malloc(256);
printf("q=%p, &q=%p\n",q,&q);
printf("\n");
/*一定要进行free,否则,就有内存泄露*/
free(q);
运行结果:
x=10, &x=0x7ffee115788c
y=20, &y=0x7ffee1157888
p=0x7ffee115788c, &p=0x7ffee1157880
q=0x7f7f0ac05990, &q=0x7ffee1157878
可见,和我们的预想结果一样,q本身的地址和其它变量的地址都紧挨着,它们的内存都是系统在栈上分配的;而q中存储的值,和其它的变量的地址离的特别远,其实,这个地址就是malloc在堆中分配的内存地址。
3.静态存储区的地址测试:
我们再加上静态全局变量和非静态全局变量来看一下:
#include <stdio.h>
#include <stdlib.h>
/*初始化数据段, 0x402000, 0x402004*/
/*m=1024, &m=0x402000
n=2048, &n=0x402004*/
int m = 1024;
int n = 2048;
/*非初始化数据段, 0x403100*/
int arr[10];
/*静态存储,初始化数据段*/
int static MAX = 256;
int static MIN;
int test1() {
/*栈上分配,猜测,x和y的地址相邻*/
int x = 10;
int y = 20;
/*预想: p = x的地址; &p =p的地址(而且,和y的地址相邻); 实际结果:和预想的一样*/
int *p = &x;
printf("x=%d, &x=%p\n",x,&x);
printf("y=%d, &y=%p\n",y,&y);
printf("p=%p, &p=%p\n",p,&p);
/*预想:q的值和p的值离的很远,因为,q的值是在堆中分配的,q本身的地址在栈中分配*/
char *q = (char*)malloc(256);
printf("q=%p, &q=%p\n",q,&q);
/*初始化数据段*/
printf("m=%d, &m=%p\n",m,&m);
printf("n=%d, &n=%p\n",n,&n);
printf("\n");
/*非初始化数据段*/
printf("arr[0]=%d,&arr[0]=%p\n",arr[0],&arr[0]);
printf("&arr=%p\n",&arr);
printf("\n");
/*静态存储,初始化数据段*/
printf("MAX=%d, &MAX=%p\n",MAX,&MAX);
printf("MIN=%d, &MIN=%p\n",n,&MIN);
printf("\n");
/*一定要进行free,否则,就有内存泄露*/
free(q);
return 0;
}
int main() {
test1();
}
运行结果:
x=10, &x=0x7ffeef42988c
y=20, &y=0x7ffeef429888
p=0x7ffeef42988c, &p=0x7ffeef429880
q=0x7ffcd2c05990, &q=0x7ffeed011878
/*1.初始化数据段*/
m=1024, &m=0x1007de010
n=2048, &n=0x1007de014
/*2.非初始化数据段*/
arr[0]=0,&arr[0]=0x1007de020
&arr=0x1007de020
/*3.静态存储,初始化数据段*/
MAX=256, &MAX=0x1007de018
MIN=2048, &MIN=0x1007de01c
可以看出:
1)m,n,arr,arr,MAX,MIN的地址挨着,但和前面的栈中分配的x,y,p, 以及malloc分配的堆中的内存地址,都相隔甚远;
2)其实,m,n,arr,arr,MAX,MIN这些变量,对于系统在具体分配内存的时候,并无差别。虽然我们从逻辑上将其分成了初始化数据段中,非初始化数据段中,以及静态存储的初始化数据段。
内存分配malloc,千万别忘了free。
更多推荐
所有评论(0)