IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [C语言] free 崩溃的常见原因小结 -> 正文阅读

[C++知识库][C语言] free 崩溃的常见原因小结

系统环境:Ubuntu 18.04.5 LTS

GCC 版本:7.5.0

没有与内存分配函数配套使用

??对一个不是由mallocrealloccalloc等内存分配函数得到的指针进行内存释放操作

int main(void)

    int arr[10] = {0};

    free(arr);

    return 0;
}

这种是比较容易发现和排除的,一般在编译阶段就会弹出警告信息

有点奇怪的是为什么不直接提示错误,而仅仅只是警告,难道这种写法还有其他妙用嘛?

在这里插入图片描述

运行后一样会弹出常规的段错误提示

在这里插入图片描述

重复释放

??对一个指针进行两次及以上的free操作,如下

int main(void)
{
    int i;
    int *arr = NULL;

    arr = (int *)malloc(sizeof(int) * 10);

    free(arr);
    free(arr);	// error

    return 0;
}

这是因为free函数只对指针指向的内存空间执行释放操作,并不会重置指针的内容,这可以通过打印指针内容观察得知

int main(void)
{
    int *arr = NULL;

printf("%p\n", arr);
    arr = (int *)malloc(sizeof(int) * 10);

printf("%p\n", arr);
    free(arr);
printf("%p\n", arr);

    return 0;
}

执行结果如下,可以看到释放后指针的内容还是原内存空间的地址,如果再对这片内存空间进行释放操作就会报错

在这里插入图片描述

此时报错信息中除了常规的core dumped之外,还会给出明确的重复释放提示

在这里插入图片描述

预防措施

??实际代码中两个free之间可能相隔比较远,或是分布在比较杂乱的条件分支,诸如此类的难以察觉的情况,不过由于free不会对空指针NULL做相关操作,因此可以在每次free后都将指针置为NULL来预防重复释放的报错

不过为了保证代码质量,非必须的重复free还是要删掉的

int main(void)
{
    int i;
    int *arr = NULL;

    arr = (int *)malloc(sizeof(int) * 10);

    free(arr);
    arr = NULL;
    free(arr);		// no error

    return 0;
}

指针指向改变

??这一错误的原因网上有不少相关解答,大意就是分配内存时,所给的内存块前后各有一段用来存储内存分配的信息,free则根据这些信息执行对应的内存释放操作,这应该就是为什么malloc等内存分配的时候要指定内存空间大小,但是free的时候却不需要这一参数。所以,如果改变了指针的值,free读取不到对应的信息就会报错,典型的错误代码如下所示

int main(void)
{
    int *arr = NULL;

printf("%p\n", arr);
    arr = (int *)malloc(sizeof(int) * 10);
printf("%p\n", arr);
    arr = arr + 1;

printf("%p\n", arr);
    free(arr);
    arr = NULL;
printf("%p\n", arr);

    return 0;
}

这里加了些调试语句,执行结果如下图,可以看到,传递给free的函数指针与一开始分配的指针不一样了,报错提示invalid pointer,与前两种错误的提示信息不完全一样,倒是可以作为一定的 debug 参考

在这里插入图片描述

调试方式

??如上述代码所示,加入一些指针内容打印的调试语句,检查分配内存时的指针内容与释放内存时的指针内容是否一致

内存越界

??分配内存空间比实际使用内存空间要小,产生内存访问越界,如果依照前述内存分配函数的操作进行理解,或许可以视为破坏了分配内存空间的结尾那一段内存分配信息,因此free会报错。但是实际测试时发现,free似乎对这种越界有一定的”容错率“,测试代码如下

int main(void)
{
    int i;
    long *arr = NULL;
    const int arr_len = 10;
    int test_arr_len = 10;

    while (1) {
        arr = (long *)malloc(sizeof(long) * arr_len);
        for (i = 0; i < test_arr_len; ++i) {
            arr[i] = i;
        }

        free(arr);
        arr = NULL;

        test_arr_len *= 10;
        printf("test array length = %d\n", test_arr_len);
    }
}

编译执行结果如下,可以看到,数组长度只分配了10,但是直到读写长度为1000000free才出现报错

在这里插入图片描述

但是,在编写实际代码的时候发现,这个”越界容忍度“应该是与程序运行规模有关,如果程序其他变量已经分配了不少内存空间,可能稍微出现一点越界就会报错。并且,更为麻烦的是,这种情况下越界可能会影响到其他变量的free,比如说A变量越界了,B变量没越界,有可能B变量先于A进行free时也会报错,因此,在检查这类错误时,如果free出错的变量并没有问题的话,那就需要检查其他分配了内存空间的变量,如果把动态内存按照的单向增长来理解的话,检查的顺序可以从free出错的变量往前回溯,找较早分配内存的变量。

调试方式

??按顺序挨个检查

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:32:27  更:2022-07-03 10:34:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:00:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码