C語言函數內部改變指針本身

今天發一個C語言基礎的小知識點:C語言中函數參數傳遞方式只有一種:值傳遞。

 

可能大家在剛開始學習C的時候都被一些教材誤導,認爲C中有值傳遞和地址傳遞兩種方式。其實只有值傳遞一種,無論函數以什麼形式進行傳遞,其實傳遞的都只是參數的一份拷貝!

 

舉個簡單的例子,一個改變某個整型變量參數的函數

int change_value(int *pChange, int val)

{

       *pChange = val;

        return *pChange;

}

 

那麼pChange所指向地址內容的指改變了嗎?確實改變了。

因此一些教材就認爲該方式是傳址,其實過程應該是這樣

比如調用的 時候有如下:

 

int a = 0x55aa;

change_value(&a, 0xaa55);

這樣a的值改變了,真正的情況是參數傳遞後,編譯器做了一個參數拷貝過程,比如聲明一個整型指針pCopy = &a;

這樣,pCopy只是傳進來參數&a的一份拷貝,但是他們都指向了a的地址,因此用這種方法可以改變a 的值。

 

那麼現在有個問題,通過傳遞一個指針,可以改變該指針所指向地址的內容,那麼如何改變指針本身呢?即如何改變指針的指向?

先看一個錯誤的例子

void change_ptr(void *ptr, void *dest)

{

      ptr = dest;

}

如果是這樣,能達到改變指針本身的目的嗎?

 

如果你有迷惑,可以這樣看,把類型去掉,把參數ptr傳遞進去,能改變ptr嗎?

顯然不能!

那該怎麼做才能改變ptr呢?

既然ptr也是一個變量,我要在函數內部改變它,那麼就傳遞一個指向ptr的指針!也就是二級指針!

正確的函數形式如下

void change_ptr(void **ptr, void *dest)

{

     *ptr = dest;

}

 

其實指針也是一個變量,我們如果要改變它,必須找到它在內存中的地址,也就是指針的地址。

當然,也可以通過另一種方式,只不過該方式需要綁定調用者的行爲

void *change_ptr(void *ptr, void *dest)

{

     return (ptr = dest);

}

 

 這樣在調用的時候必須做如下形式的調用

char *string;

string = change_ptr(string, dest);

否則string本身是不會改變的!但是這樣做意義不大,不如直接來個string = dest方便。

能用到在函數內部改變指針指向的地方通常是:一個函數完成某項功能後,得到一個指針,需要把這個指針以參數的 形式返回。

比如: foo(..., type **value);

在使用的時候通常這樣:

type *val = NULL;

foo(..., &val);

這樣之後,val指針就指向了正確的位置。

這裏申明一點,想去改變一個變量本身的地址是不可能的,無論你怎麼做,在聲明(定義)變量的時候,它的地址就由編譯器決定好了。

比如這裏,你能修改val本身的地址嗎?這就如同你能修改常量嗎?

 

 

 另外,如果我們想改變結構體中某個變量,需要傳遞一個指向該結構體的指針!

這樣,不管你想改變的是結構體中的成員是一個普通變量還是一個指針,都是可以改變的,因爲通過該結構體指針,可以獲得該結構體(也是該結構體中第一個成員)的地址,進而也就知道了結構體中任一成員的地址,因此對於結構體內容,想怎麼改變就怎麼改變!

比如

typedef struct xxx {

    int *head;

}xxx_t;

 

xxx_t my_struct;

 

void change(xxx_t *dst, void *src)

{

   dst->head = str; //dst->head已經改變!

}

 

調用時

change(&my_struct, src);

 

這時my_struct.head本身已經改變了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章