[英]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.