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的代码发现一个共同点在于:函数调用时,传入的参数都不是外部变量所存储的值,而是传入了外部变量的地址,而内部形参则被定义为了比外部变量更高一个维度的指针。这个共同点反映了利用形参进行反向传值的核心思想————让函数内部的形参指向外部空间!通过对形参寻址来传值给外部空间。

基于这一核心思想,可以实现利用三维(或更高维度的)指针实现形参的反向传值操作。

这一思想与其他高级语言中的“引用”传递有异曲同工之妙(传递的不是值,而是引用)。

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