指针与数组

这是一个看似简单,但却不是那么容易搞清楚的问题。以下是在Andrew Koenig的杰作中看到的一些关于数组和指针的讲解,我只作了部分整理。
C语言中指针与数组这两个概念之间的联系是如此密不可分,以至于如果不能理解一个概念,就无法彻底理解另一个概念。C语言中的数组值得注意的地方有以下两点:
1:C语言只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来。
然而C语言中数组的元素可以是任何类型的对象,当然可以是另外一个数组,这样啊,
要”仿真”出一个多维数组就不是一件难事。(C99标准允许变长数组(VLA)。GCC编译器
实现了变长数组,但是细节与C99标准不完全一致。)
2:对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的
元素的指针。其他关于数组的操作,哪怕他们看上去是以数组下标进行运算的,实际上都是
通过指针进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我
们完全可以依据指针行为定义数组下标的行为。一旦我们彻底理解这两点以及他们所隐含
的意思,那么理解C语言的数组运算不过就是“小菜一碟”。对于指针加上一个整数,与给该
指针的二进制表示加上同样的整数,两者的含义截然不同,这点大家应该都是清楚的。

下面一个问题是关于指针加减问题的:
如果两个指针指向的是同一个数组中的元素,我们可以把这两个指针相减,这样是有意义的,例如:int *q=p+i;我们可以通过q-p而得到i的值。值得注意的是如果他们指向的不是同一个数组的元素,即使他们所指向的地址在内存中的位置正好间隔一个数组元素的整数倍,所得的结果仍然是无法保证其正确性的。至于指针相加的情况暂时好象没有发现有。
现在定义一个数组inta[3];如果我们在应该出现指针的地方,却采用了数组名来替换,那么
数组名就被当作指向该数组下标为0的元素的指针,这点大家也都很清楚。但是要注意一点,除了a被用做运算符sizeof的参数这一情形,在其他的所有情形中数组名a都代表指向该数组下标为0的元素的指针。正如我们合乎情理的期待,sizeof(a)的结果就是整个数组的大小,而不是指向该数组的元素的指针的大小。

下面来看看二维的情况(其他的都可以类推):
int ta[12[31];
int p;
int i;
因为ta是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整形
元素的数组,所以ta[4]是数组ta的第5个元素,是ta数组中12个有着31个整形元素的数组之一。
因此,ta[4]的行为也就表现为一个有着31个整形元素的数组的行为。例如,sizeof(ta[4])的
结果是31与sizeof(int)的乘积。
又如:
p=ta[4];这个语句使指针p指向了数组ta[4]中下标为0的元素。
如果ta[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像:
i=ta[4][7],与一维类似的道理,这个语句可以写成下面这样意思不变:
i=
(ta[4]+7);
或者:
i=((ta+4)+7);
但是可以看出第一种最简洁明了。
下面我们再看:
p=ta;
大家一看就知道这个语句是非法的,但具体原因是什么呢?
因为ta是一个二维数组,即“数组的数组”,在此处的上下文中使用ta名称会将其转换为
一个指向数组的指针;而p是一个指向整形变量的指针,这个语句试图将一种类型的指针
赋值给另一种类型的指针,所以是非法的。由于我们都很熟悉数组时针,即指向数组的指针,所以很快就会想到一个数组指针int (*p)[31];这时就可以这样赋值:p=ta;暂时就说到这里了。