【C语言】常见的动态内存错误和笔试题分享

目录

一.常见的动态内存错误

1.对NULL指针的解引用操作

2.对动态开辟的内存空间越界访问

 3.对非动态内存开辟的空间进行free释放

4.free释放动态内存开辟空间的一部分 

5.多次free同一块动态内存 

6.忘记释放动态开辟的内存空间

二.笔试题分享 

题目1:

题目2: 

题目3: 

题目4: 


一.常见的动态内存错误

1.对NULL指针的解引用操作

​
void test()
{
    int* p = (int*)malloc(INT_MAX);//INT_MAX是代表最大整数值的宏,INT_MAX= 2147483647
    *p = 20;
    free(p);
}

​

如果malloc函数开辟内存失败就会返回NULL,在这串代码中,malloc由于需要开辟的空间过大,所以返回了NULL,那么*p就是在对NULL指针的解引用,碰到这种情况程序就会崩溃。

2.对动态开辟的内存空间越界访问

​
void test()
{
    int i = 0;
    int *p = (int *)malloc(10*sizeof(int));//开辟10个整形空间
    if(NULL == p)
    {
        exit(EXIT_FAILURE);//EXIT_FAILURE代表文件异常退出。stdio.h中:#define EXIT_FAILURE 1
    }
    for(i=0; i<=10; i++)
    {
        *(p+i) = i;
    }
    free(p);
}

​

显然,当i=0的时候越界访问了。

 3.对非动态内存开辟的空间进行free释放

void test()
{
    int a = 100;
    int *p = &a;
    free(p);
}

动态内存开辟的空间是属于堆区,非动态内存开辟的空间属于栈区,栈区是属于系统管理的,绝对不能free。当以动态内存开辟的形式向系统申请空间时,实际上是将内存中未使用的内存地址返回,然后再将这块空间标记为已使用,free实际上是将那块地址重新标记为未使用,对一块已经是未使用的地址再次标记未使用是肯定不行的。

4.free释放动态内存开辟空间的一部分 

void test()
{
    int *p = (int *)malloc(100);
    p++;
    free(p);
}

这串代码中,开辟空间后由于p++,所以p不再指向空间的起始位置,所以也不能free。

5.多次free同一块动态内存 

void test()
{
    int *p = (int *)malloc(100);
    free(p);
    free(p);
}

也是相当于将同一块空间二次标记为未使用。

6.忘记释放动态开辟的内存空间

void test()
{
    int *p = (int *)malloc(100);
    if(NULL != p)
    {
        *p = 20;
    }
}
int main()
{
    test();
    while(1);
}

不再使用的动态内存空间忘记释放的话会造成内存泄漏。

二.笔试题分享 

题目1:

​//请问程序运行的结果是什么?为什么会出现这种情况?
void GetMemory(char* p)
{
    p = (char*)malloc(100);
}
void Test(void)
{
    char* str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);
}
int main()
{
    Test();
    return 0;
}

​

程序运行后肯定是会崩溃的,调运函数GetMemory后str并未发生变化,其中依旧是NULL,GetMemory中的p只是str的一份临时拷贝,对p进行动态内存开辟不会影响到str。所以程序运行到strcpy处就会崩溃。并且没有对内存是否开辟成功进行判断,没有手动释放开辟的空间。

题目2: 

//程序运行的结果是什么?为什么会出现这种情况?
char* GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char* str = NULL;
    str = GetMemory();
    printf(str);
}
int main()
{
    Test();
    return 0;
}

显然,程序最终输出的肯定是乱码。p数组的作用域只在GetMemory中存在,当出了GetMemory时p会被销毁,最后返回的p指向不明,因此打印出来的肯定是乱码。并且没有对内存是否开辟成功进行判断,没有手动释放开辟的空间。

题目3: 

//程序运行的结果?
void GetMemory(char** p, int num)
{
    *p = (char*)malloc(num);
}
void Test(void)
{
    char* str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);
}

程序最终成功打印hello,上诉代码中最终开辟动态内存的是*p也就是str,即str开辟内存后p会在GetMemory结束后销毁,所以对str没有影响,所以最终打印hello,但由于未对开辟内存进行成功与否的判断,未手动释放开辟的内存,所以依旧存在问题。

题目4: 

//运行结果?为社么?
void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL)
    {
        strcpy(str, "world");
        printf(str);
    }
}
int main()
{
    Test();
    return 0;
}

运行结果肯定是打印world。因为这串代码虽然free了str,但并未将str置空,导致str是一个野指针,因此if判断始终成立。

最后,感谢你的观看! 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值