C语言中的可变长度数组:初学者指南

你好,未来的程序员们!今天,我们将踏上一段激动人心的旅程,探索C语言中的可变长度数组(Variable Length Arrays,简称VLAs)。如果你是编程新手,不用担心——我会作为你的友好向导,一步步解释所有内容。那么,让我们开始吧!

C - Variable Length Arrays

可变长度数组是什么?

在我们开始之前,先来了解一下可变长度数组是什么。想象你正在计划一个派对,但你不确定会有多少客人来。如果你能设置一个可以神奇地根据客人数量调整大小的桌子,那岂不是很好?这正是编程中VLAs的作用!

可变长度数组是一种在运行时(程序运行时)而不是在编译时(程序准备运行时)确定大小的数组。这个特性在C99标准中引入,为创建数组提供了更大的灵活性。

创建可变长度数组

让我们从一个简单的例子开始,创建一个VLA:

#include <stdio.h>

int main() {
int n;
printf("你想存储多少个数字? ");
scanf("%d", &n);

int numbers[n];  // 这就是我们的可变长度数组

printf("输入 %d 个数字:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &numbers[i]);
}

printf("你输入了:");
for (int i = 0; i < n; i++) {
printf("%d ", numbers[i]);
}

return 0;
}

让我们分解一下:

  1. 我们询问用户想要存储多少个数字。
  2. 我们根据用户输入的大小创建一个名为numbers的数组。
  3. 我们使用循环从用户那里输入n个数字。
  4. 最后,我们打印用户输入的所有数字。

这就是VLAs的美妙之处——我们在编写代码时不需要知道数组的大小。大小是在程序运行时确定的!

二维可变长度数组

现在,让我们升级一下,看看二维的VLA。想象你正在为一个婚礼创建座位图,但你不知道会有多少桌子或者每张桌子会有多少座位。二维VLA可以帮助你!

这里有一个例子:

#include <stdio.h>

int main() {
int tables, seats;

printf("有多少桌子? ");
scanf("%d", &tables);

printf("每张桌子有多少座位? ");
scanf("%d", &seats);

int seating[tables][seats];  // 我们的2D可变长度数组

// 分配座位号
for (int i = 0; i < tables; i++) {
for (int j = 0; j < seats; j++) {
seating[i][j] = i * seats + j + 1;
}
}

// 打印座位安排
printf("\n座位安排:\n");
for (int i = 0; i < tables; i++) {
printf("桌子 %d: ", i + 1);
for (int j = 0; j < seats; j++) {
printf("%3d ", seating[i][j]);
}
printf("\n");
}

return 0;
}

在这个例子中:

  1. 我们询问用户桌子的数量和每张桌子的座位数量。
  2. 我们创建一个名为seating的2D VLA,尺寸为[tables][seats]
  3. 我们分配座位号。
  4. 最后,我们打印座位安排。

这种灵活性允许我们在运行时创建任何大小的座位图!

锯齿数组

现在,事情变得更加有趣。如果我们的婚礼上每张桌子都有不同数量的座位怎么办?这时候就引入了锯齿数组——一个数组,其中的子数组可以有不同的长度。

虽然C语言不直接支持像其他一些语言那样的锯齿数组,但我们可以使用VLA和指针来模拟它们。以下是如何操作的:

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

int main() {
int tables;
printf("有多少桌子? ");
scanf("%d", &tables);

int *seats = malloc(tables * sizeof(int));
int **seating = malloc(tables * sizeof(int*));

// 输入每张桌子的座位数量
for (int i = 0; i < tables; i++) {
printf("桌子 %d 有多少座位? ", i + 1);
scanf("%d", &seats[i]);
seating[i] = malloc(seats[i] * sizeof(int));
}

// 分配座位号
for (int i = 0; i < tables; i++) {
for (int j = 0; j < seats[i]; j++) {
seating[i][j] = j + 1;
}
}

// 打印座位安排
printf("\n座位安排:\n");
for (int i = 0; i < tables; i++) {
printf("桌子 %d: ", i + 1);
for (int j = 0; j < seats[i]; j++) {
printf("%3d ", seating[i][j]);
}
printf("\n");
}

// 释放分配的内存
for (int i = 0; i < tables; i++) {
free(seating[i]);
}
free(seating);
free(seats);

return 0;
}

这个例子更复杂一些,让我们分解一下:

  1. 我们创建一个数组seats来存储每张桌子的座位数量。
  2. 我们创建一个指向指针的指针seating来模拟我们的锯齿数组。
  3. 我们根据每张桌子的座位数量动态分配内存。
  4. 我们分配座位号并像之前一样打印安排。
  5. 最后,我们释放分配的内存以防止内存泄漏。

这种方法允许我们每张桌子都有不同数量的座位——真正的灵活性!

方法表

这里是一个我们例子中用到的方法的快速参考表:

方法 描述 示例
scanf() 从用户读取格式化输入 scanf("%d", &n);
printf() 向控制台打印格式化输出 printf("你好,%s!", name);
malloc() 动态分配内存 int *arr = malloc(n * sizeof(int));
free() 释放动态分配的内存 free(arr);

记住,能力越大,责任越大。VLAs和动态内存分配是强大的工具,但需要谨慎使用,以避免栈溢出或内存泄漏等问题。

就是这样!你已经迈出了进入C语言可变长度数组世界的第一步。记住,熟能生巧,所以不要害怕尝试这些概念。快乐编码!

Credits: Image by storyset