写链表时的问题——函数参数

来源:互联网 发布:淘宝上怎么样买东西呢 编辑:程序博客网 时间:2024/06/09 19:54

原程序

#include<stdio.h>#include<stdlib.h>#include<iostream.h>using namespace std;typedef struct _ListNode{int data;_ListNode* next;} ListNode;ListNode* CreateList(){ListNode* node=NULL;return node;}ListNode* FindDataInList(ListNode* ListHead,int number){if(ListHead==NULL)return NULL;ListNode* node=ListHead;while(node){if(node->data==number)return node;elsenode=node->next;}return NULL;}bool InsertDataIntoList(<span style="color:#ff0000;">ListNode* ListHead</span>,int number){ListNode* node=ListHead;while(node)node=node->next;node=(ListNode*)malloc(sizeof(ListNode));node->data=number;return true;}void traverse(ListNode* head){ListNode* node;node=head;if(node){cout<<node->data<<" ";node=node->next;}}int main(){ListNode* ListHead=CreateList();InsertDataIntoList(ListHead,5);InsertDataIntoList(ListHead,4);InsertDataIntoList(ListHead,6);InsertDataIntoList(ListHead,3);InsertDataIntoList(ListHead,8);InsertDataIntoList(ListHead,1);InsertDataIntoList(ListHead,2);traverse(ListHead);return 0;}
出错的原因其实是一个很简单的函数参数传递的问题,但是可能是由于夹杂着指针之类的东西变得比较复杂。首先来说说函数参数传递的问题:

函数参数的传递

在函数未被调用时,函数的形参并不占有实际的内存空间,也没有实际的值。只有在函数被调用时才为形参分配储存空间(即在栈中分配一个储存空间),并将实参与形参结合。实参可以使常量,变量,或者是表达式,其类型必须与形参相符。函数的参数传递至指就是形参与实参结合的过程,形实结合的方式有值调用和引用调用。
1.值调用
值调用是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。这一过程是参数值的单向传递过程,一旦获得了值便与实参脱离关系,此后无论形参发生怎样的变化,都不会影响到实参。
我这里就是这种情况出的问题。
打个最简单的比方
void fun(int a){a=3;}int main(){int  b=4;fun(b);cout<<b;return 0;}

这个代码输出会是什么呢?显然会是4,而不是3,因为这里的参数传递只是单向传递,用内存来解释就是函数调用时为形参分配了一个栈空间,并用实参去初始化形参变量,之后实参与形参便脱离关系,无论函数里怎样改变形参,都不会改变实参的值。
2.引用调用
引用时一种特殊类型的变量,可以被认为是另一个变量的别名。通过引用名和通过被应用的变量访问变量的效果是一样的,例如:
int i,j;int &ri=i;   //建立一个int型的引用ri,并将其初始化为变量i的别名j=10;ri=j; //相当于i=j

引用也可以作为形参,如果将引用作为形参,情况便稍有不同。这是因为,形参的初始化不在类型说明时进行,而是在执行主调函数中的调用表达式时,才为形参分配内存空间,同时用实参来初始化形参。

void fun(int &a){a=3;}int main(){int  b=4;fun(b);      //这里等于执行了int &a=b cout<<b;return 0;}

因此输出为3。

上面的代码就是这个问题,红字部分表示传入的参数是一个ListNode型指针,我的想法是这个指针作为头节点,之后通过这个指针去访问链表,所以我希望在函数中插入建立的链表与这个指针有关联,无论是在这个指针指向的地址上建立链表还是改变指针指向的位置使指针指向创建的链表都行。指针指向的地址上建立链表显然不可能,首先指针我们声明时将其至空了,其次创建链表肯定是动态创建在堆内存空间中(这里思路有些乱,总而言之,就是说指针只是用来访问内存的,刚声明出来其实什么用也没有,只有赋值后才能起到访问内存的作用),所以只有可能将此指针作为值传入函数后,将创建的内存地址赋值给指针,我这里也是这样想的,然而我没有想到函数中的所有操作都只是对函数调用时形成的形参的操作,实参只是给形参初始化使用,而不是对我们想使用来访问链表的实参指针的操作。其实想这样也很简单,函数定义是参数前加个&使参数变为引用就可以使函数对实参进行操作了。

还有一个使我犯错的原因就是其实通过指针也是可以改变实参的值的,这里看到参数是个指针比较复杂也就没有往深层次想,先来看一个简单的例子:

void fun(int* p){*p=3;}int main(){int a=2;int *b=&a;fun(b);    //等于执行了int *p=b =&a;cout<<a;return 0;}

这里的参数是一个int型指针,当函数调用对形参进行初始化时实际上是将指针的值即指针指向变量的地址传递给了形参,然后函数中再用*取形参指向地址的变量对其进行赋值,所以说要用函数完成对实参的修改,必要条件就是要传递实参的地址。
而在我写的链表的插入函数中如何实现用指针传递呢?
<span style="color:#323e32;">bool InsertDataIntoList(</span><span style="color:#ff0000;">ListNode* ListHead</span><span style="color:#323e32;">,int number){ListNode* node=ListHead;while(node)node=node->next;node=(ListNode*)malloc(sizeof(ListNode));node->data=number;return true;}</span>

这是我的函数原型

ListNode* ListHead=CreateList();InsertDataIntoList(ListHead,5);

这是我的函数调用语句,首先以后想通过ListHead去访问链表,也就是希望InsertDataIntoList能对ListHead做出改变的操作,于是我们就需要传入ListHead的地址,首先要取得ListHead地址,在主函数中进行如下修改:

ListNode* ListHead=CreateList();ListNode** head=&ListHead;InsertDataIntoList(ListHead,5);

或者直接传入地址

ListNode* ListHead=CreateList();InsertDataIntoList(&ListHead,5);

而函数传入的参入要改为指向指针的指针
<span style="color:#323e32;">bool InsertDataIntoList(</span><span style="color:#ff0000;">ListNode** ListHead</span><span style="color:#323e32;">,int number){ListNode* node=*ListHead;while(node)node=node->next;node=(ListNode*)malloc(sizeof(ListNode));node->data=number;return true;}</span>




0 0