You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言链表二次遍历打印符号而非单词的问题求助

链表二次遍历单词显示异常问题

我是C语言初学者,代码可能不够规范。我想实现一个链表,节点结构体包含char数组(存储单词)和int类型的frequency(频率)。程序从测试文件读取内容并打印,第一次读取文件和遍历链表均正常,但第二次遍历链表时,行数和整数频率正确,单词却被符号替代。附上代码寻求帮助。我有一定编程基础,学C是为了深入理解程序运行底层逻辑,助力后续开发。

#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");
    current = head; 
    while (current != NULL)
    {
        printf("%s %d\n", current->word, current->frequency);
        current = current->next;
    }
    free(current);
    free(line);
}

问题根源

你在第一次遍历链表时,已经通过free(temp)把所有节点的内存都释放了,此时head指向的是已经被系统回收的内存区域,属于野指针。第二次遍历访问的是已释放的内存,word数组的内容被系统覆盖所以显示乱码;frequency数值正确只是巧合,属于未定义行为。

修复方案

  1. 移除第一次遍历的free操作:如果后续还要使用链表,不能提前释放节点。
  2. 调整内存释放时机:在最后一次遍历完成后,再逐个释放所有链表节点,避免内存泄漏。
  3. 修正main函数返回类型:C标准中main返回类型应为int,而非void。
  4. 清理多余的free调用:free(current)是多余的(最后current为NULL),最后一次malloc的空节点line需要在循环结束后释放。

修复后的代码示例

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

#define Word_MAX_LENGTH 255

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

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;
}

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

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

    struct WordFreq *line = malloc(sizeof(struct WordFreq));
    if (line == NULL)
    {
        printf("Cannot do dynamic memory management\n");
        fclose(f);
        return 1;
    }

    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\n");
            fclose(f);
            // 此处可添加已插入节点的释放逻辑,避免内存泄漏
            return 1;
        }
    }
    fclose(f);
    free(line); // 释放最后一次malloc的空节点

    // 第一次遍历链表
    struct WordFreq *current = head;
    printf("\nContent of linked list:\n");
    while (current != NULL)
    {
        printf("%s %d\n", current->word, current->frequency);
        current = current->next;
    }

    // 第二次遍历链表
    printf("\n\nSecond traversal of linked list:\n");
    current = head;
    while (current != NULL)
    {
        printf("%s %d\n", current->word, current->frequency);
        current = current->next;
    }

    // 最后释放所有链表节点
    current = head;
    while (current != NULL)
    {
        struct WordFreq *temp = current;
        current = current->next;
        free(temp);
    }
    head = NULL; // 清空头指针,避免野指针

    return 0;
}

额外注意事项

  • 野指针是C语言常见错误,访问已释放内存属于未定义行为,结果不可预测,必须避免。
  • 内存管理要配对:每个malloc对应一个free,既不能泄漏也不能重复释放。
  • 原结构体定义后的WordFreq是多余的全局变量,建议移除。

内容的提问来源于stack exchange,提问作者dirthogger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:53:22