【问题标题】:Memory leak when allocating strings as struct members将字符串分配为结构成员时发生内存泄漏
【发布时间】:2019-03-29 15:28:55
【问题描述】:

我已经构建了一个将节点插入双向链表的函数。该结构包括 2 个字符串,为此我在函数内动态分配空间。根据 Valgrind 的说法,这会导致内存泄漏。这是我的代码的简化版本:

typedef struct Node {
    char *str1, *str2;
    Node *next, *prev;
};

void add(Node* list, char* string1, char* string2) {         
   Node* temp = list;
   Node* new_node = (Node*) malloc(sizeof(Node));
   if (!new_node) return;

   new_node->str1 = (char*) malloc(30*sizeof(char));
   new_node->str2 = (char*) malloc(30*sizeof(char));
   strcpy(new_player->str1, string1);
   strcpy(new_player->str2, string2);

   if (!temp) {
      temp = new_node;
      new_node->prev = new_node->next = NULL;
      new_node = NULL;
      free(new_node);
      return;
   } else {
       while (temp->next) temp = temp->next;

       new_node->prev = temp;
       new_node->next = NULL;
       temp->next =new_node;

       new_node = NULL;
       free(new_node);
   }

   void destroy(Node* list) {
      Node* temp;
      while (list) {
         temp = list->next;
         free(list->str1); 
         free(list->str2);
         free(list); 
         list = temp;
      }  
  }

在处理完列表后,我在 main() 中使用了 destroy 函数。这还不够吗?我应该以某种方式释放 add 函数中的字符串吗?

我在我的程序中反复使用这个函数,所以它会导致大约 10.0000 字节的丢失。你能告诉我为什么会发生这种内存泄漏,我该如何摆脱它?

【问题讨论】:

  • 唯一一次你想free'add'函数中的东西是在发生错误时清理一个未完全分配的节点。
  • 如何初始化列表?也发布您的main 函数(即发布minimal reproducible example!)

标签: c string data-structures struct memory-leaks


【解决方案1】:

您的add 函数mallocs 一个Node,将其链接到列表中,然后frees 分配的Node 出于某种原因。这将在列表中留下悬空指针。

您的add 函数也没有将第一个Node 添加到空列表的机制。有两种方法可以做到这一点。第一种方式是返回一个指向链表第一个节点的指针:

Node* add(Node* list, char* string1, char* string2) {         
    Node* temp = list;
    Node* new_node = malloc(sizeof(Node));
    if (!new_node) return NULL;

    new_node->str1 = malloc(strlen(string1)+1);
    new_node->str2 = malloc(strlen(string2)+1);
    if (!new_node->str1 || !new_node->str2) {
        // allocation error for one of the strings
        free(new_node->str1);
        free(new_node->str2);
        free(new_node);
        return NULL;
    }

    strcpy(new_node->str1, string1);
    strcpy(new_node->str2, string2);
    new_node->next = NULL;

    if (!temp) {
        new_node->prev = NULL;
        list = new_node;
    } else {
        while (temp->next) temp = temp->next;

        new_node->prev = temp;
        temp->next = new_node;
    }

    // return pointer to first node
    return list;
}

使用第一种方式调用示例:

Node* mylist = NULL;
...
mylist = add(mylist, "hello", "world");

第二种方式是把第一个参数改成指向链表开头的指针:

void add(Node** list, char* string1, char* string2) {         
    Node* temp = *list;
    Node* new_node = malloc(sizeof(Node));
    if (!new_node) return;

    new_node->str1 = malloc(strlen(string1)+1);
    new_node->str2 = malloc(strlen(string2)+1);
    if (!new_node->str1 || !new_node->str2) {
        // allocation error for one of the strings
        free(new_node->str1);
        free(new_node->str2);
        free(new_node);
        return;
    }

    strcpy(new_node->str1, string1);
    strcpy(new_node->str2, string2);
    new_node->next = NULL;

    if (!temp) {
        new_node->prev = NULL;
        *list = new_node;
    } else {
        while (temp->next) temp = temp->next;

        new_node->prev = temp;
        temp->next = new_node;
    }
}

第二种方式调用示例:

Node* mylist = NULL;
...
add(&mylist, "hello", "world");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    相关资源
    最近更新 更多