指针–指针与数组
数组是由地址上连续的若干相同类型的数组组合而成,对int类型数组a来说,a[0]、a[1]、…、a[n-1]在地址上都是连续的。这样可以在元素前面加取地址运算符&来取其地址,例如a[0]的地址为&a[0],即数组a的首地址为&a[0].
不过C语言中,数组的名称也作为数组的首地址使用,因此上面的例子中,a == &a[0]成立。
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
int a[10] = {1};
int *p = a;
printf("%d\n", *p);
return 0;
}
输出
```plain text 1
1
2
3
4
5
6
7
在上述代码中,a作为数组a的首地址&a[0]而被赋值给指针变量p,因此输出的*p为输出首地址存储的内容a[0]。
指针变量中提到还可以进行加减法,结合这个知识点很容易理解,a+i等同于&a[i],这是因为a+i就是数组a的首地址偏移i个int型变量的位置。但是也应该注意,a+i其实只是地址,如果想要访问其中的元素a[i]需要加上星号*。使其变成*(a+i)后才和a[i]等价。由此可以得到一种输入数组元素的新写法:
```c
scanf("%d", a + i);
原先在a+i的位置是填写&a[i],由于a+i和&a[i]是等价的,因此使用a+i作为a[i]的地址是完全适合的。下面是用词读取一整个数组并给出输出的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
int a[10];
for (int i = 0; i < 10; i++)
{
scanf("%d", a + i);
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(a + i));
}
return 0;
}
输入
```plain text 1 2 3 4 5 6 7 8 9 10
1
2
3
4
5
输出
```plain text
1 2 3 4 5 6 7 8 9 10
此外,由于指针变量还可以使用自增操作,因此可以这样枚举数组中的元素。
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int *p = a; p < a + 10; p++)
{
printf("%d ", *p);
}
return 0;
}
输出
```plain text 1 2 3 4 5 6 7 8 9 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里说明的是for循环当中的语句for(int* p =a; p< a + 10; p++) 代表了最开始定义的为指针变量p赋值数组首地址,用a(可以换为&a[0]),之后判断循环结束的为a偏移10个int类型变量位移,而p++则代表了每次偏移一个int单位。如此输出了是个数组当中的内容。因为每个数组的地址都是每个int类型的第一个字节存储的因此可以这样操作。
再说明指针的减法,代码如下:
```c
#include <stdio.h>
int main()
{
int a[10] = {1, 4, 9, 16, 25, 36, 49};
int *p = a;
int *q = &a[5];
printf("q = %d\n", q);
printf("p = %d\n", p);
printf("q - p = %d\n", q - p);
return 0;
}
输出
plain text q=6356756 p=6356736 q-p=5
值得注意的是,pq分别取的是数组的首地址和数组的第6个值a[5](数组从0开始),因此两者之间的差一定是相差5个int,每个int四个Byte(字节)因此应该相差是20我们观察pq的地址数组也看出相差了20 (pq的具体指与运行环境有关系,但是一定是相差20的地址),但是指针对减输出的是5却不是20。是值得大家思考的一件事情。
前面说过,数组名a是直接作为数组a的首元素地址的,因此p和q其实分别是&a[0]和&a[5]。这样q-p就是指两个地址之间的距离,这个距离需要注意是以int为单位。因此由于1个int占用4个Byte,因此实际上指针之间的距离应该是20/4=5,因此被输出的数值为5(int)而不是20(Byte)。
可能还是有点绕,这里说的更加通俗一些:两个int型的指针相减,等价于在求两个指针之间相差了几个int。由于&a[0]与&a[5]之间相差了5个int,因此输出“5”,这个解释对其他类型的指针同样适用。联系加法也可以发现,加法中p++也是加一个int,一次是加4个字节,此时+1其实是加一个int单位,但地址上是加4个字节,就更好理解了。