• C语言学习笔记--内存操作常见错误


    1. 野指针

    (1)指针变量中的值是非法的内存地址,进而形成野指针

    (2)野指针不是 NULL 指针,是指向不可用内存地址的指针

    (3)NULL 指针并无危害,很好判断,也很好调试

    (4)C 语言中无法判断一个指针所保存的地址是否合法

     2. 野指针的由来

    (1)局部指针变量没有被初始化

    (2)指针所指向的变量在指针之前被销毁

    (3)使用己经释放过的指针

    (4)进行了错误的指针运算

    (5)进行了错误的强制类型转换

    #include <stdio.h>
    #include <malloc.h>
    
    
    int main()
    {
        int* p1 = (int*)malloc(40); //这里只分配40字节
        int* p2 = (int*)1234567;    //该地址是非法的,进行了错误的强制转换
        int i = 0;
        
        for(i = 0;i < 40; i++)
        {
            *(p1 + i) = 40 - i; //越界访问,p1所指内存总共才40字节,而这里要写入40*4字节
        }
    
        free(p1);
    
        for(i = 0; i < 40; i++)
        {
           p1[i] = p2[i]; //p1越界访问,p2非法内存
        }
    
        return 0;
    }

    3. 基本原则

    (1)绝不返回局部变量和局部数组的地址

    (2)任何变量在定义后必须用 0 初始化

    (3)字符数组必须确认 0 结束符后才能成为字符串

    (4)任何使用与内存操作相关的函数必须指定长度信息

    #include <stdio.h>
    #include <malloc.h>
    #include <string.h>
    
    struct Student
    {
        char* name;
        int number;
    };
    
    char* func()
    {
        char p[] = "Hello World!";
        return p; //返回栈中数组,这是很危险的。
    }
    
    void del(char* p)
    {
        printf("%s
    ", p);
        free(p);  //不符谁申请谁释放的原则!
    }
    
    int main()
    {
        struct Student s; //危险,结构体应先初始化,因为结构体里有指针!
        char* p = func(); //危险,返回局部的数组地址
    
        //strcpy(s.name, p);//s结构体的name指针是野指针!
    
        s.number = 99;//合法
    
        p = (char*)malloc(5);
    
        strcpy(p, "Hello World!");//越界,源字符串比目标内存大!
    
        del(p);
    
        return 0;
    }

    4.常见内存错误

    (1)结构体成员指针未初始化

    (2)结构体成员指针未分配足够的内存

    (3)内存分配成功,但并未初始化

    (4)内存操作越界

    #include <stdio.h>
    #include <malloc.h>
    
    void test(int* p, int size) //对内存操作时,有带长度信息
    {
        int i = 0;
        for(i = 0; i<size; i++)
        {
            printf("%d
    ",p[i]);
        }
    
        free(p);//不合符谁申请谁释放原则
                //当p指向一个数组时,该操作是非法的,因为
                //只能free堆中的内存。
    }
    
    void func(unsigned int size)
    {
        int* p = (int*)malloc(size * sizeof(int));
        int i = 0;
    
        if(size % 2 != 0)  //当size为奇数时会p产生内存泄漏
        {
             return;
        }
    
        for(i=0; i<size; i++)
        {
            p[i] = i;
            printf("%d
    ", p[i]);
        }
    
        free(p);
    
    }
    
    int main()
    {
        int* p = (int*)malloc(5 * sizeof(int));
        
        test(p, 5); //test内部释放了p所指内存,不符合谁申请谁释放原则
    
        free(p); //这里重复释放p,会造成程序崩溃
    
        func(9); //参数为奇数,会造成内存泄漏!
        func(10);//正常
    
        return 0;
    }

    5.内存操作的交通规则

    (1)动态内存申请之后,应该立即检查指针的值是否为 NULL,防止使用 NULL 指针

    int* p = (int*)malloc(56);
    
    if (p != NULL){
    
         //do something here!
    
    }
    
    ……

    (2)free 指针之后必须立即赋值为 NULL。(如 free(p);p=NULL;)

    (3)任何与内存操作相头的函数都必须带长度信息!!!!!!!!!

    void printf(int* p, int size) //带长度信息size
    {   
    
        int i = 0;
        snprintf(buf,sizeof(buf), "%s
    ", "Hello World!");
    
        for(i = 0;i< size; i++){  //长度信息size
            printf("%s
    ",p[i])
        }
    }

    (4)malloc 操作和 free 操作必须匹配,防止内存泄露和多次释放。并且遵循谁申请谁释放的原则。

    #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] = i; //d1.p指针未被初始化,内存空间也未分配
        }
    
        d2.p = (char*)calloc(5, sizeof(char));
        
        printf("%s
    ", d2.p);
    
        for(i='a'; i< 'z'; i++)
        {
            d2.p[i] = i;
        }
    
        free(d2.p);
    
        return 0;
    }

    内存错误的本质源于指针保存的地址为非法值(如指针未初始化或指针运算导致的越界)。内存泄漏源于malloc和free不匹配。当malloc次数多于free里产生内存泄漏。反之程序可能崩溃。

    参考资料:
    www.dt4sw.com
    http://www.cnblogs.com/5iedu/category/804081.html

  • 相关阅读:
    idea 缺失右侧maven窗口
    SpringCloud
    Java面试题——Java基础
    json对象、json字符串的区别和相互转换
    java中的 private Logger log=Logger.getLogger(this.getClass());
    http网络编程
    ansible和helm
    template模板
    http中get和post请求方式
    session和cookie
  • 原文地址:https://www.cnblogs.com/CoderTian/p/5911538.html
Copyright © 2020-2023  润新知