链表与字符串

4

我正在尝试创建一个程序,首先解析一些字符串并将它们添加到链表中,最后打印出每个字符串的出现次数。

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct Node Node;

struct Node
{
    char* word;
    int count;
    struct Node *next;
};

Node *head = NULL;
Node *curr = NULL;

Node* listAdd(char* word, bool toEnd) {
    Node* tmp = head;
    while (tmp) {
        if (strcmp(tmp, word) == 0) {
            tmp->count++;
            return tmp;
        }
        tmp = tmp->next;
    }
    printf("allocate memory for node");
    Node *ptr = malloc(sizeof(Node));

    printf("initialize count to 0");
    ptr->count = 0;

    printf("allocate memory to hold word");
    ptr->word = malloc(strlen(word) + 1);

    printf("copy the current word");
    strcpy(ptr->word, word);

    ptr->next = NULL;

    if (toEnd)
    {
        curr->next = ptr;
        curr = ptr;
    }
    else
    {
        ptr->next = head;
        head = ptr;
    }
    return ptr;
}

void printList()
{
    Node *ptr = head;
    while (ptr)
    {
        printf("\nThe word [%s] has had [%d] occurrences.\n",ptr->word, ptr->count);
        ptr = ptr->next;
    }
}

char* readWord()
{
    static char buffer[100];
    scanf("%s", buffer);
    printf("listAdd() call");
    listAdd(buffer);
    return buffer;
}

int main(void)
{
    int i = 0;
    printf("How many words would you like to type?\n");
    scanf("%d", &i);
    for (i; i != 0; i--)
    {
        readWord();
    }
    printList();
}

当前输出:

How many words would you like to input?
3
hi
bye
yes
How many words would you like to input?
Occurrences: 12086064

任何帮助将不胜感激——我是从C#转向C的新手 :(

1
建议您坚持调试程序而不是立刻求助于SO。特别地,启动您喜欢的调试器,逐步执行程序,并在每个阶段检查代码是否按照您的预期运行。或者,即使只有几个可靠的调试打印语句也可以帮助您理解程序实际正在执行的操作。 - kaylum
1
你没有使用函数 searchListcount 没有被初始化。 - Jacob Seleznev
@Cyclone 我是否需要为计数器也分配内存?我认为searchList函数是一个很糟糕的想法。我将在listAdd()中增加计数器。在发布此处之前,我已尝试了调试打印语句 - 它们都没有打印出来。 - Sleepless
@MOehm 我应该将这两个 malloc 简化为一个,例如 malloc(sizeof(Node) + strlen(word)) 吗? - Sleepless
@Moehm 哦,明白了。不幸的是,即使将 count 初始化为 0 并删除第三个 ptr->word,我仍然得到相同的结果。 - Sleepless
显示剩余8条评论
2个回答

7

您的代码存在几个错误。首先,您分配了两次指向Node的指针:

Node* listAdd(char* word, bool toEnd) {
  // .. 

  Node *ptr = malloc(sizeof(Node));
  return ptr;
}

return语句之前删除最后一个。

您还需要分配内存来保存每个读取的单词。目前,每次调用readWord()时都会覆盖缓冲区。您可以像这样操作:

Node* listAdd(char* word, bool toEnd) {
  // allocate memory for node
  Node *ptr = malloc(sizeof(Node));
  // initialize count to 0
  ptr->count = 0;
  // allocate memory to hold word
  ptr->word = malloc(strlen(word) + 1);
  // copy the current word
  strcpy(ptr->word, word);

你的printList()函数应该长这样:
void printList() {
  Node* ptr = head;
  while(ptr) {
    printf("Word: %s %d\n", ptr->word, ptr->count);
    ptr = ptr->next;
  }
}

由于您从未检查输入的单词是否已经存在于列表中,因此每个单词将始终被报告为具有1个出现次数。可以通过以下方式解决此问题:

// check if the word alreay exists in the list and then increment its count by 1
// this code should go at the top (before allocating ptr) in listAdd()
Node* tmp = head;
while(tmp) {
   if(strcmp(tmp->word, word) == 0) {
     tmp->count++;
     return tmp;
   }
   tmp = tmp->next;
}

当然,在退出应用程序之前,您还应该释放分配的内存:
void freeList() {
  Node* ptr = head;
  Node* tmp = 0;
  while(ptr) {
    tmp = ptr->next;
    free(ptr->word);
    free(ptr);
    ptr = tmp;
  }

我已按照您的建议更新了OP,但仍然得到相同的结果。这是因为我没有初始化“count”吗? - Sleepless
@Sleepless - 是的,那可能是问题所在。看一下上面的代码,我正在将计数初始化为0。 - Cyclonecode
是的,我看到了你的编辑并在我的机器上尝试了一下(而且很晚才编辑了OP!),但仍然没有运气。另外,既然我们正在这个问题上,我应该在我的if (head == NULL)块中将count初始化为0,然后在块之后递增它吗? - Sleepless
@Sleepless - 按照上述更改代码对我来说很好用? - Cyclonecode
@Sleepless - 这里有一个带有可工作代码的链接 http://codeshare.io/5VPUo 不要忘记你应该释放已使用的内存,例如 free(ptr->word); free(ptr); 在退出程序之前,这应该对列表中的所有节点进行操作。 - Cyclonecode
1
非常感谢Cyclone的帮助——这是一次很好的学习经历! - Sleepless

1
你需要使用malloc和strcpy来存储单词,并使用strcmp进行比较。你正在保存对读取单词的缓冲区数组的重复引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接