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