LV050-变长数组
一、变长数组简介
在 C语言中,变长数组(Variable Length Array,简称 VLA)是一种可以在运行时动态确定大小的数组。变长数组是 C99 标准(ISO/IEC 9899:1999)引入的新特性,它允许数组的长度不是固定的编译时常量,而是根据程序运行时的变量或表达式来决定。
1. 什么是变长数组
在 C 语言里,传统的数组(如 int arr[10])要求在声明时指定一个固定的长度,这个长度必须是编译时已知的常量。而变长数组打破了这一限制,其大小可以在运行时动态计算,通常由变量或函数参数决定。
变长数组的内存分配仍然是在栈上完成的(与动态分配的堆内存不同),它的核心特点包括:
- 大小在运行时确定。
- 内存分配在栈上,自动管理生命周期。
- 仅限于局部作用域(不能是全局变量)。
2. 怎么声明
变长数组的声明与普通数组类似,但长度部分可以用变量或表达式替代。基本语法如下:
// 直接定义
数据类型 数组名[表达式];这里的 表达式 在运行时计算,确定数组的大小。例如:
int n = 5;
int arr[n]; // 变长数组,大小为 n
// 也可以在函数形参中确定大小
void process(size_t n) {
int arr[n]; // VLA:长度为运行时变量n
// ... 数组操作
}需要注意的是,n 的值必须在数组声明时已经确定,且不能为负数或零,否则会导致未定义行为。
3. 使用实例
让我们通过一个简单示例来看看变长数组的实际应用。假设我们要根据用户输入的大小创建一个数组:
#include <stdio.h>
int main(int argc, char *argv[]) {
int n = 5;
int arr[n]; // 变长数组
// 初始化数组
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
// 打印数组
printf("数组内容:");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}输出结果:
数组内容:1 2 3 4 5在这个例子中,arr 的大小由用户输入的 n 决定。程序根据 n 创建了一个变长数组,并对其进行初始化和输出。
4. 在函数中的应用
变长数组特别适合作为函数的局部变量,尤其在需要动态大小的场景中。例如,我们可以编写一个函数,根据参数创建变长数组并计算元素之和:
#include <stdio.h>
void sum_array(int size) {
int arr[size]; // 变长数组
for (int i = 0; i < size; i++) {
arr[i] = i * 2;
}
int sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
printf("数组元素之和:%d\n", sum);
}
int main(int argc, char *argv[]) {
int n = 5;
sum_array(n);
return 0;
}输出结果:
数组元素之和:20这里,arr[size] 的长度由函数参数 size 决定,数组元素为 0、2、4、6,总和为 12。
5. 优点与局限性
5.1 优点
- 简单易用:无需手动分配和释放内存。
- 局部优化:栈上分配通常比堆上分配更快。
- 动态性:无需提前知道固定大小。
5.2 局限性
- 栈空间限制:栈大小有限(通常几 MB),过大的变长数组会导致栈溢出。
- 仅限局部:不能声明为全局变量或静态变量。
- 兼容性:C11 将 VLA 设为可选特性,部分编译器可能不支持。
5.3 注意事项
- 大小检查:确保长度不为负数或零,避免未定义行为。
- 栈溢出:避免声明过大的变长数组,例如
int arr[1000000]可能崩溃。 - 编译器支持:使用前确认编译器支持 C99 或更高版本(如 gcc 使用
-std=c99)。
示例(检测栈溢出风险):
#include <stdio.h>
int main() {
int n = 1000000; // 过大可能溢出
int arr[n];
printf("创建了一个大小为 %d 的数组\n", n);
return 0;
}这种代码在小型栈环境中可能失败,需谨慎使用。
二、多维变长数组
C99 还支持多维变长数组,常用于动态矩阵等场景。声明时,至少有一个维度可以是运行时表达式。例如:
#include <stdio.h>
void print_matrix(int rows, int cols) {
int matrix[rows][cols]; // 多维变长数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i + j;
}
}
printf("矩阵内容:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(int argc, char *argv[]) {
print_matrix(3, 4);
return 0;
}输出结果:
矩阵内容:
0 1 2 3
1 2 3 4
2 3 4 5在这个例子中,matrix 是一个 3 行 4 列的变长数组,行数和列数由函数参数动态指定。
三、变长数组与动态内存分配的对比
变长数组常被拿来与动态内存分配(malloc 和 free)对比,二者都能实现动态大小的数组,但有显著区别。对比如下:
| 特性 | 变长数组 | 动态内存分配 |
|---|---|---|
| 内存位置 | 栈 | 堆 |
| 生命周期 | 自动释放(离开作用域) | 需手动释放(free) |
| 大小限制 | 受栈空间限制(较小) | 受堆空间限制(较大) |
| 语法复杂度 | 简单 | 需手动管理 |
示例(动态内存分配版本):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int n;
printf("请输入数组大小:");
scanf("%d", &n);
int *arr = (int *)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
printf("数组内容:");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}变长数组更简洁,但动态分配更灵活,适合大数组或需要跨作用域使用的情况。
四、总结
变长数组是 C99 标准新增的特性,它允许数组的长度不是固定的编译时常量,而是根据程序运行时的变量或表达式来决定,特别适合需要动态大小的局部数组场景。
参考资料: