愛悠閑 > 傳值和傳址易錯點

傳值和傳址易錯點

分類: 編程開發  |  標簽: fun,struct,編譯器,ini  |  作者: xu819241519 相關  |  發布日期 : 2014-05-29  |  熱度 : 131°

例:

//建立排序二叉樹,每次輸入一個數字就將其插入到樹中,當輸入完數字之后一棵排好序的//二叉樹就已經創建完畢。
typedef struct BTnode
{
  int vaule;
  struct BiTnode *lchild, * rchild;
}BitTnode;
typedef BiTnode * Bitree;
//定義指向root節點的指針
Bitree T;
//通過將T傳入函數從而建立二叉樹。
void Ceate(Bitree t,int key)
{
         Bitree s;
      s=(Bitree)malloc(sizeof(BiTnode));
       //判斷并移動指針t到葉子節點
      // ``````````````
         t=s;
       //````````````
}
Int main()
{
//```
       for(i=0;i<n;i++)
       {
scanf(“%d”,&key);
Create(T,key);
}
//```
}

錯誤在于將T傳入函數并試圖改變指針T的指向。

當函數返回時T的值還是傳遞給函數前的值,函數并不能改變T的指向,只能改變指針T指向的內存的值。

為了更好的理解,我們來看一下傳值和傳址的概念。

函數傳遞時的傳值:

例:

Int a=4;
Void fun(int x);
void main()
{
//```
 fun(a);//此時相當于將a的值復制給一個臨時創建的變量x,x和a是不同的變量,在函數中的操作//修改的都是x,并不能改變a的值。
//````
}


函數傳遞時的傳址:

例:

int a=4;
int *pt=&a;
void fun(int *x);
void main()
{
//````
fun(pt);  //此時相當于將pt指向的內存地址(&a)復制一份并賦給臨時創建的指針變量x,此//時x和pt也是不同的變量,在函數中若是使用解引用*x就相當于*pt,但是若想改變pt的//指向是不行的。
//````
}


為什么改變pt的指向是不行的呢?

pt也是變量,在內存中也需要空間存放,而此空間里存放的是pt指向的內存的地址。假設存放指針變量的內存為6666,pt指向的a的內存為8888,臨時變量x的地址是7777,如圖示


若想要改變pt的指向,需要修改存放指針變量pt的內存里的值8888,但是指針在傳遞時只是傳遞了8888的這個值給臨時指針變量x,并沒有將存放指針變量pt的地址傳遞到函數中,此時函數內是對x的操作,根本無法取得存放指針變量pt的內存(6666),也就無法改變pt的指向。當函數返回時pt還是指向8888。

 

了解了這些再來分析第一個例子的錯誤就簡單了。

函數Create(T,key)將未初始化的指針變量T傳遞進去,在里面想通過創建節點時順便將T初始化指向root節點。這是錯誤的,在傳遞指針的過程中只是把T指向的內存地址復制一份傳遞給t,無法改變存放指針變量T的內存內容,也就無法改變T的指向,當函數返回時T還是未初始化的指針。


上圖是剛進入Create(T,key)函數時T和t的狀態,當執行完t=s;后,變為下圖:


此時T的指向并沒有改變,改變的是t的指向。當函數結束返回時出現以上錯誤時應該的。(注:若是函數聲明中的t換成T,即形參和實參名字相同,此時編譯器也會生成一個臨時變量,不會因為形參和實參的名字相同而直接用實參)

所以要想修改T的指向,可以傳遞指向指針的指針,也可以在root前建立一個空的結構體避免在函數中修改T的指向。



快乐彩中奖说明