分配数组
预留堆内存。
分配数组 是 CoddyKit 上的免费 C Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。
为什么需要动态数组
普通数组的大小在编译时就已经固定。但在许多情况下,只有等程序运行后,您才知道需要多少个元素。
动态数组可以解决这个问题:您可以在运行时使用 malloc 向操作系统申请一块内存,并通过变量决定其大小。
认识内存分配函数
malloc(memory allocate,内存分配)位于 <stdlib.h> 中。您向它传入字节数,它会返回指向该内存块的指针;如果失败,则返回 NULL。
这块内存来自堆,并会一直存在,直到您释放它。
int *p = malloc(10 * sizeof(int));使用 sizeof 计算大小
不要硬编码字节数。请使用 sizeof,这样代码在不同平台上都能保持正确。
要为 n 个整数分配空间,请将 n 乘以 sizeof(int)。常见的写法是 n * sizeof(*p),它会使用指针自身的类型。
int *p = malloc(n * sizeof(*p));始终检查 NULL
如果系统内存不足,malloc 会返回 NULL。解引用 NULL 指针会导致程序崩溃。
请在使用结果之前进行检查。这个简单的习惯可以避免许多难以调试的故障。
int *p = malloc(n * sizeof(*p));
if (p == NULL) {
fprintf(stderr, "out of memory\n");
return 1;
}完整的内存分配
下面是一个完整的程序,它会为 5 个整数分配空间,填入这些整数,然后将它们打印出来。
请注意其中的对应关系:开始时使用 malloc,结束时使用 free。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 5;
int *a = malloc(n * sizeof(*a));
if (!a) return 1;
for (int i = 0; i < n; i++) a[i] = i * i;
for (int i = 0; i < n; i++) printf("%d\n", a[i]);
free(a);
return 0;
}malloc 不会清零
malloc 返回的内存未经初始化:其中保存的是之前遗留的任意数据。
在写入之前读取它,会得到不可预测的值。请始终先为每个元素赋值,再读取它。
int *a = malloc(3 * sizeof(*a));
/* a[0], a[1], a[2] hold garbage here */
a[0] = 10;calloc 会自动清零
calloc(count, size) 会为 count 个元素分配空间,每个元素占用 size 个字节,并将每个字节都设置为零。
当您需要一个干净、填充为零的数组时,可以使用它。它还可以防止乘法运算发生溢出。
int *a = calloc(5, sizeof(*a));
/* every element is now 0 */calloc 的实际应用
这个程序使用 calloc,并确认数组在我们修改之前已经从零开始。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 4;
int *a = calloc(n, sizeof(*a));
if (!a) return 1;
for (int i = 0; i < n; i++) printf("%d\n", a[i]);
free(a);
return 0;
}为内存块建立索引
指向堆内存块的指针,其行为与数组名称完全相同。您可以使用 a[i] 读取和写入从 0 到 n-1 的任意元素。
在底层,a[i] 与 *(a + i) 完全相同。
int *a = malloc(3 * sizeof(*a));
a[0] = 1;
*(a + 1) = 2; /* same as a[1] = 2 */
a[2] = 3;注意边界
如果您分配了 n 个元素,有效索引就是从 0 到 n-1。向 a[n] 写入属于未定义行为。
C 不会替您检查边界,因此越界一位的错误可能会悄无声息地破坏内存。
int *a = malloc(3 * sizeof(*a));
a[2] = 99; /* OK, last valid index */
/* a[3] = 0; BUG: out of bounds */在运行时读取大小
动态分配真正强大的地方在于:大小可以来自输入、文件或计算结果。同一段代码既可以分配 2 个元素,也可以分配 200 万个元素。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 6; /* could be scanf'd */
long *a = malloc(n * sizeof(*a));
if (!a) return 1;
long sum = 0;
for (int i = 0; i < n; i++) { a[i] = i + 1; sum += a[i]; }
printf("%ld\n", sum);
free(a);
return 0;
}快速检查
测试您对内存分配的理解。
回顾
您可以使用 malloc(n * sizeof(*p)) 分配动态数组,或使用 calloc(n, sizeof(*p)) 分配一个填充为零的数组。
请始终检查 NULL,记住 malloc 不会清除原有数据,索引范围从 0 到元素个数减一,并为每次分配配对使用一个 free。接下来,您将学习如何在保留数据的同时调整内存块的大小。
常见问题解答
「分配数组」课时是免费的吗?
是的 — 「分配数组」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「分配数组」这节课中我会学到什么?
预留堆内存。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「分配数组」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。