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

如何修复qsort比较器引发的段错误问题

解决qsort调用导致的段错误问题

我来帮你排查代码里的几个关键问题,正是这些问题触发了段错误:

1. qsort的元素个数参数完全错误

你用int i = sizeof(AllRecords);把数组总字节数传给了qsort的第二个参数,但qsort的第二个参数需要的是元素的数量,不是总字节数。sizeof(AllRecords)得到的是file_size * 100,而实际有效的元素个数是你计算的number_of_records = file_size / 100。用错误的元素个数会让qsort访问超出数组范围的内存,直接触发段错误。

2. fread的参数顺序错误

fread的调用格式是fread(ptr, 单个元素大小, 元素数量, 流),你现在写的fread(AllRecords, 100, file_size, file)会尝试读取file_size个100字节的元素,总共要读100*file_size字节,远超过文件实际大小,会导致数组越界写入,破坏栈内存。正确的应该是用number_of_records作为要读取的元素个数。

3. 栈上分配过大数组的风险

char AllRecords[file_size][100];是在栈上分配数组,栈的空间通常只有几MB(比如Linux下默认是8MB),如果你的文件比较大(比如超过80KB,8MB/100=81920),就会触发栈溢出,直接导致段错误。应该用动态内存分配(malloc/calloc)来分配堆内存,避免栈溢出。

4. compare函数的类型转换问题

qsort传给compare函数的r1和r2是指向数组元素的指针(也就是char (*)[100]类型),直接传给strcmp(需要const char*)最好显式转换,避免类型不匹配导致的未定义行为。


修正后的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sort.h"

// 正确的compare函数:显式转换为const char*
int compare(const void *r1, const void *r2) {
    return strcmp((const char*)r1, (const char*)r2);
}

int main(int argc, char *argv[]) {
    // 检查命令行参数是否足够
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *file = fopen(argv[1], "r");
    if (!file) {
        perror("Failed to open input file");
        exit(EXIT_FAILURE);
    }

    struct stat fs;
    if (stat(argv[1], &fs) == -1) {
        perror("Failed to get file stats");
        fclose(file);
        exit(EXIT_FAILURE);
    }

    int file_size = fs.st_size;
    int number_of_records = file_size / 100;
    // 检查文件大小是否是100的整数倍,避免处理不完整记录
    if (file_size % 100 != 0) {
        fprintf(stderr, "File size is not a multiple of 100 bytes\n");
        fclose(file);
        exit(EXIT_FAILURE);
    }

    // 动态分配堆内存,避免栈溢出
    char (*AllRecords)[100] = malloc(number_of_records * sizeof(*AllRecords));
    if (!AllRecords) {
        perror("Failed to allocate memory");
        fclose(file);
        exit(EXIT_FAILURE);
    }

    // 正确读取number_of_records个100字节的元素
    size_t read_count = fread(AllRecords, 100, number_of_records, file);
    if (read_count != number_of_records) {
        fprintf(stderr, "Failed to read all records\n");
        free(AllRecords);
        fclose(file);
        exit(EXIT_FAILURE);
    }
    fclose(file);

    // qsort参数:元素个数是number_of_records,每个元素大小100字节
    qsort(AllRecords, number_of_records, 100, compare);

    FILE *file2 = fopen(argv[2], "w");
    if (!file2) {
        perror("Failed to open output file");
        free(AllRecords);
        exit(EXIT_FAILURE);
    }

    // 写入正确数量的元素
    size_t write_count = fwrite(AllRecords, 100, number_of_records, file2);
    if (write_count != number_of_records) {
        fprintf(stderr, "Failed to write all records\n");
        free(AllRecords);
        fclose(file2);
        exit(EXIT_FAILURE);
    }
    fclose(file2);

    // 释放动态分配的内存,避免内存泄漏
    free(AllRecords);
    return EXIT_SUCCESS;
}

额外的改进点

  • 增加了命令行参数检查,避免用户输入错误
  • 增加了文件打开、stat、malloc等操作的错误处理,让程序更健壮
  • 检查文件大小是否是100的整数倍,避免处理不完整的记录
  • 使用EXIT_SUCCESS/EXIT_FAILURE替代魔法数字,代码更易读
  • 释放了动态分配的内存,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:53:09