内存是程序运行的基础。所有正在运行的代码都保存在内存里面。内存需要处理各种各样的数据,包括键盘的数据、鼠标的数据、usb的数据、串口的数据、摄像头的数据,那么这些数据经过程序的处理之后,就要进行输出到串口、屏幕、usb等。
一、栈空间
在函数体中定义的变量,申请栈空间。自动申请和释放。
void test_stack_mem(void)
{
int a = 10;
printf("a=%d\n",a);
}
在申请开始起作用,在函数结束时变量申请的空间释放。
二、全局变量区
在函数体下定义的变量,申请在全局变量区。不加static的全局变量可以被其他文件所调用。
int g_InTemp = 100;
void test_gl_mem(void)
{
printf("g_InTemp=%d\n",g_InTemp);
g_InTemp = 10;
printf("g_InTemp=%d\n",g_InTemp);
}
在全局变量中前面加static字样,称为静态全局变量。它的作用不能被其他文件所调用。
static int g_InFlag = 100;
void test_add_dl(void)
{
g_InFlag++;
}
void test_st_gl_mem(void)
{
printf("g_InFlag=%d\n",g_InFlag);
}
注意申请全局变量不能和堆空间搞混。
//int g_InVal = (int)malloc(sizeof(int));//ERROR
编译时:
三、堆空间
在函数体定义变量时,用malloc在堆空间申请。需要主动申请和释放(free)。
void test_hp_mem(void)
{
int* g_InVal = (int*)malloc(sizeof(int));
*g_InVal = 100;
printf("g_InVal=%d\n",*g_InVal);
free(g_InVal);
printf("g_InVal=0x%x\n",*g_InVal);
}
注意malloc后面的大小,一般申请空间大小与指针指向空间的大小,并非指针本身。
free后的操作相当指针指向的空间释放,此时指针为野指针。
总结:
1) 全局数据是我们喜欢使用的类型,用起来比较方便
2)堆数据是系统给我们安排的空间
3)堆栈空间只能存在于当时的函数之中,函数返回即失去意义
虽然我们上面这么说,但是这三个概念有的时候也是可以相互迁移的,比如说:
1) 有的时候,我们为了测试的需要,首先构建一个全局内存池,以后测试的内存都是通过自定义的malloc在内存池中分配的,所以这个时候,堆分配和全局联系在了一起。
全局内存空间 < =========> 内存池 < =========> 本地空间分配
2) 如果我们使用的函数空间比较小,那么所有的操作就可以在一个函数内部完成了,那么这时候全局空间和临时堆栈是不是一致的呢
全局空间 < =============> 本地堆栈
上面的说法有些绕,但是我们的目的只是想让大家时刻明白:
a)必须时刻明白我们的数据在哪块空间里面
b)内存会不会越界
c)内存会不会泄露
d)内存访问的数据是否依然有效