指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针
数组指针:a pointer to an array,即指向数组的指针
还要注意的是他们用法的区别,下面举例说明。
int* a[4] 指针数组
表示:数组a中的元素都为int型指针
元素表示:a[i] (a[i])是一样的,因为[]优先级高于*
int (*a)[4] 数组指针
表示:指向数组a的指针
元素表示:(*a)[i]
我们先看维基百科中对于数组指针的解释:
数组名出现在表达式中时,绝大多数情况(除了数组名作为sizeof的操作数或者作为取地址&元素符的操作数)会被隐式转换为指向数组的首个元素的指针右值。
当数组名作为取地址&元素符的操作数,则表达式的值为指向整个数组的指针右值。
例子:
char s[]="hello";
int main() {
char (*p1)[6]=&s; //OK!
char (*p2)[6]=s; //compile error: cannot convert 'char*' to 'char (*)[6]'
char *p3=&s;//compile error: cannot convert 'char (*)[6]' to 'char*'
}
根据上述C语言标准中的规定,表达式 &s 的值的类型是char ()[6],即指向整个数组的指针;而表达式 s 则被隐式转换为指向数组首元素的指针值,即 char 类型。同理,表达式 s[4] ,等效于表达式 *(s+4)。
对于上面的内容中提到的“当数组名作为取地址&元素符的操作数,则表达式的值为指向整个数组的指针右值。”我们参考如下程序进行理解:
#include <stdio.h>
int main ()
{
int a[5] = {1,2,3,4,5};
int *p = (int*)(&a + 1);//&a表示整个数组的地址
printf("%d %d\n" , *(a + 1), *(p - 1));
printf("%p\n",&a);
printf("%p\n",&a+1);
return 0;
}
//输出结果为:
2 5
0x7ffc113aad80
0x7ffc113aad94
这是一道非常常见的C语言面试题。
0x7ffc113aad94-0x7ffc113aad80=0x14=20
因此可以判断&a表示整个数组,对&a+1将会偏移整个数组的大小。
a[0] 0x7ffc113aad80
a[1] 0x7ffc113aad84
a[2] 0x7ffc113aad88
a[3] 0x7ffc113aad8C
a[4] 0x7ffc113aad90
因此&a+1指向的是a[5],使用*(p-1)即可访问a[4]的元素。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int e = 50;
/*指针数组*/
int *p[5]={&a,&b,&c,&d,&e};
printf("a = %d\n",*p[0]);
/*数组指针*/
int arr[5] = {10,20,30,40,50};
int (*ptr)[5] = &arr;
printf("%d\n",(*ptr)[0]);
return 0;
}