函數參數的傳遞問題(一級指針和二級指針)

原以爲自己對指針掌握了,卻還是對這個問題不太明白。請教!  
程序1:  
void  myMalloc(char  *s)  //我想在函數中分配內存,再返回  
{  
     s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //這裏的p實際還是NULL,p的值沒有改變,爲什麼?  
     if(p)  free(p);  
}  
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //這裏的p可以得到正確的值了  
     if(p)  free(p);  
}  
程序3:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       int  b=100;  
       p=&b;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d\n",*q);  
       fun(q);  
       printf("%d\n",*q);  
       return  0;  
}  
結果爲  
10  
10  
程序4:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       *p=100;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d\n",*q);  
       fun(q);  
       printf("%d\n",*q);  
       return  0;  
}  
結果爲  
10  
100  
爲什麼?  
 
 
 
 
---------------------------------------------------------------  
 
1.被分配內存的是行參s,p沒有分配內存  
2.被分配內存的是行參s指向的指針p,所以分配了內存  
---------------------------------------------------------------  
 
不是指針沒明白,是函數調用的問題!看看這段:  
 
7.4指針參數是如何傳遞內存的?  
           如果函數的參數是一個指針,不要指望用該指針去申請動態內存。示例7-4-1中,Test函數的語句GetMemory(str,  200)並沒有使str獲得期望的內存,str依舊是NULL,爲什麼?  
 
void  GetMemory(char  *p,  int  num)  
{  
           p  =  (char  *)malloc(sizeof(char)  *  num);  
}  
void  Test(void)  
{  
           char  *str  =  NULL;  
           GetMemory(str,  100);            //  str  仍然爲  NULL              
           strcpy(str,  "hello");            //  運行錯誤  
}  
示例7-4-1  試圖用指針參數申請動態內存  
 
毛病出在函數GetMemory中。編譯器總是要爲函數的每個參數製作臨時副本,指針參數p的副本是  _p,編譯器使  _p  =  p。如果函數體內的程序修改了_p的內容,就導致參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。在本例中,_p申請了新的內存,只是把 _p所指的內存地址改變了,但是p絲毫未變。所以函數GetMemory並不能輸出任何東西。事實上,每執行一次GetMemory就會泄露一塊內存,因爲沒有用free釋放內存。  
如果非得要用指針參數去申請內存,那麼應該改用“指向指針的指針”,見示例7-4-2。  
 
void  GetMemory2(char  **p,  int  num)  
{  
           *p  =  (char  *)malloc(sizeof(char)  *  num);  
}  
void  Test2(void)  
{  
           char  *str  =  NULL;  
           GetMemory2(&str,  100);            //  注意參數是  &str,而不是str  
           strcpy(str,  "hello");              
           cout<<  str  <<  endl;  
           free(str);              
}  
示例7-4-2用指向指針的指針申請動態內存  
 
由於“指向指針的指針”這個概念不容易理解,我們可以用函數返回值來傳遞動態內存。這種方法更加簡單,見示例7-4-3。  
 
char  *GetMemory3(int  num)  
{  
           char  *p  =  (char  *)malloc(sizeof(char)  *  num);  
           return  p;  
}  
void  Test3(void)  
{  
           char  *str  =  NULL;  
           str  =  GetMemory3(100);              
           strcpy(str,  "hello");  
           cout<<  str  <<  endl;  
           free(str);              
}  
示例7-4-3  用函數返回值來傳遞動態內存  
 
用函數返回值來傳遞動態內存這種方法雖然好用,但是常常有人把return語句用錯了。這裏強調不要用return語句返回指向“棧內存”的指針,因爲該內存在函數結束時自動消亡,見示例7-4-4。  
 
char  *GetString(void)  
{  
           char  p[]  =  "hello  world";  
           return  p;            //  編譯器將提出警告  
}  
void  Test4(void)  
{  
char  *str  =  NULL;  
str  =  GetString();            //  str  的內容是垃圾  
cout<<  str  <<  endl;  
}  
示例7-4-4  return語句返回指向“棧內存”的指針  
 
用調試器逐步跟蹤Test4,發現執行str  =  GetString語句後str不再是NULL指針,但是str的內容不是“hello  world”而是垃圾。  
如果把示例7-4-4改寫成示例7-4-5,會怎麼樣?  
 
char  *GetString2(void)  
{  
           char  *p  =  "hello  world";  
           return  p;  
}  
void  Test5(void)  
{  
           char  *str  =  NULL;  
           str  =  GetString2();  
           cout<<  str  <<  endl;  
}  
示例7-4-5  return語句返回常量字符串  
 
函數Test5運行雖然不會出錯,但是函數GetString2的設計概念卻是錯誤的。因爲GetString2內的“hello  world”是常量字符串,位於靜態存儲區,它在程序生命期內恆定不變。無論什麼時候調用GetString2,它返回的始終是同一個“只讀”的內存塊。  
 
---------------------------------------------------------------  
 
看看林銳的《高質量的C/C++編程》呀,上面講得很清楚的  
---------------------------------------------------------------  
 
對於1和2:  
如果傳入的是一級指針S的話,  
那麼函數中將使用的是S的拷貝,  
要改變S的值,只能傳入指向S的指針,即二級指針  
 
---------------------------------------------------------------  
 
程序1:  
void  myMalloc(char  *s)  //我想在函數中分配內存,再返回  
{  
     s=(char  *)  malloc(100);  //  s是值參,  函數返回後就回復傳遞前的數值,無法帶回分配的結果  
}  
這個和調用  void  func  (int  i)  {i=1;};  一樣,退出函數體,i指復原的  
 
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);  //  這個是可以的  
}  
等價於  
void  int  func(int  *  pI)  {*pI=1;}  pI指針不變,指針指向的數據內容是變化的  
值參本身不變,但是值參指向的內存的內容發生了變化。  
 
程序3:  
void  fun(int  *p)  
{  
       int  b=100;  
       p=&b;                  //  等同於第一個問題,  b的地址並沒有被返回  
}  
 
程序4:  
 
void  fun(int  *p)  
{  
       *p=100;    //  okay  
}  
 
 
 
 
---------------------------------------------------------------  
 
其實樓主的問題和指針沒有多大關係,就是行參和值參的問題  
 
函數調用的時候,值參傳遞的是數值,是不會返回的  
這個數值,在函數體內部相當於一個變量,是可以改變,但是這個改變是無法帶出函數體外部的  
 
---------------------------------------------------------------  
 
程序1:  
void  myMalloc(char  *s)  //我想在函數中分配內存,再返回  
{  
     s=(char  *)  malloc(100);//傳過來的是P所指的地址,並不是P的地址,所以改變S不會改變P  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //這裏的p實際還是NULL,p的值沒有改變,爲什麼?  
     if(p)  free(p);  
}  
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);//S指向的是P的地址,所以改變了P所指的內存單元.  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //這裏的p可以得到正確的值了  
     if(p)  free(p);  
}  
程序3:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       int  b=100;  
       p=&b;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d\n",*q);  
       fun(q);////道理同第一個程序.  
       printf("%d\n",*q);  
       return  0;  
}  
結果爲  
10  
10  
程序4:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       *p=100;//參數P和實參P所指的內存單元是相同的.所以改變了參數P的內存單元內容,就改變了實參  
                     //的內存單元內容  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d\n",*q);  
       fun(q);  
       printf("%d\n",*q);  
       return  0;  
}  
結果爲  
10  
100  
爲什麼?  
---------------------------------------------------------------  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //這裏的p實際還是NULL,p的值沒有改變,爲什麼?  
     if(p)  free(p);  
}  
 
 
void  myMalloc(char  *s)  //我想在函數中分配內存,再返回  
{  
     s=(char  *)  malloc(100);  
}  
 
myMalloc(p)的執行過程:  
分配一個臨時變量char  *s,s的值等於p,也就是NULL,但是s佔用的是與p不同的內存空間。此後函數的執行與p一點關係都沒有了!只是用p的值來初始化s。  
然後s=(char  *)  malloc(100),把s的值賦成malloc的地址,對p的值沒有任何影響。p的值還是NULL。  
注意指針變量只是一個特殊的變量,實際上它存的是整數值,但是它是內存中的某個地址。通過它可以訪問這個地址。  
 
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //這裏的p可以得到正確的值了  
     if(p)  free(p);  
}  
程序2是正確的,爲什麼呢?看一個執行過程就知道了:  
myMalloc(&p);將p的地址傳入函數,假設存儲p變量的地址是0x5555,則0x5555這個地址存的是指針變量p的值,也就是Ox5555指向p。  
調用的時候同樣分配一個臨時變量char  **s,此時s  的值是&p的值也就是0x5555,但是s所佔的空間是另外的空間,只不過它所指向的值是一個地址:Ox5555。  
*s=(char  *)  malloc(100);這一句話的意思是將s所指向的值,也就是0x5555這個位置上的變量的值賦爲(char  *)  malloc(100),而0x5555這個位置上存的是恰好是指針變量p,這樣p的值就變成了(char  *)  malloc(100)的值。即p的值是新分配的這塊內存的起始地址。  
 
這個問題理解起來有點繞,關鍵是理解變量作函數形參調用的時候都是要分配一個副本,不管是傳值還是傳址。傳入後就和形參沒有關係了,它不會改變形參的值。myMalloc(p)不會改變p的值,p的值當然是 NULL,它只能改變p所指向的內存地址的值。但是myMalloc(&p)爲什麼就可以了,它不會改變(&p)的值也不可能改變,但是它可以改變(&p)所指向內存地址的值,即p的值。  
 
---------------------------------------------------------------  
 
你要弄清楚的是指針變量和指針所指的變量(可能是一片內存)。  
 
指針變量和普通變量一樣存儲的,  
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
閱讀(31) | 評論(0) | 轉發(0) |
給主人留下些什麼吧!~~
評論熱議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章