C修改函数的指针型形参对其实参的影响

这一次的Leetcode题又给我贡献了两篇文章,太棒了!

前言

在做Leetcode第21题时,原本觉得有些代码重复调用了,就想弄成函数形式,是这个作用:
传参两个链表结点,比较值的大小,将值小的作为返回值,并将该指针后移一个结点。
但在使用中,出现无限循环,测试发现是因为函数内虽然后移了指针,但实参并不受影响。
因此好奇这是Leetcode编译器的特性还是我的C理解不到位。
于是有了这次测试,测试的结果,的确是我学的不到位了。

原测试代码

  • 代码使用两个结点进行测试,分别是:
    • 结点1:val==1,next指向结点2,结点1是头结点。
    • 结点2:val==2,next指向NULL。
  • 代码中会先输出头结点的值及其地址,
    • 再通过nextNode将头结点后移,并输出其值及其地址,
      • 再返回主函数继续输出头结点的值及其地址。
#include <stdio.h>

struct ListNode{
	int val;
	struct ListNode* next;
};

void nextNode(struct ListNode* node);

int main(){
	struct ListNode* testNode = (struct ListNode*)malloc(sizeof(struct ListNode));
	testNode->val = 1;
	testNode->next = (struct ListNode*)malloc(sizeof(struct ListNode));
	testNode->next->val = 2;
	testNode->next->next = NULL;
	printf("val: %d, pointer: %p, next pointer:%p\n", testNode->val, testNode, testNode->next);
	nextNode(testNode);
	printf("val: %d, pointer: %p, next pointer:%p\n", testNode->val, testNode, testNode->next);
}

void nextNode(struct ListNode* node){
	node->val = 3;
	node = node->next;
	printf("val: %d, pointer: %p, next pointer:%p\n", node->val, node, node->next);
}

结果分析

运行结果如下:

val: 1, pointer: 00000000007313E0, next pointer:0000000000731400
val: 2, pointer: 0000000000731400, next pointer:0000000000000000
val: 3, pointer: 00000000007313E0, next pointer:0000000000731400
  • 可以看出:
    • 第一次,在主函数中输出第一个结点的信息,
    • 第二次,在函数内部输出第二个结点的信息,
    • 第三次,返回主函数输出第一个结点的信息。
  • 即通过nextNode函数后移结点后,虽然函数内部形参发生了变化,但实参并没有改变。
    • 这与我的认知不同,修改指针型的形参理应影响实参。
    • 然后回想了下我几个月没碰的C语言,想起了似乎是还需要加*。
    • 于是修改了nextNode函数,进行了新一次测试。
      • 即,将node = node->next;修改成了*node = *node->next;

新测试代码

代码仅将nextNode函数中的node = node->next;修改成了*node = *node->next;

#include <stdio.h>

struct ListNode{
	int val;
	struct ListNode* next;
};

void nextNode(struct ListNode* node);

int main(){
	struct ListNode* testNode = (struct ListNode*)malloc(sizeof(struct ListNode));
	testNode->val = 1;
	testNode->next = (struct ListNode*)malloc(sizeof(struct ListNode));
	testNode->next->val = 2;
	testNode->next->next = NULL;
	printf("val: %d, pointer: %p, next pointer:%p\n", testNode->val, testNode, testNode->next);
	nextNode(testNode);
	printf("val: %d, pointer: %p, next pointer:%p\n", testNode->val, testNode, testNode->next);
}

void nextNode(struct ListNode* node){
	node->val = 3;
	*node = *node->next;
	printf("val: %d, pointer: %p, next pointer:%p\n", node->val, node, node->next);
}

第二次结果分析

运行结果如下:

val: 1, pointer: 0000000000A213E0, next pointer:0000000000A21400
val: 2, pointer: 0000000000A213E0, next pointer:0000000000000000
val: 2, pointer: 0000000000A213E0, next pointer:0000000000000000
  • 结果与预想的一致,函数内部修改形参后反馈到了实参。

总结

  • 在通过函数修改指针形参时,要注意是否加了*,
    • 不加*,修改的是地址值,
    • 加了*,修改的才是地址对应的值。
  • 尤其是修改链表、树这一类数据结构时要注意。

You may also like...

发表评论

邮箱地址不会被公开。 必填项已用*标注