外部函式中申請記憶體

2021-04-15 00:08:16 字數 2589 閱讀 7214

在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體(空位址、錯誤位址)進行操作。下面我們通過乙個程式來說明一些需要注意的問題。

#include

#include

void

test1

(char* p

, int

num)

void

test2

(char

** pp

, int

num)

void

main()

在上面的程式中,我們實現了兩個函式,

test1中我們使用傳入的引數char* p申請了一段記憶體,該段記憶體用於儲存char型的資料。test2中我們使用傳入的引數char** pp申請了一段記憶體,該段記憶體也是儲存char型資料的。但是兩個申請過程有所不同。需要注意的是p是char*, *pp也是char*。

闡明上面的程式之前我想先說乙個老例子,函式

void

plus1

(intn)

不用廢話大家都知道

plus1

是不會修改

n的值的,因為在

n傳入函式之後會拷貝乙份,修改的只是這份拷貝,而傳入的這個

n值是不會變的。

void

plus2

(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);

這段程式的來由,現在大家明白我為什麼注釋掉

no.3那段程式了吧,因為它根本不能執行。 而在

test2(&p

, 10)中x

實際一進存在了,就是

p啊,所以不需要提前申請。

通過這個例子,大家可以看到了通過函式申請記憶體是一件麻煩、危險的事情。所以我們在處理類似程式的時候,一定要小心。

外部函式中申請記憶體

在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體 空位址 錯誤位址 進行操作。下面我們通過乙個程式來說明一些需要注意的問題。include include voidtest1 char p,intnum voidtest2 char pp,intnum voidmain 在上面的...

申請記憶體的函式

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大小的記憶體,並且初...