1.6 指针数组和数组指针

对于指针数组和数组指针,单从字面上似乎很难分清它们是什么,先来看看指针数组和数组指针各自的定义形式。

指针数组的定义形式为:


类型名*数组名[数组长度];


如:


int*p[8];


数组指针的定义形式为:


类型名(*指针名)[数组长度];


如:


int(*p)[8];


现在来分析上述两种定义形式,通过“intp[8];”这条定义语句可以定义一个指针数组。因为优先级的关系,所以p先与[]结合,说明p是一个数组,然后再与结合说明数组p的元素是指向整型数据的指针。元素分别为p[0],p[1],p[2],……,p[7],相当于定义了8个整型指针变量,用于存放地址单元,在此,p就是数组元素为指针的数组,本质为数组。如果使用的定义方式为“int(p)[8];”,p先与号结合,形成一个指针,该指针指向的是有8个整型元素数组,p即为指向数组首元素地址的指针,其本质为指针。介绍了指针数组和数组指针的含义,接下来,我们通过下面一段代码来看看指针数组和数组指针如何访问二维数组。


include<stdio.h>

void main(int argc,char*argv[])

{

int arr[4][4]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

int(*p1)[4];

int*p2[4];

int i,j,k;

p1=arr;

printf("使用数组指针的方式访问二维数组arr\n");

for(i=0;i<4;i++)

{

for(j=0;j<4;j++)

{

printf("arr[%d][%d]=%d\t",i,j,(p1+i)+j));

}

printf("\n");

}

printf("\n使用指针数组的方式访问二维数组arr\n");

for(k=0;k<4;k++)

p2[k]=arr[k];

for(i=0;i<4;i++)

{

for(j=0;j<4;j++)

{

printf("arr[%d][%d]=%d\t",i,j,*(p2[i]+j));

}

printf("\n");

}

return;

}


运行结果:


使用数组指针的方式访问二维数组arr

arr[0][0]=0 arr[0][1]=1 arr[0][2]=2 arr[0][3]=3

arr[1][0]=4 arr[1][1]=5 arr[1][2]=6 arr[1][3]=7

arr[2][0]=8 arr[2][1]=9 arr[2][2]=10 arr[2][3]=11

arr[3][0]=12 arr[3][1]=13 arr[3][2]=14 arr[3][3]=15

使用指针数组的方式访问二维数组arr

arr[0][0]=0 arr[0][1]=1 arr[0][2]=2 arr[0][3]=3

arr[1][0]=4 arr[1][1]=5 arr[1][2]=6 arr[1][3]=7

arr[2][0]=8 arr[2][1]=9 arr[2][2]=10 arr[2][3]=11

arr[3][0]=12 arr[3][1]=13 arr[3][2]=14 arr[3][3]=15


我们成功地使用数组指针和指针数组的方式访问了二维数组,在分析它们各自的访问方式之前,先通过图1-5了解二维数组中元素的存放方式。

1.6 指针数组和数组指针 - 图1

图 1-5 二维数组

在分析指针数组和数组指针如何访问二维数组中的各个元素之前,我们要明白二维数组每行的起始地址并不是只能用图1-5中的那种表示方式,还有很多方法可以表示每行的起始地址,如*(arr+i)和arr+i等。为了帮助读者更好地记忆,我们通过下面一段代码来学习其他表示二维数组每行起始地址的方式。


include<stdio.h>

void main(int argc,char*argv[])

{

int arr[4][4]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

int i;

for(i=0;i<4;i++)

{

printf("使用arr+i求得二维数组arr第%d行的起始地址为:%d\n",i+1,arr+i);

printf("使用arr[i]求得二维数组arr第%d行的起始地址为:%d\n",i+1,arr[i]);

printf("使用(arr+i)求得二维数组arr第%d行的起始地址为:%d\n",i+1,(arr+i));

printf("使用&arr[i]求得二维数组arr第%d行的起始地址为:%d\n\n",i+1,&arr[i]);

}

return;

}


运行结果:


使用arr+i求得二维数组arr第1行的起始地址为:1244996

使用arr[i]求得二维数组arr第1行的起始地址为:1244996

使用*(arr+i)求得二维数组arr第1行的起始地址为:1244996

使用&arr[i]求得二维数组arr第1行的起始地址为:1244996

使用arr+i求得二维数组arr第2行的起始地址为:1245012

使用arr[i]求得二维数组arr第2行的起始地址为:1245012

使用*(arr+i)求得二维数组arr第2行的起始地址为:1245012

使用&arr[i]求得二维数组arr第2行的起始地址为:1245012

使用arr+i求得二维数组arr第3行的起始地址为:1245028

使用arr[i]求得二维数组arr第3行的起始地址为:1245028

使用*(arr+i)求得二维数组arr第3行的起始地址为:1245028

使用&arr[i]求得二维数组arr第3行的起始地址为:1245028

使用arr+i求得二维数组arr第4行的起始地址为:1245044

使用arr[i]求得二维数组arr第4行的起始地址为:1245044

使用*(arr+i)求得二维数组arr第4行的起始地址为:1245044

使用&arr[i]求得二维数组arr第4行的起始地址为:1245044


在上面的代码中,我们使用了4种方式来获得每行的起始地址,因此行起始地址的表示方式并不唯一,读者在使用的时候可以自行选择。

下面接着讲解数组指针和指针数组是如何访问二维数组的,先看数组指针的访问方式。因为数组指针指向的是一个有4个整型元素的数组,所以可以把二维数组arr看成由4个元素arr[0],arr[1],arr[2],arr[3]组成,每个元素都是含有4个整型元素的一维数组,所以当在代码中使用p1=arr的时候,p1就指向了二维数组的第一行的首地址。在接下来的访问中,由于p1指向的类型是int[4],所以从p1到p1+1的变化值为44个字节,即p1+1=1245012。从前面的运行结果中可以发现,p1+1刚好指向第二行的起始地址。至于为什么刚好能指向二维数组arr的第二行的首地址,这个问题将在第4章进行讲解。通过p1+i刚好能够取遍每行的起始地址,有了每行的起始地址之后,就可以通过“(p1+i)+j)”来取出二维数组中每行的每一个元素。

指针数组的访问方式要更容易一些,因为定义的指针数组p2由4个元素p2[0],p2[1],p2[2],p2[3]组成,每个元素都是一个整型指针,所以只需要在程序中取出每行的起始地址并放到p2指针数组对应的元素中,就可以访问二维数组arr中的元素了。

所以,在程序中使用指针数组和数组指针的时候,必须对它们有清晰的认识,要知道它们的本质是什么,以及如何使用。