二級指標做參數

來源:互聯網
上載者:User

程式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的值。

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

你要弄清楚的是指標變數和指標所指的變數(可能是一片記憶體)。

指標變數和普通變數一樣儲存的,

 

//////////////////////////////////////////////////////////////////

 

1.如果是函數內進行記憶體申請,很簡單,標準用法就可以了:
test()
{
 int *array;
 
 array=(int *)malloc(sizeof(int)*10);//申請10*4 bytes,即10個單位的int記憶體單元
}
注意,malloc使用簡單,但是注意參數和傳回值,參數是申請記憶體的位元組數,多位元組的類型如int,short,float等需要乘上類型位元組數,傳回值是沒有定義類型的指標,使用時需要自己指定。2.使用一級指標實現記憶體申請,通過函數傳回值帶出malloc的地址:
char *my_malloc(int m)
{
 char *p;
 p=malloc(m);
 return p;
}
test()
{
 char * buff=NULL;  //指標如果在函數內沒有賦值,注意開始賦值為NULL
 buff=my_malloc(10); printf("buff adress is %x/n",buff); free(buff);  
}3.使用二級指標實現記憶體申請,通過指標值傳遞:void my_malloc1(char **p1)
{
 *p1=(char *)malloc(100);
}
test()
{
 char *buffer=NULL;
 
 my_malloc1(&buffer); printf("buffer adress is %x/n",buffer); free(buffer);
}小結:一級指標和二級指標在做形參時的不同:指標用作形參,改變指標地址則值不能傳回,改變指標內容而地址不變則值可以傳回。(特殊情況:改變指標地址採用傳回值也可以傳回地址)
對於一級指標,做形參時傳入地址,如果函數只改變該指標內容,OK,該指標可以正常返回,如果函數改變了指標地址,除非返回該指標,否則該指標不能正常返回,函數內對指標的操作將無效。
對於二級指標,做形參時傳入地址(注意此時傳入的是二級指標的地址),如果改變該二級指標地址(**p),對該指標的操作也將無效,但是改變二級指標的內容(例如*p),則該二級指標可以正常返回。總之,指標使用最關鍵的是弄清地址和內容,指標做形參時只有改變其內容時才能正常返回。 4.編程執行個體:/*
date:20100823
file name:my_pointer.c
description:指標作為形參的值傳遞分析
result:
1.指標作為形參時,如果只需要改變指標指向的值,可以使用一級指標,如果需要改變指標本身的地址,則需要使用二級指標,相當於改變的是一級指標指向的值。
2.指標作為形參時,指標指向的內容變化是可以帶回的,指標地址的變化是不可帶回的,即指標作為參數,其地址不可改變,否則形參就無法傳回實參的值。
*//*********************************************************************************/
//指標作為形參,指標指向的內容改變,函數返回時這種變化是可以帶回的
void change(int *p)
{
 *p+=5; 
}test1() 
{
 int a=1;
 
 change(&a);
 
 printf("After change a is %d/n",a);  //結果為6
}/*********************************************************************************/
//指標作為形參,指標本身的地址改變,函數返回時這種變化將無效
void my_malloc(char *pp,int num)  
{
 pp=(char *)malloc(num); 
}test2()      
{
 char *buf=NULL;
 
 my_malloc(buf,100);
 
 printf("After my_malloc buf adress is %x/n",buf); //函數返回後,buf的地址依然為NULL
 strcpy(buf,"hello");         //這裡會出錯,運行出現段錯誤,程式直接退出了,下面的輸出也沒有了
 puts(buf);
}main()
{
 test1();
 //test2();
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.