【關注我,后續持續新增專題博文,謝謝!!!】
上一篇我們講了:
? ? ? ? 這一篇我們開始講:?高效C/C++之九:Coverity修復問題:關于數組操作 和 內存操作
目錄
【關注我,后續持續新增專題博文,謝謝!!!】
一、關于數組操作
? ??2.1:使用沒有初始化的下標變量
? ? 2.2 :下標越界操作
二、:關于內存操作
? ??2.1:申請和釋一一對應
? ? 2.2 :釋放后切勿再訪問,賦nullptr
? ? 2.3 :關于 delete 和 delete [ ]
? ? 2.4 :對象釋放之后再次釋放
? ? 2.5?:c/c++內存分配
?
【關注我,后續持續新增專題博文,謝謝!!!】
一、關于數組操作
? ??2.1:使用沒有初始化的下標變量
使用沒有初始化的下標變量,進行寫入,可能會寫入一些系統內存,導致安全風險。
習慣對變量賦值的用法是,先判斷變量是否是某個初值,然后進行相關操作,將返回值賦給變量。
異常代碼
uint size;
buff[size] = 7;
正確代碼
uint size = 0;
buff[size] = 7;
? ? 2.2 :下標越界操作
數組下標越界,讀寫非法內存,造成內存踩踏,數組下標越界不會被編譯器檢查到,且會在運行時導致程序隨機崩潰。
使用下標之前,需要校驗下標是否在數組長度的范圍內。
異常代碼
char c = buff[offset];
正確代碼
if ((offset >= 0) && (offset < size)) {char c = buffer[offset];
} else {return -1;
}
二、:關于內存操作
? ??2.1:申請和釋一一對應
1:棧空間會隨著生命周期的消失而消失,堆空間則不會,因為申請的內存一定要去釋放;malloc 和 free、new 和 delete、new[]和 delete[] 申請和釋放要一一對應;
? ? 2.2 :釋放后切勿再訪問,賦nullptr
釋放的內存包括調用free()、delete()釋放的堆內存和函數執行完后自行釋放的棧內存,這兩類已釋放內存如果還被訪問,會存在很大風險。
所以我們在釋放后,要給指針變量賦值為nullptr,避免野指針,就算再釋放nullptr,也不會有問題。
? ? 2.3 :關于 delete 和 delete [ ]
一維數組
int *array=new int [m];
delete [] array;
二維數組
int **array
array = new int *[m];
for (int i=0; i<m; i++ ) {array[i] = new int [n] ;
}for( int i=0; i<m; i++ ) {delete [] array[i];
}
delete [] array;
對于簡單的數組來說 delete [] array 和 delete array,釋放效果相同,原因在于:分配簡單類型內存時,內存大小已經確定,系統可以記憶并且進行管理,在析構時,系統并不會調用析構函數, 它直接通過指針可以獲取實際分配的內存空間,哪怕是一個數組內存空間
class Obj
{public:Obj() { cout << "construct function" <<endl; }~Obj() { cout << "destruct function" <<endl; }
};Obj* ObjArray = new Obj[4];
//1 調用使用類對象的析構函數,2 釋放了 ObjArray 指針指向的全部內存空間
delete [] ObjArray;//1 釋放了 ObjArray 指針指向的全部內存空間 2 只調用了 ObjArray[0]對象的析構函數
delete ObjArray;
? ? 2.4 :對象釋放之后再次釋放
重復關閉內存(double-free)會導致內存管理器出現問題。重復釋放內存在一定情況下,有可能導致"堆溢出"漏洞,可以被用來執行惡意代碼,具有很大的安全隱患。
所以我們在釋放后,要給指針變量賦值為nullptr,避免野指針,就算再釋放nullptr,也不會有問題。
? ? 2.5?:c/c++內存分配
int g_int1 = 1;
int g_int2 = 0;
int g_int3;
static int g_sInt1 = 1;
static int g_sInt2 = 0;
static int g_sInt3;int main() {int int1 = 1;int int2 = 0;int int3;static int s_int1 = 1;static int s_int2 = 0;static int s_int3;char *p;char *p1;char cStr[20] = "hello world!";char cStr1[10];char cStr2[10];char *qStr = "hello world!";char *qStr1 = "world hello!";p = (char *)malloc(100);p1 = (char *)malloc(100);/* heap area start */printf("p1 %p, %d\n", p1, p1);printf("p %p, %d\n", p, p);/* heap area end /* stack area start */printf("int1 %p, %d\n", &int1, &int1);printf("int2 %p, %d\n", &int2, &int2);printf("int3 %p, %d\n", &int3, &int3);printf("cStr %p, %d\n", cStr, cStr);printf("cStr1 %p, %d\n", cStr1, cStr1);printf("cStr2 %p, %d\n", cStr2, cStr2);/* stack area end *//* static area start *//* data segment start */printf("s_int1 %p, %d\n", &s_int1, &s_int1);printf("g_sInt1 %p, %d\n", &g_sInt1, &g_sInt1);printf("g_int1 %p, %d\n", &g_int1, &g_int1);/* data segment end *//* bss segment start */printf("s_int3 %p, %d\n", &s_int3, &s_int3);printf("s_int2 %p, %d\n", &s_int2, &s_int2);printf("g_sInt3 %p, %d\n", &g_sInt3, &g_sInt3);printf("g_sInt2 %p, %d\n", &g_sInt2, &g_sInt2);printf("g_int3 %p, %d\n", &g_int3, &g_int3);printf("g_int2 %p, %d\n", &g_int2, &g_int2);/* bss segment end *//* const segment start */printf("world hello! %p, %d\n", &"world hello!", &"world hello!");printf("qStr %p, %d\n", qStr1, qStr1);printf("hello world! %p, %d\n", &"hello world!", &"hello world!");printf("qStr %p, %d\n", qStr, qStr); /* const segment end *//* static area end *//* text area start */printf("code addr start: %p, %d\n", &main, &main);/* text area start */free(p);free(p1);return 0;
}
【關注我,后續持續新增專題博文,謝謝!!!】
下一篇講解: