【C语言进阶剖析】42、内存操作的经典问题分析(二)

梦想的初衷 提交于 2020-01-28 17:11:54

1 常见内存错误

  • 结构体成员指针未初始化
  • 结构体成员指针未分配足够的内存
  • 内存分配成功,但未初始化
  • 内存操作越界

我们记得定义一个指针的时候要初始化,却容易忘记定义结构体变量时初始化指针成员。指针未分配足够的内存会导致越界操作的问题。内存分配成功,但未初始化,这个可能回造成字符串方面的错误。内存操作越界可能会操作不因该操作的内存,比如字符串没有结尾的 ‘\0’,复制的时候没有发现结尾的 ‘\0’,导致越界了。第四条包括的 2,3 条。

2 找内存错误

下面我们来找找下面的程序中哪里出现了内存错误呢?

// 42-1.c
#include <stdio.h>
#include <malloc.h>
void test(int* p, int size)
{
    int i = 0;
    for(i=0; i<size; i++)
    {
        printf("%d\n", p[i]);
    }
    free(p);
}
void func(unsigned int size)
{
    int* p = (int*)malloc(size * sizeof(int));
    int i = 0;
    if( size % 2 != 0 )
    {
        return; 
    }
    for(i=0; i<size; i++)
    {
        p[i] = i;
        printf("%d\n", p[i]);
    }
    free(p);
}
int main()
{
    int* p = (int*)malloc(5 * sizeof(int));
    test(p, 5);
    free(p); 
    func(9);
    func(10);
    return 0;
}

错误1:第 30 行申请的内存在第 11 行和第 32 行释放了两次,会导致程序崩溃。(应该采用在哪里申请就在哪里释放的方法)
错误2:func 函数中,如果 size 值为奇数,则直接返回,申请的内存没有释放,导致内存泄漏。

下面再看一个实例,同样的找出内存操作的错误。

// 41-2.c
#include <stdio.h>
#include <malloc.h>
struct Demo
{
    char* p;
};
int main()
{
    struct Demo d1;
    struct Demo d2;
    char i = 0;
    for(i='a'; i<'z'; i++)
    {
        d1.p[i] = 0; 
    }
    d2.p = (char*)calloc(5, sizeof(char));
    printf("%s\n", d2.p);
    for(i='a'; i<'z'; i++)
    {
        d2.p[i] = i; 
    }
    free(d2.p);
    return 0;
}

错误1:第 10,11 行,定义了结构体变量,但是没有对结构体变量的指针初始化。所以第 15 行在操作野指针。(所以要记得定义变量的时候就要初始化)
错误2:第 17 行申请了 5 个字节的内存,但是第 19 行却操作了大于 5 字节的内存,越界操作了。

3 内存操纵的规则

下面总结一下内存操纵的规则,来减少内存错误。
1、动态内存申请之后,应该立即检查指针值是否为 NULL,防止使用 NULL指针。
在这里插入图片描述
2、free 指针之后必须立即赋值为 NULL。
在这里插入图片描述
3、任何于内存操作相关的函数都必须带长度信息
在这里插入图片描述
4、malloc 操作和 free 操作必须匹配,防止内存泄漏和多次释放。
在这里插入图片描述

4 小结

1、内存错误的本质源于指针保存的地址为非法值

  • 指针变量未初始化,保存随机值
  • 指针运算导致内存越界
    2、内存泄漏源于 malloc 和 free 不匹配
  • 当 malloc 次数多余 free 是,产生内存泄漏
  • 当 malloc 次数少于 free 时,程序可能崩溃
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!