C

C语言中函数参数的传递

对值传递的深入理解

Posted by iStar on June 8, 2021

本文是自己对 C 语言参数传递的理解,实际上 C 语言只有值传递一种参数传递方式。

回顾

在初学 C 语言时,从教材或者课堂上会学到 C 语言有两种参数传递方式,一种是值传递,另一种是地址传递。

  • 值传递只向函数中传递实参的值,形参是实参的拷贝,在函数中修改形参的值,并不会改变函数外实参的值。
  • 地址传递向函数中传递参数的地址,形参是指向实参地址的指针,修改形参指向的内容时将直接修改实参本身。

例如要想交换 a, b 两个变量的值,应该写为

void swap(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

这样在调用 swap()函数后,a, b 两数的值才被真正调换,这就是所谓的地址传递。

问题发现

当我在写编译原理实验时,我想要通过递归遍历语法树,生成中间代码的链表,并每次插入在链表头部,这就需要在函数间传递一个指向链表头的指针。但我发现我并不能在调用函数后获取到处理后的链表头,好像并没有进入递归函数一样。

问题分析

指针在 C 语言中实际山也是一个变量,只不过它存储的值是一个地址。那么当向函数中传递一个指针时,传递的实际上也是值的拷贝,只不过这里拷贝的是一个地址,之后函数是通过这个地址访问实参并修改的,与函数参数传递方式无关。而在函数调用结束后,指针的值是不可能被更改的,只能利用“*”或“->”操作符改变指针指向的变量。

因此 C 语言实际上只有一种传参方式,那就是值传递,地址传递只不过是值传递的特例。

那么如果想改变指针自身的值应该如何传参呢?

其实前面已经给出了答案,既然指针也是变量,那么要想改变函数外变量的值,只需要声明一个指向它的指针,然后向函数中传递这个指针的拷贝就可以了。所以要改变指针的值,需要传递指针的指针,即二级指针。

例如声明

void analyse(..., InterCode** node);

在使用时按如下方式调用:

InterCode* head = NULL;
analyse(..., &head);

就可以改变 head 所指向的内容。