簡體   English   中英

刪除鏈接列表元素會導致無限循環

[英]Deleting a linked list element causes an infinite loop

我正在編寫一個程序,它在輸入中獲取整數列表,並根據整數執行以下操作:

  1. 如果輸入中的值為負,則刪除絕對值

  2. 如果數字為正數且均勻,則在列表頂部添加

  3. 如果數字是正數和奇數,請將其添加到列表的尾部

  4. 如果該數字等於零,則結束程序並打印列表。

我的問題是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;
}

這是測試用例(在輸入中傳遞)我正在測試代碼:

4
5
2
-4
-5
-3
9
2
0

應產生以下輸出:

2
2
9

任何線索?

好幾件事,

pop_el

1.如果previousNULL則只需將head ptr移動到下一個節點即可。 這樣它就會成為新的head

if(previous == NULL)
{
    backup = current->next;
    free(current);      
    //current = backup;   ---> Not needed.
    //previous = current; ---> Not needed.
    break;  //            ---> No need of setting found flag. You can remove it
}

2.如果之前不是NULL則需要將上previous節點下一個ptr指向current節點的下一個節點。

else
{
    previous->next = current ->next;
    free(current);          
    //current = current->next; ---> Not needed.
    break;  //            ---> No need of setting found flag. You can remove it
}

3.在push_tail您為current->next節點分配內存,在下一行中,您將v添加到當前節點的v 那是錯的。 檢查以下,

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;
}

4.您可以改善您的print邏輯

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;
    }   
}

push_tail()所指出的,通過修復push_tail()函數可以解決您的直接問題。 原始代碼不僅將值存儲在錯誤的節點中,而且還無法將新分配的尾節點的next字段設置為NULL 此函數還有一個問題: push_head()push_tail()函數都需要在使用NULL head指針調用時創建並返回節點指針。 原始的push_head()函數執行此操作,但push_tail()函數不執行此操作。 如果用戶輸入的第一個數字是奇數,則第一個節點通過push_tail()函數添加到列表中,導致未定義的行為(很可能是分段錯誤)。

更重要的是,您應該努力簡化代碼。 這將使編寫更容易,也更容易調試。 例如, print()函數可以減少為三行:

void print(ll_node_ptr current)
{
    while(current) {
        printf("%d\n", current->v);
        current = current->next;
    }
}

可以采取一些措施來改進push_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()的結果。 關於你是否應該這樣做的意見不同 ,但是沒有演員的寫作簡化了代碼。 此外,您應該檢查以確保malloc()已成功分配所請求的內存。 如果您使用realloc() ,這一點尤其重要,因為如果不這樣做會導致內存泄漏。 在此處創建新尾節點后,立即設置vnext字段。

通過查看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;

你可以free current引用的內存,然后你嘗試取消引用指向這個內存的指針。 在調用free() ,您不再擁有此內存,這是未定義的行為 相反,你想要:

current = previous->next;

但這並不重要,因為found下一個設置為1 ,循環終止,並且函數return s backup ,不再使用current 您應該只刪除上面的current分配,因為它不需要。

您應該能夠使用此信息來改進程序中的其余代碼。 您可能還需要查看其他問題。 typedef指針通常是一種不好的做法 - 這只會使代碼混淆並增加編程錯誤的可能性。 如果有多個節點包含相同的值,即您應該刪除一個或所有節點,那么您提供的規范並不清楚會發生什么? 而且,如果用戶輸入的第一個數字是0 ,該怎么辦?

首先,我建議在使用列表時使用遞歸函數。 它更容易調試和理解。

我想我發現你的push_tail函數存在問題:

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

您為current-> next分配內存,但將值分配給當前節點。 這應該是

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

也許這與你的問題有關。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM