一维数组:从定义到实战
数组这东西,说白了就是一块连续的内存空间,里面存了一堆相同类型的数据。我刚开始学C语言时,总觉得数组没啥了不起的,直到后来做嵌入式项目,才发现数组简直是数据管理的基石。
你想想看,如果没有数组,你要存100个学生的成绩,难道要定义100个变量?那代码写出来自己都不想看。数组就是来解决这个问题的。
1.1 一维数组的定义
定义数组的语法很简单:
类型 数组名[元素个数];
举个例子:
int scores[100]; // 100个整型成绩
float temperatures[50]; // 50个温度值
char name[20]; // 20个字符的字符串
这里有个坑,我必须要说——数组的大小必须是常量,不能是变量。至少在C89标准下是这样的。我在项目中遇到过有人这么写:
int n = 10;
int arr[n]; // 这在C89中是错误的!
1.2 数组的初始化
初始化数组有几种常见方式,我习惯用第一种:
// 方式1:完全初始化
int a[5] = {1, 2, 3, 4, 5};
// 方式2:部分初始化,未指定的补0
int b[5] = {1, 2}; // 等价于 {1, 2, 0, 0, 0}
// 方式3:不指定大小,编译器自动计算
int c[] = {1, 2, 3, 4, 5}; // 自动推断为5个元素
// 方式4:全部初始化为0
int d[100] = {0}; // 所有元素都是0
1.3 数组元素的访问
访问数组元素用下标运算符 []:
int arr[5] = {10, 20, 30, 40, 50};
printf("%d\n", arr[0]); // 输出10
printf("%d\n", arr[2]); // 输出30
arr[3] = 99; // 修改第4个元素为99
这里有个冷知识——arr[i] 本质上等价于 *(arr + i)。所以你也可以写成 i[arr],虽然没人这么干。嗯,知道就好,别真这么写,会被同事打的。
1.4 数组的遍历
遍历数组最常用的就是 for 循环:
int arr[5] = {10, 20, 30, 40, 50};
int i;
for (i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
遍历时要注意循环条件。我见过有人写成 i <= 5,结果越界访问了 arr[5],那个位置存的是啥?天知道。这种bug最难查,因为它可能偶尔不报错,但关键时刻就崩。
1.5 数组的排序:冒泡排序
排序是数组的经典操作。冒泡排序虽然效率不高(O(n²)),但胜在简单直观,适合入门。它的原理就像气泡往上冒——每次比较相邻两个元素,把大的往后挪。
void bubble_sort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n - 1; i++) {
// 每轮把最大的元素"冒"到最后
for (j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
为什么内层循环要减去 i?因为每轮结束后,最后 i 个元素已经排好了,不用再比较。这是一个小优化,但能省不少事。
1.6 数组的查找:线性查找
线性查找,说白了就是从头到尾挨个找。数据量小的时候挺好用,数据量大了就慢了。
int linear_search(int arr[], int n, int target) {
int i;
for (i = 0; i < n; i++) {
if (arr[i] == target) {
return i; // 找到了,返回下标
}
}
return -1; // 没找到,返回-1
}
调用示例:
int scores[] = {78, 85, 92, 67, 88};
int pos = linear_search(scores, 5, 92);
if (pos != -1) {
printf("找到了,位置是:%d\n", pos);
} else {
printf("没找到\n");
}
线性查找的时间复杂度是 O(n)。如果数组是有序的,可以用二分查找,效率高得多。这个我们后面会讲。
知识体系总览
下面这张图把本章的核心内容串起来了,你可以对照着复习:
避坑指南
最后,我把自己踩过的坑总结一下,你遇到了可以少走弯路:
- 越界访问: 我曾经在嵌入式项目中,数组越界写到了别的变量上,导致系统随机死机。排查了三天才发现是数组下标多写了1。
- 未初始化: 局部数组不初始化,里面是垃圾值。我建议定义时就初始化,哪怕只是 {0}。
- 数组作为函数参数: 数组名传进函数后,会退化为指针,sizeof 就失效了。所以必须同时传数组长度。
- 冒泡排序的优化: 如果某一轮没有发生交换,说明已经有序了,可以提前退出。这个优化在数据接近有序时效果明显。
📌 本章小结: 一维数组是C语言中最基础的数据结构。你要掌握它的定义、初始化、访问方式,然后学会遍历、排序(冒泡)、查找(线性)。这些操作虽然基础,但它们是后续所有复杂数据结构的基石。我建议你多写代码,把每个操作都亲手实现一遍。
公众号:蓝海资料掘金营,微信deep3321