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

gcc编译的词频统计程序运行触发Segmentation fault问题排查

解决C语言单词频率统计程序的段错误问题

问题描述

我编写了一段用于返回.txt文件中出现频率最高的前n个单词的C语言代码:

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

#define MAX_WORD_LENGTH 100
#define MAX_LINE_LENGTH 1000

struct WordFrequency {
    char word[MAX_WORD_LENGTH];
    int frequency;
};

char** find_frequent_words(const char* path, int32_t n) {
    FILE* file = fopen(path, "r");
    if (file == NULL) {
        fprintf(stderr, "Failed to open file: %s\n", path);
        return NULL;
    }

    // Create a hash table to count word frequencies
    struct WordFrequency* wordFrequencies = NULL;
    int uniqueWordCount = 0;
    int maxWordCount = 10000;

    char line[MAX_LINE_LENGTH];
    while (fgets(line, sizeof(line), file) != NULL) {
        char* word = strtok(line, " \t\n");
        while (word != NULL) {
            int existingIndex = -1;
            for (int i = 0; i < uniqueWordCount; i++) {
                if (strcmp(wordFrequencies[i].word, word) == 0) {
                    existingIndex = i;
                    break;
                }
            }

            if (existingIndex >= 0) {
                wordFrequencies[existingIndex].frequency++;
            } else {
                if (uniqueWordCount == maxWordCount) {
                    // Increase the size of the word frequencies array
                    maxWordCount *= 2;
                    struct WordFrequency* newWordFrequencies = realloc(
                        wordFrequencies, maxWordCount * sizeof(struct WordFrequency)
                    );
                    if (newWordFrequencies == NULL) {
                        fprintf(stderr, "Memory allocation failed.\n");
                        fclose(file);
                        free(wordFrequencies);
                        return NULL;
                    }
                    wordFrequencies = newWordFrequencies;
                }
                strncpy(wordFrequencies[uniqueWordCount].word, word, sizeof(wordFrequencies[uniqueWordCount].word) - 1);
                wordFrequencies[uniqueWordCount].word[sizeof(wordFrequencies[uniqueWordCount].word) - 1] = '\0';
                wordFrequencies[uniqueWordCount].frequency = 1;
                uniqueWordCount++;
            }

            word = strtok(NULL, " \t\n");
        }
    }

    fclose(file);

    // Sort word frequencies in descending order
    for (int i = 0; i < uniqueWordCount - 1; i++) {
        for (int j = 0; j < uniqueWordCount - i - 1; j++) {
            if (wordFrequencies[j].frequency < wordFrequencies[j + 1].frequency) {
                struct WordFrequency temp = wordFrequencies[j];
                wordFrequencies[j] = wordFrequencies[j + 1];
                wordFrequencies[j + 1] = temp;
            }
        }
    }

    // Create the result array with the most frequent words
    int resultCount = (n < uniqueWordCount) ? n : uniqueWordCount;
    char** frequentWords = malloc((resultCount + 1) * sizeof(char*));
    if (frequentWords == NULL) {
        fprintf(stderr, "Memory allocation failed.\n");
        free(wordFrequencies);
        return NULL;
    }

    for (int i = 0; i < resultCount; i++) {
        frequentWords[i] = strdup(wordFrequencies[i].word);
        if (frequentWords[i] == NULL) {
            fprintf(stderr, "Memory allocation failed.\n");
            for (int j = 0; j < i; j++) {
                free(frequentWords[j]);
            }
            free(frequentWords);
            free(wordFrequencies);
            return NULL;
        }
    }
    frequentWords[resultCount] = NULL;

    free(wordFrequencies);

    return frequentWords;
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <file_path> <n>\n", argv[0]);
        return 1;
    }

    const char* path = argv[1];
    int32_t n = atoi(argv[2]);
    if (n <= 0) {
        fprintf(stderr, "Invalid value for n: %s\n", argv[2]);
        return 1;
    }

    char** frequentWords = find_frequent_words(path, n);
    if (frequentWords == NULL) {
        return 1;
    }

    printf("The %d most frequent words:\n", n);
    for (int i = 0; frequentWords[i] != NULL; i++) {
        printf("%s\n", frequentWords[i]);
    }

    // Free the memory allocated for the frequentWords array and its elements
    for (int i = 0; frequentWords[i] != NULL; i++) {
        free(frequentWords[i]);
    }
    free(frequentWords);

    return 0;
}

使用以下命令编译并运行程序:

gcc -o frequent_words frequent_words.c
./frequent_words tiny_shakespeare.txt 5

运行时出现错误:

Segmentation fault (core dumped)

问题根源

段错误的核心原因是**wordFrequencies指针初始化为NULL,但第一次添加单词时未分配初始内存**:

  • 代码中struct WordFrequency* wordFrequencies = NULL;,当第一个单词处理时,uniqueWordCount为0,进入else分支,此时uniqueWordCount != maxWordCount(0≠10000),直接执行strncpy(wordFrequencies[uniqueWordCount].word, ...),但wordFrequencies是空指针,访问其成员会直接触发内存访问违规,导致段错误。

修复方案

在初始化wordFrequencies时,先分配初始大小的内存,并添加分配失败的判断:

// 修改原来的初始化代码
int maxWordCount = 10000;
struct WordFrequency* wordFrequencies = malloc(maxWordCount * sizeof(struct WordFrequency));
if (wordFrequencies == NULL) {
    fprintf(stderr, "Memory allocation failed.\n");
    fclose(file);
    return NULL;
}
int uniqueWordCount = 0;

额外优化提示

  • 当前代码用线性遍历检查单词是否存在,当文件中单词数量较多时效率极低,建议改用哈希表(比如基于链表的哈希桶)来优化查找速度。
  • 单词分割仅处理了空格、制表符和换行,未处理标点符号(如逗号、句号、引号),会导致类似"hello"和"hello,"被判定为不同单词,可在分割前先过滤或转换标点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:25:15