本文是自己对 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 所指向的内容。