一,内存分配
1,内存分配的类型:
在C/C++中内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。
静态内存分配:编译时分配。包括:全局、静态全局、静态局部三种变量。
动态内存分配:运行时分配。包括:栈(stack): 局部变量。堆(heap): c语言中用到的变量被动态的分配在内存中。(malloc或calloc、realloc、free函数)
2.变量的内存分配:
栈区(stack):指那些由编译器在需要的时候分配,不需要时自动清除的变量所在的储存区,如函数执行时,函数的形参以及函数内的局部变量分配在栈区,函数运行结束后,形参和局部变量去栈(自动释放)。栈内存分配运算内置与处理器的指令集中,效率高但是分配的内存空间有限。
堆区(heap):指哪些由程序员手动分配释放的储存区,如果程序员不释放这块内存,内存将一直被占用,直到程序运行结束由系统自动收回,c语言中使用malloc,free申请和释放空间。
静态储存区(static):全局变量和静态变量的储存是放在一块的,其中初始化的全局变量和静态变量在一个区域,这块空间当程序运行结束后由系统释放。
常量储存区(const):常量字符串就是储存在这里的,如“ABC”字符串就储存在常量区,储存在常量区的只读不可写。const修饰的全局变量也储存在常量区,const修饰的局部变量依然在栈上。
程序代码区:存放源程序的二进制代码。
原文来自:
C语言:内存分配
代码来源:C语言中,局部变量、全局变量、静态变量、堆、栈的内存地址
创建1.c文件并写入代码:
#include
#include
#include
void before()
{
}
char g_buf[16];
char g_buf2[16];
char g_buf3[16];
char g_buf4[16];
char g_i_buf[]="123";
char g_i_buf2[]="123";
char g_i_buf3[]="123";
void after()
{
}
int main(int argc, char **argv)
{
char l_buf[16];
char l_buf2[16];
char l_buf3[16];
static char s_buf[16];
static char s_buf2[16];
static char s_buf3[16];
char *p_buf;
char *p_buf2;
char *p_buf3;
p_buf = (char *)malloc(sizeof(char) * 16);
p_buf2 = (char *)malloc(sizeof(char) * 16);
p_buf3 = (char *)malloc(sizeof(char) * 16);
printf("g_buf: 0x%x\n", g_buf);
printf("g_buf2: 0x%x\n", g_buf2);
printf("g_buf3: 0x%x\n", g_buf3);
printf("g_buf4: 0x%x\n", g_buf4);
printf("g_i_buf: 0x%x\n", g_i_buf);
printf("g_i_buf2: 0x%x\n", g_i_buf2);
printf("g_i_buf3: 0x%x\n", g_i_buf3);
printf("l_buf: 0x%x\n", l_buf);
printf("l_buf2: 0x%x\n", l_buf2);
printf("l_buf3: 0x%x\n", l_buf3);
printf("s_buf: 0x%x\n", s_buf);
printf("s_buf2: 0x%x\n", s_buf2);
printf("s_buf3: 0x%x\n", s_buf3);
printf("p_buf: 0x%x\n", p_buf);
printf("p_buf2: 0x%x\n", p_buf2);
printf("p_buf3: 0x%x\n", p_buf3);
printf("before: 0x%x\n", before);
printf("after: 0x%x\n", after);
printf("main: 0x%x\n", main);
if (argc > 1)
{
strcpy(l_buf, argv[1]);
}
return 0;
}
编译1.c并运行
gcc 1.c -o 1
./1
详细请参考:
C/C++程序内存的各种变量存储区域和各个区域详解
C语言中,局部变量、全局变量、静态变量、堆、栈的内存地址
C语言中关键字volatile追根问底
利用之前的串口通信代码,修改main.c如下:
#include "stm32f10x.h"
#include "bsp_usart.h"
char quanju1[16];
char quanju2[16];
char quanju3[16];
int main(void)
{
char bufen1[16];
char bufen2[16];
char bufen3[16];
USART_Config();
printf("bufen1: 0x%p\n", bufen1);
printf("bufen2: 0x%p\n", bufen2);
printf("bufen3: 0x%p\n", bufen3);
printf("quanju1: 0x%p\n", quanju1);
printf("quanju2: 0x%p\n", quanju2);
printf("quanju3: 0x%p\n", quanju3);
while(1)
{
}
}
生成hex文件
按照之前串口通信同样的步骤,点击stm32板上的reset按键,出现下图所示
#include "stm32f10x.h"
#include "bsp_usart.h"
#include
int main(void)
{
static char m1[16];
static char m2[16];
static char m3[16];
char *n1;
char *n2;
char *n3;
USART_Config();
printf("m1: 0x%p\n", m1);
printf("m2: 0x%p\n", m2);
printf("m3: 0x%p\n", m3);
n1 = (char *)malloc(sizeof(char) * 16);
n2 = (char *)malloc(sizeof(char) * 16);
n3 = (char *)malloc(sizeof(char) * 16);
printf("n1: 0x%p\n", n1);
printf("n2: 0x%p\n", n2);
printf("n3: 0x%p\n", n3);
while(1)
{
}
}
编译生成hex文件
串口调试
根据串口数据可知从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段,如图
详细请参考:
【IoT】STM32 内存分配详解
基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM
STM32 KEIL下的堆栈设置