在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體(空位址、錯誤位址)進行操作。下面我們通過乙個程式來說明一些需要注意的問題。
#include
#include
voidtest1(char* p, intnum)
voidtest2(char** pp, intnum)
voidmain()
在上面的程式中,我們實現了兩個函式,test1中我們使用傳入的引數char* p申請了一段記憶體,該段記憶體用於儲存char型的資料。test2中我們使用傳入的引數char** pp申請了一段記憶體,該段記憶體也是儲存char型資料的。但是兩個申請過程有所不同。需要注意的是p是char*, *pp也是char*。
闡明上面的程式之前我想先說乙個老例子,函式
voidplus1(intn)
不用廢話大家都知道plus1是不會修改n的值的,因為在n傳入函式之後會拷貝乙份,修改的只是這份拷貝,而傳入的這個n值是不會變的。
voidplus2(int* n)
plus2因為使用指標,也就是傳入了n的位址值,那麼對*n的操作實際上就是對n的操作。所以*n增1,也就是n增1。這個例子雖然簡單,但是真的是經典,指標的好處和壞處都顯示出來了。好處就是可以通過傳遞指標來實際運算元值,壞處就是傳遞指標有可能對記憶體進行非法操作。
再回到上面的程式,我們可以看到輸出結果為:
no1.after test1(p, 10), the value of p is: 0
no2.after test2(&p, 10), the value of p is: 0x3407e0
no4.after test2(pp, 10), the value of pp is: 0x340818
明顯的使用test1(p, 10)申請記憶體失敗了,如果大家真正明白了上面plus1和plus2的例子,就也應該明白了test1(p, 10)申請失敗的原因。事實上是「如果我們希望在函式外部獲得函式引數在函式內部被修改的結果,那麼我們需要使用該引數的『上一層』指標」。需要注意的是這句話中的上一層指標的概念,這是我自己發明的乙個詞語,例如char* 就是char的上一層指標,char** 就是char*的上一層指標,依此類推。
那麼好,讓我們來看一下test1(p, 10)失敗的原因。當我們傳入char* p的時候,實際上此時p==null,那麼我們的原因是希望在test1呼叫完成之後讓p指向乙個記憶體位址,也就是希望在外部獲取p在函式內部的修改結果。此時如果我們傳入p,那麼進入函式test1後,會拷貝乙份p,我們稱之為_p,那麼後續語句中對p的操作實際上就是對_p的操作,緊接著我們呼叫了malloc申請記憶體,返回值放入了_p中,也就是修改了_p。函式結束後,p並沒有受到這份改變的影響,依舊是null。所以輸出為0。
看到這裡如果大家明白的話,就應該立刻反映出我們應該使用char** p來獲得申請的記憶體。答案是yes,但是也沒有那麼簡單,還是存在乙個陷阱。
再看函式test2,函式test2和test1的目的一樣,只是引數改為了char** p。那麼我們可以使用兩種方式呼叫該函式第一種是test2(&p, 10),其中p還是char*,這個函式會呼叫成功,char* p會儲存申請後的位址。或者我們直接呼叫test2(pp, 10),其中pp是char**型別,我們會發現程式異常結束,因為程式會試圖在非法記憶體中寫入資料。為什麼會這樣呢?因為char** pp==null,也就是說pp指向的記憶體空間並不存在,我們可以先設pp指向的記憶體為x,而我們在test2中的目的是讓x中儲存某個記憶體塊的位址。在x不存在的情況下,這麼做自然是向非法位址寫入資料了。那麼怎麼辦呢?呵呵,只需要先申請這個x就可以了,也就是
pp = (char **)malloc(10*sizeof(char *));
test2(pp, 10);
printf("after test2(pp, 10), the value of pp is: 0x%x/n", pp);
外部函式中申請記憶體
在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體 空位址 錯誤位址 進行操作。下面我們通過乙個程式來說明一些需要注意的問題。include include void test1 char p int num void test2 char pp int num void main...
申請記憶體的函式
c語言跟記憶體申請相關的函式主要有 alloca,calloc,malloc,free,realloc等,都位於標頭檔案malloc.h中 注意沒有alloc函式 其中 alloca是向棧申請記憶體,因此無需釋放.malloc分配的記憶體是位於堆中的,並且沒有初始化記憶體的內容,因此基本上mallo...
申請記憶體的庫函式
1 void malloc size t size 申請一段size大小的記憶體,返回這段記憶體的首位址 指標 申請失敗返回null,malloc申請的記憶體空間可以用memset來初始化 2 void calloc size t num,size t size 申請一段size大小的記憶體,並且初...