多重指针的理解

简介

其实这本不是一个很难理解的内容: 指针就是指向一个数据的地址

而所谓的多重指针就是指向指针的指针,反复的嵌套。

指针的值存储着对应类型的地址

背景

在实现一个节点数据的移动代码时,仿佛对这个问题有了更新的理解

所有特此记录一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 LRUNode **new_list = new LRUNode *[new_length];
memset(new_list, 0, sizeof(new_list[0]) * new_length);
for (uint32_t i = 0; i < length_; i++) {
LRUNode *h = list_[i]; // h 指向list连续地址中偏移i个单位的地址
while (h != nullptr) {
LRUNode *next = h->next_hash; // next 获取h的下一个节点
uint32_t hash = h->hash;

LRUNode **ptr = &new_list[hash & (new_length - 1)];
h->next_hash = *ptr;
*ptr = h;
h = next;
}
}

理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 +--------------+                  +--------------+
| | | |
| | | |
+--------------+ +--------------+
| next_hash | | next_hash | real data
| 0x50 | | |
+--------------+ +--------------+
0x200 0x220 0x400 0x420
^ ^
| |
| |
+--------------+--------------+ +--------------+--------------+
| | | | | |
| 0x200 | | ... | 0x400 | | new_list
| | | | | |
+--------------+--------------+ +--------------+--------------+
0x00 0x08 0x10 0x50 0x58 0x60
^
|
|
+--------------+ +--------------+
| | | |
| 0x200 | | 0x50 |
| | | |
+--------------+ +--------------+
0x90 0x98 0x100 0x108

h ptr

说明

图示地址仅仅是为了方便,简化表示。

由于 new_list 是指向指针的指针,所以每一个元素为8字节,对应图示为 0x00 - 0x60

real data 为真实的数据地址,每一个数据块的大小为32字节

ptr 被声明为一个二维指针,本质也是一个指针,所以为8字节, 对应地址 0x100 - 0x108

h 是一个一维指针,为8字节,对应地址为 0x90 - 0x98

分析

1
LRUNode *h = list_[i];

当 i = 0 时, list_[i] 对应的地址空间为 0x00 - 0x08,其值为 0x200

所以此时,h 被赋值为 0x200

1
LRUNode **ptr = &new_list[hash & (new_length - 1)];

这段代码中,ptr 指向 list连续地址中偏移 [hash & (new_length - 1)] 个单位的地址

ptr 本身也是有一个地址的,不过指针本身对应的值不同于常见数据类型,是一个地址值,如图所示。

1
h->next_hash = *ptr;

对于 *ptr ,代表着地址空间为 0x50 - 0x58, 值为 0x400

h 对应着地址段 0x200 - 0x220 , 所以在该地址空间中,将对应指针的值变为 0x50

1
*ptr = h;

*ptr 的值为 0x400 , h 的值为 0x200

所以现在 *ptr 的值变为 0x200 , 即指向第一个数据块