C语言数组的定义和使用(非常详细,大量示例)
所谓数组(Array),就是一系列数据的集合。这些数据具有相同的类型,并且在内存中挨着存放,彼此之间没有缝隙。换句话说,数组用来存放多份数据,但是它有两个要求:
这些数据的类型必须相同;这些数据在内存中必须连续存储。
如果没有数组,存储多份数据就需要多个变量名,管理和使用起来都非常麻烦;而有了数组,只需要一个变量名就能搞定。 数组包含的每份数据,都叫做数组的一个元素(Element);数组包含的数据的个数,叫做数组的长度(Length)。
数组不是C语言的专利,Java、C++、C#、JavaScript、PHP 等其他编程语言也有数组。
数组的定义
在C语言中,定义数组需要遵循特定的语法,一般形式如下:
dataType arrayName[length];
其中,dataType 是每个元素的类型,比如 int、float、char 等;dataType 是数组的名字,它是一个自定义的标识符,符合标识符的命名规则;方括号[ ]中的 length 是数组的长度,也即数组包含的元素的个数。 来看个简单的例子:
int nums[4];
这样就定义了一个名为 nums 的数组,它包含 4 个 int 类型的元素。再比如:
float temperatures[100]; //定义一个可以存储 100 个浮点数的数组
char name[20]; //定义一个可以存储 20 个字符的数组
数组下标
在C语言中,数组中的每个元素都有一个序号,这个序号从 0 开始,而不是从我们熟悉的 1 开始,称为下标(Index)。使用数组元素时,指明下标即可,形式为:
arrayName[index]
arrayName 为数组名称,index 为下标。例如,nums[0] 表示第 1 个元素,nums[3] 表示第 4 个元素。 通过下标,我们可以访问数组元素,也可以给数组元素赋值。例如,给 nums 数组中的所有元素赋值:
nums[0] = 20;
nums[1] = 345;
nums[2] = 700;
nums[3] = 22;
nums[4] = -59
这里的 0、1、2、3、4 就是数组下标,a[0]、a[1]、a[2]、a[3]、a[4] 就是数组元素。 然后,再通过下标访问(读取)数组中的元素:
printf("%d", nums[2]);
输出第 3 个元素的值,结果是 700。
示例1:使用循环结构将数据放入数组中(也就是为数组元素逐个赋值),然后再使用循环结构输出(也就是依次读取数组元素的值),下面我们就来演示一下如何将 1~10 这十个数字放入数组中:
#include
int main(){
int nums[10];
int i;
//将1~10放入数组中
for(i=0; i<10; i++){
nums[i] = (i+1);
}
//依次输出数组元素
for(i=0; i<10; i++){
printf("%d ", nums[i]);
}
return 0;
}
运行结果:
1 2 3 4 5 6 7 8 9 10
变量 i 既是数组下标,也是循环条件;将数组下标作为循环条件,达到最后一个元素时就结束循环。数组 nums 的最大下标是 9,也就是不能超过 10,所以我们规定循环的条件是 i<10,一旦 i 达到 10 就得结束循环。 示例2:更改上面的代码,让用户输入 10 个数字并放入数组中:
#include
int main(){
int nums[10];
int i;
//从控制台读取用户输入
for(i=0; i<10; i++){
scanf("%d", &nums[i]); //注意取地址符 &,不要遗忘哦
}
//依次输出数组元素
for(i=0; i<10; i++){
printf("%d ", nums[i]);
}
return 0;
}
运行结果:
22 18 928 5 4 82 30 10 666 888↙
22 18 928 5 4 82 30 10 666 888
第 8 行代码中,scanf() 读取数据时需要一个地址(地址用来指明数据的存储位置),而 nums[i] 表示一个具体的数组元素,所以我们要在前边加&来获取地址。 注意:访问数组元素时,下标的取值范围为 0 ≤ index < length,过大或过小都会越界,导致数组溢出,发生不可预测的情况,我会在《C语言数组的越界和溢出》一节重点讨论,请大家务必要引起注意。
数组的初始化
上面的代码是先定义数组再给数组赋值,我们也可以在定义数组的同时赋值,这叫做初始化。例如:
int nums[5] = {20, 345, 700, 22, -94};
数组元素的值由{ }包围,各个值之间以,分隔。
对于数组的初始化需要注意以下几点:
1) 可以只给部分元素赋值。当{ }中值的个数少于元素个数时,只给前面部分的元素赋值。例如:
int a[10]={12, 19, 22 , 993, 344};
表示只给 a[0]~a[4] 这 5 个元素赋值,而后面的 5 个元素自动初始化为 0。 当赋值的元素少于数组总体元素的时候,剩余的元素自动初始化为 0:
对于short、int、long,就是整数 0;对于char,就是字符 '\0';对于float、double,就是小数 0.0。
我们可以通过下面的形式将数组的所有元素初始化为 0:
int nums[10] = {0};
char str[10] = {0};
float scores[10] = {0.0};
由于剩余的元素会自动初始化为 0,所以只需要给第 1 个元素赋值为 0 即可。 2) 只能给元素逐个赋值,不能给数组整体赋值。例如给 10 个元素全部赋值为 1,只能写作:
int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
而不能写作:
int a[10] = 1;
3) 如果给全部元素赋值,那么在定义数组时可以不指明数组长度,编译器会根据元素的个数自动推断出数组长度。例如:
int a[] = {1, 2, 3, 4, 5};
等价于:
int a[5] = {1, 2, 3, 4, 5};
数组内存是连续的
数组是一个整体,它的内存是连续的;也就是说,数组元素之间是相互挨着的,彼此之间没有一点缝隙。下图演示了int a[4];在内存中的存储情形:
「数组内存是连续的」这一点很重要,所以我使用了一个大标题来强调。连续的内存为指针操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等)提供了便利,这使得数组可以作为缓存(临时存储数据的一块内存)使用。大家暂时可能不理解这句话是什么意思,等后边学了指针和内存自然就明白了。
综合示例
示例3:将全班同学的成绩保存在数组中,然后计算全班同学的平均成绩。
#include
int main() {
int scores[] = { 85, 92, 78, 95, 88, 60, 100, 92, 88 };
int sum = 0;
float average;
int length = sizeof(scores) / sizeof(scores[0]);
for (int i = 0; i < length; i++) {
sum += scores[i];
}
average = (float)sum / length;
printf("平均分数:%.2f\n", average);
return 0;
}
输出结果:
平均分数:86.44
在第 4 行代码中,因为在初始化的过程中要给所有元素赋值,所以我们没有手动指明数组的长度,而是留空,让编译器自动推断。 在第 7 行代码中,我们使用 sizeof(scores) / sizeof(scores[0]) 来计算数组长度。sizeof 是C语言中的一个关键字,专门用来获取数据或者类型的长度,也即它们在内存中所占用的字节数。sizeof(scores) 可以获取整个数组的字节数,sizeof(scores[0]) 可以获取一个元素的字节数,它们的商就是数组元素的个数(也即数组长度)。 示例4:把用户输入的数据填充到数组,然后找出数组中的最大值和最小值。
#include
#define SIZE 5
int main() {
int numbers[SIZE];
int i, max, min;
printf("请输入 %d 个整数:", SIZE);
for (i = 0; i < SIZE; i++) {
scanf("%d", &numbers[i]);
}
max = min = numbers[0];
for (i = 1; i < SIZE; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
if (numbers[i] < min) {
min = numbers[i];
}
}
printf("你输入的数组是:");
for (i = 0; i < SIZE; i++) {
printf("%d ", numbers[i]);
}
printf("\n最大值:%d\n最小值:%d\n", max, min);
return 0;
}
输出结果(假设用户输入:23 45 12 67 9):
请输入 5 个整数:23 45 12 67 9↙
你输入的数组是:23 45 12 67 9
最大值:67
最小值:9