多维数组
1. 对两维数组的理解
对于Float rain[5][12],把它理解为有这样一个数组,它的可以表示为rain[5],而其中的每一个元素(总共有5个)是另外一个数组,这个数组有12个float类型的数据。
所以rain的首元素rain[0]是一个包含12个float数值的数组,且rain[1],rain[2]等等也是如此。换言之,rain是包含5个元素(每一个元素又是包含12个float数的数组)的数组。
2. 对于两维数组的地址计算
根据刚才的分析,可以得出以下结论。
如果有数组int a[3][3], 在32位机子上运行,且假设a的地址为2000,那么a[1]的地址就是2012(2000 + 4 * 3),而且a[1]的地址就是a[1][0]的地址,正如a的地址就是a[0][0]的地址(数组名其实就是该数组首元素的地址)。
另外,a[2][1] == *(*(a + 2) + 1) , 理解两维数组的关键是a[1]是个int *型指针,因为a[1]是指向其首元素a[1][0]的指针,而a[1][0]是int * 型。
3. 如何将数组作为参数传递到函数
处理数组的函数其实使用指针指针作为参数的。在C中,a[i]在后台就是被解析为*(a + i)。
(1) 一维数组
方法一,如果有float a[3],那么对应的函数原型至少为 int sum(float * a, int n),其中float * a 是因为以后将会传入数组名,而数组名就是数组第一个元素的地址,所以要与之匹配,对于这个例子,数组的第一个元素是float型,所以如果传入参数的话就应该是float*. int n是为了传入这个数组的大小,防止函数内越界。
方法二,如果有float a[3],那么对应的函数原型至少为 int sum(float * a, float * end)
调用如下 sum(a , a + 3)。然后需要在sum中做的事情是判断,注意在做while的时候的判定条件是 while ( a < end),其中千万不能用等号,因为a的最后一个元素为a[2]。
(2) 两维数组
利用指针数组(形似int (*p)[2]),函数原型写成 int sum( int (*p)[2], int rows)。其中要已知两维数组的列数为2,行数作为一个参数传进sum.
4. 指针可以使用的基本操作
(1) 赋值
(2) 求值(*操作符)
(3) 取指针的地址(&操作符)
(4) 将整数加给指针(包括自加)
(5) 从指针中减去一个整数(包括自减)
(6) 求差值——通常对分别指向同一个数组内两个元素的指针求差值,以求出元素之间的距离。
(7) 比较——前提是两个指针具有相同的类型
5. 对指针的加减法运算
在C中,对一个指针加1的结果是对该指针增加1个存储单元(即它所指向的对象的字节大小)。比如说有int * p. 如果p的地址是2000,那么++p的结果是2004(在32位机子上,int占用4个字节)。
对于数组而言,由于这个特性,地址会增加到下一个元素的地址。
于是,如果有double dates[10],则显然 (date + 2) == &dates[2],而且*(dates + 2) == dates[2]
注意,这里是对指针的加减法,虽然dates代表dates[0]的地址,但是它毕竟不是指针,而是地址的常量。所以语句dates++是违法的。
6. 关于const int * p与int * const p
前者const了int *, 即p所指向的地址是不能够被改变了,但是这个地址所代表的内容却是可以改变的。后者const了p,即p的内容(*p)是不能够被改变了,但是p所指向的地址却是可以转换的。
7. 指针数组与数组指针
关键在于[]的优先级高于*
(1) Int (*pz)[2]
pz是一个指针,指向一个int[2]的匿名数组。
(2) Int * pz[2]
Pz是一个数组,他有2个元素,而且每一个元素是int *型。
8. 指针的兼容性
指针赋值非常严格,只能够赋给相同类型的值。
例如有如下声明:
Int * pt;
Int (*pa)[3];
Int ar1[2][3];
Int ar2[3][2];
Int **p2
那么有如下结论
Pt = & ar1[0][0] //成立
Pt = ar1[0] //成立 ,因为ar1[0]就是int * 型指针。可以这样理解。 &Ar1[0][0] == *(ar1 + 0) + 0
Pt = ar1 // 非法,因为ar1是指向由3个int值构成的数组的指针,说白了其实是一个int[3]型的指针,而不是int *型指针。Ar1是指向ar1[0]的指针,而ar1[0]是一个int[3],所以ar1是int[3]型指针。
Pa = ar1 // 成立,理由见上
Pa = ar2 //不成立, 因为pa是int[3]型指针,而ar2是int[2]型指针
P2 = &pt //成立
*p2 = ar2[0] //成立,因为ar2[0]是int * 型指针,因为ar2[0]是指向其首元素ar2[0][0]的指针
P2 = ar2 //不成立,p2是int **,而ar2是int[2]型指针。