[CSDN转载]数组指针和指针数组

文章转载自http://t.csdnimg.cn/bLXHv

首先,理解一下数组指针和指针数组这两个名词:

“数组指针”和“指针数组”,只要在名词中间加上“的”字,就知道中心了——

数组的指针:是一个指针,什么样的指针呢?指向数组的指针。

指针的数组:是一个数组,什么样的数组呢?装着指针的数组。

然后,需要明确一个优先级顺序:()>>*,所以:

(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

*p[n]:根据优先级,先看,则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

根据上面两个分析,可以看出,p是什么,则词组的中心词就是什么,即数组“指针”和指针“数组”。

`

1.  int *p1[5];
    
2.  int (*p2)[5];
    

`


首先,对于语句“int*p1[5]”,因为“”的优先级要比“*”要高,所以 p1 先与“”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组。

                                 ![](https://img-blog.csdnimg.cn/20190917164233526.jpg)  图1 

其次,对于语句“int(*p2)[5]”,“()”的优先级比“”高,“*”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含 5 个 int 类型数据的数组,如图 2 所示。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组。

                                ![](https://img-blog.csdnimg.cn/20190917164330539.jpg)

                                                           图2 

由此可见,对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。

数组指针 (*p)[n]

数组指针:是指针——指向数组的指针。

看下面的例子进行理解

`

1.  #include "stdafx.h"
    

4.  int main()
    
5.  {
    
6.  	//一维数组
    
7.  	int a[5] = { 1, 2, 3, 4, 5 };
    
8.  	//步长为5的数组指针,即数组里有5个元素
    
9.  	int (*p)[5];
    
10.  	//把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身
    
11.  	p = &a;
    

13.  	//%p输出地址, %d输出十进制
    
14.  	//\n回车
    
15.  	//在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。
    
16.  	printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址
    
17.  	printf("%p\n", p); //根据上面,p为数组a的地址,输出数组a的地址
    
18.  	printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组
    
19.  	printf("%p\n", &a[0]); //a[0]的地址
    
20.  	printf("%p\n", &a[1]); //a[1]的地址
    
21.  	printf("%p\n", p[0]); //数组首元素的地址
    
22.  	printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1
    
23.  	printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1
    
24.  	printf("%d\n", *p[1]); //为一个绝对值很大的负数,不表示a[1]...表示什么我还不知道
    

28.  	//将二维数组赋给指针
    
29.  	int b[3][4];
    
30.  	int(*pp)[4]; //定义一个数组指针,指向含4个元素的一维数组
    
31.  	pp = b; //将该二维数组的首地址赋给pp,也就是b[0]或&b[0],二维数组中pp=b和pp=&b[0]是等价的
    
32.  	pp++; //pp=pp+1,该语句执行过后pp的指向从行b[0][]变为了行b[1][],pp=&b[1]
    

34.  	int k;
    
35.  	scanf_s("%d", &k);
    

37.      return 0;
    
38.  }
    



`

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)


根据上面二维数组可以得出,数组指针也称指向一维数组的指针,所以数组指针也称行指针。

指针数组 *p[n]

指针数组:是数组——装着指针的数组。

看下面的例子进行理解:

`

1.  #include "stdafx.h"
    

4.  int main()
    
5.  {
    
6.  	int a = 1;
    
7.  	int b = 2;
    
8.  	int *p[2];
    
9.  	p[0] = &a;
    
10.  	p[1] = &b;
    

12.  	printf("%p\n", p[0]); //a的地址
    
13.  	printf("%p\n", &a); //a的地址
    
14.  	printf("%p\n", p[1]); //b的地址
    
15.  	printf("%p\n", &b); //b的地址
    
16.  	printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
    
17.  	printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值
    

20.  	//将二维数组赋给指针数组
    
21.  	int *pp[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
    
22.  	int c[3][4];
    
23.  	for (int i = 0; i<3; i++)
    
24.  		pp[i] = c[i];
    

26.  	int k;
    
27.  	scanf_s("%d", &k);
    

29.      return 0;
    
30.  }
    



`

![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)


最后,从上文来看:

数组指针是一个指针变量,占有内存中一个指针的存储空间;

指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。

了解指针数组和数组指针二者之间的区别之后,继续来看下面的示例代码:

`

1.  int arr[5]={1,2,3,4,5};
    
2.  int (*p1)[5] = &arr;
    
3.  /*下面是错误的*/
    
4.  int (*p2)[5] = arr;
    

`


不难看出,在上面的示例代码中,&arr 是指整个数组的首地址,而 arr 是指数组首元素的首地址,虽然所表示的意义不同,但二者之间的值却是相同的。那么问题出来了,既然值是相同的,为什么语句“int(*p1)[5]=&arr”是正确的,而语句“int(*p2)[5]=arr”却在有些编译器下运行时会提示错误信息呢(如在 Microsoft Visual Studio 2010 中提示的错误信息为“a value of type"int*“cannot be used to initialize an entity of type"int(*)[5]””)?

其实原因很简单,在 C 语言中,赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。在这里,p1 和 p2 都是数组指针,指向的是整个数组。p1 这个定义的“=”号两边的数据类型完全一致,而 p2 这个定义的“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。