簡體   English   中英

鏈表無限循環

[英]Linked List Infinite Loop

嘗試創建一個程序,以在將當前節點移到頭部時計算使用strcmp進行的比較次數。 雖然算法有一些問題,但有時會“起作用”,而在其他時候卻給了我無限循環。 現在已經嘗試了lldb幾個小時,並按每兩行代碼逐字地輸入printf消息,但我不知道如何確定問題所在。 我認為它在算法中的某個位置,但是我看不到任何錯誤。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node2
{
    char* word;
    struct Node2 *next;
} Node2;

Node2* head = NULL;
Node2* now = NULL;
int uniqueWords = 0;
int totalMTFRComparisons = 0;


Node2* iNode(char* word)
{   
    Node2* ptr = malloc(sizeof(Node2));
    Node2* tmp = head;
    Node2* prev = head;

    while (tmp)
    {
        totalMTFRComparisons++;
        printf("Current word: %s", tmp->word);
        if (strcmp(tmp->word, word) == 0)
        {
            prev->next = tmp->next;
            tmp->next = head;
            return tmp;
        }
        prev = tmp;
        tmp = tmp->next;
        printf("tmp incremented.\n");
    }

    ptr->word = malloc(strlen(word) + 1);
    strcpy(ptr->word, word);
    ptr->next = NULL;
    if (head == NULL)
    {
        head = now = ptr;
        return ptr;
    }
    else
    {
        ptr->next = head;
        head = ptr;
    }
    return ptr;
}

char* getString()
{
    static char buffer[128];
    while (fgets(buffer, 128, stdin) != NULL)
    {
        iNode(buffer);
    }
    return buffer;
}

int main()
{
    getString();
    printf("Total words: %d, total MTFR comparisons: %d\n", uniqueWords, totalMTFRComparisons);

    Node2* ptr2 = head;
    Node2* tmp2 = head;
    while (ptr2 != NULL)
    {
        tmp2 = ptr2->next;
        free(ptr2->word);
        free(ptr2);
        ptr2 = tmp2;
    }
}

我的控制台發了垃圾短信: tmp incremented. 但這並不總是會發生-它只會偶爾發生,所以我不知道是什么原因造成的。

輸入和輸出示例: http : //pastebin.com/QfuCm7gt

您為字符串分配的內存太少:

ptr->word = malloc(strlen(word));
strcpy(ptr->word, word);

您需要分配strlen(word) + 1個字節以允許空終止符。

當您寫超出分配的空間時,您將調用未定義的行為。 對於您來說不幸的是,這可能意味着它有時似乎可以正常工作-這是對未定義行為的有效響應,似乎可以按預期工作,除非它適合使系統改變主意並異常行為。

考慮是否可以使用strdup()函數。 如果不是,請考慮是否應該編寫和使用自己的版本。 不要忘記檢查內存分配是否成功。

(直到您解決了未定義的行為,如果還有其他問題是不對的,那么想知道還有什么問題是沒有意義的。)


我寫了這段代碼,看看是否可以模擬您的問題。 我不能:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node
{
    char *word;
    struct Node *next;
} Node;

int totalMTFRComparisons = 0;

Node* head = NULL;
static Node* iNode(char* word)
{   
    Node* ptr = malloc(sizeof(Node));
    Node* tmp = head;
    Node* prev = head;

    while (tmp)
    {
        totalMTFRComparisons++;
        if (strcmp(tmp->word, word) == 0)
        {
            prev->next = tmp->next;
            tmp->next = head;
            //tmp->next = prev;

/* JL: Still a memory leak here. */
/* Either free(ptr) or don't allocate until after the loop */

            return tmp;
        }
        prev = tmp;
        tmp = tmp->next;
        printf("tmp incremented.\n");
    }
    ptr->word = malloc(strlen(word) + 1);
    strcpy(ptr->word, word);
    ptr->next = NULL;
    if (head == NULL)
    {
        head = ptr;
        return ptr;
    }
    else
    {
        ptr->next = head;
        head = ptr;
    }
    return ptr;
}

static void dump_list(Node *node)
{
    while (node != 0)
    {
        printf("Node word: [[%s]]\n", node->word);
        node = node->next;
    }
}

static void free_list(Node *node)
{
    printf("Freeing list\n");
    while (node != 0)
    {
        Node *next = node->next;
        printf("Freeing: [[%s]]\n", node->word);
        free(node->word);
        free(node);
        node = next;
    }
}

int main(void)
{
    char line[4096];

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        printf("Line: [[%s]]\n", line);
        char *ptr = line;
        char *tok;
        while ((tok = strtok(ptr, "\n\t ")) != 0)
        {
            printf("Word: [[%s]]\n", tok);
            iNode(tok);
            ptr = NULL;
        }
        dump_list(head);
    }
    free_list(head);
    return 0;
}

那或多或少是一個MCVE。 dump和free函數只是讓我確保可以看到列表中的內容並釋放所有內存。

除了解決內存覆蓋問題外,我只提供了Node類型的定義,將static放在函數的前面(以避免我否則會收到的編譯警告之一),並添加了兩個支持函數和main() ; 否則,我沒有更改您的代碼。 (順便說一句,第一次編譯時唯一的抱怨是關於cur2 ,我注意到了,但是忘記刪除了-很好;很少有程序,甚至是我編寫的程序,都能通過得那么干凈。)

運行時,我鍵入:

abc def ghi
mno pqr stuvwxyz humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long word!

我得到了輸出:

abc def ghi
Line: [[abc def ghi
]]
Word: [[abc]]
Word: [[def]]
tmp incremented.
Word: [[ghi]]
tmp incremented.
tmp incremented.
Node word: [[ghi]]
Node word: [[def]]
Node word: [[abc]]
mno pqr stuvwxyz humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long word!
Line: [[mno pqr stuvwxyz humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long word!
]]
Word: [[mno]]
tmp incremented.
tmp incremented.
tmp incremented.
Word: [[pqr]]
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
Word: [[stuvwxyz]]
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
Word: [[humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long]]
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
Word: [[word!]]
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
tmp incremented.
Node word: [[word!]]
Node word: [[humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long]]
Node word: [[stuvwxyz]]
Node word: [[pqr]]
Node word: [[mno]]
Node word: [[ghi]]
Node word: [[def]]
Node word: [[abc]]
Freeing list
Freeing: [[word!]]
Freeing: [[humongously-and-tempestuously-but-neither-abstemiously-nor-facetiously-long]]
Freeing: [[stuvwxyz]]
Freeing: [[pqr]]
Freeing: [[mno]]
Freeing: [[ghi]]
Freeing: [[def]]
Freeing: [[abc]]

在Valgrind下運行時,我得到了一些奇怪的輸出,但這是因為我已經升級了操作系統(從Mac OS X Yosemite升級到El Capitan),而沒有更新抑制功能。 泄漏全部在系統代碼中,而不是在此代碼AFAICT中。


即時通訊

該代碼的功能之一是,如果兩次輸入該單詞,則該單詞應移至列表的開頭。 我的測試是針對獨特的單詞集。 問題在於處理第一個單詞的重復項。 這段代碼似乎很可靠:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>


typedef struct Node2
{
    char* word;
    struct Node2 *next;
} Node2;

Node2* head = NULL;
Node2* now = NULL;
int uniqueWords = 0;
int totalMTFRComparisons = 0;

bool DEBUG = true;

static
Node2* iNode(char* word)
{   
    if (DEBUG)
        printf("addNode2 called [[%s]].\n", word);
    Node2* tmp = head;
    Node2* prev = 0;

    while (tmp)
    {
        totalMTFRComparisons++;
        printf("Current word: %s\n", tmp->word);
        if (strcmp(tmp->word, word) == 0)
        {
            printf("Already entered: [[%s]]\n", tmp->word);
            if (prev != 0)
            {
                prev->next = tmp->next;
                tmp->next = head;
                head = tmp;
            }
            //tmp->next = prev;
            return tmp;
        }
        prev = tmp;
        tmp = tmp->next;
        printf("tmp incremented.\n");
    }

    Node2* ptr = malloc(sizeof(Node2));
    printf("New word: [[%s]]\n", word);
    uniqueWords++;
    ptr->word = malloc(strlen(word) + 1);
    strcpy(ptr->word, word);
    ptr->next = NULL;
    if (head == NULL)
    {
        head = now = ptr;
        return ptr;
    }
    else
    {
        ptr->next = head;
        head = ptr;
    }
    return ptr;
}

static
char* getString(void)
{
    static char buffer[128];
    while (fgets(buffer, 128, stdin) != NULL)
    {
        char *nl = strchr(buffer, '\n');
        if (nl != 0)
            *nl = '\0';
        printf("Line: [[%s]]\n", buffer);
        iNode(buffer);
    }
    return buffer;
}

int main(void)
{
    getString();
    printf("Total words: %d, total MTFR comparisons: %d\n", uniqueWords, totalMTFRComparisons);

    Node2* ptr2 = head;
    Node2* tmp2 = head;
    while (ptr2 != NULL)
    {
        printf("Freeing: [[%s]]\n", ptr2->word);
        tmp2 = ptr2->next;
        free(ptr2->word);
        free(ptr2);
        ptr2 = tmp2;
    }
}

它具有一些診斷打印。 換行剝離表示,如果您不願意看一下聊天(字符串的末尾有換行符,則將診斷輸出比您在聊天中看到的短-換行被視為單詞,包括換行符)。

ptr->word = malloc(strlen(word));

在上一行:錯誤,幾乎沒有內存例如:strlen(“ hello”)= 5而sizeof(“ hello”)將給您6

將行更改為

ptr->word = malloc(sizeof(word));

然后在strcpy之后將正常工作

暫無
暫無

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

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