函數參數的傳遞問題(指針的指針)

程序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 <iostream>
using namespace std;

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);
      
      system("pause");
      return 0;
}
複製代碼
複製代碼

結果:

 

程序4:

複製代碼
複製代碼
#include <iostream>
using namespace std;

void fun(int *p)
{
     *p = 100;
}

main()
{
      int a = 10;
      int *q;
      q = &a;
      printf("%d\n", *q);
      fun(q);
      printf("%d\n", *q);
      
      system("pause");
      return 0;
}
複製代碼
複製代碼

 

結果爲

爲什麼?

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

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

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

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

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

程序5指針參數是如何傳遞內存的?

     如果函數的參數是一個指針,不要指望用該指針去申請動態內存。程序5中,Test函數的語句GetMemory(str, 200)並沒有使str獲得期望的內存,str依舊是NULL,爲什麼?

複製代碼
複製代碼
#include <iostream>
using namespace std;

void GetMemory1(char *p, int num)
{
     p = (char *)malloc(sizeof(char)*num);
}

int main()
{
    char *str = NULL;
    GetMemory1(str, 100);                  // str仍然爲 NULL 
    strcpy(str, "hello")                  // 運行錯誤 
   system("pause"); return 0; 
}
複製代碼
複製代碼

 

程序5 試圖用指針參數申請動態內存

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

如果非得要用指針參數去申請內存,那麼應該改用“指向指針的指針”,見程序6

複製代碼
複製代碼
#include <iostream>
using namespace std;

void GetMemory2(char **p, int num)
{
     *p = (char *)malloc(sizeof(char)*num);
}

int main()
{
    char *str = NULL;
    GetMemory2(&str, 100);                  // 注意參數是&str,而不是str 
    strcpy(str, "hello");                  
    cout << str << endl;
    free(str); 
     
    system("pause");                     
    return 0;
}
複製代碼
複製代碼

 

程序6用指向指針的指針申請動態內存

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

複製代碼
複製代碼
#include <iostream>
using namespace std;

char *GetMemory3(int num)
{
     char *p = (char *)malloc(sizeof(char)*num);
     return p;
}

int main()
{
    char *str = NULL;
    str = GetMemory3(100);                  
    strcpy(str, "hello");                  
    cout << str << endl;
    free(str); 
     
    system("pause");                     
    return 0;
}
複製代碼
複製代碼

 

程序7 用函數返回值來傳遞動態內存

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

複製代碼
複製代碼
#include <iostream>
using namespace std;

char *GetString(void)
{
     char p[] = "hello world";
     return p;  //編譯器將提出警告 
}

int main()
{
    char *str = NULL;
    str = GetString();             //str 的內容是垃圾 
    cout << str << endl;
     
    system("pause");                     
    return 0;
}
複製代碼
複製代碼

結果:

程序8 return語句返回指向“棧內存”的指針

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

如果把示例程序7改寫成程序8,會怎麼樣?

複製代碼
複製代碼
#include <iostream>
using namespace std;

char *GetString2(void)
{
     char *p = "hello world";
     return p;  //編譯器將提出警告 
}

int main()
{
    char *str = NULL;
    str = GetString2();             //str 的內容是垃圾 
    cout << str << endl;
     
    system("pause");                     
    return 0;
}
複製代碼
複製代碼

 

程序8 return語句返回常量字符串

函數程序8運行雖然不會出錯,但是函數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)進行修改,而不能修改指針指向,也就是指針地址!(函數中不得修改指針參數的地址,否則請使用指針的指針!)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章