2017-12-18 155 views
0

我試圖做一個鏈接列表,其中每個節點存儲一個字符串,但我有一個問題,其中每個節點最終在每個節點中存儲相同的確切字符串單節點。在main()的結尾處,我打印出存儲在每個節點中的單詞,它總是重複爲整個列表輸入的最後一個字符串。鏈接列表的每個節點具有相同的字符串

我沒有任何線索發生了什麼事情,因爲如果我將它製作成一串字符,它就可以很好地工作,每個字符都存儲在正確的節點中。

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

struct wordnode { 
    char *word; 
    struct wordnode *next; 
}; 

struct wordnode *link = NULL; 

void addword(char *aword); 

int main(void) { 


    char *aword; 
    int i; 

    for(i = 0; i < 10; i++) { 
     scanf(" %s", aword); 
     addword(aword); 
    } 
    printf("\n"); 
    for(; link != NULL; link = link->next) { 
     printf("|%s ", link->word); 
    } 

    printf("|\n"); 
    return 0; 
} 

void addword(char *aword) { 
    struct wordnode *cur, *prev, *new_node; 

    new_node = malloc(sizeof(struct wordnode)); 

    new_node->word = aword; 

    for(cur = link, prev = NULL; cur != NULL; prev = cur, cur = cur->next) { 
     ; 
    } 

    new_node->next = cur; 

    if(prev == NULL) { 
     link = new_node; 
    } else { 
     prev->next = new_node; 
    } 
} 
+3

您有多個問題。它開始於你如何使用'scanf'傳遞未初始化的指針。 'scanf'函數需要一些足夠大的分配內存來寫入輸入。它不分配內存本身。 –

+2

您應該複製輸入的字符串。 –

+2

指針不會奇蹟般地創建內存。 'char * aword'未初始化並指向未定義的位置。像這樣使用它會調用未定義的行爲。它應該是char char [SIZE];'爲了*分配char數組。你不應該簡單地複製指針('new_node-> word = aword;'),而是複製指向的位置(參見'strdup')。最後,在C中一貫的做法是釋放所有分配的內存。祝你好運,練習C ;-) ... –

回答

0

char * aword未被初始化和定位。它應該是:

char aword[100]; 

(100僅僅是一個數字,數組的大小可以與任意數量的你想要的東西取代它。)

+0

正如在評論中提到的,這不是唯一的問題,請改善您的答案。 –

+0

這個答案對我很有用,因爲它很簡單。這讓我想出了其他問題。 我認爲scanf會自動將內存分配到一個字符串中,所以這就是爲什麼我沒有初始化字。 –

1

有在代碼中的許多問題。其中一些已經提到。代碼將是這樣的。代碼結尾的解釋。

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

#define STR2(x) #x 
#define STR(X) STR2(X) 
#define MAXWORD 10 
#define MAXWORDLEN 20 

struct wordnode { 
    char *word; 
    struct wordnode *next; 
}; 


struct wordnode* addword(char *aword, struct wordnode *link); 
void printList(struct wordnode*link); 
void freeList(struct wordnode *link); 

int main(void) { 
    char aword[MAXWORDLEN+1]; 

    struct wordnode *link = NULL; 
    for(size_t i = 0; i < MAXWORD; i++) { 
     if(scanf("%" STR(MAXWORDLEN) "s", aword[i]) == 1){ 
      link = addword(aword, link); 
     } 
     else{ 
      fprintf(stderr, "%s\n","Error in input"); 
      exit(1); 
     } 
    } 

    printList(link); 

    freeList(link); 
    return 0; 
} 
void printList(struct wordnode*link){ 
    while(link){ 
     printf("%s \n", link->word); 
     link = link->next; 
    } 
} 
void freeList(struct wordnode *link){ 
    struct wordnode *temp; 
    while(link){ 
     temp = link; 
     link = link->next; 
     free(temp); 
    } 
} 

struct wordnode* addword(char *aword, struct wordnode *link) { 

    struct wordnode *new_node = malloc(sizeof(struct wordnode)); 

    if(new_node == NULL){ 
     fprintf(stderr, "%s\n", "Error in malloc"); 
     exit(1); 
    } 
    new_node->word = strdup(aword); 
    if(new_node->word == NULL){ 
     fprintf(stderr, "%s\n", "Error in strdup"); 
     exit(1); 
    } 
    new_node->next = NULL; 

    if(link == NULL){ 
     return new_node; 
    } 
    struct wordnode *cur = link; 
    while(cur->next != NULL){ 
     cur = cur -> next; 
    } 
    cur->next = new_node; 
    return link; 
} 

你想存儲一些字符串(nul終止字符數組),然後你想添加它們在列表中。同樣從你的示例實現中,你試圖將它添加到尾部的列表中。

綜上所述 -

  • scanf需要一個指針到一些內存在那裏可以存儲輸入的數據。但你的未初始化。

  • 其次,你複製字符串的方式,它只是一個淺拷貝(你指的是一些已經存在的內存)。您需要使用strdupmalloc - memcpymalloc-strcpy來複制它。

  • 如果POSIX strdup()不可用,您可以使用Jonathan Leffler提到的內容。

  • 在這裏您可以看到我們已經使用freeList()函數釋放了分配的內存。 完成對分配的內存的處理後,釋放內存。

  • 請勿施放返回值malloc

  • 同時檢查malloc是否成功檢查它的返回值。

  • 您已將列表頭用作全局變量。這裏不需要。

+0

謝謝,但我不能使用strdup,我正在與國際標準化組織C. 但我做了結構有一個字符到一定大小的數組,所以它被初始化,而不是一個指針,然後調用scanf把字符串在調用malloc之後直接進入每個節點的數組中,這看起來工作得很好,這完全消除了aword變量。 –

0

您還沒有爲字符串分配內存。因此aword將包含垃圾值,並將其傳遞給scanf是未定義的行爲。假設aword0x7fffe4e0cdf0,並且您的scanf將字符串存儲在地址0x7fffe4e0cdf0,並將此地址傳遞給addword函數,並且您的結構成員word也將使用相同的值進行更新。下一個scanf還將新值存儲在aword指向的同一內存中,並傳遞給該函數。因此,所有鏈接列表中的word都指向相同的內存位置。理想的解決方案是爲正在掃描的每個字符串分配內存並將其傳遞給「addword」函數。

相關問題