不会飞的章鱼

熟能生巧,勤能补拙;念念不忘,必有回响。

指针系列_指针变量也是变量

任务

假设有如下结构体数组,请看如下代码:

1
2
3
struct Data {
int x, y;
} a[2];

请用尽可能多的形式,替换下面代码中 &a[1].x 的部分,使得代码效果不变:

1
2
struct Data *p = a;
printf("%p", &a[1].x);

编码

方法一,间接引用

减号大于号(->),组合起来,叫做“间接引用”运算符,作用可以和“直接引用”运算符对比。

例如:a 是一个结构体变量,a 中有一个字段叫做 x,由 a 去找到 x,这个过程比较直接,我们就用 a.x 来表示。可如果 p 是一个指针,指向 a 变量,如果要是由 p 去找到 x,这个过程就是个间接的过程,所以我们就使用 p->x。
简单来说,就是:是结构体变量引用字段,就直接引用,如果是指针想引用字段,就是间接引用。

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>

struct Data {
int x, y;
} a[2];

int main() {
struct Data *p = a;
printf("%p", &((a + 1)->x)); //用a+1定位到第二个结构体元素的首地址,然后间接引用x字段,最后再对 x 字段取地址,那么得到的和原任务中所输出的地址是一样的。
}

//0x55e3c8fa0028

方法二,巧妙使用指针类型

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>

struct Data {
int x, y;
} a[2];

int main() {
struct Data *p = a;
printf("%p", &(a[0].y) + 1);
}

//0x55e3c8fa0028

利用地址类型这个知识点,先定位到 a[0] 元素中 y 字段的首地址,然后对 y 字段取地址,这个时候,由于 y 字段是整型,所以取到的地址类型就是整型地址,之后再对这个整型地址执行 +1 操作,得到的也是 a[1].x 的首地址。

a数组内存结构示意图

小结

  • 可以通过 C 语言里面的工具来描述这种类型的特点,这个可以用来描述和定义新类型的工具,就叫做:结构体。
  • 对于某个结构体类型而言,其存储单元大小,等于它当中占用空间最大的基础类型所占用的字节数量。
  • 结构体的字段在内存中存储的顺序,是按照结构体定义时的顺序排布的,而且当本存储单元不够安放的时候,就从下个存储单元的头部开始安放。
  • 指针是变量,指针是一种用来存储地址的变量。
  • 指针的类型,决定了指针取值时所取的字节数量。
  • 指针的类型,决定了指针加减法过程中,所跨越的字节数量。
  • 无论是什么类型的指针,大小都相等,因为地址信息是统一规格的。
------ 本文结束------
如果本篇文章对你有帮助,可以给作者加个鸡腿~(*^__^*),感谢鼓励与支持!