别再用30个变量存身高了,数组才是批量数据的正确打开方式
想象一下这个场景:你是一位体育老师,刚给全班30个学生测完身高,现在要算出平均身高。如果你的第一反应是拿起计算器一个个加,那这篇文章可能帮不了你。但如果你是那个负责写代码统计的程序员,恭喜你,你即将经历一场"变量地狱"。
让我们先看一个反面教材。假设某个新手程序员真的用30个变量来存身高:
int h1 = 150, h2 = 165, h3 = 172, h4 = 158, h5 = 180;
// 然后继续写25行...
int sum = h1 + h2 + h3 + h4 + h5 + ... // 写到怀疑人生
这代码不仅长得像恐怖片,而且一旦人数从30变成300,代码量直接爆炸。更要命的是,你没法用循环去处理这些变量——因为循环需要的是"规律",而 h1、h2、h3 这种变量名在编译器眼里就是三个互不相干的陌生人。
数组就是来解决这个问题的。它像一排带编号的抽屉,编号从0开始,每个抽屉里放一个数据。数组的本质,就是把"名字"变成"编号",让数据可以被循环遍历。
三个最常用的数组套路
套路一:累加求和
这是数组最基础的用法,也是后面所有复杂操作的地基。核心就一句话:初始化一个累加器,然后循环把每个元素加进去。
int scores[5] = {88, 92, 73, 85, 96};
int sum = 0;
for(int i = 0; i < 5; i++) {
sum += scores[i]; // 等价于 sum = sum + scores[i];
}
double average = (double)sum / 5; // 注意类型转换
这里有个新手最容易踩的坑:平均值计算时忘记转类型。sum / 5 是整数除法,结果会截断小数。比如 434 / 5 在C++里等于 86,而不是 86.8。正确做法是 (double)sum / 5 或者 sum / 5.0。
套路二:找最大值和最小值
这个套路的关键在于初始值的设定。很多新手喜欢把最大值初始化为0,这在处理身高、成绩这类正数数据时没问题,但如果数据全是负数(比如温度),0就会变成"最大"的那个,结果全错。
正确做法是:用数组的第一个元素作为初始值,然后从第二个元素开始逐个比较。
int maxVal = height[0]; // 不要设成0!
int minVal = height[0];
for(int i = 1; i < n; i++) {
if(height[i] > maxVal) maxVal = height[i];
if(height[i] < minVal) minVal = height[i];
}
套路三:倒序输出
这个套路最简单,但最容易在边界条件上出错。数组最后一个元素的下标是 n-1(因为下标从0开始),所以倒序循环要从 n-1 开始,到 0 结束:
for(int i = n-1; i >= 0; i--) {
cout << height[i] << " ";
}
注意循环条件是 i >= 0,不是 i > 0。很多新手写 i > 0 会漏掉第一个元素。
实战:扫雷游戏的地雷数计算
这三个套路组合起来,就能解决很多实际问题。比如经典的扫雷游戏——计算每个格子周围的地雷数量。
这道题的核心思路是:遍历每个非地雷格子,检查它的8个邻居中有多少个是地雷。这不就是"累加求和"的变体吗?只不过累加的不是数值,而是"邻居是地雷"这个条件的次数。
// 方向数组:8个邻居的偏移量
int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
// 对每个非地雷格子,统计周围地雷数
if(map[i][j] != '*') {
int count = 0;
for(int k = 0; k < 8; k++) {
int ni = i + dx[k];
int nj = j + dy[k];
// 检查边界,防止越界
if(ni >= 0 && ni < n && nj >= 0 && nj < m && map[ni][nj] == '*') {
count++;
}
}
map[i][j] = '0' + count; // 数字转字符
}
这里有个关键点:方向数组。把8个方向的偏移量提前存好,用循环遍历,比手动写8个if判断要简洁得多,也不容易漏掉某个方向。这就是数组的另一个应用——用数据驱动逻辑。
常见错误:比你想的更危险
错误一:数组越界
int arr[5];
for(int i = 0; i <= 5; i++) {
arr[i] = i; // 当 i=5 时,arr[5] 越界了!
}
arr[5] 访问的是数组之外的内存,程序可能崩溃,也可能不崩溃但产生奇怪的结果。这种bug最难排查,因为它在不同环境下表现不一样。
错误二:未初始化的累加器
int sum; // 没有初始化!
for(int i = 0; i < 10; i++) {
sum += a[i]; // sum 的初始值是随机的!
}
sum 没有初始化,它的值是内存中残留的随机数。这就像你往一个没倒空的杯子里加水,最后得到的水量完全不可预测。
错误三:找最大值时初始值设错
前面说过,把最大值初始化为0在处理负数数据时会出错。永远用第一个元素作为初始值,这是最安全的做法。
写在最后
数组的这三种典型用法——累加、找极值、倒序——看起来简单,但它们组合起来能解决大量实际问题。扫雷游戏、成绩统计、数据分析,本质上都是这些基础操作的组合。
进阶建议:学完一维数组后,去了解一下二维数组(处理表格数据)、字符数组(处理字符串)、以及vector容器(动态数组)。这些都是数组的延伸,理解了数组的本质,学起来会事半功倍。
最后送你一句话:编程的核心不是记住语法,而是把复杂问题拆解成简单操作的组合。数组就是你手中的积木,学会用积木搭出各种形状,才是真正的本事。
关于作者
我是赵老师,持有 NOI 信息学奥赛教练证书,拥有 15 年以上的软件开发经验,从事信息学少儿编程教学已有 8 年时间。
这些年累计帮助 多名 学生通过编程特长升入自己心仪的目标学校。
如果你在编程学习上有任何疑问,欢迎联系我:18620372957(微信同号)