=
=
=
朝花夕拾-C语言指针定义和数组定义的歧义问题-指针和数组疑难辩证-终极解答2
这一篇主要目标讲多维数组和指针类型。
原理1:C语言中只有一维数组。2维数组可以看成是一维数组的一维数组。多维数组以此类推。
原理1:C语言中只有一维数组,:数组名称后面跟着的第一个数字维度就是数组的真实维度。除此之外,其他的参数则是数组元素的信息描述。
C语言中只有一维数组,而且数组的大小必须在编译时期就确定下来(旧标准)。然而,C语言数组的元素可以是任意对象,包括数组。这样就给多维数组的实现或者仿真提供了可能。
2维数组: int a[2][3];
分解为一维数组的代数法为:
a的1维类型为:int a[];
a[i]的类型为 int B[];
结合起来看,a的类型为:a[][3]。【从高级语言来看,a的类型为a[][],但是c语言要求写类型的时候,后面维数写确定。】
原理2:不同的指针类型也是不同类型,也是不能互用的,切记别以为都是指针,就属于一个类型了:
一定要重视指针类型,这一点往往刚学的时候容易忽略。
不同的类型是不能互用的(强制转换不算)。例如int和float是不能互用的。
同理,不同的指针类型也是不同类型,也是不能互用的,切记别以为都是指针,就属于一个类型了。
不同的指针类型,其指针使用方法遵从指针原理(比如:指针加法减法),其取值使用方法遵从指针类型(比如int **p类型的指针,**p取到int值,遵从int的操作)。
类型有强制转换的需求,指针类型,应该也可以强制转换,比如可以把p强转为:float *p8 = (int *) p;
原理3:指针和数组的关系,在多为数组上的应用,以2维数组为例:int a[m][n],a的类型为int (*)[n],a的类型不是int *。
int a[2];
//a等价于指针 int *
int a[2][3];
//等价于int A[2];
//而A[0]的类型为int[3]等价于int *,所以a等价于类型:int (*)[3];【注意不是(int *)[3]】。
//根据括号左移法则(见上一篇),a的类型是int[][3], 等价于指针类型是int[3] *,因为c语言要求[3]在后面,所以只能写为 int (*)[3] 【注意不是(int *)[3]】。
//如果全用指针来看,a的类型应该是int * *。推理:a的类型是int *A,A的类型是int *,所以合并为 int *(int *)==int **。
知晓了上面的原理,我们来看看容易混淆的地方。
int a[m][n];
*(a+i)==a[i]//为什么a[i]不是(a+i)而是*(a+i)?因为a的类型和a[i]的类型是不同的。a+i的类型依然和a的类型一样是int (*)[n],而a[i]的类型确实int *。
这里的核心是a的类型和a[i]的类型是不同的。
a[i][j]的不同表示法:
(*(a+i))[j];
*( (*(a+i))+j )
*(a[i] + j)
*的作用:
*定义指针。在定义时,用来定义某个类型的指针。
*指针取值。在使用时,用来取值指针指向类型的值。
int a[m][n];
问题就出在a[0]并不真实的存在,不存在a[0]这个中间变量,只是编译器根据指针类型编译的时候使用的。
比如a[0]真实存在,那么就成了下面的形式:
a = &a[0];
a[0] = &a[0][0];
这完全不是一回事。
可以说,c和指针,确实存在设计问题。这就导致c语言很多混淆难懂不好用。高级语言之所以高级,就在于对人友好。
比如定义一个一维指针:int *p = a; 等价于int *p = &a[0];等价于int *p = &a[0][0];
因为p是一维指针,那么就可以完全把p当成一维指针用,因为p就是这么用的。
而c内存分配,以连续分配,则可以把p移动完所有的数组值。
具体见下面的代码:
printf("把二维数组当成一维数组使用的原理:\n");
int *p = a;
for(i = 0; i < 2; i++){
for(j = 0; j < 3; j++){
printf("%d, ", *(p++) );
}
}
例子代码:
#include <stdio.h> int main(void){ int a[2][3]; //init int i = 0, j = 0; for(i = 0; i < 2; i++){ for(j = 0; j < 3; j++){ a[i][j] = i + j; } } //traverse for(i = 0; i < 2; i++){ for(j = 0; j < 3; j++){ printf("%d, ", a[i][j]); } } printf("\n"); printf("把二维数组当成一维数组使用的原理:\n"); int *p = a; for(i = 0; i < 2; i++){ for(j = 0; j < 3; j++){ printf("%d, ", *(p++) ); } } printf("\n"); printf("取值的不同方法:\n"); printf("%d \n", a[1][2]); printf("%d \n", *(*(a+1) + 2) ); printf("%d \n", (*(a+1))[2] ); printf("%d \n", *(a[1]+2) ); printf("\n"); }
=
=
=