工作中優化一段代碼,代碼中有一大段分配堆內存的內容,我覺得這段代碼太長了,更適合放在子函數里面。
我把指針作為參數,然后在子函數中malloc分配內存,結果出現了問題,函數結束后,以參數傳進來的指針並沒有指向分配的內存。
比如說:
int fun(unsigned char *p, unsigned char **p1) { p = (unsigned char *)malloc(N * sizeof(unsigned char)); if (NULL == p) return -1; // 給二維指針p1分配 p1 = fun_set_p1(); if (NULL == p1) { free(p); return -1; } return 0; } unsigned char *p; unsigned char **p1 fun(p, p1);
運行完fun后,*p和**p1並沒有發生變化。
指針作為參數不是傳的是地址嗎?怎么沒變化呢?
其實這樣想是一種誤區,其實指針作為參數也是值傳遞,在函數中將參數復制一份而已。指向的是同一塊內存地址。假設參數傳的是int *p,函數內copy的j是int *p_1。在函數中操作*p_1,例如*p_1 = 1, 則p_1所指向的內容就變成了1.,由於他們是指向同一塊地址,所以即使他們不是同一個指針*p所指向的內存也會被改變。
但如果讓p_1指向其他的內存地址,則由於是值傳遞,p並不會因此而改變。
其實反匯編可以看出,參數的傳遞其實就是將變量放入新開辟的函數棧空間,也就是我說的“copy一份”,函數中再對棧空間里的內容操作,這就是值傳遞的本質。
所以這種情況該怎么辦呢?
一種情況是函數 返回 指向新申請內存的指針
unsigned char* fun() { unsigned char* p = malloc(N * sizeof(unsigned char)); return p; }
但如果你需要設置多個指針就不合適了。
另一種辦法就是使用二級指針、三級指針。
int fun(unsigned char **p, unsigned char ***p1) { *p = (unsigned char *)malloc(N * sizeof(unsigned char)); if (NULL == *p) return -1; // 給二維指針p1分配 *p1 = fun_set_p1(); if (NULL == *p1) { free(*p); return -1; } return 0; } unsigned char* p; unsigned char** p1; fun(&p, &p1);
其實就是指向指針的指針。
函數內值傳遞,拷貝一份,其指向的內存的內容改變了,參數指向的內存的內容就跟着變了。