近期写二叉树的数据结构实验。想用一个没有返回值的函数来创建一个树,发现这个树就是建立不起来,那么我就用这个样例讨论一下c语言中指针作为形參的函数中传递中隐藏的东西。
大家知道C++中有引用的概念,两个数据引用同一个数据,那么更改随意的一个都相当于更改了本体,那么还有一个数据所相应的值也会改变。但是C中是没有这个概念的。所以就产生了一些东西。和我们本来想的有区别。
一、明白C语言中函数的入口:
C语言中函数的形參负责接收外部数据。那么数据到底怎么进入函数的呢。事实上我们在函数体内操作的形參仅仅是传递进来參数的一个副本,也就是说这两个參数尽管名字一样,相应的值一样,可是他们两个相应的内存地址是不一样的,也就是说这就是两个“看上去一模一样”的全然不同的变量。
所以一定要知道。C语言中函数是值传递的。也就是说,C语言仅仅能把值传给函数,而不能把你想要传递的变量全然的放进函数内部。
二、指针传递给函数:
指针作为一个特殊的东西。他的强大之处就在于指针能够直接改动内存地址上的数据。尽管指针特别强大,可是他也难逃函数的限制,你传递给函数一个指针。由于是值传递。那么你在函数体内的使用的形參指针也仅仅是一个副本,仅仅是一个指向的值和你传进来的那个指针一样的一个另外的一个变量。也就是说他和普通常量是没有差别的。
三、我想要达到引用的效果怎么实现
C语言中由于是值传递的。那么我们就传递值,仅仅要讲想要传递进函数的东西的地址传进函数。而且函数用一个指针接收。那么就相当于把这个变量地址原封不动的传递给了函数,形參的指针指向的是外面传进来的地址。有了地址不就好办了吗。
四、以下是我写的一个二叉树建立的一个无返回值的版本号:
由于二叉树是用递归建立的,就像建立链表一样,一个节点一个节点建立,假设不获得上一个节点的地址。你怎么把链表连接起来呢,链表就散开了。
所以仅仅能通过传递地址来达到找到已经建好的链表的前驱,才干把各个节点穿起来。
#include <stdio.h> #include <stdlib.h> typedef struct tree { char t; struct tree *lchild; struct tree *rchild; }Tree; void initTree(Tree **T) { char ch; ch = getchar(); if (ch == '#') { *T = NULL; } else { *T = (Tree *)malloc(sizeof(Tree)); (*T)->t = ch; initTree(&(*T)->lchild); initTree(&(*T)->rchild); } } void qianT(Tree *T) { if (T) { printf("%c ",T->t); qianT(T->lchild); qianT(T->rchild); } } int main (void) { Tree *T; initTree(&T); qianT(T); return 0; }
注意看树的建立那个函数。我每次都是穿进去一个节点的地址,然后通过地址来找到已经建立好的树,才干将树建立起来。
那么有的人会问了?为什么不是以下这个写法呢?
void initTree(Tree *T) { char ch; ch = getchar(); if (ch == '#') { T = NULL; } else { T = (Tree *)malloc(sizeof(Tree)); T->t = ch; initTree(T->lchild); initTree(T->rchild); } }这样的写法,你每次传进来的都是一个变量。说过,c语言是值传递的。那么每次你申请的节点空间都是给副本申请的。然后递归的是副本的左右孩子,也就是说你的树根本没有建立起来,由于每次申请的内存都没有连接上。
为什么我的那个写法能够呢,由于我是用一个指向指针的指针来存地址的,我给传进来的地址申请了内存,也就相当于给穿进来的那个节点本身申请了内存,而不是给副本,所以二叉树就顺其自然建立起来了。
最后记住,c语言是值传递的,不论什么东西传递给函数的都仅仅是值!