C修改函数的指针型形参对其实参的影响
这一次的Leetcode题又给我贡献了两篇文章,太棒了!
前言
在做Leetcode第21题时,原本觉得有些代码重复调用了,就想弄成函数形式,是这个作用:
传参两个链表结点,比较值的大小,将值小的作为返回值,并将该指针后移一个结点。
但在使用中,出现无限循环,测试发现是因为函数内虽然后移了指针,但实参并不受影响。
因此好奇这是Leetcode编译器的特性还是我的C理解不到位。
于是有了这次测试,测试的结果,的确是我学的不到位了。
原测试代码
- 代码使用两个结点进行测试,分别是:
- 结点1:val==1,next指向结点2,结点1是头结点。
- 结点2:val==2,next指向NULL。
- 代码中会先输出头结点的值及其地址,
- 再通过nextNode将头结点后移,并输出其值及其地址,
- 再返回主函数继续输出头结点的值及其地址。
- 再通过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
- 结果与预想的一致,函数内部修改形参后反馈到了实参。
总结
- 在通过函数修改指针形参时,要注意是否加了*,
- 不加*,修改的是地址值,
- 加了*,修改的才是地址对应的值。
- 尤其是修改链表、树这一类数据结构时要注意。
共有 0 条评论