最近寫二叉樹的數據結構實驗,想用一個沒有返回值的函數來創建一個樹,發現這個樹就是建立不起來,那麼我就用這個例子討論一下c語言中指針作為形參的函數中傳遞中隱藏的東西。
大家知道C++中有引用的概念,兩個數據引用同一個數據,那麼更改任意的一個都相當於更改了本體,那麼另一個數據所對應的值也會改變,可是C中是沒有這個概念的。所以就產生了一些東西。和我們本來想的有差別。
一、明確C語言中函數的入口:
C語言中函數的形參負責接收外部數據,那麼數據究竟怎麼進入函數的呢,其實我們在函數體內操作的形參只是傳遞進來參數的一個副本,也就是說這兩個參數雖然名字一樣,對應的值一樣,但是他們兩個對應的內存地址是不一樣的,也就是說這就是兩個“看上去一模一樣”的完全不同的變量。
所以一定要知道,C語言中函數是值傳遞的,也就是說,C語言只能把值傳給函數,而不能把你想要傳遞的變量完全的放進函數內部。
二、指針傳遞給函數:
指針作為一個特殊的東西,他的強大之處就在於指針可以直接修改內存地址上的數據。雖然指針特別強大,但是他也難逃函數的限制,你傳遞給函數一個指針,因為是值傳遞,那麼你在函數體內的使用的形參指針也只是一個副本,只是一個指向的值和你傳進來的那個指針一樣的一個另外的一個變量。也就是說他和普通常量是沒有區別的。
三、我想要達到引用的效果怎麼實現
C語言中因為是值傳遞的,那麼我們就傳遞值,只要講想要傳遞進函數的東西的地址傳進函數,並且函數用一個指針接收,那麼就相當於把這個變量地址原封不動的傳遞給了函數,形參的指針指向的是外面傳進來的地址,有了地址不就好辦了嗎。
四、下面是我寫的一個二叉樹建立的一個無返回值的版本:
因為二叉樹是用遞歸建立的,就像建立鏈表一樣,一個節點一個節點建立,如果不獲得上一個節點的地址,你怎麼把鏈表連接起來呢,鏈表就散開了。
所以只能通過傳遞地址來達到找到已經建好的鏈表的前驅,才能把各個節點穿起來。
#include#include 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語言是值傳遞的,那麼每次你申請的節點空間都是給副本申請的,然後遞歸的是副本的左右孩子,也就是說你的樹根本沒有建立起來,因為每次申請的內存都沒有連接上。