处理 10 个成绩可以写 10 个变量,处理 10000 个呢?数组让"同一类型的批量数据"可以用一个名字管理。而 C 的字符串本质上就是字符数组——理解了数组,字符串就懂了一半。本文从一维数组讲到排序实战。
1. 一维数组的基本操作
数组是连续内存中同类型元素的集合,下标从 0 开始。声明格式:类型 数组名[元素个数];
#include <stdio.h>
int main(void) {
int scores[5] = {88, 92, 75, 69, 96};
printf("第一个: %d\n", scores[0]); // 88
printf("最后一个: %d\n", scores[4]); // 96
scores[2] = 80; // 修改第 3 个元素
return 0;
}
访问 scores[5] 是越界——C 不检查下标,越界读写是未定义行为,可能悄悄破坏其他数据,务必小心。
2. 遍历与统计
数组 + for 循环是黄金搭档。计算平均分:
#include <stdio.h>
int main(void) {
int scores[5] = {88, 92, 75, 69, 96};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += scores[i];
}
printf("总分 %d, 平均 %.1f\n", sum, sum / 5.0);
return 0;
}
注意 sum / 5.0 用的是浮点数除法,如果写 sum / 5 结果会被截断成整数。
3. 初始化规则
数组初始化有几个常用技巧:
int a[5] = {0};全部初始化为 0(第一个显式写 0,其余自动补 0)。int b[] = {1, 2, 3};省略大小,编译器自动数出 3 个。int c[5] = {1, 2};前两个是 1、2,后面自动补 0。- 局部数组不初始化时内容是垃圾值,使用前必须赋值。
4. 二维数组
二维数组适合表达表格、矩阵。存储顺序是"按行优先",初始化用花括号分行写更直观:
#include <stdio.h>
int main(void) {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
5. 字符串:特殊的字符数组
C 字符串以 '\0'(空字符)结尾,所以存 "CodeLab" 需要 8 个字符的空间。标准库 string.h 提供了常用函数:
#include <stdio.h>
#include <string.h>
int main(void) {
char name[20] = "CodeLab";
char greeting[50];
strcpy(greeting, "Hello, "); // 拷贝
strcat(greeting, name); // 拼接
printf("%s, 长度=%zu\n", greeting, strlen(greeting));
if (strcmp(name, "CodeLab") == 0) { // 比较
printf("名字一致\n");
}
return 0;
}
比较字符串必须用 strcmp,直接用 == 比较的是两个指针(地址),几乎永远不相等。
6. 实战:冒泡排序
冒泡排序是最经典的入门排序:每轮把相邻的逆序对交换,最大的数"冒"到末尾:
#include <stdio.h>
int main(void) {
int arr[] = {5, 2, 9, 1, 7};
int n = 5;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
内层循环的 n - 1 - i 是关键:每轮结束,末尾 i 个元素已经就位,无需再比较。
💡 学习建议:用 printf 在每轮排序后打印整个数组,亲眼看数字如何"冒泡"到末尾。可视化调试是理解算法的捷径。