【问题标题】:Exception when deleting element from linked list从链表中删除元素时出现异常
【发布时间】:2020-12-25 10:01:11
【问题描述】:

我尝试从链接列表中删除一个词(char* 值),但是当我将我的词与链接列表节点词进行比较时出现异常。

EXC_BAD_ACCESS(代码=1,地址=0xa00000002)

我不确定为什么会发生这种情况,我希望能找到任何解决问题的方法。

LinkedList* DeleteWordElement(LinkedList* head, char* value){

    LinkedList *previous=head, *current=head->next;
    if (head == NULL)
        return head;
    if (head->data == value) 
    {
        LinkedList *temp = head;
        head = head->next;
        free(temp);
        return head;
    }
    while (previous!=NULL)
    {
        if (previous->data == value) // Exception
            break;
        current = previous;
        previous = previous->next;
    }
    if (previous != NULL)
        current->next = previous->next;
    free(previous);
    return head;
}

【问题讨论】:

  • *current=head->next;这应该在确保头部不为 NULL 之后完成

标签: c pointers linked-list


【解决方案1】:

做之前:

LinkedList *previous=head, *current=head->next;

您需要检查head 是否为NULL。那么你应该使用strcmp,而不是==,来比较C字符串value

strcmp 比较实际的 C 字符串内容,同时使用 == between 两个 C 字符串询问这两个 char 指针是否指向同一个 位置。 (source)

最后,你不需要保留previous指针,current->next指针就足够了:

LinkedList* DeleteWordElement(LinkedList* head, char* value){
    if (head == NULL)
        return head;

    if (strcmp(value, head->data) == 0){
       LinkedList *next = head->next;
       free(head);
       return next;
    }
    LinkedList *current=head;
    while (current->next != NULL){
        if (strcmp(value, current->next->data) == 0){
           LinkedList *next = current->next;
           current->next = current->next->next;
           free(next);
           break;
        }
        current = current->next;
    }
    return head;
}

如果您使用递归版本,代码可以缩短,尽管以性能为代价:

LinkedList* DeleteWordElement(LinkedList* current, char* value){
    if(current != NULL){
       if (strcmp(value, current->data) == 0){
          LinkedList *result = current->next;
          free(current);
          return result;
       }
       current->next = DeleteWordElement(current->next, data);
    }
    return current;
}

【讨论】:

    【解决方案2】:

    正如在另一个答案和 cmets 部分中已经指出的那样,表达式

    current=head->next

    head == NULL时会导致undefined behavior

    另一个问题是表达式

    head->data == value

    不比较实际的字符串内容,而是比较指针本身(即内存地址)。这不是您想要的,因为指针可能总是不同的,即使字符串内容相同。为了比较实际的字符串内容,您必须使用函数strcmp

    另一个答案已经包含问题的解决方案。但是,我想提供一个替代解决方案,它对计算机来说更短更高效,但对于程序员来说可能更难理解,因为它使用双指针(即指向指针的指针):

    LinkedList* DeleteWordElement( LinkedList *head, char* value )
    {
        LinkedList **pp = &head, *p;
    
        while ( (p=*pp) != NULL )
        {
            if ( strcmp( p->data, value ) == 0 )
            {
                //found node, so unlink and remove it
                *pp = p->next;
                free( p );
                break;
            }
    
            pp = &p->next;
        }
    
        return head;
    }
    

    如您所见,此解决方案只需要一个 if 语句,而您的答案中的代码需要 4 个 if 语句,而另一个答案需要 3 个 if 语句。这些额外的if 语句在使用双指针时不是必需的,因为相同的代码可以处理所有情况。因此,您无需为每个案例都引入额外的代码路径。因此,该解决方案也无需重复代码。

    还值得一提的是函数签名

    LinkedList* DeleteWordElement(LinkedList* head, char* value)

    效率有点低。返回值是新的头部,所以调用函数的代码必须根据返回值更新列表头部。如果调用函数的代码简单地传递链表头指针的地址会更简单,因此函数可以在必要时更新链表头本身。这样,调用该函数的代码就不必做任何额外的工作了。

    为了实现这一点,您可以将函数签名更改为以下内容:

    void DeleteWordElement( LinkedList** pp_head, char* value )

    因为指针的地址是指向指针的指针(即双指针),所以您现在必须使用** 而不仅仅是*

    此外,既然您不再使用函数的返回值,您可能希望将其用于其他用途。例如,您可能希望函数返回是否找到该值。因此,您可能希望将签名更改为以下内容:

    bool DeleteWordElement( LinkedList** pp_head, char* value )

    现在你可以在找到值时使函数return true,否则return false表示没有找到值。请注意,您必须#include <stdbool.h> 才能访问booltruefalse

    虽然我们通过添加布尔返回值使函数更强大,但它和我们之前的一样简单。

    bool DeleteWordElement( LinkedList **pp_head, char* value )
    {
        LinkedList **pp = pp_head, *p;
    
        while ( (p=*pp) != NULL )
        {
            if ( strcmp( p->data, value ) == 0 )
            {
                //found node, so unlink and remove it, and then return true
                *pp = p->next;
                free( p );
                return true;
            }
    
            pp = &p->next;
        }
    
        //return false because we did not find any matching node in the list
        return false;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-30
      • 1970-01-01
      • 2020-03-16
      • 2011-07-29
      • 2017-12-28
      • 2023-03-16
      • 1970-01-01
      • 2020-10-29
      相关资源
      最近更新 更多