【问题标题】:Program throws heap use after free error when I perform certain test cases当我执行某些测试用例时,程序在释放错误后抛出堆使用
【发布时间】:2021-12-04 00:31:21
【问题描述】:

当我运行程序时,它可以工作,除非我删除了一个相当大的数字,例如 100 或更大,每当我远程输入任何与该数字一样大的东西时,我都会在出现错误后得到堆使用。终端说它是由insert() 中的第 53 行引起的,即这一行,tail->next = newNode;。我知道将头指针和尾指针作为全局变量并不是最好的编写方法,但是一旦我让它工作,我会改变它。

void insert(int nData) {
    struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
    
    newNode->data = nData;
    newNode->next = NULL;
    if(checkDuplicates(nData)==1){
        return;
    }else{
        if(head == NULL){
            head = newNode;
            tail = newNode;
        }
        else {  
            tail->next = newNode;  
            tail = newNode;  
        }  
    }
}

void delete(int n){
    if(head -> data==n){
        struct Node *tempHead = head;
        head= head -> next;
        free(tempHead);
        return;
    } else{
        struct Node *current = head;
        struct Node *prev = NULL;
        while(current!=NULL&&current->data!=n){
            prev = current;
            current = current -> next;
        }
        if(current==NULL) return;
        
        prev->next = current->next;
        free(current);
    }
}

【问题讨论】:

  • +10 是干什么用的?
  • 您应该在分配新节点之前检查重复项。否则你有内存泄漏。
  • 我在发布的代码中看不到任何可能导致释放后使用错误的内容。但也许你还有其他代码可以释放节点?或者代码中的其他一些错误会破坏堆,这是一个副作用。尝试使用valgrind 运行您的程序。
  • @Kush Patel 如果您不想在列表中有重复项,请构建一个排序列表。

标签: c linked-list heap-memory free singly-linked-list


【解决方案1】:

有一种可能的情况是tail->next = newNode 会在一个已释放的节点上执行:这发生在您之前调用delete 并且删除了列表中的尾节点时。在这种情况下,您的代码不会调整 tail 的值。

所以在delete更改:

    head = head -> next;

到:

    head = head -> next;
    if (head == NULL) {
        tail == NULL;
    }

并在else 块更改:

    prev->next = current->next;
    free(current);

到:

    prev->next = current->next;
    if (tail == current) {
        tail = prev;
    }
    free(current);

【讨论】:

    【解决方案2】:

    对于初学者来说,函数insert 可能会产生内存泄漏,因为首先分配了内存

    struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
    

    (此外,不清楚10 在这个表达式sizeof(struct Node)+10 中的含义是什么)。然后是if语句的条件

    if(checkDuplicates(nData)==1){
        return;
    

    评估为逻辑真,函数退出而不释放分配的内存。

    您首先需要检查该值是否已存在于列表中,然后才能为新节点分配内存。

    至于错误的原因,错误的原因似乎在函数delete内部。当列表中存在单个节点或指针尾指向的节点被删除时,该函数不会重置指针尾。

    除此之外,甚至是函数的第一条语句

    if(head -> data==n){
    

    当为空列表调用函数时,可以调用未定义的行为。

    函数的定义方式如下

    int delete( int n )
    {
        struct Node *current = head;
        struct Node *prev = NULL;
    
        while ( current != NULL && current->data != n )
        {
            prev = current;
            current = current->next;
        }
    
        int success = current != NULL;
    
        if ( success )
        {
            if ( prev == NULL )
            {
                head = head->next;
                if ( head == NULL ) tail = NULL;
            }
            else
            {
                prev->next = current->next;
                if ( prev->next == NULL ) tail = prev;
            }  
    
            free( current );
        }
    
        return success;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-06
      • 1970-01-01
      • 2020-11-13
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      相关资源
      最近更新 更多