一、使用指針做函數返回值:
1、當使用指針做爲函數的返回值時,主函數處的char *p;將獲得調用函數char *pf;的值,即一個地址值,如oxAE72。此時需要我們注意的是該地址值所指向的空間是否存在(即已向操作系統聲明註冊,不會被釋放,即可能被其他操作修改);
2、使用棧內存返回指針是明顯錯誤的,因爲棧內存將在調用結束後自動釋放,從而主函數使用該地址空間將很危險。
例如:
char* GetMemory()
{
char p[] = "hi";
return p;
}
void main()
{
char *str = GetMemory(); //出錯! 得到一塊已釋放的內存
printf(str);
}
3、使用堆內存返回指針是正確的,但是注意可能產生內存泄露問題,在使用完畢後主函數中釋放該段內存。
例如:
char* GetMemory()
{
char *p = new char[100];
return p;
}
void main()
{
char *str = GetMemory();
delete [] str; //防止內存泄露!
}
二、使用指針做函數參數:
1、有的情況下我們可能需要需要在調用函數中分配內存,而在主函數中使用,而針對的指針此時爲函數的參數。此時應注意形參與實參的問題,因爲在C語言中,形參只是繼承了實參的值,是另外一個量(ps:返回值也是同理,傳遞了一個地址值(指針)或實數值),形參的改變並不能引起實參的改變。
2、直接使用形參分配內存的方式顯然是錯誤的,因爲實參的值並不會改變,如下則實參一直爲NULL:
void GetMemory(char* p)
{
char *p = new char[100];
}
void main()
{
char *str;
GetMemory(str);
strcpy(str, "hi"); //出錯! str = NULL!
}
3、由於通過指針是可以傳值的,因爲此時該指針的地址是在主函數中申請的棧內存,我們通過指針對該棧內存進行操作,從而改變了實參的值。
void Change(char *p)
{
*p = 'b';
}
void main()
{
char a = 'a';
char* p = &a;
Change(p);
printf("%c"n", a); //值a改變!
}
4、根據上述的啓發,我們也可以採用指向指針的指針來進行在調用函數中申請,在主函數中應用。如下:假設a的地址爲ox23,內容爲'a';而str的地址是ox46,內容爲ox23;而pstr的地址是ox79,內容爲ox46。
我們通過調用函數GetMemory,從而將pstr的內容賦給了p,此時p = ox46。通過對*p(ox23)的操作,即將內存地址爲ox23之中的值改爲char[100]的首地址,從而完成了對char* str地址的分配。
void GetMemory(char** p)
{
char *p = new char[100];
}
void main()
{
char a = 'a';
char* str = &a;
char** pstr = &str;
GetMemory(pstr);
strcpy(str, "hi");
}
5、注意指針的釋放問題,可能形成懸浮指針。
當我們釋放掉一個指針p後,只是告訴操作系統該段內存可以被其他程序使用,而該指針p的地址值(如ox23)仍然存在。如果再次給這塊地址賦值是危險的,應該將p指針置爲NULL。
調用函數刪除主函數中的內存塊時,雖然可以通過地址傳遞直接刪除,但由於無法對該指針賦值(形參不能傳值),可能造成懸浮指針,所以此時也應該採用指向指針的指針的形參。例如:
void MemoryFree(char** p)
{
delete *p;
*p = NULL;
}
void main()
{
char *str = new char[100];
char *pstr = &str;
MemoryFree(pstr);
}