本文目的解决下面这个问题:我们一起加油吧!
什么情况下要使用指向类型中元素的指针,目的是什么,为什么在这里给的是一个空值,s存储的到底是什么?
以这个代码为例:
cpp
struct Node {
int value;
};
int main() {
int* p = nullptr;
int Node::* s = nullptr;
s = &Node::value;
}
1.普通指针和成员指针的区别?
(1)普通指针:
cpp
int* p = nullptr;
普通指针 p 指向int 变量 ,存的是内存地址
(2)成员指针:
cpp
int Node::* s = nullptr;
成员指针 s 指向 Node 类里的一个 int 成员变量 存的是 ,成员在类里的偏移量
2.为什么都是等于nullptr,但是监测值不一样?

(1)int* p = nullptr;
- 这是普通空指针,表示 "不指向任何内存地址"。
- 在 32/64 位系统里,它就是一个全 0 的地址:
- 32 位:
0x00000000 - 64 位:
0x0000000000000000
- 32 位:
- 所以调试器里显示
0x00000000 {???},这是最直观的 "空地址"。
(2)int Node::* s = nullptr;
- 这是成员指针空值,表示 "不指向任何类成员"。
- 成员指针本质存的是偏移量,而不是内存地址。
- 编译器为了区分 "空成员指针" 和 "偏移量 0",会用一个特殊值表示
nullptr:- 常见实现:用
-1(即全 1 的二进制,64 位就是0xffffffffffffffff)
- 常见实现:用
- 所以调试器里显示
0xffffffffffffffff {???},这是编译器约定的 "空成员指针" 标记,不是地址,也不是有效偏移量。
3.什么情况下要使用成员指针?
当你需要把 "类里面的某个成员" 当作一个变量来传递、选择、复用的时候。
比如:
- 你写一个通用函数,不知道要访问 Node 的哪一个成员
- 想让调用者传进来 "你要访问哪个字段"
- 实现类似 "反射""动态访问成员" 的效果
cpp
struct Node {
int a;
int b;
};
// 这个函数可以打印 Node 的任意一个 int 成员
void show(Node& obj, int Node::* mem) {
cout << obj.*mem << endl;
}
int main() {
Node n{10, 20};
show(n, &Node::a); // 传成员 a
show(n, &Node::b); // 传成员 b
}
4.使用成员指针的目的是什么?
让 "类的成员" 可以像普通数据一样被传递、保存、复用。
普通指针保存的是:某个内存地址(一个具体变量)
成员指针保存的是:类内部 "哪个成员" 不绑定具体对象,可以对任意对象使用。
5. s 到底存储的是什么?
s 里存的不是内存地址! 它存的是:成员在结构体 / 类内部的偏移量(offset)
(1)偏移量是什么?
偏移量 = 从对象开头,到这个成员的距离(字节数)
你可以把一个 struct 对象想象成 一长排连续的小格子(字节):
- 第 0 个字节
- 第 1 个字节
- 第 2 个字节......
一个成员在第几个字节开始,它的偏移量就是多少。
比如:
cpp
struct Node {
int value;
};
value 在对象开头,偏移是 0。所以 s 里实际存的数字是 0。
如果是:
cpp
struct Node {
char c; // 0
int value; // 4
};
(2)监测值?
那么 s = &Node::value 时,s 里存的就是 4。

所以当代码执行到s=&Node::value这一行时,s由0xffffffff =>0x00000000
6.为什么这里给 nullptr?
cpp
int Node::* s = nullptr;
原因和普通指针一样:
- 定义指针时,还没有确定指向哪个成员
- 不初始化会是随机值,不安全
nullptr表示:当前不指向任何成员
就是一个安全的初始空状态。
你真棒你应该也会了吧!我也学会啦!