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
相关产品推荐
相关产品推荐

