Skip to content
📖 Auto 版 Modern C本书目录

第十三章:存储 ​

级别 2 — 认知

malloc、存储期、初始化——C 如何管理对象生命周期以及 Auto 如何使其自动化。

内存管理是 C 程序最容易出错的地方。内存泄漏、释放后使用、双重释放和悬空指针占据了 C 安全漏洞的很大一部分。本章研究 C 的存储机制,并展示 Auto 如何消除整类内存错误。


13.1 malloc 及相关函数 ​

C 提供四个函数用于动态内存分配:

c
// C 深入:动态分配
void *malloc(size_t size);        // 分配 size 字节(未初始化)
void *calloc(size_t n, size_t s); // 分配 n*s 字节(零初始化)
void *realloc(void *p, size_t s); // 调整分配大小(可能移动)
void free(void *p);               // 释放

C 中的典型用法:

c
// C 深入:malloc 生命周期
int *arr = malloc(10 * sizeof(int));  // 分配
if (!arr) { /* 处理错误 */ }           // 检查 NULL
for (int i = 0; i < 10; i++) {
    arr[i] = i * i;                    // 使用
}
// ... 稍后 ...
free(arr);                             // 释放
arr = NULL;                            // 避免悬空指针

问题层出不穷:

  • 忘记释放:随时间增长的内存泄漏。
  • 释放后使用:未定义行为,通常可被利用。
  • 双重释放:破坏堆分配器的内部状态。
  • 不检查 NULL:解引用失败的分配导致崩溃。
  • 错误大小:写 malloc(sizeof(int*)) 而本意是 malloc(sizeof(int))。

Auto 的替代:自动存储。 Auto 自动管理对象生命周期。Auto 中没有 malloc、free、realloc 或 calloc:

auto
// Auto:没有 malloc/free,自动生命周期管理
var arr [10]int
for i in 0..10 {
    arr[i] = i * i
}
print("First:", arr[0])
// 不需要 free——存储自动回收

当 Auto 需要动态大小的集合时,标准库提供带有自动清理的可增长容器:

auto
// Auto:可增长缓冲区
type Buffer {
    data [256]int
    size int
}

fn Buffer.new() Buffer {
    Buffer([256]int{}, 0)
}

fn Buffer.push(b Buffer, val int) {
    if b.size < 256 {
        b.data[b.size] = val
        b.size = b.size + 1
    }
}

基于 MIT 许可发布。