数组
由数据类型
相同的一系列元素
组成。数组元素
按顺序储存在内存
中,通过整数下标subscript
(或索引index
)可以访问各元素。C把数组
看作是派生类型
,因为数组是建立在其他类型
的基础上。
1、初始化数组
int powers[8] = {1,2,4,6,8,16,32,64}; /* 从ANSI C开始支持这种初始化 */
以逗号分隔的值列表(用花括号括起来)来初始化数组,
各值之间用逗号分隔。在逗号和值之间可以使用空格。
当初始化列表中的值少于
数组元素个数时,编译器会把剩余的元素都初始化为0
。也就是说,如果不初始化数组,数组元素和未初始化的普通变量一样,其中储存的都是未定义
;但是,如果初始化数组部分元素
,剩余的元素
就会被初始化为0。
如果初始化列表的项数多于
数组元素个数,编译器会将其视为错误。
2、数组边界
编译器不会检查数组下标是否使用得当。使用越界下标的结果是未定义的。使用越界的数组下标会导致程序改变其他变量的值。不同的编译器运行该程序的结果可能不同,有些会导致程序异常中止。
不检查边界,C 程序可以运行更快。编译器没必要捕获所有的下标错误,因为在程序运行之前,数组的下标值可能尚未确定。因此,为安全起见,编译器必须在运行时添加额外代码检查数组的每个下标值,这会降低程序的运行速度。C相信程序员能编写正确的代码,这样的程序运行速度更快。
3、数组与指针
指针提供一种以符号形式使用地址的方法。因为计算机的硬件指令非常依赖地址,指针在某种程度上把程序员想要传达的指令以更接近机器的方式表达。因此,使用指针的程序更有效率。尤其是,指针能有效地处理数组。数组表示法其实是在变相地使用指针。
下面的等式体现了C语言的灵活性:
dates + 2 == &date[2] // 相同的地址
*(dates + 2) == date[2] // 相同的值
ar[i]和*(ar+1)这两个表达式都是等价的。无论ar是数组名还是指针变量,这两个表达式都没问题。但是,只有当ar是指针变量时,才能使用ar++这样的表达式。
指针表示法(尤其与递增运算符一起使用时)更接近机器语言,因此一些编译器在编译时能生成效率更高的代码。然而,许多程序员认为他们的主要任务是确保代码正确、逻辑清晰,而代码优化应该留给编译器去做。
4、数组与函数
函数的形参,还有一点要注意。只有在函数原型
或函数定义
中,才可以用int ar[]
代替int * ar
:
int sum (int arr[] , int n);
int *arr
形式和int arr[]
形式都表示arr
是一个指向int的指针。int ar[]
只能用于声明形式参数,表明arr指向的不仅仅一个int类型值,还是一个int类型数组的元素。
因为数组名是该数组首元素的地址,作为实际参数的数组名要求形式参数是一个与之匹配的指针。只有在这种情况下,C才会把int arr[]
和int * arr
解释成一样。也就是说,arr
是指向int的指针。
函数原型可以省略参数名,但是,在函数定义中不能省略参数名。