C中这种狡猾的内存泄漏的原因是什么

rdxdk

我有一个函数,该函数需要一个只读字符串数组,然后将其复制,然后将新的字符串传递给另一个函数,该函数将根据某些条件将一些字符串放入链接列表中,然后将其返回给初始列表。呼叫者。我需要同时复制数组和其中的字符串,因为必须保留原始数组,并且必须以某种方式修改字符串,然后它们才能最终出现在列表中。

结果始终是正确的,但是valgrind抱怨内存泄漏,我注意到它的发生取决于选择要放入列表中的字符串条件,或者数组是否包含重复的字符串(实际上,这是这两者的混合)因素,我无法理解为什么它会像这样)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node {
    const char *str;
    struct node *next;
} NODE;

typedef NODE *LIST;

LIST bar(char **arr, size_t n)
{
    LIST l = NULL;

    for (size_t i = 0; i < n; i++) {
        /* FOOTNOTE #1 */
        if (i == 3 || i == 4) {
            NODE *n = malloc(sizeof(NODE));

            n->str = arr[i];
            n->next = l;
            l = n;
        }
    }

    return l;
}

LIST foo(const char **arr, size_t n)
{
    char **copy = malloc(sizeof(char *) * n);

    for (size_t i = 0; i < n; i++) {
        /* each original string is copied into a new one, which is modified in some way before
         * being saved in the new array. Here the original strings are saved directly in the
         * array because the code that alters them doesn't affect the memory leak
         */

        // the malloc at this line is the one that valgrind doesn't like
        copy[i] = malloc(strlen(arr[i]) + 1);
        strcpy(copy[i], arr[i]);
    }

    LIST l = bar(copy, n);

    // checks which strings haven't been put in the list and frees them
    for (size_t i = 0; i < n; i++) {
        NODE *n = l;

        while (n != NULL && strcmp(copy[i], n->str) != 0) {
            n = n->next;
        }

        if (n == NULL) {
            free((char *) copy[i]);
        }
    }

    // frees the array, at this point only the strings in the list should be still allocated
    free(copy);
    return l;
}

int main(void)
{
    /* FOOTNOTE #2 */
    const char *arr[] = {"amet", "sit", "dolor", "sit", "amet"};
    LIST l = foo(arr, sizeof(arr) / sizeof(arr[0]));

    // for every node in the list prints the string in it and frees both the string and the node
    while (l != NULL) {
        printf("%s", l->str);

        if (l->next != NULL) {
            printf("%s", ", ");
        }

        NODE *tmp = l;

        l = l->next;
        free((char *) tmp->str);
        free(tmp);
    }

    free(l);
    puts("");
}

脚注1:这是选择列表中哪些字符串的标准。如果我使用i == 3 || i == 4FOOTNOTE#2中的数组包含重复的字符串,则valgrind会发现泄漏。如果我使用i % 2 == 1它很好,但是如果数组不包含重复项,那么也可以i == 3 || i == 4打败我。

这是上面代码的valgrind的输出(i == 3 || i == 4重复):

$ gcc prog.c -g -o prog
$ valgrind --tool=memcheck --leak-check=full ./prog

==12118== Memcheck, a memory error detector
==12118== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12118== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==12118== Command: ./prog
==12118==
amet, sit
==12118==
==12118== HEAP SUMMARY:
==12118==     in use at exit: 9 bytes in 2 blocks
==12118==   total heap usage: 9 allocs, 7 frees, 1,120 bytes allocated
==12118==
==12118== 9 bytes in 2 blocks are definitely lost in loss record 1 of 1
==12118==    at 0x483980B: malloc (vg_replace_malloc.c:309)
==12118==    by 0x40128E: foo (test2.c:38)
==12118==    by 0x4013E1: main (test2.c:66)
==12118==
==12118== LEAK SUMMARY:
==12118==    definitely lost: 9 bytes in 2 blocks
==12118==    indirectly lost: 0 bytes in 0 blocks
==12118==      possibly lost: 0 bytes in 0 blocks
==12118==    still reachable: 0 bytes in 0 blocks
==12118==         suppressed: 0 bytes in 0 blocks
==12118==
==12118== For lists of detected and suppressed errors, rerun with: -s
==12118== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
rdxdk

由于Avi Berger提供的提示,找到了罪魁祸首。给定字符串是动态分配的,在字符串free末尾正确的方法foo()是检查数组中的地址是否等于列表中的地址:

while (n != NULL && copy[i] != n->str) {
    n = n->next;
}

这是因为,如果列表中的字符串在数组中具有重复项,则strcmp像我之前所做的那样,“按值”比较将保留所有重复项,这就是内存泄漏的来源。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

这种奇怪的Scala内存泄漏的原因是什么?

来自分类Dev

这种细分错误的原因是什么?

来自分类Dev

C中访问分段错误的原因是什么

来自分类Dev

在iOS 13.3.1中触摸后,标签样式立即发生这种变化的原因是什么?

来自分类Dev

xkcd笑话中这种特定的“ rm”序列的原因是什么?

来自分类Dev

在这种情况下python比C慢得多的原因是什么?

来自分类Dev

这种奇怪的安全行为的原因是什么?

来自分类Dev

javascript中结果的原因是什么?

来自分类Dev

Windows 10中“系统和压缩内存”的CPU使用率高的原因是什么?

来自分类Dev

这种输出“println”顺序的原因是什么?如何在这段代码中初始化对象?

来自分类Dev

什么是C中的内存泄漏?

来自分类Dev

RejctedExecutionException的原因是什么?

来自分类Dev

BufferOverflowException的原因是什么?

来自分类Dev

是什么导致iOS中的内存泄漏

来自分类Dev

在C ++和Java中只有一个返回值的原因是什么?

来自分类Dev

C程序中“异常程序终止”错误的可能原因是什么?

来自分类Dev

输出提示中[1]的名称和原因是什么?

来自分类Dev

在XML模式中避免匿名类型的原因是什么?

来自分类Dev

Chrome解析URI中的双点的原因是什么?

来自分类Dev

MySQL中重复唯一索引的原因是什么

来自分类Dev

在单独的类中定义未知枚举的原因是什么?

来自分类Dev

SQL中的LEFT和Right连接的原因是什么

来自分类Dev

在Python中,冲洗是如何工作的,原因是什么?

来自分类Dev

在apache wicket中获取对象模型的原因是什么?

来自分类Dev

JSON中此错误的可能原因是什么?

来自分类Dev

我的代码中StringIndexOutOfBoundsException的原因是什么

来自分类Dev

下述代码中左值错误的原因是什么?

来自分类Dev

mysql查询中的计数不同的原因是什么?

来自分类Dev

在XML模式中避免匿名类型的原因是什么?

Related 相关文章

  1. 1

    这种奇怪的Scala内存泄漏的原因是什么?

  2. 2

    这种细分错误的原因是什么?

  3. 3

    C中访问分段错误的原因是什么

  4. 4

    在iOS 13.3.1中触摸后,标签样式立即发生这种变化的原因是什么?

  5. 5

    xkcd笑话中这种特定的“ rm”序列的原因是什么?

  6. 6

    在这种情况下python比C慢得多的原因是什么?

  7. 7

    这种奇怪的安全行为的原因是什么?

  8. 8

    javascript中结果的原因是什么?

  9. 9

    Windows 10中“系统和压缩内存”的CPU使用率高的原因是什么?

  10. 10

    这种输出“println”顺序的原因是什么?如何在这段代码中初始化对象?

  11. 11

    什么是C中的内存泄漏?

  12. 12

    RejctedExecutionException的原因是什么?

  13. 13

    BufferOverflowException的原因是什么?

  14. 14

    是什么导致iOS中的内存泄漏

  15. 15

    在C ++和Java中只有一个返回值的原因是什么?

  16. 16

    C程序中“异常程序终止”错误的可能原因是什么?

  17. 17

    输出提示中[1]的名称和原因是什么?

  18. 18

    在XML模式中避免匿名类型的原因是什么?

  19. 19

    Chrome解析URI中的双点的原因是什么?

  20. 20

    MySQL中重复唯一索引的原因是什么

  21. 21

    在单独的类中定义未知枚举的原因是什么?

  22. 22

    SQL中的LEFT和Right连接的原因是什么

  23. 23

    在Python中,冲洗是如何工作的,原因是什么?

  24. 24

    在apache wicket中获取对象模型的原因是什么?

  25. 25

    JSON中此错误的可能原因是什么?

  26. 26

    我的代码中StringIndexOutOfBoundsException的原因是什么

  27. 27

    下述代码中左值错误的原因是什么?

  28. 28

    mysql查询中的计数不同的原因是什么?

  29. 29

    在XML模式中避免匿名类型的原因是什么?

热门标签

归档