【C语言】常见的动态内存错误

在上篇文章中我们了解了内存操作函数,不难发现使用内存操作函数中很容易发生错误,所以本篇博客我们就来看看C语言中使用动态内存函数中经常出现的错误,从而在以后写代码过程中避免出现这些错误。

目录

一、常见的动态内存错误

1.1对NULL指针进行解引用操作

1.2对非动态开辟的内存使用free释放

1.3对动态开辟的空间的越界访问

1.4使用free释放一块动态开辟内存的一部分

1.5对一块动态内存多次释放

1.6动态开辟内存忘记释放(内存泄漏)

二、经典笔试题

题目1

题目2

题目3

三、总结


一、常见的动态内存错误

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.释放完空间后,一定要及时将指针置为空,要不然会指针仍指向那块地址,极易发生非法访问的错误。

本篇文章就介绍到这了,希望能对大家有所帮助,看到最后留个赞呗~~

我们下期再见

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brant_zero2022

素材免费分享不求打赏,只求关注

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值