指针数组:首先它是一个数组,每一个元素都是一个指针。
数组指针:首先它是一个指针,它指向一个数组。它是"指向数组的指针"的简称。
运算符的优先级关系:() > [] > *
数组指针(也称行指针)
例如:int (*p)[n];
根据优先级,先看( )内,p是一个指针,后面的[ ]又说明了p是一个指向数组的指针,由于前面的int,所以p是一个指向 int 类型数组的一个指针。
将二维数组赋给指针:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
所以数组指针也称指向一维数组的指针,亦称行指针。
指针数组
例如: int *p[n];
根据优先级,p先与[ ]结合,所以p是一个数组,再结合 *,表明数组里面的元素是指针,再加上int,说明p数组中的元素是int类型的指针。
将二维数组赋给指针数组:
int *p[3];
int a[3][4];
p++; //该语句表示p数组指向下一个数组元素。
for(i=0;i<3;i++)
p[i]=a[i]
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]所以要分别赋值。
在二维数组里面
a,&a,a[0],&a[0],&a[0][0]五个值是一样的,都指向二维数组的首地址(起始位置)。区别在于这五种表达方式的类型是不同的,以int a[2][3]举例:
a是二维数组名,是常量,存放着二维数组的首地址,类型为二维数组,sizeof(a)=24。
&a 二维数组a的(首)地址,本身是一个指针,sizeof(&a)=4,指针类型都为4。
a[0]指向二维数组中的第一行数组a[0][],类型是一维数组sizeof(a[0])=12。
&a[0]代表a[0]的地址,与一维数组名a[0]值相同,但本身是指针类型sizeof(&a[0])=4。
&a[0][0]表示二维数组中第一个元素的地址,指针类型sizeof(&a[0][0])=4。
A和&A之间的区别
分析如下代码:
int main()
{
char a[5]={'A','B','C','D'};
char (*p3)[5] = &a;
char (*p4)[5] = a;
return 0;
}
上面对p3 和p4 的使用,哪个正确呢?p3+1 的值会是什么?p4+1 的值又会是什么?毫无疑问,p3 和p4 都是数组指针,指向的是整个数组。&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。在C/C++里,赋值符号“=”号两边的数据类型必须是相同的,如果不同需要显示或隐式的类型转换。p3 这个定义的“=”号两边的数据类型完全一致,而p4 这个定义的“=”号两边的数据类型就不一致了。左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。在Visual C++6.0 上给出如下警告:
warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。
这里给出了警告,可是由于&a 和a 的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。虽然能运行,但不能这么用。
现在清楚了p3 和p4 都是指向整个数组的,那p3+1和p4+1的值就很好理解了。测试代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char a[5]={'a','b','c','d'};
char (*p1)[5]= &a;
char (*p2)[5]=(char (*)[5])a;
printf("a = %p\n",&a); //%p打印数组地址
printf("a = %c\n",a[0]);
printf("p1 = %c\n",**p1);
printf("p2 = %p\n",*p2);
printf("p1+1 = %p\n",*(p1+1)); //p1是数组指针,数组a的长度是5个字节,所以p1+1将指向a[0]向后移动5个字节的位置
printf("p2+1 = %p\n",*(p2+1));
return 0;
}
结论:根据指针类型及所指对象,表示指针大小,每次加1,表示增加指针类型大小的字节。
另一个实例
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a[4]={1,2,3,4};
int *ptr1=(int *)(&a+1); //指向a数组后面的内存单元,&a+1表示向后移16个存储单元
int *ptr2=(int *)(a+1); //表示a的存储单元的地址增加一个字节
printf("%d,%d",ptr1[-1],*ptr2); //ptr1[-1]其实指向的是a数组的最后一个单元
return 0;
}
其内存布局如下图: