如何避免unscramble命令行程序运行时出现段错误?
C语言unscramble程序段错误问题排查与修复
程序功能说明
我编写了一个名为unscramble的C程序,用于读取Jumbled.txt和dictionary.txt两个文件,找出字符组成完全相同的单词。示例输入输出如下:
示例输入
Jumbled.txt:
Hello Wassup Rigga Boyka Popeye
dictionary.txt:
olleH Yello elloH lloeH aggiR ggiRa giRag yokaB Bakoy kaBoy eyePop poePye
示例输出
Hello: olleH elloH lloeH Wassup: NO MATCHES Rigga: aggiR ggiRa giRag Boyka: yokaB Bakoy kaBoy Popeye: eyePop poePye
原程序代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_WORD_LENGTH 50 #define MAX_NUM_WORDS 500000 int compare_char(const void *a, const void *b) { return *(char*)a - *(char*)b; } void sort_word(char *word) { qsort(word, strlen(word), sizeof(char), compare_char); } int is_valid_word(char *jumbled_word, char *word) { char sorted_jumbled_word[MAX_WORD_LENGTH]; char sorted_word[MAX_WORD_LENGTH]; strcpy(sorted_jumbled_word, jumbled_word); strcpy(sorted_word, word); sort_word(sorted_jumbled_word); sort_word(sorted_word); return strcmp(sorted_jumbled_word, sorted_word) == 0; } int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: unscramble <dictionary> <jumbles>\n"); exit(1); } char *dict_filename = argv[1]; char *jumbles_filename = argv[2]; char dictionary[MAX_NUM_WORDS][MAX_WORD_LENGTH]; int num_words = 0; FILE *dict_file = fopen(dict_filename, "r"); if (dict_file == NULL) { printf("Error: Could not open dictionary file %s\n", dict_filename); exit(1); } char line[MAX_WORD_LENGTH]; while (fgets(line, sizeof(line), dict_file) != NULL) { // Remove trailing newline character line[strcspn(line, "\n")] = '\0'; // Copy word into dictionary strcpy(dictionary[num_words], line); num_words++; } fclose(dict_file); // Loop over jumbled words file FILE *jumbles_file = fopen(jumbles_filename, "r"); if (jumbles_file == NULL) { printf("Error: Could not open jumbled words file %s\n", jumbles_filename); exit(1); } while (fgets(line, sizeof(line), jumbles_file) != NULL) { line[strcspn(line, "\n")] = '\0'; char sorted_word[MAX_WORD_LENGTH]; strcpy(sorted_word, line); sort_word(sorted_word); int found_match = 0; for (int i = 0; i < num_words; i++) { if (is_valid_word(sorted_word, dictionary[i])) { if (!found_match) { printf("%s:", line); found_match = 1; } printf(" %s", dictionary[i]); } } if (!found_match) { printf("%s: NO MATCHES", line); } printf("\n"); } fclose(jumbles_file); return 0; }
运行错误
编译并运行程序后出现段错误:
xxxxxxxxx@LAPTOP-xxxxxxxx:~$ gcc -Wall -W -pedantic -o unscramble unscramble.c xxxxxxxxx@LAPTOP-xxxxxxxx:~$ ./unscramble dictionary.txt Jumbled.txt Segmentation fault xxxxxxxxx@LAPTOP-xxxxxxxx:~$
问题根源
- 栈溢出:原程序在栈上声明了巨型二维数组
char dictionary[MAX_NUM_WORDS][MAX_WORD_LENGTH],计算可得该数组占用25MB内存,而系统默认栈大小通常仅为8MB左右,直接导致栈溢出触发段错误。 - 数组越界风险:读取字典时未限制
num_words不超过MAX_NUM_WORDS,若字典单词数超过上限会越界访问数组。 - 缓冲区溢出风险:使用
strcpy复制字符串时未检查长度,可能导致缓冲区溢出。 - const缺失:函数参数未添加
const修饰,不符合const正确性原则。
修改后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_WORD_LENGTH 50 #define MAX_NUM_WORDS 500000 int compare_char(const void *a, const void *b) { return *(const char*)a - *(const char*)b; } void sort_word(char *word) { qsort(word, strlen(word), sizeof(char), compare_char); } int is_valid_word(const char *jumbled_word, const char *word) { char sorted_jumbled_word[MAX_WORD_LENGTH]; char sorted_word[MAX_WORD_LENGTH]; strcpy(sorted_jumbled_word, jumbled_word); strcpy(sorted_word, word); sort_word(sorted_jumbled_word); sort_word(sorted_word); return strcmp(sorted_jumbled_word, sorted_word) == 0; } int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: unscramble <dictionary> <jumbles>\n"); return 1; } char *dict_filename = argv[1]; char *jumbles_filename = argv[2]; char (*dictionary)[MAX_WORD_LENGTH] = malloc(MAX_NUM_WORDS * sizeof(*dictionary)); if(!dictionary) { printf("Error: malloc failed\n"); return 1; } int num_words = 0; FILE *dict_file = fopen(dict_filename, "r"); if (dict_file == NULL) { printf("Error: Could not open dictionary file %s\n", dict_filename); return 1; } char line[MAX_WORD_LENGTH]; while (fgets(line, sizeof(line), dict_file) != NULL && num_words < MAX_NUM_WORDS) { // Remove trailing newline character line[strcspn(line, "\n")] = '\0'; // Copy word into dictionary safely strncpy(dictionary[num_words], line, MAX_WORD_LENGTH - 1); dictionary[num_words][MAX_WORD_LENGTH - 1] = '\0'; num_words++; } fclose(dict_file); // Loop over jumbled words file FILE *jumbles_file = fopen(jumbles_filename, "r"); if (jumbles_file == NULL) { printf("Error: Could not open jumbled words file %s\n", jumbles_filename); return 1; } while (fgets(line, sizeof(line), jumbles_file) != NULL) { // Remove trailing newline character line[strcspn(line, "\n")] = '\0'; if (strlen(line) > MAX_WORD_LENGTH - 1) { printf("Error: Jumbled word %s is too long\n", line); continue; } char sorted_word[MAX_WORD_LENGTH]; strcpy(sorted_word, line); sort_word(sorted_word); int found_match = 0; for (int i = 0; i < num_words; i++) { if (is_valid_word(sorted_word, dictionary[i])) { if (!found_match) { printf("%s:", line); found_match = 1; } printf(" %s", dictionary[i]); } } if (!found_match) { printf("%s: NO MATCHES", line); } printf("\n"); } fclose(jumbles_file); free(dictionary); return 0; }
关键修改点
- 栈转堆分配:用
malloc在堆上分配字典数组,避免栈溢出,使用后用free释放内存防止泄漏。 - 限制单词数量:读取字典时增加
num_words < MAX_NUM_WORDS判断,避免数组越界。 - 安全字符串复制:替换
strcpy为strncpy,手动添加字符串结束符,防止缓冲区溢出。 - const正确性:修改函数参数为
const char*,明确参数不会被修改,提升代码健壮性。 - 长度检查:读取乱序单词时检查长度是否超过上限,避免后续处理出错。
内容的提问来源于stack exchange,提问作者Deezel
相关产品推荐
相关产品推荐

