结构体指针作为函数传入参数的注意事项

问题来源

在研究构造链表节点插入函数,使用结构体指针作为函数传入参数的时候发现的问题。

在链表指针还没有开辟内存空间的时候就作为函数的传入函数的时候,不使用函数回传的结构体给链表指针重新赋值,链表的节点插入无效。而给链表指针开辟内存空间之后,作为函数的传入参数,不需要函数的回传的结构体给链表指针重新赋值,链表的节点插入也能正常插入。

这就引起了我的好奇,为什么在给函数传入参数之前一定需要给参数指针开辟内存空间才行呢?

先看节点插入函数

 
//插入节点,参数:插入那个链表,插入节点的数据是多少
struct Node* insertNodeByHead(struct Node* headNode, int data){
    struct Node* newNode = createNode(data);
    if(headNode==NULL){
        headNode = (struct Node*)malloc(sizeof(struct Node));
        headNode->data = 9;
        headNode->next = NULL;
    }
    newNode->next = headNode->next; //此时两个节点共同指向下一个节点 
    headNode->next = newNode;       //现在headNode节点指向newNode节点
    return headNode; 
} 

我学习的教程是没有判断改链表是否为空的情况,我考虑到如果链表是空的话,那我先给链表分配内存(也就是问题的关键点)。然后问题出现:

这里没有给传入的链表指针参数开辟内存空间,也没有将函数的返回结果给链表指针重新赋值,结果是插入节点失败:

int main(){
    struct Node* List = NULL;      //创建一个链表变量    重点:有很多编译器都需要初始化为空,不然会出错
    insertNodeByHead(List, 4);
    insertNodeByHead(List, 3);
    insertNodeByHead(List, 5);
    insertNodeByHead(List, 6);
    printList(List);       
    return 0;
}

在这里插入图片描述
没有给传入的链表指针参数开辟内存空间,但将函数的返回结果给链表指针重新赋值,结果是插入节点成功。

int main(){
    struct Node* List = NULL;      //创建一个链表变量    未初始化 
    List = insertNodeByHead(List, 4);
    List = insertNodeByHead(List, 3);
    List = insertNodeByHead(List, 5);
    List = insertNodeByHead(List, 6);
    printList(List);       
    return 0;
}

在这里插入图片描述

问题分析

其实这个是指针的问题,指针变量是存放了数据的地址。

在这里List是一个链表指针,它存放了第一个节点的地址,所以当我们还没有给链表指针开辟一个空间的时候,也就是这个链表指针还没有指向任何一个地址。我们暂且将这种还没开辟空间的链表指针叫为空指针,当我们将空指针作为函数的传入参数时, List只能讲一个空地址传给insertNodeByHead(struct Node* headNode, int data)函数的链表指针变量headNode,headNode也成为一个空指针,而在这个函数里面,按代码逻辑,将会给链表指针变量headNode开辟一个内存空间,那现在headNode将不再是一个空指针,它存放了一个地址,这个地址就是新开辟的一个节点空间。但是这只是headNode链表指针变量指向了第一个节点而已,而函数外面的List链表指针变量还是空指针变量。在insertNodeByHead函数里后面的插入节点代码都只是对headNode链表指针变量的操作,而List并没有一点改变,如果没有将insertNodeByHead函数的返回指针值给List重新辅助的操作,也就是List没有“继承”insertNodeByHead函数对headNode的一切操作。当将insertNodeByHead的返回指针值给List重新赋值,也就是headNode变量存放的地址“分享”给List变量,那么List也会指向第一个节点了。

int main(){
    struct Node* List = NULL;      //创建一个链表变量    未初始化 
    insertNodeByHead(List, 4);
    List = insertNodeByHead(List, 3);
    List = insertNodeByHead(List, 5);
    List = insertNodeByHead(List, 6);
    printList(List);       
    return 0;
}

在这里插入图片描述
从实验结果可以看出,第一次插入节点并赋值为4的操作并没有成功。

结论

通过上述的推论和实验可知,使用指针变量作为函数的传入参数时,我们仅是利用了这个指针变量存放的地址而已,如果这个指针变量是一个空指针,那么这个传入参数将毫无用处。如果我们使用了空指针作为传入参数,我们需要使用函数返回的指针值给原来的指针变量重新赋值才可以获得函数的操作结果。那么按结论来说,只有我们的指针变量List获得第一个节点后,我们就不需要再使用函数返回的指针值给List重新赋值了。

int main(){
    struct Node* List = NULL;      //创建一个链表变量    未初始化 
    insertNodeByHead(List, 4);
    List = insertNodeByHead(List, 3);
    insertNodeByHead(List, 5);
    insertNodeByHead(List, 6);
    printList(List);       
    return 0;
}
 

在这里插入图片描述
实验正确。

使用空指针作为传入参数的另一种解决办法

使用二级指针变量就可以解决这个问题,也就是使用指针的指针作为函数的传入参数,这样就不需要使用返回指针值重新赋值了。关于使用二级指针的代码我还没尝试,这是知道这个办法可以解决,等我会了再贴代码出来。

关于链表的学习,可以看这篇文章哦LeetCode算法学习——链表

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

39度C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值