C++中的野指针问题
文章目錄
1 C和C++中的野指針問題
1.1 野指針的概念
1.2 野指針的由來
1.3 杜絕野指針的基本原則
2 C和C++中的常見內存錯誤
2.1 常見內存錯誤
2.2 內存操作的基本規則
1 C和C++中的野指針問題
1.1 野指針的概念
野指針的概念:
指針變量中的值是非法的內存地址,進而形成野指針。
野指針不是NULL指針,是指向不可用內存地址的指針。
NULL指針并無危害,很好判斷,也很好調試。
C語言中無法判斷一個指針所保存的地址是否合法。
1.2 野指針的由來
如下情況可能導致野指針的出現:
局部指針變量沒有被初始化。
指針所指向的變量在指針之前被銷毀(返回局部變量和局部數組)。
使用已經釋放過的指針。
進行了錯誤的指針運算。
進行了錯誤的強制類型轉換。
野指針初探:
#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;//由于指針運算產生了野指針,改寫了非法的內容
? ? }
? ? free(p1);?
? ? for(i=0; i<40; i++)
? ? {
? ? ? ? p1[i] = p2[i];//使用了已經釋放的內存空間
? ? }
? ? return 0;
}
1.3 杜絕野指針的基本原則
基本原則:
絕不返回局部變量和局部數組的地址。
任何變量在定義后必須0初始化。
字符數組必須確認0結束符后才能成為字符串。
任何使用與內存相關的函數必須指定長度信息。
無處不在的野指針:
#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;//由于沒有初始化,產生野指針
? ? char* p = func();//產生了野指針
? ? strcpy(s.name, p); //使用野指針
? ? s.number = 99;
? ? p = (char*)malloc(5);
? ? strcpy(p, "D.T.Software");//產生內存越界,操作了野指針所指向的內存空間
? ? del(p);
? ? return 0;
}
內存錯誤是實際產品開發中最常見的問題,然而絕大多數的bug都可以通過遵循基本的編程原則和規范來避免。因此,在學習的的時候要牢記和理解內存操作的基本原則,目的和意義。
2 C和C++中的常見內存錯誤
2.1 常見內存錯誤
常見內存錯誤如下:
結構體成員指針未初始化。
結構體成員指針未分配足夠的內存。
內存分配成功,但并未初始化。
內存操作越界。
常見內存錯誤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)。
*/
常見內存錯誤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申請出來的內存會被全部置0。
2.2 內存操作的基本規則
1.動態內存申請之后,應該立即檢查指針值是否為NULL,防止使用NULL指針。
2.free指針之后必須立即賦值為NULL。
3.任何與內存操作相關的函數都必須帶長度信息。
補充: int snprintf(char restrict buf, size_t n, const char restrict
format, …);函數說明:最多從源串中拷貝n-1個字符到目標串中,然后再在后面加一個0。所以如果目標串的大小為n的話…
基本功能: 將可變個參數(…)按照format格式化成字符串,然后將其復制到str中 (1) 如果格式化后的字符串長度 <
size,則將此字符串全部復制到str中,并給其后添加一個字符串結束符(‘\0’); (2) 如果格式化后的字符串長度 >=
size,則只將其中的(size-1)個字符復制到str中,并給其后添加一個字符串結束符(‘\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操作必須匹配,防止內存泄漏和多次釋放。
內存錯誤的本質源于指針保存的地址為非法值:
指針變量未初始化,保存隨機值;
指針運算導致內存越界。
內存泄漏源于malloc和free不匹配:
當malloc次數多于free時,產生內存泄漏;
當malloc次數少于free時,程序可能崩潰。
應對的措施:在哪個函數里申請就在哪個函數里釋放,不要跨函數釋放動態內存空間。
/**************************野指針產生的三種情況
C/C++中野指針產生的三種情況
?1、指針變量未初始化:
?任何指針變量剛被創建時不會自動成為NULL指針,它的缺省值是隨機的,它會亂指一氣,此時若未初始化,則產生野指針。
?2、指針釋放后未置空:
?有時指針在free或delete后未賦值 NULL,便會使人以為是合法的,此時指針指向一塊未定義、未分配的內存。其實free和delete只是把指針所指的內存給釋放掉,但并沒有把指針本身干掉。指針指向的就是“垃圾”內存。所以釋放后的指針應立即將指針置為NULL,防止產生“野指針”。
?3、指針操作超越變量作用域:
?不要返回指向棧內存的指針或引用,因為棧內存在函數結束時會被釋放。
?
總結
以上是生活随笔為你收集整理的C++中的野指针问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: scan8[16+2*4]的内容
- 下一篇: Java 8: LocalDate、Lo