c# 链表在第二次迭代中打印符号而不是单词

g6baxovj  于 2023-09-28  发布在  C#
关注(0)|答案(1)|浏览(211)

我是一个C语言的初学者,所以我知道我的代码可能看起来像垃圾。我想做的就是用一个结构体做一个链表,这个结构体包含一个字符数组和int作为频率。它从测试文件中读取行并简单地打印出文件。它正确地读取文件,第一次遍历链表并正确地打印出来。然而,在链表的第二次迭代中,它打印出正确的行数和正确的整数,但单词被符号取代。我到处都找过了,我只是需要一些帮助。这是我的代码。

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

#define Word_MAX_LENGTH 255

struct WordFreq
{
    char word[Word_MAX_LENGTH];
    int frequency;
    struct WordFreq *next;
} WordFreq;

struct WordFreq *head = NULL;

void insert(struct WordFreq *newNode)
{
    if (head == NULL)
    {
        head = newNode;
        newNode->next = NULL;
        return;
    }

    struct WordFreq *current = head;

    while (current->next != NULL)
    {
        current = current->next;
    }

    current->next = newNode;
    newNode->next = NULL;
}

void main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Please run as %s [filename]\n", argv[0]);
        return;
    }

    FILE *f;
    f = fopen(argv[1], "r");

    if (f == NULL)
    {
        printf("File (%s) does not exist\n", argv[1]);
        return;
    }

    struct WordFreq *line = malloc(sizeof(struct WordFreq));

    if (line == NULL)
    {
        printf("Cannot do dynamic memory managment\n");
        return;
    }

    printf("File content in %s:\n", argv[1]);

    while (fscanf(f, "%s %d", line->word, &(line->frequency)) != EOF)
    {
        printf("%s %d\n", line->word, line->frequency);

        insert(line);

        line = malloc(sizeof(struct WordFreq));

        if (line == NULL)
        {
            printf("Cannot do dynamic memory management");
            return;
        }
    }
    fclose(f);

    // To keep head intact for sorting portion
    struct WordFreq *current = head;
    
    printf("\nContent of linked list:\n");

    while (current != NULL)
    {
        printf("%s %d\n", current->word, current->frequency);
        struct WordFreq *temp = current;
        current = current->next;

        free(temp);
    }
    
    printf("\n\n\n");
    current = head; 
    while (current != NULL)
    {
        printf("%s %d\n", current->word, current->frequency);
        current = current->next;
    }
    free(current);
    free(line);
}

非常感谢任何帮助。很遗憾,我已经编程了一段时间,但我想学习C,因为我想了解程序为什么要做它们所做的事情,以帮助未来的努力。

wpx232ag

wpx232ag1#

在第一次迭代中释放了链表,所以第二次迭代具有未定义的行为,因为head已成为无效指针,并且列表节点的内存内容已更改。从它们阅读具有未定义的行为,任何事情都可能发生,包括程序因无效的内存访问或随机输出而停止。
你应该写函数:一个用于打印列表内容,另一个用于释放列表。将这些操作组合在一起会造成混乱,并导致像下面这样的逻辑错误。
还要注意这些备注:

  • main的返回类型是int。修改return语句,在错误时返回1,在成功时返回0,即:正常运行。
  • printf("File (%s) does not exist\n", argv[1])可能不是正确的诊断:该文件可能存在,但fopen将失败,如果该进程没有适当的访问权限。您可以使用errno并输出相应的错误消息:
#include <errno.h>
 #include <string.h>

 [...]

     if (f == NULL) {
         fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
         return 1;
     }
  • 而不是fscanf(f, "%s %d", line->word, &(line->frequency)) != EOF,您应该在执行以下两种转换时测试fscanf()是否成功:它应该返回2。更好的是:使用fgets一次读取一行输入,然后使用sscanf()转换行内容,并使用包含违规输入行的显式消息报告转换错误。
  • head被释放两次:free(current)在结束时必须删除。

以下是修改后的版本:

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

#define WORD_MAX_LENGTH 255

struct WordFreq {
    char word[WORD_MAX_LENGTH];
    int frequency;
    struct WordFreq *next;
} WordFreq;

struct WordFreq *head = NULL;

void insert(struct WordFreq *newNode) {
    if (head == NULL) {
        head = newNode;
    } else {
        struct WordFreq *current = head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
    }
    newNode->next = NULL;
}

void print_list(const struct WordFreq *node) {
    while (node != NULL) {
        printf("%s %d\n", node->word, node->frequency);
        node = node->next;
    }
}

void free_list(struct WordFreq *node) {
    while (node != NULL) {
        struct WordFreq *temp = node;
        node = node->next;
        free(temp);
    }
}

int main(int argc, char *argv[]) {
    char line[WORD_MAX_LENGTH + 20];

    if (argc != 2) {
        fprintf(stderr, "Please run as %s [filename]\n", argv[0]);
        return 1;
    }

    FILE *f = fopen(argv[1], "r");
    if (f == NULL) {
        fprintf(stderr, "Cannot open %s: %s\n", argv[1], strerror(errno));
        return 1;
    }

    printf("File content in %s:\n", argv[1]);

    while (fgets(line, sizeof line, f)) {
        struct WordFreq *node = malloc(sizeof(*node));
        if (node == NULL) {
            fprintf(stderr, "Cannot allocate node for %s\n", line);
            fclose(f);
            return 1;
        }
        if (sscanf(line, "%254s %d", node->word, &node->frequency) == 2) {
            printf("%s %d\n", node->word, node->frequency);
            insert(node);
        } else {
            fprintf(stderr, "invalid line: %s\n", line);
            free(node);
        }
    }
    fclose(f);

    printf("\nContent of linked list:\n");

    print_list(head);
    // ...
    free_list(head);
    return 0;
}

相关问题