内存的五个分区:代码、常量、静态、堆、栈。
代码区 以编译的机器码形式存放着程序的代码。函数的名称是一个指针(函数指针),它指向代码区中存放该函数的位置。
常量区 存储常量(程序运行期间不能被修改的量,例如各个数值和字符串的字面量等),只能改变常量指针指向的地址,不能改变常量指针指向位置的内容,因为常量不可被修改。
#include <stdio.h>
int main(){
const char *p = "abcd";
printf("%p: %s\n", p, p);
//=> 00007ff668569000: abcd
p = "1234";
printf("%p: %s\n", p, p);
//=> 00007ff66856900d: 1234
return 0;
}
编译器在常量区 00007ff668569000 创建了一个字符串常量"abcd"
,并将它赋值给字符型指针 p (p = "abcd"
),这里看起来是将一个字符串赋值给一个字符型指针非常不靠谱,实际上是将常量的内存地址赋值给了指针,非常靠谱。修改指针 p 的值,实际上是让指针 p 指向了另一个常量,因此 p 的指向地址发生了变化。
常量区的对象由系统自动维护,因此开发者不需要担心某个常量因为无人使用而一直得不到释放。
静态区 存放静态变量和全局变量。
// 未初始化的静态全局变量
static int a;
// 未初始化的全局变量
int b;
void test() {
// 定义在函数内部的静态变量
static int c = 1;
}
全局变量和静态变量只会执行一次初始化,即使test
函数被多次调用,静态变量 c 只有在第一次被调用时才会初始化,其余调用该行会被忽略。
未执行初始化的全局变量和静态变量,编译器会自动给一个初始值。
静态区的内存直到程序结束才会被释放。
堆区 的空间需要程序员自己手动申请和释放,忘记释放容易造成内存泄漏。
void test() {
// 申请一个 4 字节的空间,malloc 函数返回指向申请空间首地址的 void * 指针
// void * 类型的指针可以转换为任意类型的指针,这里我们声明了 p 是 int * 指针
int *p = malloc(4);
// 现在我们可以将 p 当做 32 bits 整型指针使用
// 使用完毕使用 free 函数释放内存区域(清空存储内容并将该空间标记为可用)
free(p);
// 此时 p 指向了一片没有分配的空间,重置 p 的指向避免野指针
p = nullptr;
}
堆的空间按照地址递增的顺序进行分配,后申请的空间地址更大。
栈区 由编译器管理,主要用来保存函数调用的数据,例如参数、返回值和局部变量等。
评论区