数组入门
我们能从容的使用循环输出ASCII码表的内容,得益于这些字符是连续编码的。然而很多时候真实的数据是离散的,要对它们应用计算,有效的方式就是想办法通过循环进行连续访问,这表示我们需要一个存储数据的容器,数组正是这样的存在。
定义数组
典型的定义变量,其通用语法是:类型 变量名; 比如:
int a;
double pi;
数组是一种容器,定义时自然要表现出容器与单个变量的区别,这由下标运算符[]指示,即:
类型 数组名[元素个数];
其中,元素的个数不能为零,且必须是一个编译期常量。
int age[5]; // 存储5个年龄值的int数组
char letter[23]; // 存储23个字符的char数组
double score[25]; // 存储25个成绩值的double数组
数组也可以在定义的同时初始化,使用{}包围数据,数据之间用 ',' 隔开。
int a1[5] = { 23, 24, 8, 6, 9 }; // 初绐化元素的个数不能多于数组的大小
int a2[5] = { 1, 2, 3 }; // 初始值少于数组大小时,剩余值将用0值代替(如果是浮点数,则是0.0)
double a3[5] = { 1.0 }; // 除第一个值外剩余值均为0.0
char a4[] = { 'r', 'g', 'b' }; // 定义的同时并初始化,这时可以省略数组大小,最终大小就是初始化值的个数。
数组的特性
- 数组是存放同一类型数据的集合:如age数组只存储整型, score存储浮点数。
- 数组元素的访问采用下标运行算[]:第一个元素的索引为0,最后一个元素的索引为(N-1)
程序1:演示使用下标运算符访问与修改数组元素。
printf("%d\n", a1[0]); // 23
a1[0] = 44; // 修改第1个元素的值
printf("%d\n", a1[0]); // a1[0]的值为44
// 输出数组a2的所有元素
for (int i = 0; i < 5; i++)
printf("%d ", a2[i]);
// 反向输出数组a4的所有元素(最后一个元素的下标为2)
for (int i = 2; i >= 0; --i)
printf("%c ", a4[i]);
程序2:使数组的每个元素变为自身的平方,演示了数组元素作为左右值的使用。
#include <stdio.h>
int main()
{
int vals[5] ={1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++)
{
vals[i] *= vals[i];
printf("%d\n", vals[i]);
}
return 0;
}

越界
对于数组元素的读写,最重要的一点就是不要越界访问。程序中ia只有5个元素,最后一个元素ia[4],但我们却越界读取了2个元素。假如是写操作,在一个复杂的程序中,这种做法极有可能导致程序的后续行为是不确定的。C语言不保证数组访问范围的有效性检查,这一点得由我们来负责。
#include <stdio.h>
int main()
{
int ia[5] = { 6, 8, 9, 23, 24 };
for (int i = 0; i < 7; i += 1)
printf("%d\n", ia[i]);
return 0;
}

练习
1 编写程序,输出数组 a1, a2, a3, a4 的所有元素。
2 定义一个数组,让它在屏幕上输出 "glimix.com" 的字样。
3 在你的机器上测试越界写数组。