最近在論壇上看到有一篇文章提問下面的問題:
char * fun(char *p)
{
return p;
}
提問:此函數返回的是誰的值,是參數p的地址,還是p的值?
回答:
p的值,但其值指向一個記憶體位址
p是棧中的地址,和局部變數的地址一樣,函數返回後這塊記憶體就無效了。
這種用法還是很常見的,比如鏈表中。
雖然p是棧中的地址,但是因為它只是指標副本,所以可以改變指標的指向(通過return的傳回值),指向其他地方。
記得在學習C語言函數那部分的時候,有一個很重要的概念是區別:值傳遞、指標傳遞、引用傳遞(好像是這三種說法)。
我覺得要理解這部分知識點,首先應該知道不同種類的變數在記憶體中是如何分配儲存的,它們的生命週期多長等這些問題,然後再看上面的三種情況就好理解了。函數的參數都是在stack棧上分配的,所以它們的生命週期就在它們所屬的函數內,函數執行完畢的時候,它們所佔的記憶體將被回收。
如果我們想在函數內對實參進行操作(不是對實參的副本,形參)的話,一般會使用引用,即聲明函數的形參為參考型別,比如char * fun(char * &p),這樣實參和形參為同一個變數,我們在函數中操作形參p就等於直接在操作實參變數。在看C++文法書的時候,書上說這樣用還有一個好處是,在調用函數的時候,不用再為形參分配記憶體了,所以這樣執行效率會高一點兒。
下面是函數形參為指標的幾種情況:
#include <iostream><br />using namespace std;<br />char* func1(char *p);<br />void func2(char *p);<br />void func3(char * &p);<br />char s1[]="原來的";<br />char s2[]="指向我了嗎";<br />int main()<br />{<br /> char *ptr=s1;<br /> cout<<ptr<<endl;<br /> ptr=func1(ptr); //傳回值改變ptr使它指向另一個地址<br />//func2(ptr); //ptr的指向沒有改變,func2函數中改變的只是它的副本(一個局部變數)<br />//func3(ptr); //改變了ptr的指向,func3函數的形式參數為參考型別,實參和形參是同一個變數<br /> cout<<ptr<<endl;<br /> return 0;<br />}<br />char* func1(char *p)<br />{<br /> p=s2;<br /> return p;<br />}<br />void func2(char *p)<br />{<br /> p=s2;<br />}<br />void func3(char * &p)<br />{<br /> p=s2;<br />}
下面再看一個在實際應用中經常會出錯的一個例子(檢測一下我們是否理解了上面的概念):
#include <malloc.h><br />struct stack<br />{<br />char *elem[10];<br />int top;<br />};<br />void initial1(struct stack *s)//值傳遞<br />{<br />s = (stack*)malloc(sizeof(stack));<br />}<br />void initial2(struct stack **s)//指標傳遞<br />{<br />*s = (stack*)malloc(sizeof(stack));<br />}<br />void initial3(struct stack *&s)//引用傳遞<br />{<br />s = (stack*)malloc(sizeof(stack));<br />}<br />int main(int argc, char* argv[])<br />{<br />struct stack *s;<br /> //initial1(s); // error,沒有獲得返回的值<br />initial2(&s); // ok<br />initial3(s); // ok</p><p>return 0;<br />}
下面是某company對此知識點出的考題:
[Q1]<br />void Getmemory(char*p)<br />{<br />p=(char*)malloc(100);<br />}<br />void Test(void)<br />{<br />char *str=NULL;<br />Getmemory(str);<br />strcpy(str,"Hello world");<br />printf(str);<br />}<br />//modified to:<br />#include <stdio.h><br />#include <string><br />void Getmemory(char**p)<br />{<br />*p=(char*)malloc(100*sizeof(char));<br />}<br />void Test()<br />{<br />char *str=NULL;<br />Getmemory(&str);<br />strcpy(str,"Hello world");<br />printf(str);<br />}<br />int main()<br />{<br />Test();<br />return 0;<br />}</p><p>[Q2]<br />char* Getmemory(void)<br />{<br />char p[]="hello world";<br />return p;<br />}<br />void Test(void)<br />{<br />char *str=NULL;<br />str=Getmemory();<br />printf(str);<br />}<br />//modified to:<br />#include <stdio.h><br />char* Getmemory(void)<br />{<br />char p[]="hello world";<br />return p; //returning address of local variable or temporary<br />}<br />void Test()<br />{<br />char *str=NULL;<br />str=Getmemory();<br />printf(str); //unknown results<br />}<br />int main()<br />{<br />Test();<br />return 0;<br />}</p><p>[Q3]<br />void Getmemory(char**p,int num)<br />{<br />*p=(char*)malloc(num);<br />}<br />void Test(void)<br />{<br />char *str=NULL;<br />Getmemory(&str,100);<br />strcpy(str,"Hello world");<br />printf(str);<br />}<br />//modified to:<br />#include <stdio.h><br />#include <string><br />void Getmemory(char**p,int num)<br />{<br />*p=(char*)malloc(num*sizeof(char));<br />}<br />void Test()<br />{<br />char *str=NULL;<br />Getmemory(&str,100);<br />strcpy(str,"Hello world");<br />printf(str); //print "Hello world"<br />}<br />int main()<br />{<br />Test();<br />return 0;<br />}</p><p>[Q4]<br />void Test(void)<br />{<br />char *str=(char*)malloc(100);<br />strcpy(str,"Hello");<br />free(str);<br />if(str!=NULL)<br />strcpy(str,"world");<br />printf(str);<br />}<br />//modified to:<br />#include <stdio.h><br />#include <string><br />void Test()<br />{<br />char *str=(char*)malloc(100*sizeof(char));<br />strcpy(str,"Hello");<br />free(str); // free the contents which str points<br /> //in this place, we'd better set str to NULL otherwise the pointer str will to be a wild pointer<br />if(str!=NULL) //this statement is always true,for str is non-NULL<br />strcpy(str,"world");<br />printf(str); //print "world"<br />}<br />int main()<br />{<br />Test();<br />return 0;<br />}