Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 删除链表元素会导致无限循环_C_Loops_Linked List_Infinite - Fatal编程技术网

C 删除链表元素会导致无限循环

C 删除链表元素会导致无限循环,c,loops,linked-list,infinite,C,Loops,Linked List,Infinite,我正在编写一个程序,该程序在输入中获取整数列表,并根据该整数执行以下操作: 如果输入中的值为负值,则删除绝对值 如果数字是正数和偶数,则在列表顶部添加 如果数字是正数和奇数,则将其添加到列表的末尾 如果数字等于零,则结束程序并打印列表 我的问题是pop_el函数,它会导致列表上出现无限循环,因此当我打印列表时,程序会进入无限循环。 这是我的代码: #include <stdio.h> #include <stdlib.h> typedef struct ll_node_

我正在编写一个程序,该程序在输入中获取整数列表,并根据该整数执行以下操作:

  • 如果输入中的值为负值,则删除绝对值

  • 如果数字是正数和偶数,则在列表顶部添加

  • 如果数字是正数和奇数,则将其添加到列表的末尾

  • 如果数字等于零,则结束程序并打印列表

  • 我的问题是pop_el函数,它会导致列表上出现无限循环,因此当我打印列表时,程序会进入无限循环。 这是我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct ll_node_S * ll_node_ptr;
    struct ll_node_S
    {
        int v;
        ll_node_ptr next;
    };
    typedef struct ll_node_S ll_node;
    
    ll_node_ptr push_tail(ll_node_ptr head, int v)
    {
        ll_node_ptr backup = head;
        ll_node_ptr current = head;
    
        while(current->next != NULL)
        {
            current = current->next;
        }
        current->next = (ll_node_ptr) malloc(sizeof(ll_node));
        current->v = v;
        return backup;
    }
    
    ll_node_ptr push_head(ll_node_ptr head, int v)
    {
        ll_node_ptr new_head = (ll_node_ptr)malloc(sizeof(ll_node));
        new_head->v = v;
        new_head->next = head;
        return new_head;
    }
    
    ll_node_ptr pop_el(ll_node_ptr head, int el)
    {
        ll_node_ptr backup = head;
        ll_node_ptr current = head;
        ll_node_ptr previous = NULL;
        int found = 0;
    
        while(current != NULL && !found)
        {
            if(current->v == el)
            {
                if(previous == NULL)
                {
                    backup = current->next;
                    free(current);
                    current = backup;
                    previous = current;
                }
                else
                {
                    previous->next = current ->next;
                    free(current);
                    current = current->next;
                }
    
                found = 1;
            }
            else
            {
                previous = current;
                current = current->next;
            }
        }
        return backup;
    }
    
    void print(ll_node_ptr head)
    {
        ll_node_ptr current = head;
        printf("%d\n", head->v);
        while(current->next != NULL)
        {
            current = current->next;
            printf("%d\n", current->v);
        }   
    }
    
    int isPair(int n)
    {
        return ((n % 2) == 0);
    }
    
    int main(int argc, char** argv)
    {
        int n = 1;
        ll_node_ptr list = NULL;
        while(n != 0)
        {
            scanf("%d", &n);
    
            if(n < 0)
            {
                list = pop_el(list, -n);
            }
            else
            {
                if(isPair(n))
                {
                    list = push_head(list, n);
                }
                else
                {
                    list = push_tail(list, n);
                }
    
            }
    
    
        }
    
        print(list);
        //should free the list
        return 0;
    }
    
    应产生以下输出:

    2
    2
    9
    

    有什么线索吗?

    首先,我建议在处理列表时使用递归函数。它更容易调试和理解

    我想我发现你的推尾功能有问题:

    current->next = (ll_node_ptr) malloc(sizeof(ll_node));
    current->v = v;
    
    为当前->下一步分配内存,但将值分配给当前节点。 这应该是

    current->next = (ll_node_ptr) malloc(sizeof(ll_node));
    current->next->v = v;
    current->next->next = NULL;
    

    也许这与您的问题有关。

    首先,我建议在处理列表时使用递归函数。它更容易调试和理解

    我想我发现你的推尾功能有问题:

    current->next = (ll_node_ptr) malloc(sizeof(ll_node));
    current->v = v;
    
    为当前->下一步分配内存,但将值分配给当前节点。 这应该是

    current->next = (ll_node_ptr) malloc(sizeof(ll_node));
    current->next->v = v;
    current->next->next = NULL;
    

    也许这与你的问题有关。

    正如@Vitek所指出的,你眼前的问题可以通过修复
    push\u tail()
    函数来解决。原始代码不仅将值存储在错误的节点中,而且未能将新分配的尾部节点的
    next
    字段设置为
    NULL
    。此函数中还有一个问题:
    push\u head()
    push\u tail()
    函数在使用
    NULL
    head
    指针调用时都需要创建并返回节点指针。原始的
    push\u head()
    函数可以执行此操作,但是
    push\u tail()
    函数不能执行此操作。如果用户输入的第一个数字是奇数,则通过
    push_tail()
    函数将第一个节点添加到列表中,从而导致未定义的行为(很可能是分段错误)

    更重要的是,您应该努力简化代码。这将使它更容易编写,也更容易调试。例如,
    print()
    函数可以减少为三行:

    void print(ll_node_ptr current)
    {
        while(current) {
            printf("%d\n", current->v);
            current = current->next;
        }
    }
    
    要改进
    push\u tail()
    功能,可以做几件事。以下是一个新版本:

    ll_node_ptr push_tail(ll_node_ptr head, int v)
    {
        ll_node_ptr current = head;
        ll_node_ptr prev = NULL;
        ll_node_ptr tail = malloc(sizeof(ll_node));
    
        if (tail == NULL) {
            fprintf(stderr, "Tail node allocation error\n");
            exit(EXIT_FAILURE);
        }
    
        tail->v = v;
        tail->next = NULL;
    
        while (current) {
            prev = current;
            current = current->next;
        }
    
        if (head) {
            prev->next = tail;
        } else {
            head = tail;
        }
    
        return head;
    }
    
    您不需要强制转换
    malloc()
    的结果,但是不使用cast编写代码简化了代码。此外,您应该检查以确保
    malloc()
    已成功分配请求的内存。如果改用
    realloc()
    ,这一点尤其重要,因为如果不这样做,可能会导致内存泄漏。在此处创建新的尾部节点后,立即设置
    v
    next
    字段

    通过查看
    current
    节点,而不是查看
    current->next
    节点,在链表上迭代似乎更简单。使用
    prev
    节点指针有助于实现这一点。新函数在列表上迭代,直到
    current==NULL
    ,此时
    prev
    指向列表的最后一个节点。如果
    head
    作为
    NULL
    指针传入(即,列表为空,如果用户输入的第一个数字是奇数,则可能发生这种情况),则跳过迭代循环,因为
    current
    初始化为
    head
    。循环后的代码将最后一个节点的
    next
    字段设置为指向新创建的尾部节点(如果函数具有非空列表),否则
    head
    将成为新的尾部节点。最后,
    head
    返回给调用函数

    可以对
    pop_el()
    函数进行许多简化,并且还有许多多余的代码。这个功能真的应该完全重新设计。如果您有:

    previous->next = current ->next;
    free(current);
    current = current->next;
    
    您将
    释放
    d当前
    引用的内存,然后尝试取消引用指向该内存的指针。在调用
    free()
    后,您不再拥有此内存,并且这是。相反,您希望:

    current = previous->next;
    
    但这并不重要,因为
    found
    下一步设置为
    1
    ,循环终止,函数
    返回
    s
    backup
    ,不再使用
    current
    。您只需将上述分配删除到
    current
    ,因为它不是必需的


    您应该能够使用这些信息来改进程序中的其余代码。您可能还需要考虑其他问题。通常使用
    typedef
    指针是一种不好的做法——这只会混淆代码,增加编程错误的可能性。您提供的规范没有明确说明如果有多个节点包含相同的值会发生什么情况,即是否应该删除一个或全部节点?而且,如果用户输入的第一个数字是
    0

    您眼前的问题可以通过修复@Vitek指出的
    push_tail()
    函数来解决。原始代码不仅将值存储在错误的节点中,而且未能将新分配的尾部节点的
    next
    字段设置为
    NULL
    。此函数中还有一个问题:
    push\u head()
    push\u tail()
    函数在使用
    NULL
    head
    指针调用时都需要创建并返回节点指针。原始的
    push\u head()
    函数可以执行此操作,但是
    push\u tail()
    函数不能执行此操作。如果用户输入的第一个数字是奇数,则第一个节点将通过<
    else
    {
        previous->next = current ->next;
        free(current);          
        //current = current->next; ---> Not needed.
        break;  //            ---> No need of setting found flag. You can remove it
    }
    
    ll_node_ptr push_tail(ll_node_ptr head, int v)
    {
        ll_node_ptr backup = head;
        ll_node_ptr current = head;
        ll_node_ptr new = NULL; // Created new pointer
        while(current->next != NULL)
        {
            current = current->next;
        }
        //current->next = (ll_node_ptr) malloc(sizeof(ll_node));
        new = (ll_node_ptr) malloc(sizeof(ll_node));
        //current->v = v;   ----> incorrect. new Value is actually replacing the old value.
        new->v = v;       // New value is added in the newly created node.
        new->next = NULL;
        current->next = new;
        return backup;
    }
    
    void print(ll_node_ptr head)
    {
        ll_node_ptr current = head;
        //printf("%d\n", head->v);
        while(current != NULL)
        {
            printf("%d\n", current->v);
            current = current->next;
        }   
    }