您的位置:首页 > 其它

内存使用问题应该注意这五点

2016-10-26 13:25 267 查看
* 在程序员的世界里,“内存”这个词被比作“雷区”,因为很多时候程序代码编译能通过,但是结果却不是我们想要的,或者编译的时候中断,这时候,我们便开始绞尽脑汁地调试,想尽各种办法,经过七七四十九天之后,突然眼前一亮,oh my god!居然是一个语句中内存使用错误。所以,与其花费那么多时间调试,还不如好好想想如何尽量少出现这种错误。下面,我总结了在内存使用时的常见错误。*

1.对NULL指针进行解引用操作

内存使用最常见的错误就是忘记检查所请求的内存分配是否成功,此外,在函数实现的时候,如果有指针变量作为形参,没有对参数进行NULL判断。下面给出几点建议:

(1)使用malloc()的时候,一定要使用if()语句进行判断,如code1所示。当然,你也可以按照自己的方式进行指针检查。

//code1:
int *ptr = (int *)(10 * sizeof(int));
if (NULL == ptr)
exit(EXIT_FAILURE);


(2)在函数的入口处,若形参为指针变量,则用assert()检查指针是否为空,形如assert(NULL!=ptr);

(3)定义一个指针变量时,一定要将其初始化,可以为某个值的地址,可以为NULL。

2.对内存的使用越界

对内存的使用越界,比如你申请了一块空间,每次使用一定的字节,若算法出错,导致使用了你所申请的空间的下一个空间。这个时候,这块空间有可能是不可访问的,对于这种情况你还是很幸运的,至少编译器会有错误提示。然而,如果这块空间正好存放了其他有用的数据,那么你的做法将会改变这块空间的内容,这个问题是非常让人头疼的,因为在大多数情况下,编译器是不会报错的,而且还能显示结果,只是结果很可能不是你想要的。来看code2,先自己想想结果是什么?

//code2

#include<stdio.h>
#include<stdlib.h>

int main()
{
int i = 0;
int arr[10];
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("%d ", arr[i]);
}

system("pause");
return 0;
}


来看结果



简直让人大吃一惊,出现了死循环。我们知道,栈是向下增长的,而数组元素的地址是依次升高的,在vs2013编译器下,变量i和数组arr中间空了2个字节的大小(注意,在其他编译器下很可能不是两个字节,比如vc6.0或者gcc)。当arr[9]被赋值为0时,循环会继续进行,此时,(arr+10)、(arr+11)(arr+12)这三快内存都被赋值为0,但是,注意到arr+12这块内存空间正好是变量i的空间,当我们执行(arr+12)=0;的时候,变量i又从新变成了0。这样,明白了为什么会死循环了吧。

3.释放并非动态分配的内存

在第2中情况下,假如这块空间是使用malloc()在堆上开辟的,当你想要用free()释放的时候,程序便会中断(我的环境是在Windows平台的vs2013下)。如code2所示。

//code3
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
char *p = "hello world!";
char *ptr = NULL;
int len = strlen(p);

ptr = (char *)malloc(len*sizeof(char));
if (NULL == ptr)
exit(0);
strcpy(ptr, p);

printf("%s\n", ptr);

system("pause");
return 0;
}




结果的确是我们想要的,可是,这里出现什么问题了呢?注意到代码中没有用free()释放,这时我们在printf(“%s\n”, ptr);语句后面加上free(ptr)会发生什么了?如下图所示:



当我们调试的时候,会发现程序终止在free(ptr)处,因为strlen()计算长度的时候并没有把‘\0’加进去,但是在拷贝的时候,把‘\0’也放到了ptr所指向的内存中,但是很明显空间不够用,这时‘\0’放在了我们申请的空间的下一个字节的地方。当我们使用free()释放的时候,企图把不是动态分配的空间也给释放掉,这时非法的,所以程序发生了中断。

4.释放动态分配内存的一部分

在使用free()时,传递给free函数的指针必须是一个从malloc、calloc或realloc函数返回的指针,并且不能企图释放这块内存的一部分。比如free(ptr+2),其中ptr是由malloc分配的内存。但是,relloc函数可以缩小一块动态分配的内存,可是有效地释放它尾部的部分内存。

5.使用了已被释放的内存

有时候,当我们的代码量非常大的时候,会容易犯这样的错误,在free掉某个内存之后,我们依然对其进行使用。这种情况下,在vs2013软件中会出现如下图所示的中断。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息