本节书摘来自异步社区《指针的编程艺术(第二版)》一书中的第3章,第3.5节,作者 蔡明志,更多章节内容可以访问云栖社区“异步社区”公众号查看
3.5 指向数组的指针
指针的编程艺术(第二版)
ptr[4] 和 (ptr)[4] 所表示的意义是不同的。ptr[4]已在前面讨论过了,而(ptr)[4]是指向数组的指针(pointer to array){XE "指向陣列的指標(pointer to array)"},表示ptr是一指针,指向一个有4个元素的数组,其实它也可视为是一个二维数组ptr[][4],因为*和[]是互通的,我们以范例pointerToArray-1来说明。
范例pointerToArray-1
/* pointerToArray-1.c */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i[][3]={10, 20, 30, 40, 50, 60};
int (*ptr)[3];
int a, b, total=0;
for(a=0; a<2; a++)
for(b=0; b<3; b++)
printf("&i[%d][%d]=%x\n", a, b, &i[a][b]);
printf("\n");
for(a=0; a<2; a++)
for(b=0; b<3; b++)
printf("i[%d][%d]=%d\n", a, b, i[a][b]);
ptr=i;
printf("\n");
printf("ptr=%x, *ptr=%x, i[0]=%x, i=%x, *i=%x\n", ptr, *ptr,
i[0], i, *i);
for(a=0; a<2; a++)
for(b=0; b<3; b++)
total += *(*(ptr+a)+b);
printf("Sum of array = %d\n", total);
system("PAUSE");
return 0;
}
输出结果
程序中的循环
for(a=0; a<2; a++)
for(b=0; b<3; b++)
total += *(*(ptr+a)+b);
表示第一次,将第1行的3个元素相加;第二次,将第2行的3个元素相加。因为
*(ptr+a) == ptr[a]```
所以上述的循环可以改为
for(b=0; b<3; b++)
total += *(ptr[a]+b);`
同理,*(ptr[a]+b) == ptra
所以上述的循环又可以改为
for(a=0; a<2; a++)
for(b=0; b<3; b++)
total += ptr[a][b];```
请参阅范例pointerToArray-2。
范例pointerToArray-2
/ pointerToArray-2.c /
include
include
int main()
{
int i[][3]={10, 20, 30, 40, 50, 60};
int (*ptr)[3];
int a, b, total=0;
for(a=0; a<2; a++)
for(b=0; b<3; b++)
printf("&i%d=%xn", a, b, &ia);
printf("n");
for(a=0; a<2; a++)
for(b=0; b<3; b++)
printf("i%d=%dn", a, b, ia);
ptr=i; / 将 ptr 指向数组的第一个元素的地址 /
for(a=0; a<2; a++)
for(b=0; b<3; b++)
total += *(ptr[a]+b);
printf("Sum of array = %dn", total);
total=0;
printf("n使用另一种计算总和方法: n");
for(a=0; a<2; a++)
for(b=0; b<3; b++)
total += ptra;
printf("Sum of array = %dn", total);
system("PAUSE");
return 0;
}
输出结果
<div style="text-align: center">
<img src="https://yqfile.alicdn.com/acc40b7e8afd5c2185c3a648d41bf489eee42996.png" >
</div>
以ptr指针计算二维数组的元素和。再来看一个相似的范例,如范例pointerToArray-3所示。
范例pointerToArray-3
/ pointerToArray-3.c /
include
include
int main()
{
int i3={{1,2}, {3,4}, {5, 6}};
int k;
int (*pi)[2];
pi=i;
for(k=0; k<3; k++)
printf("pi+%d=%xn", k, pi+k);
printf("pi=%xn", pi);
printf("pi+1=%xn", pi+1);
printf("pi0=%dn", pi0);
printf("pi1=%dn", pi1);
printf("(((pi+1)+1))=%xn", (((pi+1)+1)));
printf("(pi+1)=%dn", (pi+1));
getch();
return 0;
}
输出结果
<div style="text-align: center">
<img src="https://yqfile.alicdn.com/e59a40e959ebe8f6c8c2bda588c3b7816d98dc7a.png" >
</div>
指针之间的兼容性也是很重要的,我们以范例pointerTestCompatiable来说明。
范例pointerTestCompatiable
/ pointerTestCompatiable.c /
include
include
int main()
{
int *pt;
int (*pa)[3];
int **p2;
int arr12={0, 1, 2, 3, 4, 5};
int arr23={10, 20, 30, 40, 50, 60};
printf("&arr10=%pn", &arr10);
printf("&arr20=%pnn", &arr20);
pt=&arr10;
printf("pt=%p, &arr10=%pn", pt, &arr10);
pt=arr1[0]; / 不要写成 pt=arr1 /
printf("pt=%p, arr1[0]=%pn", pt, arr1[0]);
pt=arr1[0];
printf("pt=%dn", pt);
pa=arr1; / 不要写成 pa=arr2 /
printf("pa=%dn", pa);
p2=&pt; / 不要写成p2=pt /
printf("p2=%dn", p2);
p2=arr2[0]; / 要先将 p2指向某个变量的地址,如 p2=&pt */
printf("p2=%p, arr2[0]=%pn", p2, arr2[0]);
printf("p2=%dn", p2);
getch();
return 0;
}
输出结果
<div style="text-align: center">
<img src="https://yqfile.alicdn.com/9dfb8d0d758e71f29806f7c49b37cf67b47102d8.png" >
</div>
程序定义以下的变量
int *pt;
int (*pa)[3];
int **p2;
int arr12={0, 1, 2, 3, 4, 5};
int arr23={10, 20, 30, 40, 50, 60};
pt为一个指向int的指针;pa是一个指针,它指向每一行含有3个元素的数组;p2是一个指向指针的指针;arr1是一个具有2行3列的数组;arr2是一个具有3行2列的数组。
程序首先输出arr1与arr2数组的第1行第1列元素的地址,分别是0022FF40和0022FF20。程序中要注意以下几个语句,
pt=arr1[0]; / 不要写成 pt=arr1 /`
因为pt是一个指向int的指针,所以不可以写成pt=arr1。如果是这样的话,请问 pt与arr1会相等吗?答案是否定的,因为pt得到的应该是值(它只有一个),但*arr1所得到的还是一个地址,两边的答案不一致。
接下来,
pa=arr1; /* 不要写成 pa=arr2 */```
因为pa是一个指向每一行具有3个元素数组的指针,所以不要写成 pa=arr2,因为arr2是每一行有2个元素的数组。
最后,
p2=&pt; / 不要写成 p2=pt /`
因为p2是一个具有两个*的指针,所以不可以写成p2=pt,否则就无法实现p2是一个值的答案,而且pt是错误的写法。这个范例较难,要耐心的体会才能完全了解。