数组
int a;
int b[10];
变量a为标量,它是一个单一的值,这个变量的类型是一个整数。
变量b为数组,它是一些值的集合,b[1] b[2]...每个特定值都是一个标量。
b[4]的类型是整型,但b的类型又是什么?它所表示的又是什么?
在C中,几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元素的地址。它的类型取决于数组元素的类型
如果它们是int类型,那么数组名的类型就是"指向int的常量指针";如果它们是其他类型,那么数组名的类型就是"指向其他类型的指针"。
数组具有确定数量的元素,而指针只是一个标量值。编译器用数组名来记住这些属性。只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量。
注意这个值是指针常量,而不是指针变量。你不能修改常量的值。这个限制是合理的:指针常量所指向的是内存中数组的起始位置,如果修改这个指针常量,
唯一可行的操作就是把这整个数组移动到内存的其他位置。但是,在程序完成链接之后,内存中数组的位置的固定的,所有当程序运行时,在想移动数组就
为时已晚了。因此,数组名的值是一个指针常量。
只有在两种场合下,数组名并不用指针常量来表示--就是当数组名作为sizeof操作符或单目操作符&的操作数时,sizeof返回整个数组的长度,而不是指向数组的指针的长度。
取一个数组名的地址所产生的一个指向数组的指针,而不是一个指向某个指针常量值的指针。
int a[10];
int b[10];
int *c;
c = &a[0];
表达式&a[0]是指向数组第一个元素的指针。但那正是数组名本身的值,所有下面这条赋值语句和上面那条赋值语句所指向的任务是完全一样的:
c = a;
这条赋值语句说明了为什么理解表达式中的数组名的真正含义是非常重要的。如果数组名表示整个数组,这条语句就表示整个数组被复制到一个新的数组。
但事实上完全不是这样,实际被赋值的是一个指针的拷贝,c所指向的是数组的第一个元素。因此,像下面的表达式:
b = a;
是非法的。你不能使用赋值符把一个数组的所有元素复制到另一个数组。你必须使用一个循环,每次赋值一个元素。
考虑下面这条语句:
a = c;
c被声明为一个指针常量,这条语句看上去像是执行某种形式的指针赋值,把c的值赋值给a。但这个赋值是非法的:在这个表达式中,a的值是个常量,不能被修改。
下标引用
*(b + 3)
首先,b的值是一个指向整型的指针,所以3这个值根据整型值的长度进行调整。加法运算的结果是另一个指向整型的指针,它所指向的是数组第一个元素向后移
三个整型长度的位置。然后,间接访问操作符访问这个新位置,或者取得那里的值(右值),或者把一个新值存储于该处(左值)。
它和下标引用的执行过程完全相同。
除了优先级之外,下标引用和间接访问完全相同。
array[subscript]
*(array + (subscript))
既然数组名的值只是一个指针常量,你可以证明它们的相等性。在那个下标表达式中,子表达式subscript首先进行求值。然后,这个下标值在数组中选择
一个特定的元素。在第2个表达式中,内层的那个括号保证子表达式subscript像前一个表达式那样首先求值。经过指针运算,加法运算的结果是一个指向
所需元素的指针。然后,对这个指针执行间接访问操作,访问它指向的那个元素的指针。
在使用下标引用的地方,可以使用对等的指针表达式来代替。在使用上面这种形式的指针表达式的地方,也可以使用下标表达式来代替。
如:
int array[10];
int *ap = array + 2;
记住,在进行指针加法运算时会对2进行调整。运算结果所产生的指针ap指向array[2],
阅读(2204) | 评论(0) | 转发(0) |