0.指针数组 & 数组指针(相见恨晚篇)
《C语言深度剖析》上面的解析如下:
指针数组: 首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。
数组指针: 首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占4 个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简称。
下面到底哪个是数组指针,哪个是指针数组呢:
A) int *p1[10];
B) int (*p2)[10];
- “[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10 个指向int 类型数据的指针,即指针数组。
- 至于p2 就更好理解了,在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。
我们可以借助下面的图加深理解:
这里有个有意思的话题值得探讨一下:
平时我们定义指针不都是在数据类型后面加上指针变量名么?这个指针p2 的定义怎么不是按照这个语法来定义的呢?也许我们应该这样来定义p2:
int ()[10] p2;
int () [10] 是指针类型,p2 是指针变量。这样看起来的确不错,不过就是样子有些别扭。其实数组指针的原型确实就是这样子的,只不过为了方便与好看把指针变量p2 前移了而已。你私下完全可以这么理解这点。虽然编译器不这么想。_
聪明的你,看完上面的讲解好像都理解了,是吧?
如上的解释,我再把重点啰嗦几句:
- 指针数组:本质是数组,只是里面存放的是多个指针(int * p1[10])。此处的p1是数组名,指针名没有。如果想获取指针&p1[i],这样可以获取指针
- 数组指针:本质是指针,虽然初始化的时候指向了一个数组( int(*p2)[10] ),但其实只是一个指针。p2是指针变量,想通过指针获取地址,可以用指针的偏移去获取,例如p2 + 1,代表第二个元素的地址
- 有关指针的偏移,可以参考博文:https://blog.csdn.net/chenmozhe22/article/details/106410963(图文并茂)
1.指针数组
#include <stdio.h>
int main() {
int i;
char* pch[5] = { "我", "爱", "你", "祖", "国" }; // 此处初始化只能是5个元素,多一个少一个都不行
printf("%s \n", pch[0]); // pch是数组名,所以通过索引直接可以获取到元素内的每个值
printf("%s \n", *(&pch[0])); // 既然每个变量可以找到,就能通过* + & + 变量方式,对指针取值
*(&pch[3]) = "中"; //pch[3] = "中";方式也一样效果
for (i = 0; i < 5; i++) {
printf("%s, ", pch[i]);
};
printf("\n");
printf("%s\n", *(&pch[1] + 1)); // 通过指针获取其他元素
printf("%d \n", sizeof(pch)); // 因为pch是指针数组,里面存放的是5个指针,所以4*5 = 20个字节
return 0;
};
我
我
我, 爱, 你, 中, 国,
你
20
2.数组指针
#include <stdio.h>
int main() {
int i;
int list[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* p1 = &list; // 指针指向数组方式一
printf("%p \n", p1);
printf("%p \n", p1+1); // &list[0] + 1
printf("%d \n", *p1);
printf("%d \n", *p1 + 1);
printf("===================\n");
int(*p2)[10] = &list; // 数据指针:指向了某个数组的指针,方式二
printf("%p \n", p2); //p2 和 *p2 的地址是一样的???
printf("%p \n", *p2);
printf("%d \n", **p2); // **p2是元素的实际值
printf("%p \n", *p2 + 1);
printf("%p \n", (*p2 + 2));
return 0;
};
012FF6B8
012FF6BC
1
2
===================
012FF6B8
012FF6B8
1
012FF6BC
012FF6C0
如上结果,我主要困惑的地方如下:
1.我们看到p1 & p2 & *p2的值是一样的
2.**p2才是具体的值,那p2算是指针的指针吗?
3.再谈二维数组
有关二维数组的概念和基础,可参考:https://blog.csdn.net/chenmozhe22/article/details/106280578
1.二维数组中的指针 & 数组名
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }
};
int(*p)[4];
int i, j;
p = a;
printf("%p \n", p);
printf("%p \n", *p);
printf("%d \n", **p);
printf("=================\n");
printf("%p \n", a);
printf("%p \n", *a);
printf("%d \n", **a);
return 0;
}
00D3FD94
00D3FD94
0
=================
00D3FD94
00D3FD94
0
根据代码,发现:
- **p / **a才能得到,二维数组元素对应的值
-在一维数组中(*p可以得到最终的元素),p代表的是指针变量;那么二维数组(**p可以得到最终的元素),那 *p 就是指针变量。- p则是真实指向二维数组,首元素的指针,这里有个概念,p不是指针的指针,可参考:https://blog.csdn.net/toyalll/article/details/50043193
- 我们可以通过指针、地址两种方式,分别获取并修改二维数组中的值。
2.获取二维数组中元素的值–指针法
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }};
int(*p)[4];
int i, j;
p = a;
printf("%d \n", **p);
printf("%d \n", *(*p + 1)); // *p+1,可以得到下一个元素的指针地址
printf("%d \n", *(*p + 2));
printf("=================\n");
printf("%d \n", *(*(p + 1))); //*(p+1),可以得到下一行元素的指针地址
printf("%d \n", *(*(p + 1)+1));
printf("=================\n");
printf("%d \n", *(*(p + 2)));
printf("%d \n", *(*(p + 2)+1));
return 0;
}
有关指针的偏移,可以参考:
https://blog.csdn.net/chenmozhe22/article/details/106410963
0
1
2
=================
4
5
=================
8
9
如上代码,经过优化之后如下:
#include <stdio.h>
int main() {
int a[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 },{ 8 , 9, 10, 11 }};
int(*p)[4];
int i, j;
p = a;
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf("%2d ", *(*(p + i) + j));
printf("\n");
}
return 0;
}
0 1 2 3
4 5 6 7
8 9 10 11
3.获取二维数组中元素的值–地址法
int main() {
char list[2][5] = { { '1', '2', '3', '4', '5' }, { 'a', 'b', 'c', 'd', 'e' }};
printf("%c \n", list[0][0]); //获取第一行的第一个元素
printf("%c \n", list[1][0]); //获取第二行的第一个元素
printf("%p \n", &list[0]);
printf("%p \n", &list[1]);
printf("%d-%d",&list[1],&list[0]); // 计算第一行第一个元素和第二行第一个元素相差的字节数
return 0;
};
1
a
00DBFD3C
00DBFD41
14417217-14417212
#include <stdio.h>
int main() {
char list[2][5] = { { '1', '2', '3', '4', '5' }, { '6', '7', '8', '9', '0' } };
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 5; j++)
printf("%c \t", *(&list[i][j]));
printf("\n");
};
return 0;
};
1 2 3 4 5
6 7 8 9 0
文章参考:
- 《C语言深度剖析》(强烈推荐大家看看,特别是初学者,昨天买了一本,家中常备!)
- https://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html
- https://www.cnblogs.com/mq0036/p/3382732.html#commentform