为何C语言链表传指针后原链表会被修改?
问题根源:你的
NODE是指针的别名,不是结构体副本 我来帮你理清这个困惑的核心点——你对NODE类型的定义理解错了,这才导致你误以为edit函数拿到的是链表节点的局部副本。
先看你的结构体定义:
typedef struct LIST { int timestamp; float data; struct LIST *next; } * NODE;
这里的NODE是struct LIST*的别名,也就是一个指针类型,而不是struct LIST结构体本身的别名。
那我们拆解一下edit函数的参数:
void edit(NODE pHead) { pHead->data = 1337; }
这等价于:
void edit(struct LIST *pHead) { pHead->data = 1337; }
当你调用edit(*pHead)的时候,*pHead是当前链表节点的指针(比如第一个节点的内存地址),这个指针的值会被复制一份传给edit函数里的pHead参数——注意,复制的是指针的值(也就是节点的内存地址),而不是指针指向的整个节点结构体。
换句话说:
- 原链表的节点在内存地址
0xXXXX,*pHead的值是0xXXXX edit函数里的pHead参数拿到的也是0xXXXX- 所以
pHead->data = 1337本质上是直接修改0xXXXX地址里的data值,也就是原链表节点的data
这就是为什么最终打印链表时,你看到的是修改后的结果——edit函数从始至终都在操作原链表节点的内存,根本没有创建什么“局部副本”。
如果你想让edit不修改原链表,该怎么做?
如果你的需求是让edit处理节点的副本,那需要修改NODE的定义,让它成为结构体本身的别名:
typedef struct LIST { int timestamp; float data; struct LIST *next; } NODE; // 去掉星号,现在NODE是结构体类型
然后修改edit函数的参数为传值(也就是结构体副本):
void edit(NODE pHead) { pHead.data = 1337; // 这里用.而不是->,因为pHead是结构体实例 }
但要注意,这种传结构体副本的方式开销很大(尤其是节点数据多的时候),通常链表操作不会这么做——如果你只是不想修改原链表,更合理的做法是在edit里手动创建节点的副本,修改副本后返回,而不是直接传值。
再看你的call函数逻辑
你的call函数里循环3次:
- 调用
edit(*pHead)修改当前节点的data为1337 - 把
*pHead移动到下一个节点
循环结束后又把*pHead改回链表头pFirst,所以最终链表的前3个节点的data都被改成1337了,这就是打印结果被修改的直接原因。
内容的提问来源于stack exchange,提问作者Cata Cata
相关产品推荐
相关产品推荐

