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

如何避免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:~$ 

问题根源

  1. 栈溢出:原程序在栈上声明了巨型二维数组char dictionary[MAX_NUM_WORDS][MAX_WORD_LENGTH],计算可得该数组占用25MB内存,而系统默认栈大小通常仅为8MB左右,直接导致栈溢出触发段错误。
  2. 数组越界风险:读取字典时未限制num_words不超过MAX_NUM_WORDS,若字典单词数超过上限会越界访问数组。
  3. 缓冲区溢出风险:使用strcpy复制字符串时未检查长度,可能导致缓冲区溢出。
  4. 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;
}

关键修改点

  1. 栈转堆分配:用malloc在堆上分配字典数组,避免栈溢出,使用后用free释放内存防止泄漏。
  2. 限制单词数量:读取字典时增加num_words < MAX_NUM_WORDS判断,避免数组越界。
  3. 安全字符串复制:替换strcpy为strncpy,手动添加字符串结束符,防止缓冲区溢出。
  4. const正确性:修改函数参数为const char*,明确参数不会被修改,提升代码健壮性。
  5. 长度检查:读取乱序单词时检查长度是否超过上限,避免后续处理出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:31:06