指针赋值分析
现象描述
链表中常用指针进行操作:
ListNode *slow= head;
ListNode *pre = NULL;
pre = slow;
slow = slow->next;
此时 pre 指向的仍然是 slow 第一次指向的地址,即 head
指针赋值给指针
指针变量存储的是内存地址,当执行 pre = slow 时,是将 slow 当时指向的内存地址复制给了 pre。这意味着:
pre和slow一开始指向同一个内存地址(同一个节点)- 当执行
slow = slow->next时,只是改变了slow存储的地址(让它指向了下一个节点) - 但
pre中存储的地址没有被改变,仍然是slow原来指向的那个节点的地址
从地址和值的角度分析
head: 地址0x100
节点1: 地址0x200
节点2: 地址0x300
节点3: 地址0x400
...
执行
pre = slow之前
假设此时:slow存储的地址是0x100(指向 vhead)pre尚未赋值(或存储其他地址)
执行
pre = slow时- 这是地址的复制:把
slow中存储的地址(0x100)复制到pre中 - 执行后:
slow的值(地址):0x100(不变)pre的值(地址):0x100(和 slow 相同)- 两者指向同一个内存地址(head)
- 这是地址的复制:把
执行
slow = slow->next时slow->next是slow指向节点(head)的next成员,假设是0x200(节点 1 的地址)- 这是修改 slow 自身存储的地址:把
0x200存入slow - 执行后:
slow的值(地址):0x200(现在指向节点 1)pre的值(地址):0x100(仍然指向 head,不受 slow 变化影响)
总结
- 指针变量(
pre/slow)存储的是地址 pre = slow是地址的复制,之后两者的地址值独立- 当
slow被赋值新地址(slow = slow->next)时,只是改变了slow自己存储的地址,pre中复制的旧地址不会同步变化
就像你抄了同学的家庭住址(pre = slow),后来同学搬家了(slow 变了),但你抄的旧地址(pre)不会自动变成新地址。
进一步分析
指针赋值的本质:复制门牌号
当执行 指针A = 指针B 时,本质是把指针 B 上的门牌号抄写到指针 A 上。
int a = 10; // 假设a的地址是0x100
int* p = &a; // p上写着0x100(指向a)
int* q; // q是一张空白标签
q = p; // 把p上的门牌号(0x100)抄到q上
执行后:
p和q上的门牌号完全相同(都是 0x100)- 它们指向同一块内存(变量 a)
- 但
p和q是两张独立的标签,各自保存着门牌号
两种不同的修改操作
- 修改标签上的门牌号(指针本身)
int b = 20; // 假设b的地址是0x200
p = &b; // 把p上的门牌号改成0x200(现在p指向b)
这时 q 上的门牌号还是 0x100(仍然指向 a),因为我们只改了 p 这张标签。
- 修改门牌号对应的房间内容(指向的变量)
*q = 30; // 找到q上的门牌号(0x100),把里面的内容改成30
这时通过 p 访问(如果 p 还指向 0x100 的话)也会得到 30,因为房间里的内容变了。
总结表格
总结
将指针 1 赋值给指针 2,本质是「地址的一次性复制」—— 复制完成后,指针 1 和指针 2 就变成了两个独立存储地址的变量,后续指针 1 的任何改变(无论是指向新地址,还是通过它修改指向变量的值),都不会主动影响指针 2 本身存储的地址值。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 宋振威的博客!
评论
