C语言的内存分配
文章目录
1.前言
C语言中编译后,主要把内存和ROM分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。
怎么理解这五个区呢?,我们可以想象一下,程序执行了int a=0;
这个语句,这个语句是存在于代码区的,然后,获取到这条指令后,CPU在栈区开辟一块内存给这个变量使用
[此处转载于]:https://blog.csdn.net/xiandang8023/article/details/126036564
2. 栈(Stack)和静态内存分配
-
栈是用来存储函数调用时的局部变量、函数参数和函数调用的上下文信息的内存区域。
-
在函数执行时,栈上的内存被自动分配,并在函数返回时自动释放。
-
栈的操作遵循“后进先出”(LIFO)的原则。
-
示例代码:
int add(int a, int b) { int result = a + b; // 局部变量 result 存储在栈中 return result; } int main() { int x = 5; // 局部变量 x 存储在栈中 int y = 3; // 局部变量 y 存储在栈中 int sum = add(x, y); // 调用函数时,函数参数也存储在栈中 return 0; }
3. 堆(Heap)和动态内存分配
-
堆是用于动态分配内存的区域,可以手动管理内存的分配和释放。
-
堆的大小较大,适合存储较大的数据结构和对象。
-
通过调用函数如
malloc()
、calloc()
或realloc()
来从堆中分配内存空间。 -
必须手动调用
free()
函数来释放堆内存,否则可能导致内存泄漏。 -
示例代码:
int* createIntArray(int size) { int* array = (int*)malloc(size * sizeof(int)); // 从堆中分配整数数组的内存空间 return array; } int main() { int* numbers = createIntArray(5); // 调用函数从堆中分配整数数组 free(numbers); // 释放堆内存 return 0; }
4. 全局存储区
-
全局静态区的变量在程序启动时就会被加载到内存中。具体来说,全局静态区的变量是在程序的加载和链接阶段分配内存空间的。
- 操作系统:当程序执行时,操作系统会将可执行文件加载到内存中,并完成各个模块的链接。在链接过程中,全局静态区的变量会被分配内存空间,并初始化为默认值(如果有初始化操作)。如果全局静态变量没有显式的初始化,则会被默认初始化为0或者空指针(对于字符数组和字符串常量)。
- 裸机:在没有操作系统的环境下,程序将直接加载到计算机的物理内存中(stm32是在flash中),并按照编写的代码逐行执行。全局静态区的变量会在程序执行到这条语句时执行编译时已经分配的内存空间,并初始化为默认值(如果有初始化操作)。这些变量将一直驻留在内存中,直到程序结束。
- 二者相同的是,虽然全局或者静态变量在编译时已经被分配了地址;不同的是,操作系统一开始就把五个区全部初始化好了,而裸机只有执行到才会执行已分配的地址
-
全局存储区用于存储全局变量和静态变量。
-
在程序启动时分配,在程序结束时释放。
-
全局变量具有全局作用域,可以在程序的任何位置被访问。
-
静态变量属于全局存储区,但作用域仅限于声明它的源文件。
-
示例代码:
#include <stdio.h> int globalVar = 10; // 全局变量存储在全局存储区 void modifyGlobalVar() { static count = 0; //静态变量也存在于全局存储区 globalVar = 20; // 可以在函数中修改全局变量的值 } int main() { printf("Global variable: %d\n", globalVar); // 输出全局变量的值 modifyGlobalVar(); // 调用函数修改全局变量的值 printf("Modified global variable: %d\n", globalVar); // 输出修改后的全局变量的值 return 0; }
5. 常量存储区
-
常量存储区用于存储常量数据,如字符串常量。
-
存储在该区域的数据是只读的,不能被修改。
-
常量存储区通常位于静态存储区内。
-
示例代码:
cCopy Code#include <stdio.h> int main() { const int num = 10; // 常量 num 存储在常量存储区 char* str = "Hello"; // 字符串常量存储在常量存储区 printf("Constant variable: %d\n", num); // 输出常量的值 printf("String constant: %s\n", str); // 输出字符串常量的值 return 0; }
6. 文字常量区(代码区、可执行文件)
- 文字常量区也称为代码段,用于存储程序的机器指令。
- 存储在该区域的数据是只读的,不能被修改。
- 该区域通常位于可执行文件的只读部分。
7. 总结
-
栈区由程序自动执行到那里并开辟,地址是不确定的,也就是静态内存分配
-
堆区是由程序员手动控制开辟的,地址可以是确定的,也就是动态内存分配
-
全局存储区是一开始就被编译好了地址的,有操作系统,他就先把这个地址放入这个变量值,没有操作系统,他就执行到了,再把这个变量值放入指定的地址
-
常量区既可以在 Flash 存储器中,也可以在 RAM 存储器中,具体取决于编译器和目标设备的配置。
在一些嵌入式系统中,常量数据通常存储在 Flash 存储器中,这样可以节省 RAM 的使用。Flash 存储器是非易失性存储器,它可以保持数据即使在断电后也保持不变。这意味着即使重新启动设备,常量数据仍然会存在。
和全局存储区一样,常量区也是预先被分配了地址,且有操作系统和没有操作系统是不一样的。不同的是,常量区通常和代码在一个可执行文件里。
使用。Flash 存储器是非易失性存储器,它可以保持数据即使在断电后也保持不变。这意味着即使重新启动设备,常量数据仍然会存在。
和全局存储区一样,常量区也是预先被分配了地址,且有操作系统和没有操作系统是不一样的。不同的是,常量区通常和代码在一个可执行文件里。
- 文字常量区,也就是代码区(可执行文件),代码肯定是在flash了,在个人计算机领域,代码区肯定是被加载到内存的(放在全局区);但是在嵌入式领域,代码区可以直接存在flash中,比如stm32
8. 额外补充(在操作系统下的内存区域划分)
栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。
数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
代码段:存放函数体(类成员函数和全局函数)的二进制代码。