数组指针:指向数组整个元素的指针,不是指向数组首元素的地址的,但指针的值等于数组首元素的地址,本质是指针,要仔细理解下。
指针的数组:是一个数组,什么样的数组呢?装着指针的数组。
然后,需要明确一个优先级顺序:()>[]>*,所以:
(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;
*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。
首先看个例子:
数组指针指向一维数组
int arr[5]={1,2,3,4,5};
int (*p1)[5] = &arr;
/*下面是错误的*/
int (*p2)[5] = arr;
不难看出,在上面的示例代码中,&arr 是指整个数组的首地址,而 arr 是指数组首元素的首地址(arr=&arr[0]),虽然所表示的意义不同,但二者之间的值却是相同的。那么问题出来了,既然值是相同的,为什么语句“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 这个定义的“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。
数组指针指向二维数组也是类似的:
int(*p)[10];
//()的优先级高,()先将p生命为指针,定义了一个指向长度为10 的整型数组的指针
//p+i是指指针移动了i个长度为10 的数组,若p指向了第一个数组,则p+i指向第i+1个数组
int a[10][10];
p=a; //p指向a[10]
p++ ; //p指向a[1],移动单位是行或者一个长度为10 的数组,10个元素为一行,数组指针也叫行指针
另一个概念,指针数组 *p[n]
指针数组:是数组——装着指针的数组。
看下面的例子进行理解:
#include "stdio.h"
int main()
{
int a = 1;
int b = 2;
int *p[2];
p[0] = &a;
p[1] = &b;
printf("%p\n", p[0]); //a的地址
printf("%p\n", &a); //a的地址
printf("%p\n", p[1]); //b的地址
printf("%p\n", &b); //b的地址
printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值
return 0;
}
从上面可以看出,指针数组的每个元素都是一个指针,跟定义的普通指针一样使用
数组指针 (*p)[n]例子
#include "stdio.h"
int main()
{
//一维数组
int a[5] = { 1, 2, 3, 4, 5 };
//步长为5的数组指针,即数组里有5个元素
int (*p)[5];
//把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身
p = &a;
//%p输出地址, %d输出十进制
//在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。
printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址
printf("%p\n", p); //根据上面,p为数组a的地址,值等于数组a首元素的地址
printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组
printf("%p\n", &a[0]); //a[0]的地址
printf("%p\n", &a[1]); //a[1]的地址
printf("%p\n", p[0]); //数组首元素的地址
printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1
printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1
printf("%d\n", *p[1]); //表示a[5],数组已经越界,指向最后一个元素的下一个元素的地址,实际不存在
printf("%d\n", *(p[1]-1)); //数组最后一个元素的值
//将二维数组赋给指针
int b[3][4];
int(*pp)[4]; //定义一个数组指针,指向含4个元素的一维数组
pp = b; //将该二维数组的首地址赋给pp,也就是b[0]或&b[0],二维数组中pp=b和pp=&b[0]是等价的
pp++; //pp=pp+1,该语句执行过后pp的指向从行b[0][]变为了行b[1][],pp=&b[1]
return 0;
}
执行结果:
lwl@lwl:~/test$ ./test
0x7ffc95d481b0
0x7ffc95d481b0
0x7ffc95d481b0
0x7ffc95d481b0
0x7ffc95d481b4
0x7ffc95d481b0
1
1
1600061541
5
总结:
1.数组指针是一个指针变量,可以等价于一个二维数组,数组指针是一个指针变量,在数值上,p是指向二维数组整个元素的地址, *p,p[0]都指向二维数组首元素地址,在内存中存储地址,二维数组整个元素的地址和二维数组首元素的地址都是同一个位置,它们的值是相同的。
2.数组指针指向的是整个数组元素地址,不管是指向一维数组还是二维数组,都是指向整个数组的。数组指针在一维数组中优点多余,没必要使用,在c/c++里可以专门用来指向二维数组。