C語(yǔ)言中野指針和空指針的區(qū)別
野指針
定義
野指針是指那些指向了未知、隨機(jī)、不正確或已經(jīng)被釋放的內(nèi)存地址的指針變量。它們可能指向了程序棧上的某個(gè)臨時(shí)變量(該變量可能已經(jīng)出棧并被覆蓋),或者指向了已經(jīng)被free
或delete
釋放的內(nèi)存塊,或者根本就是一個(gè)隨機(jī)的、未初始化的內(nèi)存地址。
注:野指針不會(huì)直接引發(fā)錯(cuò)誤,操作野指針指向的內(nèi)存區(qū)域才會(huì)出問(wèn)題。
用途
(實(shí)際上,野指針應(yīng)該被避免):
野指針通常是由于編程錯(cuò)誤造成的,比如忘記初始化指針、釋放內(nèi)存后未將指針置為NULL
等。由于它們指向的內(nèi)存狀態(tài)是不確定的,因此使用野指針往往會(huì)導(dǎo)致程序崩潰、數(shù)據(jù)損壞等嚴(yán)重問(wèn)題。
原理
野指針的產(chǎn)生往往與內(nèi)存管理不當(dāng)有關(guān)。在C語(yǔ)言中,需要手動(dòng)管理內(nèi)存(包括分配和釋放),如果在這個(gè)過(guò)程中出現(xiàn)了疏忽,就可能導(dǎo)致野指針的產(chǎn)生。
指針未初始化
在C語(yǔ)言中,指針變量在聲明時(shí)不會(huì)自動(dòng)初始化為NULL
或任何其他值。如果在聲明指針后沒(méi)有立即為其分配一個(gè)有效的內(nèi)存地址或顯式地將其初始化為NULL
,那么這個(gè)指針就會(huì)包含一個(gè)隨機(jī)的內(nèi)存地址,成為野指針。
int *ptr; // 聲明了一個(gè)指針變量ptr,但未初始化 *ptr = 10; // 嘗試解引用ptr,這是未定義行為,因?yàn)閜tr是野指針
指針越界訪問(wèn)
當(dāng)指針被用來(lái)訪問(wèn)數(shù)組或其他連續(xù)內(nèi)存區(qū)域時(shí),如果訪問(wèn)的索引超出了其有效范圍,那么指針就會(huì)指向一個(gè)未知的內(nèi)存地址,從而成為野指針。
int arr[10]; int *ptr = arr; for (int i = 0; i <= 12; i++) { // 注意循環(huán)條件,i會(huì)超出數(shù)組范圍 *(ptr + i) = i; // 當(dāng)i=10和i=11時(shí),ptr+i成為野指針 }
釋放內(nèi)存后未置NULL
使用free
或delete
等函數(shù)釋放了指針?biāo)赶虻膬?nèi)存后,如果沒(méi)有將指針置為NULL
,那么這個(gè)指針仍然會(huì)保留原來(lái)的內(nèi)存地址。此時(shí),如果程序繼續(xù)嘗試通過(guò)該指針訪問(wèn)內(nèi)存(盡管內(nèi)存可能已經(jīng)被系統(tǒng)重新分配給其他變量),就會(huì)導(dǎo)致未定義行為,因?yàn)樵撝羔樢呀?jīng)成為了野指針。
int *ptr = (int*)malloc(sizeof(int)); if (ptr != NULL) { *ptr = 10; free(ptr); // 釋放內(nèi)存 // 忘記將ptr置為NULL // ... // 如果之后再次使用ptr,如*ptr = 20; 則ptr是野指針 }
返回局部變量的地址
在函數(shù)中,如果返回了一個(gè)指向局部變量的指針,那么在函數(shù)返回后,局部變量會(huì)被銷(xiāo)毀,但返回的指針仍然指向那個(gè)已經(jīng)被銷(xiāo)毀的內(nèi)存地址。此時(shí),該指針就成為了野指針。
int* getPointer() { int local = 10; return &local; // 返回指向局部變量的指針 } int main() { int *ptr = getPointer(); // ptr成為野指針,因?yàn)閘ocal已經(jīng)被銷(xiāo)毀 // ... }
指針運(yùn)算錯(cuò)誤
在進(jìn)行指針運(yùn)算時(shí)(如指針加法、減法或遞增、遞減),如果運(yùn)算結(jié)果超出了合法內(nèi)存范圍,那么指針就會(huì)指向一個(gè)未知的內(nèi)存地址,從而成為野指針。
如何避免出現(xiàn)
初始化指針
在聲明指針變量時(shí),應(yīng)立即將其初始化為NULL
或指向一個(gè)有效的內(nèi)存地址。這可以防止指針在未經(jīng)初始化的情況下就被使用,從而避免野指針的產(chǎn)生。指針變量剛被創(chuàng)建時(shí)不會(huì)自動(dòng)成為NULL指針,它的缺省值是隨機(jī)的,它所指的空間是隨機(jī)的。
int *ptr = NULL; // 初始化為NULL int array[10]; int *arrayPtr = array; // 指向有效數(shù)組的首地址
檢查指針是否為NULL
在解引用指針之前,應(yīng)始終檢查它是否為NULL
。這可以確保只有在指針指向有效內(nèi)存地址時(shí)才進(jìn)行解引用操作。
if (ptr != NULL) { *ptr = 10; // 只有當(dāng)ptr不是NULL時(shí)才解引用 }
釋放內(nèi)存后置NULL
在釋放指針?biāo)赶虻膬?nèi)存后,應(yīng)立即將指針置為NULL
。這可以防止在之后的代碼中錯(cuò)誤地嘗試再次解引用該指針。
free(ptr); ptr = NULL; // 避免成為野指針
避免返回局部變量的地址
函數(shù)內(nèi)部定義的局部變量在函數(shù)返回時(shí)會(huì)被銷(xiāo)毀,因此不應(yīng)該返回指向這些局部變量的指針。如果需要返回?cái)?shù)據(jù),可以考慮返回?cái)?shù)據(jù)的副本、使用動(dòng)態(tài)分配的內(nèi)存、或者通過(guò)參數(shù)傳遞指針并在函數(shù)外部分配內(nèi)存。
// 反例 int* badFunction() { int local = 10; return &local; // 返回指向局部變量的指針,可能導(dǎo)致野指針 } // 范例之一:返回動(dòng)態(tài)分配的內(nèi)存 int* goodFunction() { int *ptr = (int*)malloc(sizeof(int)); if (ptr != NULL) { *ptr = 10; } return ptr; // 注意:調(diào)用者需要負(fù)責(zé)釋放內(nèi)存 }
使用智能指針(僅限C++)
使用std::unique_ptr
、std::shared_ptr
等智能指針可以自動(dòng)管理內(nèi)存的生命周期,從而減少野指針的風(fēng)險(xiǎn)。
注意指針運(yùn)算
在進(jìn)行指針運(yùn)算時(shí)(如遞增、遞減、加法、減法),要確保指針始終在合法范圍內(nèi)。避免指針越界訪問(wèn),這可能會(huì)導(dǎo)致野指針的出現(xiàn)(雖然不是直接的野指針,但可能導(dǎo)致不可預(yù)測(cè)的行為)。
代碼審查和測(cè)試
使用靜態(tài)分析工具、內(nèi)存泄漏檢測(cè)器和單元測(cè)試等工具。
空指針
定義
空指針是一個(gè)特殊的指針值,它不指向任何有效的內(nèi)存地址。在C語(yǔ)言中,空指針通常用宏NULL
來(lái)表示,實(shí)際上NULL
通常被定義為((void*)0)
或簡(jiǎn)單地0
。
用途
空指針主要用于表示指針當(dāng)前不指向任何對(duì)象。在初始化指針時(shí),將其設(shè)置為NULL
可以明確地表明該指針當(dāng)前不指向任何有效內(nèi)存地址。此外,在釋放指針?biāo)赶虻膬?nèi)存后,將指針置為NULL
可以防止野指針的產(chǎn)生。
原理
空指針的原理很簡(jiǎn)單,它就是一個(gè)特殊的值(通常是0),用于表示指針不指向任何內(nèi)存地址。在C語(yǔ)言中,任何嘗試解引用空指針的行為都是未定義的,通常會(huì)導(dǎo)致程序崩潰。
舉例:
#include <stdio.h> int main() { int *ptr = NULL; // 聲明了一個(gè)指針變量ptr,并將其初始化為NULL,表示它不指向任何內(nèi)存地址 if (ptr != NULL) { // 如果ptr不是NULL,則執(zhí)行這里的代碼(但在這個(gè)例子中,這里的代碼不會(huì)被執(zhí)行) } else { printf("ptr is NULL\n"); // 輸出ptr是空指針的信息 } // 嘗試解引用ptr(這是不安全的,因?yàn)閜tr是NULL) // *ptr = 10; // 這將導(dǎo)致未定義行為,因?yàn)閜tr是空指針 return 0; }
在上面的例子中,ptr
被初始化為NULL
,表示它不指向任何內(nèi)存地址。然后,我們通過(guò)if
語(yǔ)句檢查ptr
是否為NULL
,并根據(jù)結(jié)果打印相應(yīng)的信息。注意,我們并沒(méi)有嘗試解引用ptr
,因?yàn)檫@是一個(gè)空指針,解引用它是不安全的。
到此這篇關(guān)于C語(yǔ)言中野指針和空指針的區(qū)別的文章就介紹到這了,更多相關(guān)C語(yǔ)言 野指針和空指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2022永久配置OpenCV開(kāi)發(fā)環(huán)境的實(shí)現(xiàn)
本文主要介紹了VS2022永久配置OpenCV開(kāi)發(fā)環(huán)境的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C++代碼改造為UTF-8編碼問(wèn)題的總結(jié)(最新推薦)
本文總結(jié)了如何將C++程序代碼改造為UTF-8編碼,包括操作系統(tǒng)、編譯器和終端等各方面的設(shè)置,在實(shí)際操作中,可以通過(guò)漸進(jìn)式更新的方式,只在新的代碼項(xiàng)目中使用UTF-8編碼,避免大規(guī)模修改舊代碼,感興趣的朋友一起看看吧2025-02-02DSP中浮點(diǎn)轉(zhuǎn)定點(diǎn)運(yùn)算--浮點(diǎn)與定點(diǎn)概述
本文主要介紹DSP中浮點(diǎn)與定點(diǎn)概述,很值得學(xué)習(xí)一下,需要的朋友可以參考一下。2016-06-06C語(yǔ)言深入分析數(shù)組指針和指針數(shù)組的應(yīng)用
在C語(yǔ)言和C++等語(yǔ)言中,數(shù)組元素全為指針變量的數(shù)組稱(chēng)為指針數(shù)組,指針數(shù)組中的元素都必須具有相同的存儲(chǔ)類(lèi)型、指向相同數(shù)據(jù)類(lèi)型的指針變量。指針數(shù)組比較適合用來(lái)指向若干個(gè)字符串,使字符串處理更加方便、靈活2022-04-04C++使用string的大數(shù)取模運(yùn)算(5)
這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)取模運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09實(shí)例詳解C/C++中extern關(guān)鍵字
這篇文章主要介紹了C/C++中extern關(guān)鍵字詳解 的相關(guān)資料,需要的朋友可以參考下2016-04-04