C和C++中的野指针问题
文章目錄
- 1 C和C++中的野指針問題
- 1.1 野指針的概念
- 1.2 野指針的由來
- 1.3 杜絕野指針的基本原則
- 2 C和C++中的常見內(nèi)存錯誤
- 2.1 常見內(nèi)存錯誤
- 2.2 內(nèi)存操作的基本規(guī)則
1 C和C++中的野指針問題
1.1 野指針的概念
野指針的概念:
- 指針變量中的值是非法的內(nèi)存地址,進而形成野指針。
- 野指針不是NULL指針,是指向不可用內(nèi)存地址的指針。
- NULL指針并無危害,很好判斷,也很好調(diào)試。
- C語言中無法判斷一個指針所保存的地址是否合法。
1.2 野指針的由來
如下情況可能導(dǎo)致野指針的出現(xiàn):
- 局部指針變量沒有被初始化。
- 指針所指向的變量在指針之前被銷毀(返回局部變量和局部數(shù)組)。
- 使用已經(jīng)釋放過的指針。
- 進行了錯誤的指針運算。
- 進行了錯誤的強制類型轉(zhuǎn)換。
野指針初探:
#include <stdio.h> #include <malloc.h>int main() {int* p1 = (int*)malloc(40);int* p2 = (int*)1234567;//p2是一個野指針int i = 0;for(i=0; i<40; i++){*(p1 + i) = 40 - i;//由于指針運算產(chǎn)生了野指針,改寫了非法的內(nèi)容}free(p1); for(i=0; i<40; i++){p1[i] = p2[i];//使用了已經(jīng)釋放的內(nèi)存空間}return 0; }1.3 杜絕野指針的基本原則
基本原則:
- 絕不返回局部變量和局部數(shù)組的地址。
- 任何變量在定義后必須0初始化。
- 字符數(shù)組必須確認0結(jié)束符后才能成為字符串。
- 任何使用與內(nèi)存相關(guān)的函數(shù)必須指定長度信息。
無處不在的野指針:
#include <stdio.h> #include <string.h> #include <malloc.h>struct Student {char* name;int number; };char* func() {char p[] = "D.T.Software";return p; }void del(char* p) {printf("%s\n", p);free(p); }int main() {struct Student s;//由于沒有初始化,產(chǎn)生野指針char* p = func();//產(chǎn)生了野指針strcpy(s.name, p); //使用野指針s.number = 99;p = (char*)malloc(5);strcpy(p, "D.T.Software");//產(chǎn)生內(nèi)存越界,操作了野指針所指向的內(nèi)存空間del(p);return 0; }內(nèi)存錯誤是實際產(chǎn)品開發(fā)中最常見的問題,然而絕大多數(shù)的bug都可以通過遵循基本的編程原則和規(guī)范來避免。因此,在學(xué)習(xí)的的時候要牢記和理解內(nèi)存操作的基本原則,目的和意義。
2 C和C++中的常見內(nèi)存錯誤
2.1 常見內(nèi)存錯誤
常見內(nèi)存錯誤如下:
- 結(jié)構(gòu)體成員指針未初始化。
- 結(jié)構(gòu)體成員指針未分配足夠的內(nèi)存。
- 內(nèi)存分配成功,但并未初始化。
- 內(nèi)存操作越界。
常見內(nèi)存錯誤1:
#include <stdio.h> #include <malloc.h>void test(int* p, int size) {int i = 0;for(i=0; i<size; i++){printf("%d\n", p[i]);}free(p); }void func(unsigned int size) {int* p = (int*)malloc(size * sizeof(int));int i = 0;if( size % 2 != 0 ){return; }for(i=0; i<size; i++){p[i] = i;printf("%d\n", p[i]);}free(p); }int main() {int* p = (int*)malloc(5 * sizeof(int));test(p, 5);free(p); func(9);func(10);return 0; } /* 說明:兩次釋放同一個指針可能會讓程序崩潰,double free or corruption (fasttop): 0x0977b008 *** Aborted (core dumped)。 */常見內(nèi)存錯誤2:
#include <stdio.h> #include <malloc.h>struct Demo {char* p; };int main() {struct Demo d1;struct Demo d2;char i = 0;for(i='a'; i<'z'; i++){d1.p[i] = 0; }d2.p = (char*)calloc(5, sizeof(char));printf("%s\n", d2.p);for(i='a'; i<'z'; i++){d2.p[i] = i; }free(d2.p);return 0; } // 說明:calloc申請出來的內(nèi)存會被全部置0。2.2 內(nèi)存操作的基本規(guī)則
1.動態(tài)內(nèi)存申請之后,應(yīng)該立即檢查指針值是否為NULL,防止使用NULL指針。
2.free指針之后必須立即賦值為NULL。
3.任何與內(nèi)存操作相關(guān)的函數(shù)都必須帶長度信息。
補充: int snprintf(char restrict buf, size_t n, const char restrict
format, …);函數(shù)說明:最多從源串中拷貝n-1個字符到目標串中,然后再在后面加一個0。所以如果目標串的大小為n的話…
基本功能: 將可變個參數(shù)(…)按照format格式化成字符串,然后將其復(fù)制到str中 (1) 如果格式化后的字符串長度 <
size,則將此字符串全部復(fù)制到str中,并給其后添加一個字符串結(jié)束符(‘\0’); (2) 如果格式化后的字符串長度 >=
size,則只將其中的(size-1)個字符復(fù)制到str中,并給其后添加一個字符串結(jié)束符(‘\0’),返回值為格式化后的字符串的長度。
char a[20]; i = snprintf(a, 9, “%012d”, 12345);[1] printf(“i = %d, a =
%s”, i, a); 輸出為:i = 12, a = 00000001
4.malloc操作和free操作必須匹配,防止內(nèi)存泄漏和多次釋放。
內(nèi)存錯誤的本質(zhì)源于指針保存的地址為非法值:
- 指針變量未初始化,保存隨機值;
- 指針運算導(dǎo)致內(nèi)存越界。
內(nèi)存泄漏源于malloc和free不匹配:
- 當(dāng)malloc次數(shù)多于free時,產(chǎn)生內(nèi)存泄漏;
- 當(dāng)malloc次數(shù)少于free時,程序可能崩潰。
- 應(yīng)對的措施:在哪個函數(shù)里申請就在哪個函數(shù)里釋放,不要跨函數(shù)釋放動態(tài)內(nèi)存空間。
參考資料:
總結(jié)
以上是生活随笔為你收集整理的C和C++中的野指针问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么叫终端销售 最后一环节的销售
- 下一篇: C和C++的关系