【关注我,后续持续新增专题博文,谢谢!!!】
上一篇我们讲了:
这一篇我们开始讲: 高效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;
}
【关注我,后续持续新增专题博文,谢谢!!!】
下一篇讲解: