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

如何正确调用归并排序函数对C语言结构体数组排序?

归并排序适配结构体数组的问题解决

咱们来一步步拆解你遇到的问题,以及如何彻底解决它:

核心问题根源

你原来的merge_sort和merge函数是为指针数组(void**)设计的——它默认数组里存的是指向数据的指针,排序时交换的是指针地址。但你实际要排序的是连续存储的结构体数组(row_t*),数组里直接存的是row_t结构体本身。强行把row_t*转成void**传入,会让函数把结构体的二进制数据当成指针地址来操作,直接触发非法内存访问,导致程序崩溃退出。

另外你最初的比较函数还有个隐藏bug:return ra->S - rb->S用在double类型上会出错——如果两个S的差值是小数(比如0.2),转成int会被截断为0,函数会误判这两个元素相等,这也是你后续遇到段错误的潜在诱因。

适配结构体数组的归并排序实现

要直接排序连续的结构体数组,我们需要修改归并排序函数,让它能根据元素大小来拷贝整个结构体(而不是指针)。修改后的函数需要接收单个元素的大小作为参数:

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

// 归并操作:处理连续内存的数组元素
void merge(void* array, int n, int mid, size_t elem_size, int cmp(const void*, const void*)) {
    // 分配临时内存存储合并后的结果
    void* tmp = malloc(n * elem_size);
    if (!tmp) return; // 内存分配失败的安全处理
    
    // 用char*来按字节精准访问数组元素
    char* arr = (char*)array;
    char* left = arr;
    char* right = arr + mid * elem_size;
    char* tmp_ptr = (char*)tmp;
    
    int i = 0, j = 0;
    const int left_size = mid;
    const int right_size = n - mid;
    
    // 合并两个有序子数组
    while (i < left_size && j < right_size) {
        if (cmp(left + i * elem_size, right + j * elem_size) <= 0) {
            memcpy(tmp_ptr, left + i * elem_size, elem_size);
            i++;
        } else {
            memcpy(tmp_ptr, right + j * elem_size, elem_size);
            j++;
        }
        tmp_ptr += elem_size;
    }
    
    // 拷贝左半部分剩余元素
    memcpy(tmp_ptr, left + i * elem_size, (left_size - i) * elem_size);
    // 拷贝右半部分剩余元素
    tmp_ptr += (left_size - i) * elem_size;
    memcpy(tmp_ptr, right + j * elem_size, (right_size - j) * elem_size);
    
    // 将合并后的结果覆盖回原数组
    memcpy(array, tmp, n * elem_size);
    
    free(tmp);
}

void merge_sort(void* array, int n, size_t elem_size, int cmp(const void*, const void*)) {
    if (n > 1) {
        int mid = n / 2;
        // 递归排序左半部分
        merge_sort(array, mid, elem_size, cmp);
        // 递归排序右半部分:通过elem_size计算右半部分的起始地址
        merge_sort((char*)array + mid * elem_size, n - mid, elem_size, cmp);
        // 合并两个有序子数组
        merge(array, n, mid, elem_size, cmp);
    }
}

正确的调用方式与比较函数

修正后的比较函数

对于double类型的比较,绝对不能直接用差值转int,应该用逻辑判断返回标准的1/-1/0:

int row_array_s_comp(const void* a, const void* b) {
    const row_t* ra = (const row_t*)a;
    const row_t* rb = (const row_t*)b;
    // 标准浮点比较逻辑:大于返回1,小于返回-1,等于返回0
    return (ra->S > rb->S) - (ra->S < rb->S);
}

正确的函数调用

传入结构体数组指针、元素总数、单个结构体的大小,以及比较函数:

// 分配100个row_t的内存
row_t* linear_row_arr = (row_t*)malloc(sizeof(row_t)*100);
// 先给linear_row_arr的每个元素赋值(比如填充rho、u、v、S等字段)...

// 调用归并排序
merge_sort(linear_row_arr, 100, sizeof(row_t), row_array_s_comp);

关于你之前的错误尝试

你之前用merge_sort(linear_row_arr, 100, sizeof(row_t*), row_array_s_comp)导致段错误,是因为传入了sizeof(row_t*)(指针大小,通常8字节)而非sizeof(row_t)(结构体实际大小),这会让函数在拷贝元素时只操作了部分结构体数据,破坏了内存结构,最终引发段错误——和malloc/calloc无关,calloc只是初始化内存为0,不影响这里的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:43:45