0Pricing
C Academy · 课时

使用 realloc 扩展

调整动态数组的大小。

使用 realloc 扩展 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

一个 malloc 不够时

有时您分配了一个数组并填入数据,之后才发现需要更多空间。您不能直接写到数组末尾之外。

重新分配函数可以调整现有堆内存块的大小,同时保留其中已有的数据。

重新分配函数的签名

realloc(ptr, new_bytes) 接受旧指针和新的总字节数。

它会返回一个指向新大小内存块的指针。数据的前半部分会保留,保留范围截至旧大小和新大小中较小的一个。

int *bigger = realloc(a, new_n * sizeof(*a));

内存块可能会移动

重新分配函数可能会直接在原位置扩大内存块,也可能分配一个新内存块、复制数据并释放旧内存块。

无论哪种情况,旧指针都可能失效。从此以后,您必须使用返回的指针。

a = realloc(a, new_n * sizeof(*a));
/* the old value of a may no longer be valid */

自赋值陷阱

写成 a = realloc(a, ...) 看起来很简洁,但很危险:如果重新分配函数返回 NULL,您就覆盖了 a,丢失了原始指针,并泄漏旧内存块。

请改用临时变量。

int *tmp = realloc(a, new_n * sizeof(*a));
if (tmp == NULL) { /* a is still valid */ return 1; }
a = tmp;

安全地扩展数组

这个程序先为 3 个 int 分配空间,然后使用重新分配函数将容量扩大到 6,同时保留前 3 个值。

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(3 * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < 3; i++) a[i] = i + 1;

    int *tmp = realloc(a, 6 * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;

    for (int i = 3; i < 6; i++) a[i] = i + 1;
    for (int i = 0; i < 6; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

新增字节未经初始化

扩大内存块时,末尾新增的空间会像刚通过 malloc 分配的内存一样包含无用数据。

重新分配函数会保留旧数据,但不会将新区域清零。请在读取之前对其进行初始化。

a = realloc(a, 6 * sizeof(*a));
for (int i = 3; i < 6; i++) a[i] = 0;  /* clear new slots */

加倍策略

为每个元素都调用一次重新分配函数会很慢。一种经典技巧是在空间用尽时将容量加倍。

随着数组增长,这样可以减少重新分配的次数,从而获得良好的平均性能。

if (count == cap) {
    cap = cap ? cap * 2 : 4;
    int *tmp = realloc(a, cap * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;
}

通过追加构建数组

这个程序从空数组开始追加数字,并在需要时将容量加倍。

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = NULL;
    size_t count = 0, cap = 0;
    for (int v = 1; v <= 5; v++) {
        if (count == cap) {
            cap = cap ? cap * 2 : 2;
            int *tmp = realloc(a, cap * sizeof(*a));
            if (!tmp) { free(a); return 1; }
            a = tmp;
        }
        a[count++] = v;
    }
    for (size_t i = 0; i < count; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

realloc(NULL, n) 的行为类似 malloc

如果将 NULL 作为指针传入,重新分配函数的行为就与 malloc 完全相同。

因此,在加倍循环中从 a = NULL 开始是可行的:第一次调用重新分配函数就会分配初始内存块。

int *a = NULL;
a = realloc(a, 4 * sizeof(*a));  /* same as malloc(4 * sizeof(*a)) */

缩小内存块

重新分配函数也可以缩小内存块。新大小范围内的数据会被保留,其余数据会被丢弃。

缩小内存块可能会将内存释放回系统,不过具体实现也可以选择保留较大的内存块。

int *tmp = realloc(a, 2 * sizeof(*a));  /* down from more */
if (tmp) a = tmp;

避免数学运算溢出

当容量变得很大时,cap * sizeof(*a) 可能会超出 size_t 的范围并溢出,回绕成一个很小的数。

对于超大数组,请防止乘法溢出,或者在系统提供 reallocarray 时使用它。

if (cap > SIZE_MAX / sizeof(*a)) { /* overflow */ return 1; }
int *tmp = realloc(a, cap * sizeof(*a));

快速检查

请测试您对 realloc 的理解。

回顾

realloc 会调整堆块的大小,并且可能移动堆块,因此请始终使用返回的指针。

请先赋值给临时指针,这样失败时不会泄漏原来的堆块。为提高速度,请通过容量翻倍来扩容,并初始化新增的槽位;还要记住,realloc(NULL, n) 等同于 malloc。接下来,您将把这套逻辑封装到可复用的向量类型中。

常见问题解答

「使用 realloc 扩展」课时是免费的吗?

是的 — 「使用 realloc 扩展」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「使用 realloc 扩展」这节课中我会学到什么?

调整动态数组的大小。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「使用 realloc 扩展」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 分配数组
  2. 使用 realloc 扩展
  3. 可复用的向量类型
  4. 释放内存并避免泄漏
← 返回 C Academy