指針參數--指針做參數時應該注意的地方


轉自:http://blog.csdn.net/sszgg2006/article/details/9037675

首先看以下程序:

 

[cpp]  view plain  copy
 
  1. #include <stdio.h>  
  2. int *swap(int *px, int *py){   
  3.    int temp;   
  4.    temp = *px;   
  5.    *px = *py;   
  6.    *py = temp;   
  7.    return px;  
  8. }  
  9. int main(void){   
  10.    int i = 10, j = 20;  
  11.    int *p = swap(&i, &j);   
  12.    printf("now i=%d j=%d *p=%d\n", i, j, *p);   
  13.    return 0;  
  14. }  

我們知道,調用函數的傳參過程相當於用實參定義並初始化形參,swap(&i, &j)這個調用相當於:

 

int *px = &i;int *py = &j;

所以px和py分別指向main函數的局部變量i和j,在swap函數中讀寫*px和*py其實是讀寫main函數的i和j。盡管在swap函數的作用域中訪問不到i和j這兩個變量名,卻可以通過地址訪問它們,最終swap函數將i和j的值做了交換。

上面的例子還演示了函數返回值是指針的情況,return px;語句相當於定義了一個臨時變量並用px初始化:

int *tmp = px;

然后臨時變量tmp的值成為表達式swap(&i, &j)的值,然后在main函數中又把這個值賦給了p,相當於:

int *p = tmp; 

最后的結果是swap函數的px指向哪就讓main函數的p指向哪。我們知道px指向i,所以p也指向i。

 

以上就是指針在做函數參數和函數返回值時的傳遞過程,接下來分析下其要注意的一些地方。

程序1:

 

[cpp]  view plain  copy
 
  1. void myMalloc(char *s) //我想在函數中分配內存,再返回  
  2. {  
  3.   s=(char *) malloc(100);  
  4. }  
  5. void main()  
  6. {  
  7.   char *p=NULL;  
  8.   myMalloc(p); //這里的p實際還是NULL,p的值沒有改變,為什么?  
  9.   if(p) free(p);  
  10. }  

 

程序2:

 

[cpp]  view plain  copy
 
  1. void myMalloc(char **s)  
  2. {  
  3.   *s=(char *) malloc(100);  
  4. }  
  5. void main()  
  6. {  
  7.   char *p=NULL;  
  8.   myMalloc(&p); //這里的p可以得到正確的值了  
  9.   if(p) free(p);  
  10. }  

 

程序3:

 

[cpp]  view plain  copy
 
  1. #include<stdio.h>  
  2. void fun(int *p)  
  3. {  
  4.   int b=100;  
  5.   p=&b;  
  6. }  
  7. main()  
  8. {  
  9.   int a=10;  
  10.   int *q;  
  11.   q=&a;  
  12.   printf("%d\n",*q);  
  13.   fun(q);  
  14.   printf("%d\n",*q);  
  15.   return 0;  
  16. }  

 

結果為

10

10

程序4:

 

[cpp]  view plain  copy
 
  1. #include<stdio.h>  
  2. void fun(int *p)  
  3. {  
  4.   *p=100;  
  5. }  
  6. main()  
  7. {  
  8.   int a=10;  
  9.   int *q;  
  10.   q=&a;  
  11.   printf("%d\n",*q);  
  12.   fun(q);  
  13.   printf("%d\n",*q);  
  14.   return 0;  
  15. }  

 

結果為

10

100

為什么?

---------------------------------------------------------------

1.被分配內存的是形參s,p沒有分配內存

2.被分配內存的是形參s指向的指針p,所以分配了內存

---------------------------------------------------------------

不是指針沒明白,是函數調用的問題!看看這段:

7-4-1指針參數是如何傳遞內存的?

     如果函數的參數是一個指針,不要指望用該指針去申請動態內存。示例7-4-1中,Test函數的語句GetMemory(str, 200)並沒有使str獲得期望的內存,str依舊是NULL,為什么?

 

[cpp]  view plain  copy
 
  1. void GetMemory(char *p, int num)  
  2. {  
  3.      p = (char *)malloc(sizeof(char) * num);  
  4. }  
  5. void Test(void)  
  6. {  
  7.      char *str = NULL;  
  8.      GetMemory(str, 100);      // str 仍然為 NULL       
  9.      strcpy(str, "hello");      // 運行錯誤  
  10. }  

 

示例7-4-1 試圖用指針參數申請動態內存

毛病出在函數GetMemory中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是 _p,編譯器使 _p = p。如果函數體內的程序修改了_p所指向的內容,就導致參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。在本例中,_p申請了新的內存,只是把_p所指的內存地址改變了,但是p絲毫未變(本來_p=p,_p是指向p的,后來給_p申請內存使其_p指向新申請的內存空間而不在指向p)。所以函數GetMemory並不能輸出任何東西。事實上,每執行一次GetMemory就會泄露一塊內存,因為沒有用free釋放內存。

如果非得要用指針參數去申請內存,那么應該改用“指向指針的指針”,見示例7-4-2。

 

[cpp]  view plain  copy
 
  1. void GetMemory2(char **p, int num)  
  2. {  
  3.      *p = (char *)malloc(sizeof(char) * num);  
  4. }  
  5. void Test2(void)  
  6. {  
  7.      char *str = NULL;  
  8.      GetMemory2(&str, 100);      // 注意參數是 &str,而不是str  
  9.      strcpy(str, "hello");       
  10.      cout<< str << endl;  
  11.      free(str);       
  12. }  

 

示例7-4-2用指向指針的指針申請動態內存

由於“指向指針的指針”這個概念不容易理解,我們可以用函數返回值來傳遞動態內存。這種方法更加簡單,見示例7-4-3。

 

[cpp]  view plain  copy
 
  1. char *GetMemory3(int num)  
  2. {  
  3.      char *p = (char *)malloc(sizeof(char) * num);  
  4.      return p;  
  5. }  
  6. void Test3(void)  
  7. {  
  8.      char *str = NULL;  
  9.      str = GetMemory3(100);       
  10.      strcpy(str, "hello");  
  11.      cout<< str << endl;  
  12.      free(str);       
  13. }  

 

示例7-4-3 用函數返回值來傳遞動態內存

用函數返回值來傳遞動態內存這種方法雖然好用,但是常常有人把return語句用錯了。這里強調不要用return語句返回指向“棧內存”的指針,因為該內存在函數結束時自動消亡,見示例7-4-4。

 

[cpp]  view plain  copy
 
  1. char *GetString(void)  
  2. {  
  3.      char p[] = "hello world";  
  4.      return p;      // 編譯器將提出警告  
  5. }  
  6. void Test4(void)  
  7. {  
  8. char *str = NULL;  
  9. str = GetString();      // str 的內容是垃圾  
  10. cout<< str << endl;  
  11. }  

 

示例7-4-4 return語句返回指向“棧內存”的指針

用調試器逐步跟蹤Test4,發現執行str = GetString語句后str不再是NULL指針,但是str的內容不是“hello world”而是垃圾。

如果把示例7-4-4改寫成示例7-4-5,會怎么樣?

 

[cpp]  view plain  copy
 
  1. char *GetString2(void)  
  2. {  
  3.      char *p = "hello world";  
  4.      return p;  
  5. }  
  6. void Test5(void)  
  7. {  
  8.      char *str = NULL;  
  9.      str = GetString2();  
  10.      cout<< str << endl;  
  11. }  

 

示例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.函數的返回值是指針類型的,檢查是靜態內存指針還是堆內存指針還是棧內存指針,棧內存指針是絕對要不得滴!

2.函數需要使用指針參數進行傳入傳出的,在函數中只能對指針的指向的值(*p)進行修改,而不能修改指針指向,也就是指針地址!(函數中不得修改指針參數的地址,否則請使用指針的指針!)

 

另附:http://blog.chinaunix.net/uid-20788636-id-1841283.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM