第10章 数组和指针
- 数组是由数据类型相同的一系列元素组成的。
- 数组初始化方式:以逗号分隔的值列表(用花括号括起来)。
- 使用
const
声明数组,可以将数组设置为只读,此时程序只能从数组中检索值,但是不能把新值写入数组。 - 使用数组前必须先初始化。
- 初始化数组时,当初始化列表中的值少于数组元素个数时,编译器会把剩余的元素都初始化为0。如果不初始化数组,则数组元素和未初始化的普通变量一样,其中存储的都是垃圾值;但是如果部分初始化数组,剩余的元素就会被初始化为0.
- 初始化数组时,如果初始化列表的项数多余数组元素个数,则编译器会将其视为错误。
- 初始化数组时,可以省略方括号中的数组,即省略数组个数,让编译器自动匹配数组大小和初始化列表的项数。
sizeof
运算符给出其运算对象的大小(以字节为单位),sizeof 数组名
返回整个数组的大小,sizeof 数组名[0]
返回数组中一个元素的大小。整个数组的大小除以单个元素的大小就是数组元素的个数。- 指定初始化器(C99)。如果指定初始化器后面由更多的值,则后面这些值将被用于初始化指定元素后面的元素。如果再次初始化指定的元素,则最后的初始化会取代之前的初始化。如果未指定元素个数,编译器将会把数组大小设置为足够装得下初始化的值。
- C语言不允许把数组作为一个单元赋给另一个数组,并且除了初始化以外,也不允许使用花括号列表的形式赋值。
- 在使用数组是,要防止数组下标超出边界。
- 编译器不会检查数组下标是否使用得当。在C标准中,使用越界下标的结果是未定义的。这意味着程序看上去可以运行,但是运行结果很奇怪,或异常中止。
- 初始化二维数组时,可以省略内部的花括号,只保留最外面的一堆花括号。此时如果初始化的数组较小,则剩余元素均初始化为0。
- 数组名就是数组首元素的地址。
数组名
和&数组名[0]
都表示数组首元素的内存地址。两者都是常量,在程序的运行过程中不会改变。 - 系统中,地址按照字节编址,在C中,指针加1指的是增加一个存储单元。对于数组而言,指针加1后的地址时下一个元素的地址,而不是下一个字节的地址。也因此必须声明指针所指向对象的类型。
- 指针的值是它所指向对象的地址。一个较大对象的地址通常是该对象第一个字节的地址。
- 在指针前使用
*
运算符可以得到该指针所指向对象的值。 - 指针加1,指针的值递增它所指向类型的大小(以字节为单位)
- 可以使用指针标识数组的元素和获得元素的值。
- 对于数组,指针表示法和数组表示法是两种等效的方法。
int *ar
形式和int ar[]
都表示ar是一个指向int
的指针,但是int ar[]
只能用于声明形式参数。- 只有当
ar
是指针变量时,才能使用ar++
这种表达式。 - 指针操作:
(1) 赋值:把地址赋给指针
(2) 解引用
(3) 取址
(4) 指针和整数相加
(5) 递增指针
(6) 指针减去一个整数
(7) 递减指针
(8) 指针求差
(9) 比较 - 解引用未初始化的指针会导致严重的错误,因为创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。因此在使用指针前,必须先用已分配的地址初始化它。
- 对于函数,通常都是直接传递数值,只有程序需要在函数中改变该数值时,才会传递指针,因为函数通过指针世界使用了原始数据。
- 如果函数的意图不是修改数组中的数据内容,那么在函数原型和函数定义中声明形式参数时应使用关键字
const
。此时如果函数不小心修改了数组,则编译器会指出错误。 - 一般而言,如果编写的函数需要修改数组,在声明数组形参时则不适用
const
,如果编写的函数不用修改数组,则在声明数组形参时最好使用const
- const数组,程序无法改变其数组元素的值。const指针无法指向别处。指向const的指针,无法通过该指针改变数据,但是该指针可以指向别处。
- 如果指针为指向const的指针,则其可以指向const数据和非const数据;如果为普通指针,则只能指向非const数据。
int (* ptr) [n]
声明了一个指向数组的指针,其中该数组为2个int类型的数组;int * ptr [2]
声明了两个指向int类型的指针。- 不可以讲const指针赋给非const指针,因为这样可以通过使用非const指针改变const指针。但是可以将非const指针赋给const指针。