从链表中删除一个节点

Posted

技术标签:

【中文标题】从链表中删除一个节点【英文标题】:Deleting a node from linked list 【发布时间】:2022-01-11 20:47:38 【问题描述】:

我正在尝试删除按出生编号给出的节点,例如 9403133410。下次我打印链接列表时,我只想在输出中看到 Mike。

这是我要加载到链表中的 file.txt

***
Dave
9403133410
***
Mike
9458133410
***
Dave
9403133410

这是我的名为 node_t 的结构:

typedef struct node 
    char                *presenter;
    char                *birth_number;
    struct node         *next;
node_t;
node_t *node_new()
    node_t *node = malloc(sizeof(node_t));

    node->next = NULL;
    node->presenter = NULL;
    node->birth_number = NULL;

    return node;

这是我的加载函数

node_t *node_load(const char *file)
    int counter = 0, number_entries = 0, db_loaded = 0;
    char buffer[BUFFER_SIZE];
    dbFile = fopen(DATABASE_FILE, "r");

    if (!dbFile)printf("Zaznamy neboli najdene!\n");

    node_t *ptr = NULL, *head = NULL;

    while(fgets(buffer, BUFFER_SIZE, dbFile) != NULL)
        switch(counter++)
        case 0:
            if (!ptr)
                ptr = node_new();
                head = ptr;
            
            else
                ptr->next = node_new();
                ptr = ptr->next;
            
            number_entries++;
            break;
        case 1:
            ptr->presenter = strdup(buffer);
            break;
        case 2:
            ptr->birth_number = strdup(buffer);
            counter = 0;

            break;
        
   
    fclose(dbFile);
    return head;

这是我的删除节点功能:

void node_delete(node_t *head)
    node_t *temp, *previous;
    temp = head;
    char birth_n[14];

    scanf("%s", &birth_n);
    strcat(birth_n, "\n");

    for ( ; temp->next != NULL; temp = temp->next)
        if (strcmp(birth_n, temp->birth_number) == 0)
            if (temp == head)
                head = temp->next;
            
            else
                previous = temp;
                previous->next = temp->next;
            
            free(temp);
        
    

所以我正在尝试删除其出生编号给出的节点。

调试功能:

void node_delete(node_t *head)
    node_t *temp, *previous;
    previous = temp = head;
    char birth_n[14];

    scanf("%s", &birth_n);

    if (strcmp(birth_n, temp->birth_number) != 0)
        head = head->next;
        free(temp);
    

这个函数应该删除第一个节点,但它不会删除它...

【问题讨论】:

请出示minimal reproducible example scanf("%s", birth_n);为自己创建一个minimal reproducible example,并将输入逻辑与链表逻辑分开。马虎的编程导致菜鸟错误。 请edit您的问题并创建一个minimal reproducible example,即我们可以编译和运行的程序与输入(如果需要)、实际和预期输出一起重现问题。我建议添加一个 main 函数,该函数创建一个带有硬编码数据的链表并调用您的函数 node_delete 。你为值birth_n 输入了什么?如果您输入12.03.202103/12/2021 之类的内容,则数组大小会太小。 \n\0 需要另外两个字符。 没有阅读问题,我敢打赌,从没有return** 参数的链接列表中删除无法可靠地工作,正因为如此。 我编辑了问题 【参考方案1】:

函数没有意义。

首先将搜索到的字符串通过参数传递给函数。

其次,该函数处理指向头节点的指针值的副本。更改函数内的副本不会影响用作函数参数的原始指针。

至少不是这个电话

scanf("%s", &birth_n);

你应该写

scanf("%13s", birth_n);

还不清楚您为什么要尝试附加换行符'\n'

strcat(birth_n, "\n");

这个for循环

for ( ; temp->next != NULL; temp = temp->next)

可以在传递的指针是空指针时调用未定义的行为。即使该节点包含目标字符串,当列表仅包含一个节点时,也会跳过循环。

此外,当删除带有目标字符串的节点时,循环不会终止。

并在循环的第三个表达式中使用指针 temp

temp = temp->next

在这句话之后

free(temp);

调用未定义的行为。

函数可以如下所示

int node_delete( node_t **head, const char *birth_number )

    while ( *head != NULL && strcmp( ( *head )->birth_number, birth_number ) != 0 )
    
        head = &( *head )->next;
    

    int success = *head != NULL;

    if ( success )
    
        node_t *temp = *head;
        *head = ( *head )->next;
        free( temp );
    

    return success;

在 main 中,您必须输入将要搜索的目标字符串,并且至少像调用函数一样

node_delete( &head, birth_number );

您也可以检查函数的返回值,以确定是否删除了具有指定字符串的节点。

【讨论】:

谢谢,但它不起作用我尝试了一些新的东西,你能看看吗?我更新了问题......该函数应该删除第一个节点但它不会删除它,而是给出奇怪的符号 @Erri000 你错了。显示的功能有效。不起作用的是您自己的代码与提供的函数没有任何共同之处。 正如你所建议的,我尝试了它,但没有将 & 放入 scanf 并且没有 strcat,但是比较它没有它就无法工作...... @Erri000 听着你知道你在存储什么字符串吗?! 一点点,我是新手,但我只是告诉你,没有 strcat 它不起作用我不知道为什么......【参考方案2】:

如果您启用编译器警告并将警告视为错误,您可能会看到如下错误消息:

format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[14]’ [-Werror=format=]
      |     scanf("%s", &birth_n);
      |            ~^   ~~~~~~~~
      |             |   |
      |             |   char (*)[14]
      |             char *

这告诉您scanf%s 格式字符串与您输入的内容不兼容。您正在向它提供一个指向字符指针的指针,而不仅仅是您明确想要的字符指针。

您应该只将 birth_n 传递给 scanf 函数,如下所示:

 scanf("%s", birth_n);

这与链表无关,而是 C 中的基本输入和字符串处理。

【讨论】:

问题是当我想 strcmp 没有 scanf("%s", &birthnumber) 和 strcat() 它不返回零。

以上是关于从链表中删除一个节点的主要内容,如果未能解决你的问题,请参考以下文章

javascript中的链表结构—从链表中删除元素

从链表中删除节点(递归)

从链表中删除用户选择的节点,用 c 中另一个列表中的节点替换它们

从链表中删除总和值为0的连续节点

递归地从链表中删除数据

从链表 C++ 中删除节点