先说结论:

L和 副本L 本身的地址是一个存储自身的地方,二者不同,但是这两个变量所储存的地址都是链表的头节点

因此可以可以通过修改副本l->next来修改原l头节点的指向,

但是如果想要改变头节点自身的地址,如果不加&符号,那就相当于修改了副本l所储存的地址,原l不受影响

关键点:不要错误的以为 函数中的l->next 是由副本l记录的,实际上这个是由头结点记录的,副本l指向的地址实际上是记录了头结点的地址

L 和副本 L 本身是存储地址的变量

  • L 和它的副本 L 是两个不同的指针变量,它们本身(即 L 和副本 L)存在于不同的内存地址中
  • 但是,它们存储的值是相同的,都存储了链表头节点的地址(比如说地址 3)。也就是说,无论是 L 还是副本 L,它们指向的是同一个链表节点,这是链表头节点的地址。

2. L->next 是链表节点的成员

  • L->next 存储的是链表中下一个节点的地址。这个成员属于链表头节点,所以无论你是通过原始的 L 还是副本 L 来访问 L->next,你修改的都是同一个链表节点的 next 成员。

3. **修改 L->next 会影响原始 L**:

  • 因为 L 和副本 L 都指向同一个链表节点(同一个头节点),所以**修改 L->next(即修改头节点的 next 指向的地址)会同时影响原始 L->next**。
  • 这就是为什么你通过副本修改 L->next,原始的 L 也会“感知”到这个变化的原因,因为它们指向的节点是同一个。

4. **改变 L 本身(头节点的地址)需要 &**:

  • 如果你想要改变的是 L 本身(也就是想让 L 指向不同的地址,比如让 L 从指向头节点变成指向其他节点),那么不加 & 是不行的。因为如果不加 &,传递的只是 L 的副本,修改的是副本的值,不会影响原始的 L
  • 加上 & 的话,传递的就相当于 L 的地址(即指针的指针),这样在函数内修改 L 本身(让 L 指向新的节点)就能影响到原始的 L

5. L->nextL 本身是不同的东西

  • L 或副本 L 存储的是链表头节点的地址,这个值是链表头节点的地址
  • L->next 存储的是链表头节点的 next 成员,这个值是链表中下一个节点的地址。
1
2
3
4
5
typrdef strucrt LNode
{
ElemType data;
struct LNode *next;
}*LNode,LinkList;

上面是一个用于链表的结构体指针类型定义

函数一:修改一个链表第i个元素(i) 在这个函数中,/要传入的链表L/ 无需加&符号,因为他不涉及对头指针的操作

1
2
3
4
5
6
7
8
9
10
11
12
Status ChangeElem(/*要传入的链表L*/,int i,elemtype e)
{
struct *LNode point = L;
int j = 1;
while(j<=i)
{
if(!(point = point->next))
return ERROR;
j++;
}
point -> data = e;
}

函数二:初始化一个带头节点的空链表 这个函数中,传入的参数就必须是&L,因为它涉及对头指针的操作

1
2
3
4
5
6
Status LinkInit(/*要传入的链表L*/)
{
L = (LNode*)malloc(sizeof(LNode));
// *L = (LNode*)malloc(sizeof(LNode)); 如果使用指针的话
L->next = NULL;
}

如果使用引用符号&,则函数内部可以直接使用L,

但如果使用指针的话,要把所有L换成*L