boboshenqi的专栏

首先我们介绍多维数组

对于二维数组a[4][6];由于数组名代表数组的起始地址,所以a(第一层)和第一个元素a[0][0]地址的数字是相同的,但是意义却是不同的。 对于该数组我们可以理解为:a的一维数组(第一层),它有四个元素a[0]、a[1]、a[2]、a[3](第二层),而每个元素又含有6个元素a[0] [0],a[0][1],a[0][2],a[0][3],a[0][4],a[0][5](第三层),…到此我们终于访问到了每个元素了,这个过程我们 经历了:a->a[0]->a[0][0];

整体来讲:a是一个4行6列的二维数组,a表示它指向的数组的首地址(第一个元素地址&a[0]),同时a[0]指向一行,它是这个行的名字 (和该行的第一个元素的首地址相同(第一个元素为地址&a[0][0]))。所以从数字角度说:a、a[0]、&a[0][0]是相同 的,但是他们所处的层次是不同的。

既然a代表二维数组,那么a+i就表示它的第i+1个元素*(a+i)的地址,而在二维数组中*(a+i)又指向一个数组,*(a+i)+j表示这个数组的第j+1个元素的地址,所以要访问这个元素可以使用 *(*(a+i)+j)(也就是a[i][j])。

总结一下就是:我们对于二维指针a,他指向数组a[0,1,2,3],使用*,可以使他降级到第二层次,这样*a就指向了第一个真正的数组。对于其他的情况我们也可以采用相同的方式,对于其他维数和类型的数组我们可以采用相类似的思想。

说到指向数组的指针,我们还可以声明一个指针变量让它指向一个数组。例如:

int (*p)[5];

这时p就是一个指针,要指向一个含有5个int类型元素的数组,指向其他的就会出现问题。这个时候我们可以使用上面的什么东西来初始化呢?我们可以使用*a,*(a+1),a[2]等。原因很简单:我们在一个二维的数组中,那么表达方式有上面的相互类似的意义呢?只有 *a,*(a+1),a[2]等。

数组指针(行指针)

定义 int (*p)[n];()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

如要将二维数组赋给一指针,应这样赋值:int a[3][4];int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。p=a; //将该二维数组的首地址赋给p,数值上等于a[0]或&a[0][0],但是执行p++操作的时候,指针跨过的长度却不一样p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组

定义 int *p[n];[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。如要将二维数组赋给一指针数组:int *p[3];int a[3][4];for(i=0;i<3;i++)p[i]=a[i];这里int *p[3] 表示一个一维数组内存放着三个指针变量,,分别是p[0]、p[1]、p[2]所以要分别赋值。

一个指针数组是指一个数组中的每个元素都是一个指针,例如:

int *p[10];//而不能是int (*p)[10]

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。比如要表示数组中i行j列一个元素:*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

优先级:()>[]>*

指针的指针(二重指针)(二级指针)

一个指针变量内部可以存储一个值,这个值是另外一个对象的地址,所以我们说一个指针变量可以指向一个普通变量,同样这个指针变量也有一个地址,也就是 说有一个东西可以指向这个指针变量,然后再通过这个指针变量指向这个对象。那么如何来指向这个指针变量呢?由于指针变量本身已经是一个指针了(右值),那 么我们这里就不能用一般的指针了,需要在指针上体现出来这些特点,我们需要定义指针的指针(二重指针)。

int *p1=&i;int**p2=&p1;

综合以上的所有点,下面是我们常常看到一些匹配(也是经常出错的地方):

int a[3],b[2][3],c,*d[3];void fun1(int *p);void fun2(int (*p)[3]);void fun3(int **p);void fun4(int p[3]);void fun5(int p[]);void fun6(int p[2][3]);void fun7(int (&p)[3]);

函数

不会产生编译时刻的可能值(但逻辑上不一定都对)

fun1

a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]

fun2

b,b+i,

fun3

d

fun4

a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]

fun5

a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i]

fun6

b

fun7

a

为什么可以有这样的搭配,原因如下:

对于fun6,p是一个2*3的数组类型,和b恰好完全匹配;

“人”的结构就是相互支撑,“众”人的事业需要每个人的参与。

boboshenqi的专栏

相关文章:

你感兴趣的文章:

标签云: