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