C語(yǔ)言實(shí)現(xiàn)野指針的示例代碼
一、野指針
1.野指針的概念
指向位置是不可知的、隨機(jī)的、不正確的、沒(méi)有明確限制的指針就叫野指針。
2.產(chǎn)生原因
野指針產(chǎn)生的原因有:
(1) 指針未初始化
創(chuàng)建指針變量時(shí)未對(duì)其進(jìn)行初始化賦值,則這個(gè)指針指向的位置是隨機(jī)的。
#include<stdio.h> int main() { int* p;//局部變量指針未初始化,默認(rèn)為隨機(jī)值 return 0; }
(2) 指針指向的空間被釋放
①如果一個(gè)(局部)變量出了作用域或者是這個(gè)變量的生命周期結(jié)束了,那變量就會(huì)被銷(xiāo)毀,變量所占的內(nèi)存會(huì)還給操作系統(tǒng),此時(shí)如果還使用指針訪問(wèn)該變量,那就會(huì)出現(xiàn)野指針,編譯器就會(huì)報(bào)錯(cuò)了。
#include<stdio.h> int* test() { int n = 10; return &n; } int main() { int* p = test(); printf("%d\n", *p); return 0; }
②指針被free之后,沒(méi)有被置為NULL。對(duì)指針進(jìn)行free只是把指針?biāo)赶虻目臻g釋放掉,但并沒(méi)有把指針本身置為空,此時(shí)指針指向的就是垃圾內(nèi)存,所以釋放后的指針應(yīng)該立即置為NULL,養(yǎng)成良好的編程習(xí)慣,以防產(chǎn)生野指針。
(3) 指針越界訪問(wèn)
在使用指針訪問(wèn)數(shù)組元素時(shí),超出數(shù)組的范圍,就會(huì)造成非法訪問(wèn),因?yàn)槟菈K空間不屬于數(shù)組的范圍,就會(huì)出現(xiàn)野指針:
#include<stdio.h> int main() { int arr[10] = { 0 }; int* p = &arr[0]; int i = 0; for (i = 0; i <= 10; i++) { //當(dāng)指針指向的范圍超出了數(shù)組arr的范圍時(shí),p就是野指針 *(p++) = i; } return 0; }
3.如何規(guī)避野指針
(1) 指針初始化如果明確知道指針指向哪里就直接賦值地址,如果不知道指針應(yīng)該指向哪里,可以給指針賦值NULL。
NULL是C語(yǔ)言中定義的一個(gè)標(biāo)識(shí)符常量,值是0,0也是地址,這個(gè)地址是無(wú)法使用的,讀寫(xiě)該地址會(huì)報(bào)錯(cuò)。
正確使用指針示例:
#include<stdio.h> int main() { int num = 10; int* p1 = # int* p2 = NULL; return 0; }
(2) 注意指針越界一個(gè)程序向內(nèi)存申請(qǐng)了哪些空間,通過(guò)指針也就只能訪問(wèn)哪些空間,不能超出范圍訪問(wèn),超出了就是越界訪問(wèn)。
(3) 指針變量不再使用時(shí),及時(shí)置為NULL,指針使用之前檢查其有效性當(dāng)指針變量指向一塊區(qū)域的時(shí)候,我們可以通過(guò)指針訪問(wèn)該區(qū)域,后期不再使用這個(gè)指針訪問(wèn)空間的時(shí)候,我們可以把該指針置為NULL。因?yàn)榧s定俗成的一個(gè)規(guī)則就是∶只要是NULL指針就不去訪問(wèn),同時(shí)使用指針之前可以判斷指針是否為NULL。
(4) 避免返回局部變量的地址通過(guò)上面的例子就可知道,局部變量一旦離開(kāi)了作用域,就會(huì)被銷(xiāo)毀,空間被釋放,此時(shí)不能再使用這塊空間的指針來(lái)訪問(wèn)此空間。
二、assert斷言函數(shù)
assert() 斷言函數(shù),用于在程序運(yùn)行過(guò)程中捕捉程序的錯(cuò)誤。在大部分編譯器下,assert()是一個(gè)宏;在少數(shù)編譯器下,assert就是一個(gè)函數(shù)。
assert() 函數(shù)在程序運(yùn)行時(shí)會(huì)對(duì)某種假設(shè)條件進(jìn)行檢測(cè),如果條件成立,程序就繼續(xù)往下執(zhí)行,如果條件不成立就會(huì)捕捉到這種錯(cuò)誤,并打印出錯(cuò)誤信息,終止程序運(yùn)行。assert()函數(shù)包含在assert.h這個(gè)頭文件中,assert翻譯過(guò)來(lái)的意思就是“斷言”。所以可以使用assert來(lái)判斷指針是否為NULL:
assert(p != NULL);
上面的代碼,在程序運(yùn)行到這一行語(yǔ)句時(shí),驗(yàn)證變量p是否等于NULL。如果確實(shí)不等于NULL,程序繼續(xù)運(yùn)行,否則就會(huì)終止運(yùn)行,并且給出報(bào)錯(cuò)信息:
#include<stdio.h> #include<assert.h> int main() { int* p = NULL; assert(p != NULL); return 0; }
運(yùn)行結(jié)果:
由上圖,assert() 接收一個(gè)表達(dá)式作為參數(shù)。如果該表達(dá)式為真(非零),assert()不會(huì)產(chǎn)生任何作用,程序繼續(xù)運(yùn)行。如果該表達(dá)式為假(零),assert()就會(huì)報(bào)錯(cuò),在標(biāo)準(zhǔn)錯(cuò)誤流stderr中寫(xiě)入一條錯(cuò)誤信息,之后顯示沒(méi)有通過(guò)的表達(dá)式,以及包含這個(gè)表達(dá)式的文件名和行號(hào)。關(guān)于流的概念,后面會(huì)學(xué)習(xí)。
使用 assert() 的好處:
assert() 不僅能自動(dòng)標(biāo)識(shí)文件和出問(wèn)題的行號(hào),而且它還具備一種無(wú)需更改代碼就能開(kāi)啟或關(guān)閉的機(jī)制:如果已經(jīng)確認(rèn)程序沒(méi)有問(wèn)題,不需要再做斷言,就在 #include <assert.h> 語(yǔ)句的前面,定義一個(gè)宏NDEBUG,它的意思是No Debug(一旦定義了宏NDEBUG,assert() 就會(huì)失效):
#define NDEBUG #include <assert.h>
然后,重新編譯程序,編譯器就會(huì)禁用文件中所有的 assert() 語(yǔ)句。如果程序又出現(xiàn)問(wèn)題,可以移除這條 #define NDEBUG 指令(或者把它注釋掉),再次編譯,這樣就重新啟用了 assert() 語(yǔ)句。
assert() 的缺點(diǎn):
assert() 的缺點(diǎn)是:因?yàn)橐肓祟~外的檢查,增加了程序的運(yùn)行時(shí)間。
一般我們?cè)贒ebug調(diào)試版本中使用assert,而在Release發(fā)行版本中選擇禁用assert。在VS這樣的集成開(kāi)發(fā)環(huán)境中,在Release版本中,assert直接就被優(yōu)化掉了。這樣在Debug版本中使用assert有利于程序員排查問(wèn)題,而在Release版本中不影響用戶使用程序時(shí)的效率。
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)野指針的示例代碼的文章就介紹到這了,更多相關(guān)C語(yǔ)言 野指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Linux下使用C/C++進(jìn)行UDP網(wǎng)絡(luò)編程詳解
UDP 是User Datagram Protocol 的簡(jiǎn)稱,中文名是用戶數(shù)據(jù)報(bào)協(xié)議,是一種無(wú)連接、不可靠的協(xié)議,本文主要介紹了如何在Linux下使用C/C++進(jìn)行UDP網(wǎng)絡(luò)編程,有需要的可以了解下2024-10-10深入探討POJ 2312 Battle City 優(yōu)先隊(duì)列+BFS
本篇文章是對(duì)優(yōu)先隊(duì)列+BFS進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Qt實(shí)現(xiàn)部件透明陰影效果與不規(guī)則窗體詳解
這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)部件透明陰影效果與不規(guī)則窗體的相關(guān)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-01-01