一、数组的基本概念与分类
1. 核心定义
数组是相同数据类型、有限个元素的有序集合。其核心特性的:
- 连续性:数组元素在内存中占用连续的存储空间;
- 有序性:元素通过 “下标”(索引)唯一标识,下标从 0 开始;
- 单一性:所有元素必须是同一种数据类型(如 int、float 等)。
2. 数组的分类
根据维度不同,数组可分为:
- 一维数组:最常用的形式,如int a[5](存储 5 个整数);
- 二维数组:本质是 “数组的数组”,如int a[3][4](3 行 4 列的整数矩阵);
- 多维数组:二维以上的数组(如三维数组int a[2][3][4]),实际开发中较少使用。
本文重点讲解一维数组的使用(二维及多维数组可类比推导)。
二、一维数组的定义与初始化
1. 数组的定义
定义格式:数据类型 数组名[元素个数];
- 数据类型:数组元素的统一类型(如 int、float、char 等);
- 数组名:符合 C 语言命名规则(字母、数字、下划线组成,不能以数字开头);
- 元素个数:必须是常量或常量表达式(不能是变量),表示数组能存储的元素总数。
2. 数组的初始化
数组定义后若未初始化,元素值为随机值(内存中的垃圾数据),因此建议显式初始化。常见初始化方式有 3 种:
(1)全部初始化
显式指定所有元素的值,元素个数与初始化列表长度一致:
(2)局部初始化
只指定部分元素的值,未指定的元素会自动初始化为 0:
(3)默认初始化
不指定元素个数,编译器会根据初始化列表的长度自动推导数组长度:
3. 关键注意事项
- 数组下标范围:合法下标是0 ~ 元素个数-1,例如int arr[5]的合法下标是 0-4,访问arr[5]属于越界访问,会导致内存错误(如栈溢出);
- 数组长度计算:通过sizeof(arr) / sizeof(arr[0])可动态计算数组长度(避免硬编码,提高代码复用性)
三、数组的基本操作:输入与输出
数组元素的访问通过 “数组名 [下标]” 实现,结合循环可批量完成输入 / 输出。
1. 数组输入(从终端读取数据)
使用scanf结合for循环,遍历数组并接收用户输入:
#include <stdio.h>
int main(void) {
int arr[5] = {0};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0;
printf("请输入%d个整数:\\n", len);
for (i = 0; i < len; i++) {
// &arr[i]:取第i个元素的内存地址(scanf需要地址参数)
scanf("%d", &arr[i]);
}
return 0;
}
2. 数组输出(向终端打印数据)
使用printf结合for循环,遍历数组并打印元素:
// 接上面的输入代码,添加输出逻辑
printf("数组元素:");
for (i = 0; i < len; i++) {
// 打印第i个元素,加空格分隔
printf("%d ", arr[i]);
}
printf("\\n");
请输入5个整数:
3 1 4 2 5
数组元素:3 1 4 2 5
四、数组常见算法实战
数组的核心应用是批量数据处理,以下是 3 个最常用的算法(含完整代码)。
1. 求数组的最大值(及最大值下标)
算法思路:
完整代码:
#include <stdio.h>
int main(void) {
int arr[5] = {0};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int max_val = 0; // 存储最大值
int max_idx = 0; // 存储最大值下标
// 输入数组
printf("请输入%d个整数:\\n", len);
for (i = 0; i < len; i++) {
scanf("%d", &arr[i]);
}
// 初始化最大值为第一个元素
max_val = arr[0];
for (i = 1; i < len; i++) {
if (arr[i] > max_val) {
max_val = arr[i]; // 更新最大值
max_idx = i; // 更新最大值下标
}
}
// 输出结果
printf("数组最大值:%d\\n", max_val);
printf("最大值下标:%d\\n", max_idx);
return 0;
}
请输入5个整数:
3 1 4 2 5
数组最大值:5
最大值下标:4
2. 数组元素倒置(逆序)
算法思路:
将数组 “首尾元素互换”,直到中间位置:
完整代码:
#include <stdio.h>
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int tmp = 0; // 临时变量,用于交换元素
// 倒置前输出
printf("倒置前数组:");
for (i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\\n");
// 数组倒置
for (i = 0; i < len / 2; i++) {
// 交换arr[i]和arr[len-1-i]
tmp = arr[i];
arr[i] = arr[len – 1 – i];
arr[len – 1 – i] = tmp;
}
// 倒置后输出
printf("倒置后数组:");
for (i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\\n");
return 0;
}
倒置前数组:1 2 3 4 5
倒置后数组:5 4 3 2 1
3. 数组排序:冒泡排序与选择排序
排序是数组最核心的应用之一,以下讲解两种基础且常用的排序算法(升序排列)。
(1)冒泡排序
算法思路:
通过相邻元素两两比较并交换,将 “大数” 逐步 “冒泡” 到数组末尾:
完整代码:
#include <stdio.h>
int main(void) {
int arr[5] = {0};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0, j = 0;
int tmp = 0;
// 输入数组
printf("请输入%d个整数:\\n", len);
for (i = 0; i < len; i++) {
scanf("%d", &arr[i]);
}
// 冒泡排序(升序)
for (j = 0; j < len – 1; j++) { // 外层:排序轮数(len-1轮)
for (i = 0; i < len – 1 – j; i++) { // 内层:每轮比较次数
if (arr[i] > arr[i + 1]) { // 相邻元素比较,大数后移
tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
}
// 输出排序结果
printf("排序后数组:");
for (i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\\n");
return 0;
}
(2)选择排序
算法思路:
每轮找到数组中最小元素的下标,与当前轮的起始位置元素交换:
完整代码:
#include <stdio.h>
int main(void) {
int arr[5] = {0};
int len = sizeof(arr) / sizeof(arr[0]);
int i = 0, j = 0;
int tmp = 0;
int min_idx = 0; // 存储最小元素下标
// 输入数组
printf("请输入%d个整数:\\n", len);
for (i = 0; i < len; i++) {
scanf("%d", &arr[i]);
}
// 选择排序(升序)
for (j = 0; j < len – 1; j++) { // 外层:起始位置
min_idx = j; // 假设当前起始位置是最小值
// 内层:查找最小元素下标
for (i = j + 1; i < len; i++) {
if (arr[i] < arr[min_idx]) {
min_idx = i; // 更新最小元素下标
}
}
// 交换当前起始位置与最小元素位置
if (min_idx != j) {
tmp = arr[j];
arr[j] = arr[min_idx];
arr[min_idx] = tmp;
}
}
// 输出排序结果
printf("排序后数组:");
for (i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\\n");
return 0;
}
两种排序算法对比:
| 冒泡排序 | 相邻元素交换,逻辑简单 | O(n²) |
| 选择排序 | 先找最小下标再交换,交换次数少 | O(n²) |



