一.野指针
定义变量的同时最好初始化为NULL,用完指针之后也将指针变量的值设置为NULL。
二.栈(stack),堆(heap)和静态区
堆:由malloc系列函数或new操作符分配的内存,其生命周期由free或delete决定,在没有释放之前一直存在,直到程序结束。其特点是使用灵活,空间比较大,但是容易出错。
栈:保存局部变量,栈上 内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁,其特点是效率高,但是空间大小有限。
静态区:保存自动全局变量和static变量(包括static全局和局部变量)。静态区的内容在整个程序的生命周期内都存在,由编译器在编译的时候分配。
三.常见的内存错误与对策
1.指针没有指向一块合法的内存
定义了指针变量,但是没有为指针分配内存
(1)结构体成员指针未初始化
结构体里面定义的变量是一个指针类型,也需要为里面的指针变量分配空间
(2)没有为结构体指针分配足够的内存
(3)函数的入口校验
2.为指针分配的内存大小
char *p1 = "abcdefg";
char *p2 = (char *)malloc(sizeof(char) * strlen (p1));
strcpy (p2,p1);
p1是一个字符串常量,其长度为7个字符,但是其所占内存大小为8字节。
解决办法:
char *p2 = (char *)malloc(sizeof(char )*strlen(p1)+1*sizeof(char));
注意:只有字符串常量才有结束标识符
3.内存分配成功,但并未初始化
memset函数:
memset(a,0,sizeof(a));
memset有3个参数:第一个参数要被设置的内存地址,第二个参数要被设置的值,第3个参数要被设置的内存大小,单位为字节。
4.内存越界
操作数组或指针时出现“多1”或“少1”而出现。
例如:
int a[10];
for(i=0;i<=10;i++)
{
a[i] = i;
}
5.内存泄漏
会产生泄漏的内存就是堆上的内存,也就是说由malloc系列函数或new操作符分配的内存,如果用完之后没有及时free 或delet,这块内存就无法释放,直到整个程序终止。
(1)用malloc函数申请0字节内存
申请0字节内存并不返回NULL,而是返回一个正常的内存地址,但是没有办法使用这块大小为0的内存。这是if(NULL!= p)语句校验将不起作用。
(2)内存释放
free函数只有一个参数在;就是要释放内存块的首地址;程序中的malloc次数一定要和free次数相等。
(3)内存释放之后
free函数使用之后指针变量本身保存的地址并没有改变,就需要
p = NULL;
free完了之后一定要给指针置NULL。
6.内存已经释放了,但是继续通过指针来使用
(1)free(p)之后继续通过指针p来访问内存。解决办法:free完了之后一定要给指针置NULL
(2)函数返回栈内存,比如在函数内部定义了一个数组,却用return语句返回指向该数组的指针。解决办法:弄明白栈的生命周期
(3)内存使用太复杂,弄不清哪块内存被释放,哪块没有被释放,解决办法:重新设计程序,改善对象之间的调和关系。