在上篇文章中我们了解了内存操作函数,不难发现使用内存操作函数中很容易发生错误,所以本篇博客我们就来看看C语言中使用动态内存函数中经常出现的错误,从而在以后写代码过程中避免出现这些错误。
目录
一、常见的动态内存错误
1.1对NULL指针进行解引用操作
void test()
{
int*p=(int*)malloc(INT_MAX/4);
*p=20;
free(p);
}
这道题目中,我们没有对malloc开辟的空间进行判定为空,如果maloc返回的是NULL指针,则对NULL指针解引用就会产生BUG。
1.2对非动态开辟的内存使用free释放
void test()
{
int a=10;
int *p=&a;
……
free(p);
}
这种写法当然是错误的,编译器便会报出错误。
1.3对动态开辟的空间的越界访问
void test()
{
int i=0;
int* p = (int*)malloc(10*sizeof(int));
if(NULL = p)
{
exit(EXIT_FAILURE);
}
for(i=0;i<=10;i++)
{
*(p+i)=i; //当i为10时,造成了越界访问
}
free(p);
}
这道题中我们进行了越界访问,当i的值为10时,对p+i进行解引用就导致访问了未开辟的空间,程序必然会出现错误。
1.4使用free释放一块动态开辟内存的一部分
void test()
{
int *p=(int*)malloc(100);
p++;
free(p); //此时p不再指向动态内存的起始位置。
}
如果要释放,必须释放一块动态开辟空间的起始位置, 只释放一块空间是无法做到的。运行时程序会崩溃。
1.5对一块动态内存多次释放
void test()
{
int*p=(int *)malloc(100);
free(p);
free(p); //重复释放
}
这样处理必然会引起程序崩溃。
1.6动态开辟内存忘记释放(内存泄漏)
void test()
{
int *p=(int*)malloc(100);
if(NULL != p)
{
*p=20;
}
}
int main ()
{
test();
while(1);
}
在test函数中申请了100个整形的空间,直到test函数调用完都没有释放,随着test的销毁,这就会导致p指向的这块空间再也无法释放了,就会导致内存泄漏的问题。
切记: 动态开辟的空间一定要释放,并且正确释放。
二、经典笔试题
题目1:
void GetMemory(char* p)
{
p =(char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
错误原因:
1.str传参后仍为空指针。
函数传参,传的是临时拷贝,这里我们将str传入GetMemory函数中,GetMemory函数创建了一个形式参数p来接受str指针里的值,p为一份临时拷贝,p也是一个空指针。虽然p申请道了100个字节的空间,但是没有让str指向这块空间。
2.未对p申请的空间进行释放,内存泄漏。
p申请了空间,但是没有free。
3.strcpy参数为空指针。
因为GetMemory函数并没有改变str,所以str仍为空指针,这就导致strcpy出错,无法拷贝,printf自然也无法执行,程序最终奔溃。
输出结果:
(什么结果都没有,没有打印出来)
解决方案:
将指针str的地址传入GetMemory,使用二级指针p接收,再对p进行解引用就可以找到str的地址,再申请100个字节的空间,这样就可以使str指向申请的空间了,然后使用完后再进行释放。
void GteMemory(char **p) //因为传入的是指针的地址,所以要使用二级指针接受 { *p=(char)malloc(100); //对p进行接引用,就可以找到str的地址 } void Test (void) { char *str =NULL; GetMemory( &str ); //将str的地址传入GetMemory。 strcpy(str,"hello world"); printf(str); free(str); //str指向着申请的空间,使用后释放即可 }
题目2:
char *GetMemory(void)
{
char p[]="hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str= GetMemory();
printf(str);
}
错误原因:
1.非法访问内存。
因为函数调用结束,数组中的内容已被销毁,p返回来的地址赋给str使str指向数组首元素的地址,但是数组p中的内容已经被销毁,str即成了野指针。
打印结果:
题目3:
void Test(void)
{
char *str=(char*)malloc(100);
strcpy(str,"hello");
free(str);
if(str!=NULL)
{
strcpy(str,"world");
printf (str);
}
}
先看打印结果:
错误原因:
1.空间被释放了还使用。
这里str指向的空间已经被释放,str已经是一个野指针了,但是这里仍然将world拷贝到str指向的位置,虽然程序运行成功,并且输出了world,但是这个段代码就是一段有问题的代码。
三、总结
如何避免动态内存错误:
1.malloc开辟空间后对malloc的返回值进行判空,检查开辟空间是否失败。
2.使用动态开辟的空间时,对内存边界进行检查,避免越界访问。
3.使用完动态开辟的内存后一定要及时释放,并且要从动态内存的起始地址开始释放,不能多次释放,只有动态开辟的空间才能使用free释放。
4.释放完空间后,一定要及时将指针置为空,要不然会指针仍指向那块地址,极易发生非法访问的错误。
本篇文章就介绍到这了,希望能对大家有所帮助,看到最后留个赞呗~~
我们下期再见