
C语言的动态内存管理。这可是C语言的“精髓”之一,也是新手(甚至老手)的“噩梦”之源 它就像给了你一个超能力:你可以在程序运行时,向上帝(操作系统)“借”一块内存,用完了再“还”回去

我们先看看“不动态”的内存是什么样的:
int global_var = 10;这些变量在程序一开始运行时就被分配了,直到程序结束才释放。它们“长命百岁”,但不够灵活。

void my_func() { int local_var = 5; }函数里的局部变量,放在“栈”上。它们的好处是“自动”:函数一调用,它们就出生;函数一返回,它们就去世并自动释放
从一块叫堆(Heap) 的巨大内存池里按需分配的
🌊🌊所有动态内存管理都围绕着 <stdlib.h> 头文件里的四个函数🌊🌊
void* 类型的指针,指向这块内存的起始地址。void* 是“通用指针”,你需要将它强制类型转换为你需要的类型(比如 int*, char* 等)。NULL// 申请一块足够存放 100 个整数的内存
int* my_array = (int*)malloc(100 * sizeof(int));
// 🚨 **极其重要:永远检查返回值!**
if (my_array == NULL) {
// 内存分配失败了!
printf("天呐!内存不足!\n");
// 此时应该做一些错误处理,比如退出程序
return 1;
}
// 现在你可以像使用普通数组一样使用它
my_array[0] = 10;
my_array[99] = 123;void* calloc(size_t num_elements, size_t element_size);
num_elements)以及每个元素多大(element_size)。
malloc 的区别:
calloc(100, sizeof(int)))。0 malloc 不会,malloc 给你的内存里可能是任何“垃圾数据”注意: 1. 如果新大小
new_size小于 原大小,它会“截断”多余的内存 2. 如果new_size大于 原大小,它会尝试在原地扩容 3. 如果原地空间不够(这很常见),realloc会在堆上另找一个足够大的新地方,把旧内存里的数据复制到新地方,然后释放旧的内存,最后返回新地址。
正因如此,你必须用一个新指针接收 realloc 的返回值!
// 之前申请了 100 个整数
int* my_array = (int*)malloc(100 * sizeof(int));
// ... 使用 ...
// 发现不够用,需要 200 个
int* bigger_array = (int*)realloc(my_array, 200 * sizeof(int));
if (bigger_array == NULL) {
// 重新分配失败!
// 注意:此时原来的 my_array 仍然是有效的(如果 realloc 失败)
// 你需要决定怎么处理这种情况
} else {
// 成功了,现在 my_array 可能已经失效了
// 应该用 bigger_array 代替
my_array = bigger_array;
}void free(void* ptr);
ptr 指向的这块动态内存你不用了,可以回收了
free 通过 malloc, calloc, realloc 得到的指针。free(NULL) 是安全的,什么也不做int* my_array = (int*)malloc(100 * sizeof(int));
// ... 尽情使用 ...
// 好了,用完了,必须释放
free(my_array);malloc 了一块内存,但用完后忘记 free。这块内存就“丢失”了。你的程序还在运行,但它既不能使用这块内存(因为你把指向它的指针弄丢了),系统也不能把它分给别人。
2.如果你的程序(比如服务器)长时间运行,并且不断地泄漏内存,它最终会耗尽系统所有内存,然后崩溃。
free(ptr) 之后,ptr 指针本身的值(那个地址)并没有变,但它指向的内存已经不属于你了。
ptr去读写那块内存,你就是在“非法闯入”。你可能会读到垃圾数据,或者(更糟的)你可能会破坏掉其他人(程序里的另一部分)正在使用的数据。
NULL。
free(my_array);
my_array = NULL; // 好习惯!
// 之后如果不小心访问
if (my_array != NULL) {
my_array[0] = 5; // 这段代码就不会执行了
}free(ptr) 之后,过了一会儿又(不小心) free(ptr) 了一次。这会严重破坏堆的内部管理结构,几乎肯定会导致程序崩溃。
(这就是为什么 free 后设为 NULL 是个好习惯,因为 free(NULL) 是安全的)。
malloc(10 * sizeof(int)),只申请了10个整数的空间,但你却试图访问 my_array[10](这是第11个元素)
🧠 计算机内存中的“数据存储”是什么? 当你写下:
int x = 10;这句代码看起来只是一个整数,但程序运行时,它必须存在某个地方才能被 CPU 操作。 这个地方就是 内存(Memory)
1️⃣ 栈(Stack)
局部变量、函数参数、返回地址
int *func() {
int x = 100;
return &x; // ❌ x 是栈变量,函数返回后内存已被回收
}2️⃣ 堆(Heap)
malloc / free
int *p = malloc(sizeof(int));
*p = 42;
free(p); // ✅ 释放
p = NULL; // ✅ 置空避免野指针3️⃣ 全局区(静态区 / Data Segment)
int a = 10;
int b; (默认值为0)
4️⃣ 常量区(Constant Segment)
hello
char *s = "hello";
s[0] = 'H'; // ❌ 运行时错误(段错误)char s[] = "hello"; // ✅ 拷贝到栈区,可修改
s[0] = 'H';
动态内存管理是C语言强大灵活性和性能的基石。它允许你构建真正复杂、高效的数据结构(如链表、树、哈希表) 但是也会导致各种安全漏洞