0.前言
- 本文主要讲解C语言有关内存分布的相关内容,内存作为C语言最最主要的操作对象,可以说C语言主要解决的就是有关内存的访问处理问题,故本章为重点内容。
1.内存分布思想概述
内存的属性:
- 大小:定义时决定
- 位置:编译时默认方式,段位置,section
#include <stdio.h>
int main()
{
int a;
a=0x10;
printf("the a is %p\n",&a);//对a取地址,观察a放在哪里;%p相当于在十六进制%x前加0x
printf("the is %p\n",main);//main函数名,一块代码的代名词,类似数组标签,即首地址
return 0;
}
#include <stdio.h>
int a;//全部变量
int main()//main前还有引导代码,后也还有代码,无需写,所以并不是全局的
{
a=0x10;
printf("the a is %p\n",&a);//对a取地址,观察a放在哪里;%p相当于在十六进制%x前加0x
printf("the is %p\n",main);//main函数名,一块代码的代名词,类似数组标签,即首地址
return 0;
}
- 可见,变量定义位置不同,导致变量分配位置段不同。
内存分布图:
0xff...ff
...
内核空间//应用程序不许访问,读都不能读
...//linux,3G
栈空间//局部变量,可访问 RW 运行时不停地分配释放分配释放(入栈出栈)
...
运行时堆空间//malloc申请分配的,可访问
...
(静态段:)//这三个运行前就分配好了,编译时分配的
全局数据空间(分为初始化的全局数据空间data,未初始化的全局数据空间bss) //data bass RW
只读数据段 //text R "hello world"双引号是字符串常量,是归text,越多,程序越大
代码段//code,可访问 text R
...
系统保留空间//不许访问,读都不能读
...
0x0
2.只读空间
- 代码段是只读的,常量化。观察main地址分配:
#include <stdio.h>
int b=100;
int fun()
{
static int a=100;
return a++;
}
int main()
{
static int a;
unsigned char *p;
a=0x10;
printf("the a is %p\n",&a);
printf("the is %p\n",main);
p=(unsigned char *)main;
printf("the p[0] is %x\n",p[0]);
p[0]=0x12;
printf("++++the p[0] is %x\n",p[0]);
return 0;
}
3.数据段
- size build //观察分配情况
- strings build //打印出双引号的东西
- 栈空间//局部变量,可访问 RW 运行时不停地分配释放分配释放(入栈出栈)
- 全局数据空间(分为初始化的全局数据空间,未初始化的全局数据空间),如下代码理解
- 程序内部定义:
static int a;//程序内部的static定义后,就不在栈空间中,而在bss中,但仍是局部有效(与全局变量不同)
- nm build //看代码段所处地址
4.堆空间与栈空间
栈:运行时才有的,调用函数时的返回地址、函数内部使用的变量,函数返回就释放,生命周期是函数内
堆:运行时才有的,运行时可以自由分配和释放的空间,生命周期由程序员决定
只读空间:静态空间,编译时就已确定,整个程序结束时释放内存,生命周期是最长的
- 堆分配:
malloc(),一旦成功,就返回分配好的地址给我们,只需要接收,对于这个新地址的读法,由程序员灵活把握,输入参数指定分配的大小,单位就是B字节。如:int a[5]; malloc(5*sizeof(int));
*p;
p=malloc();
char *p;
p=(char)malloc();
if(p==NULL)
{
error;
}
void fun()
{
char *p;
p=(char)malloc();
return ;
}
//返回后p消失,malloc申请的没有释放,造成没人去操作,会造成内存泄漏,因此申请分配和释放必须成对
- 释放:
free( p);
5.总结
参考资料:
链接1: 嵌入式C语言
链接2: 你懂c语言的内存分布模型吗?一文详解内存分布模型