事情大概起源於這樣一個問題:
#include<stdio.h> void Try_change(int *p) { int b=7; p=&b; } int main() { int *p=NULL; int a=5; p=&a; Try_change(p); printf("%d\n",*p); return 0; }
當我第一次看到這個題目的時候我覺得答案是7,但是又好像是5,模模糊糊,傻傻分不清楚,這也是我想深入探究下這個問題的原因。
如果你一眼知道答案並且知道為什么,希望不吝指教。
首先這是一個指針作為函數變量的問題,之所以會對此類問題模糊,是因為對指針在參數傳遞過程中的流程不是很清楚。
我最初的思路:
主函數定義一個指針------------通過函數調用將此指針傳遞到Try_change中------------在Try_change中改變指針的指向--------------回到主函數輸出該指針的值
由於我看到在Try_change 中改變了指針的指向,而且參數傳遞是指針。所以就覺得答案是7;
然而通過測試發現答案依然是5,那么問題來了,究竟是什么原因呢?
通過看一些網友的資料明白:通過指針傳遞參數,其實質仍然是值傳遞,即是傳遞指針本身的地址。或者這樣說更容易理解一些,即在Try_change中操作的形參,它不會改變實參的值,因此答案依然是5.
或者可以這樣形象理解,形參是進入一個參數的時候臨時克隆實參的一個家伙,這個家伙繼承了實參的所有值,然而他和實參卻是兩個不同的家伙,Try_change函數內所有發生的行為只和形參有關,當函數結束的時候形參就會灰飛煙滅。而它所做的一切實參是沒有絲毫影響的。
下面詳細用代碼分析這個例子,看上面的YY是否成立。
#include<stdio.h> void Try_change(int *p) { int b=7; printf("Try p=%p &p=%p\n",p,&p); p=&b; } int main() { int *p=NULL; int a=5; p=&a; printf("main p=%p &p=%p\n",p,&p); Try_change(p); printf("%d\n",*p); return 0; }
輸出的結果是:
這里我們可以看到:主函數中的指針和Try_change中的指針雖然值是一樣的,但是地址卻是不一樣的,即他們屬於兩個不同的指針變量,只是值相等罷了。
到這里似乎真相大白了:指針作為參數在函數中傳遞的時候,它的實質依然是值傳遞,形參只是實參的一份拷貝,他們分別屬於不同的兩個指針變量。
這樣也就順理成章的解決了很多其他問題:
比如:
在主函數有:int a=5; int *p=&a; Try(p);
子函數有:int b=7;*p=b;
此時主函數最后輸出b的值為7,這是因為雖然子函數中的指針是拷貝的,但是該指針的值也是a的地址,因此在子函數內進行對a的地址產生新的值的時候,主函數內的b也隨之改變。
在例如,使用形參分配內存的例子,也是顯而易見的錯誤:
void GetMemory(char* p) { char *p = new char[100]; } void main() { char *str; GetMemory(str); strcpy(str, "hi"); // str = NULL }
因為這里的p和str本質上已經不是一個東東了。
我似乎明白了什么,一直以來為什么這么菜,因為從來沒有靜下心來思考每一個自己恍惚的問題!