8.C語言利用指針實現形參反向傳值問題

8.利用指針實現形參反向傳值問題

利用指針類型的形參進行反向傳值需要如下幾點:
1.外部實參應定義爲實體而非指針,因爲外部的實參需要利用實體的空間來存儲內部向外傳遞的數據。(外部若一定要使用指針則看9.利用二維指針實現形參反向傳值)
2.內部形參獲取到的是外部空間的地址,所以內部不能將形參所存儲的地址弄丟了,必須一直讓形參存儲外部空間的地址。
3.反向傳值時,是將被傳遞數據放入到外部實參的空間中的。爲獲取外部實參的空間,所以需要對形參進行尋址後再傳值。
例如:

/*
fun執行時,e自身有個地址————&e。
因爲e是指針所以e存儲的是一個另外空間的地址,由於函數調用時外部使用了a作爲實參,所以e存儲的是外部a的地址,*e則是外部a的存儲空間
*/
void fun(int* e)
{
    int num = 7;
    

    /*
    如果下面反向傳值的賦值語句寫爲:
        e = #
    則是將num的地址賦值給e,而e原本存儲的外部a的地址就被覆蓋了,所以達不到反向傳值的效果。
    所以
    正確反向傳值賦值語句寫法爲:
        *e = num;
    這樣,e存儲的一直是a的地址,*e是a的空間,這句賦值語句就將num中的7拷貝到了外部a的空間中
    */
    *e = num;
}

int main()
{
    //外部定義爲實體,不能定義爲指針int* a;定義爲實體則a的空間可以用於接收外傳的數據
    int a = 3;
    /*
    調用過程中,形參獲取到實參傳遞的值
    因爲fun函數形參e是指針類型,於是這裏實參a向形參e傳遞的是a的地址————&a,而非a的值————3
    */
    fun(&a);
    
    return 0;
}

9.利用二維指針實現形參反向傳值

先回顧一下8.利用指針實現形參反向傳值問題。
具體思路如下:
1.外部定義爲實體,傳入實體地址。
2.內部定義形參爲一維指針,這樣形參指向外部實體。
3.對形參尋址獲取外部實體空間,將要返回的值賦給外部實體空間實現對外傳值。

這裏將所有部分都進行“更一維指針化”就實現了利用二維指針進行反向傳值操作。
具體思路如下:
1.外部定義一個一維指針,傳入該指針的地址。
2.內部形參定義爲二維指針,指向外部的一維指針。
3.對形參進行尋址獲取外部指針,再進一步尋址獲取外部指針指向的空間。通過賦值語句就實現向外部指針所指空間傳值操作。

例如:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
/*************************************定義部分*************************************/
typedef struct Node {
    int number;
}Elem;

void fun(Elem** e)
{
    //進入函數,形參通過拷貝手段獲取到實參的值,於是e存儲a的地址&a,實現二維指針e指向一維指針a,一維指針a目前指向空
    //於是對e尋址就獲取了a空間,所以對*e進行賦值,就相當於對a賦值

    //maloc函數申請空間,並將空間地址返回出來,假設malloc返回的地址是0x00000001
    //因爲對*e進行賦值,就相當於對a賦值,於是將0x00000001賦值給了a
    *e = (Elem*)malloc(sizeof(Elem));

    //完成賦值語句後,二維指針e指向一維指針a,一維指針a指向空間0x00000001

    //對二維指針e尋址(即:*e)獲取一維指針a,對一維指針a尋址(即:(*(*e)))獲取空間0x00000001,
    //於是賦值語句實現將7放入0x00000001內
    (*(*e)).number = 7;
}
/*************************************使用部分*************************************/
int main()
{
    SetConsoleOutputCP(65001);
    
    //定義一個指針a,作爲實參傳入fun函數,用於接收fun函數形參(e)反向傳出的實際空間的地址0x00000001
    Elem* a = NULL;//定義指針變量,並進行初始化

    //至此我們獲取了一個指針a,她沒有指向(或者說指針a指向空)
    
    //將a的地址傳入
    fun(&a);
    //函數執行完成後,棧內存釋放,函數fun內的形參e被釋放。但是a已經存儲到malloc空間的地址0x00000001,
    //於是a指向0x00000001,通過指向符號“->”就可以獲取被指向空間0x00000001內所存的值7
    printf("%d\n",a->number);//顯然輸出的是:7
    //當然,不通過指向符號“->”的話,也可以通過對a尋址(即:*a)獲取空間0x00000001,進而通過“點操作”獲取該空間內部存儲的值7
    printf("%d\n",(*a).number);//顯然輸出的依然是:7
    

    free(a);

    system("pause");
    return 0;
}

至此可以優化一下LinkList的代碼,讓GetElem函數形參使用二維指針,這樣在外部調用時實參可以定義爲指針而非實體可以節約一定的空間性能。同時內部循環體遊標利用指針將會更省性能。

觀察問題8和問題9的代碼發現一個共同點在於:函數調用時,傳入的參數都不是外部變量所存儲的值,而是傳入了外部變量的地址,而內部形參則被定義爲了比外部變量更高一個維度的指針。這個共同點反映了利用形參進行反向傳值的核心思想————讓函數內部的形參指向外部空間!通過對形參尋址來傳值給外部空間。

基於這一核心思想,可以實現利用三維(或更高維度的)指針實現形參的反向傳值操作。

這一思想與其他高級語言中的“引用”傳遞有異曲同工之妙(傳遞的不是值,而是引用)。

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