数组初探:一维数组的定义、初始化与遍历
数组这东西,说白了就是一块连续的内存空间。我刚开始学C语言的时候,总觉得数组就是个「能存一堆数据的变量」,后来踩了几次坑才真正理解——数组的灵魂在于「连续」这两个字。
你想想看,如果让你存100个学生的成绩,难道要定义100个单独的变量?score1, score2, score3... 写到第50个你就想砸键盘了。数组就是来解决这个问题的。
一维数组的定义
定义数组的语法很简单:
类型 数组名[元素个数];
举个例子:
int scores[100]; // 存放100个整数
float prices[50]; // 存放50个浮点数
char name[20]; // 存放20个字符
这里有个关键点——元素个数必须是常量。我在早期项目里犯过这个错:
int n = 100;
int arr[n]; // 这样写?在C99之前是错的!
嗯,C99标准之后支持了变长数组(VLA),但很多嵌入式编译器还不支持。我个人习惯还是用宏定义或者常量:
#define MAX_SIZE 100
int arr[MAX_SIZE];
数组的初始化
初始化有好几种玩法,我按常用程度给你排个序:
1. 完全初始化
int a[5] = {1, 2, 3, 4, 5};
这个没啥好说的,一一对应。
2. 部分初始化
int b[5] = {1, 2}; // 等价于 {1, 2, 0, 0, 0}
注意了!未显式初始化的元素会被自动赋值为0。这个特性我经常用——想快速把数组清零?直接 int arr[100] = {0}; 搞定。
3. 省略大小初始化
int c[] = {10, 20, 30}; // 编译器自动推断大小为3
这个写法很省事,但有个坑——你没法通过 sizeof(c)/sizeof(c[0]) 以外的方式知道数组大小。我曾经在接手一个老项目时,看到别人这么写,结果数组实际大小跟我想的不一样,排查了半天。
arr[100] 它也不会报错,但后果自负。
数组在内存中的存储
这是理解数组的关键。咱们画个图看看:
看到没?arr[0] 到 arr[4] 在内存里是紧挨着的。每个 int 占4个字节,所以地址依次相差4。这就是数组的「连续存储特性」。
arr 本身就是一个指针常量,指向第一个元素。所以 arr 和 &arr[0] 是等价的。但注意,arr 不是变量,你不能写 arr++。
数组的遍历
遍历数组最常用的就是 for 循环:
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
// 正向遍历
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// 反向遍历
for (int i = 4; i >= 0; i--) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
输出结果:
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
arr[4] = 50
arr[3] = 40
arr[2] = 30
arr[1] = 20
arr[0] = 10
这里有个细节——循环变量 i 从0开始,到 n-1 结束。为什么不是从1开始?因为数组下标就是0-based的。我见过新手写成 for (i = 1; i <= 5; i++),结果 arr[5] 越界了,程序跑飞都不知道怎么回事。
arr[5] 它不会报错,但会访问到数组后面的内存。我曾经在一个通信协议栈里,因为数组越界写坏了相邻变量的值,导致整个协议栈崩溃,查了整整两天才找到原因。
数组大小计算
有时候你不知道数组有多大,可以用 sizeof 来算:
int arr[] = {2, 4, 6, 8, 10, 12, 14};
int size = sizeof(arr) / sizeof(arr[0]); // 7
原理很简单:sizeof(arr) 是整个数组占的字节数,sizeof(arr[0]) 是单个元素占的字节数,一除就是元素个数。
但注意——这个技巧只在数组定义的作用域内有效。如果你把数组传给函数,它就会退化成指针,sizeof 就失效了。这个坑我后面讲指针的时候再细说。
实际项目中的经验
我在做嵌入式开发时,经常用数组来查表。比如温度传感器采集到的电压值,通过查表转换成温度:
// 电压值到温度的映射表
int voltage_to_temp[] = {
-40, -30, -20, -10, 0, 10, 20, 30, 40, 50
};
// 假设采集到的电压索引是 4(对应0度)
int index = 4;
int temp = voltage_to_temp[index]; // 得到 0
这种查表法比实时计算快得多,尤其适合资源受限的嵌入式环境。
另外,我个人习惯在定义数组时,总是显式初始化。哪怕只是 int arr[100] = {0};,也比不初始化强。因为局部数组如果不初始化,里面存的是垃圾值,一不小心就出bug。
总结一下
数组的核心就三点:
- 连续存储——元素在内存里一个挨一个
- 下标从0开始——
arr[0]是第一个元素 - 不会越界检查——自己管好自己的下标
记住这三点,数组这块就稳了。下一节我们聊聊二维数组,其实也就是「数组的数组」,理解了今天的内容,二维数组就是水到渠成的事。
公众号:蓝海资料掘金营,微信deep3321