深入理解C語言 - 指針使用的常見錯誤


在C語言中,指針的重要性不言而喻,但在很多時候指針又被認為是一把雙刃劍。一方面,指針是構建數據結構和操作內存的精確而高效的工具。另一方面,它們又很容易誤用,從而產生不可預知的軟件bug。下面總結一下指針使用的常見錯誤。


一、使用未初始化的指針

這個錯誤很常見,指針未初始化時,系統會給指針分配個隨機地址,示例如下:

int *p; //或者 int *p = NULL;
···
*p = 10; //錯誤,指針未初始化

上述程序將值10寫到未知的內存位置,如果p指向系統內存空間,這樣很可能把系統本來地址里的內容給覆蓋了,會導致程序或者系統的崩潰。


二、沒有釋放內存

在堆中開辟內存以后,使用完成必須釋放內存,否則會造成內存泄漏,示例如下:

int *p = (int *)malloc(100);
···
free(p);
p = NULL;

三、不斷修改內存指針變量

很多時候使用指針開辟了內存空間,然后如果對指針指向進行改變操作,操作完成后直接釋放內存,會釋放了不該釋放的位置;另外程序丟失了對已開辟內存空間的控制,造成內存泄漏,示例如下:

//這種時候一般會定義兩個指向同一個開辟的內存空間的指針變量,一個用於操作,一個用於釋放,避免造成內存泄漏
char *p = (char *)malloc(100);
strcpy(p, "abcdefg");
p += 1; //對指針指向進行改變操作
*p = 'a';
free(p);
p = NULL;

四、注意"野指針"

"野指針"不是NULL指針,是指向“垃圾”內存的指針。人們一般不會錯用NULL指針,因為用if語句很容易判斷。但是“野指針”是很危險的,if語句對它不起作用。“野指針”的成因主要有兩種:

第一種,指針變量沒有初始化。任何指針變量剛被創建時不會自動成為NULL指針,它的缺省值是隨機的,它會亂指一氣。示例如下:

char *p; //錯誤,未初始化,成為野指針

第二種,指針變量被free或者delete之后,沒有置為NULL,讓人誤以為是個合法的指針。示例如下:

char *p = (char *)malloc(100);
...
free(p); //錯誤,沒有置為NULL,成為野指針

五、指針參數申請內存的常見錯誤

如果函數的參數是一個指針,不要指望用該指針去申請動態內存,示例如下:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
  
void getMemory(char *p, int num) 
{ 
	p = (char*)malloc(sizeof(char) * num); 
} 
  
int main() 
{ 
	char *pStr = NULL; 
	pStr = getMemory(pStr, 200); 
	strcpy(pStr, "hello world!"); //錯誤,pStr仍然是空指針 
	printf("%s", pStr); 
	free(pStr);
    pStr = NULL;
    
	return 0; 
} 

上面getMemory(str, 200)並沒有使pStr獲得期望的內存,pStr依舊是NULL,為什么?

問題出在getMemory函數中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是_p,編譯器使_p = p。在本例中,_p申請了新的內存,只是把_p所指的內存地址改變了,但是p絲毫未變,仍然是空指針。事實上,每執行一次getMemory函數就會泄漏一塊內存,因為沒有用free釋放內存。


指針參數申請內存的兩種正確用法
第一種用法:使用函數返回值來傳遞動態內存,示例如下:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
  
char* getMemory(char *p, int num) 
{ 
	p = (char *)malloc(sizeof(char) * num); 
	return p; 
} 
  
int main() 
{ 
	char *pStr = NULL; 
	pStr = getMemory(pStr, 200); 
	strcpy(pStr, "hello world!");
	printf("%s", pStr); 
	free(pStr);
    pStr = NULL;
    
	return 0; 
} 

這里強調不要用return語句返回指向”棧內存“的指針,因為”棧內存“指針在函數結束時已經被自動回收。


第二種用法:使用指向指針的指針作為參數來傳遞動態內存,示例如下:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
  
void getMemory(char **p, int num)
{
    *p = (char *)malloc(sizeof(char) * num);
}

int main()
{
    char *pStr = NULL;
    getMemory(&pStr, 200);
    strcpy(pStr, "hello world!");
    printf("%s", pStr);
    free(pStr);
    pStr = NULL;

    return 0;
}

在需要修改指針變量本身的時候,需要使用指向指針的指針作為參數,這也是傳值與傳地址的差別所在。


參考:

深入理解C語言-指針使用的常見錯誤



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM