一、为什么需要数组?
在编程中,我们经常需要处理多个相同类型的数据。比如存储10个学生的成绩,如果不用数组,就得定义10个单独的变量(score1, score2, …),不仅麻烦,而且无法用循环统一处理。数组正是为了解决这类问题而生的——它能在内存中连续存储多个相同类型的数据,并通过下标快速访问每个元素。
二、一维数组基础
1. 数组的定义
语法格式:
类型说明符 数组名[常量表达式];
例如:
int a[10]; // 定义一个包含10个int元素的数组
char str[32]; // 定义包含32个char元素的数组
float array[5]; // 定义包含5个float元素的数组
- 类型说明符:可以是基本数据类型(int、char、float等),也可以是构造类型,但不能是void。
- 数组名:遵循标识符命名规则(字母、数字、下划线,数字不能开头)。
- 常量表达式:表示数组元素个数,必须是编译时确定的常量(不能是变量)。
2. 数组元素的访问
通过 数组名[下标] 访问元素,下标从 0 开始,到 元素个数-1 结束。
a[0] = 10; // 给第一个元素赋值
a[5] = 99; // 给第六个元素赋值
printf("%d", a[0]); // 输出第一个元素
注意:下标可以是常量、变量或表达式(结果必须为整型)。访问时不要超出范围,否则会越界访问,可能导致程序崩溃或数据错乱。
3. 数组的初始化
初始化即在定义时给元素赋初值。
- 全部初始化:
int a[5] = {1, 2, 3, 4, 5};
- 局部初始化(未初始化的元素自动为0):
int a[5] = {1, 2, 3}; // 前三个为1,2,3,后两个为0
- 初始化全0:
int a[5] = {0}; // 所有元素为0
int a[5] = {0,0,0,0,0};
- 省略数组大小(必须初始化):
int a[] = {1,2,3,4,5}; // 编译器自动确定大小为5
重要:如果不初始化,数组元素的值是随机的(内存中遗留的值),所以定义时尽量初始化,哪怕只是{0}。
4. 数组的存储特性
- 单一性:所有元素类型相同。
- 有序性:元素按下标从0到N-1顺序存储。
- 连续性:数组占用一块连续的内存空间。
这一点非常重要,因为连续存储使得我们可以通过指针和偏移量快速访问,也是数组效率高的原因。
三、数组的经典应用:排序
排序是数组的典型应用。这里以选择排序为例,掌握其思想。
选择排序(升序):每次从待排序位置开始,往后找到最小值,放到当前位置。
int a[10] = {1, 2, –3, –4, –5, 6, 7, 8, –9, 0};
int len = sizeof(a) / sizeof(a[0]); // 计算元素个数
for (int i = 0; i < len – 1; i++) {
for (int j = i + 1; j < len; j++) {
if (a[i] > a[j]) { // 升序:如果前面大于后面,交换
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
时间复杂度:O(n²),空间复杂度:O(1)。选择排序是不稳定的(相同元素相对顺序可能改变)。
四、字符型数组(字符串)
C语言没有专门的字符串类型,而是用字符数组来存储字符串,并以'\\0'(ASCII码0)作为结束标志。
1. 定义与初始化
char str[32];
char str[32] = {'h', 'e', 'l', 'l', 'o'}; // 不推荐,未初始化部分为0
char str[32] = {"hello"}; // 推荐
char str[32] = "hello"; // 最常用
char str[] = "hello"; // 自动确定大小为6(包含'\\0')
注意:"hello"实际占6个字节(5个字符 + 1个'\\0')。
2. 输入与输出
- 输出:可以使用printf("%s", str)或puts(str)(自动换行)。
- 输入:可以使用scanf("%s", str)(遇空格或Tab停止)或gets(str)(遇换行停止,但危险,可能越界)。
char str[100] = {0};
scanf("%s", str); // 输入 "hello world" 只读入 "hello"
gets(str); // 可读入带空格的字符串,但存在越界风险
3. 常用字符串操作函数(手写实现)
虽然标准库提供了strlen、strcpy、strcat等,但理解其底层实现至关重要。
① 求字符串长度 (strlen)
统计有效字符个数(不包括'\\0')。
int my_strlen(const char *s) {
int len = 0;
while (s[len] != '\\0') {
len++;
}
return len;
}
② 字符串拷贝 (strcpy)
将源字符串复制到目标数组(目标数组空间要足够)。
void my_strcpy(char *dst, const char *src) {
int i = 0;
while (src[i] != '\\0') {
dst[i] = src[i];
i++;
}
dst[i] = '\\0'; // 别忘了结束标志
}
③ 字符串拼接 (strcat)
将源字符串追加到目标字符串末尾。
void my_strcat(char *dst, const char *src) {
int i = 0, j = 0;
while (dst[i] != '\\0') i++; // 找到dst的末尾
while (src[j] != '\\0') {
dst[i] = src[j];
i++;
j++;
}
dst[i] = '\\0';
}
五、二维数组
二维数组可以理解为“数组的数组”,常用于存储矩阵或表格数据。
1. 定义与访问
int a[3][4]; // 3行4列,共12个元素
访问方式:a[行下标][列下标],行下标范围02,列下标03。
2. 初始化
- 全部初始化(分行或不分行):
int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int a[][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}; // 可省略行数
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; // 自动按行填充
- 局部初始化(未初始化的补0):
int a[3][4] = {{1,2}, {3,4,5}, {6}};
// 第一行:1,2,0,0;第二行:3,4,5,0;第三行:6,0,0,0
注意:在初始化时,行数可以省略,但列数不能省略。
3. 二维字符型数组
用于存储多个字符串(如学生名单)。
char str[3][100] = {0}; // 3个字符串,每个最长99字符
char str[3][100] = {"hello", "world", "how"};
输入输出时,用gets(str[i])或scanf("%s", str[i]),循环处理每一行。
六、易错点与最佳实践
- sizeof是运算符,计算数组占用的总字节数(包括'\\0')。
- strlen是函数,计算字符串有效字符个数(不含'\\0')。
网硕互联帮助中心![推荐题目:洛谷 P12792 [NERC 2022] Cactus Meets Torus-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/08/20260805114901-6a73232d88bf9-220x150.png)

![打卡信奥刷题(3491)用C++实现信奥题 P10734 [NOISG 2019 Prelim] Experimental Charges-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/08/20260805014046-6a72949eaf30f-220x150.png)


评论前必须登录!
注册