2017-12-18 157 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”函数。

相关问题