【问题标题】:Sorting array of structs in C using qsort使用 qsort 对 C 中的结构数组进行排序
【发布时间】:2021-07-16 15:24:00
【问题描述】:

让我们定义一个名为“Edge”的结构。

#include <stdio.h>
#include <stdlib.h>

struct Edge{
    int first;
    int second;
    float score;
};

struct Edge* newEdge(int first, int second, float score){
    struct Edge* edge = (struct Edge*)malloc(sizeof(struct Edge*));
    edge->first = first;
    edge->second = second;
    edge->score = score;
    return edge;
}

给定一个边数组,每个边由两个顶点和一个分数组成,我必须按分数的降序/升序对边进行排序。我写了一个比较器函数。以下是我尝试过的。但是,它不会产生正确的输出。

int comparator_function(const void *v1, const void *v2){
    struct Edge* e1 = (struct Edge*) v1;
    struct Edge* e2 = (struct Edge*) v2;
    if(e1->score < e2->score){
        return 1;
    }
    return 0;
}

int main(){
    struct Edge* edges[5];
    edges[0] = newEdge(1, 2, 1.23);
    edges[1] = newEdge(4, 3, 3.222);
    edges[2] = newEdge(2, 2, 5.222);
    edges[3] = newEdge(5, 1, 4.222);
    edges[4] = newEdge(3, 4, 2.4);
    for(int i=0;i<5;i++){
        printf("%d, %d, %f\n", edges[i]->first, edges[i]->second, edges[i]->score);
    }
    printf("\n\n");

    qsort(edges, 5, sizeof(struct Edge*), comparator_function);

    for(int i=0;i<5;i++){
        printf("%d, %d, %f\n", edges[i]->first, edges[i]->second, edges[i]->score);
    }
    return 0;
}

我得到的快速排序的输出是 -

4, 3, 3.222000
5, 1, 4.222000
2, 2, 5.222000
1, 2, 1.230000
3, 4, 2.400000

我不确定我的比较功能是否正确。任何帮助将不胜感激。

【问题讨论】:

    标签: c sorting struct


    【解决方案1】:

    首先是分配

        struct Edge* edge = (struct Edge*)malloc(sizeof(struct Edge*));
    

    错了。您必须为结构分配,而不是指针。

    应该是

        struct Edge* edge = malloc(sizeof(*edge));
    

        struct Edge* edge = malloc(sizeof(struct Edge));
    

    (还要注意malloc()的转换结果是considered as a bad practice

    那么,比较函数是错误的。

    • 当第一个元素比第二个元素“小”时,您必须返回 -1
    • 参数是指向元素的指针(在本例中为struct Edge*)。

    应该是这样的:

    int comparator_function(const void *v1, const void *v2){
        /* correct casting type and add dereferencing */
        struct Edge* e1 = *(struct Edge**) v1;
        struct Edge* e2 = *(struct Edge**) v2;
        if(e1->score < e2->score){
            return 1;
        }
        /* add this */
        if(e1->score > e2->score){
            return -1;
        }
        return 0;
    }
    

    【讨论】:

    • 感谢您的快速回复。 qsort 功能现在可以正常工作。但是,如果我在 malloc 之前不强制转换 struct Edge*,则会显示“从 'void*' 到 'Edge*' 的无效转换”的错误。有没有办法在不强制转换的情况下分配内存?
    • 看起来您正在将代码编译为 C++。使用 C 编译器编译 C 代码。 C源文件的扩展名应该是.c
    【解决方案2】:

    传递给qsort的比较函数应该返回:

    • 小于0,如果左边的值更小
    • 0,如果值相等
    • 大于0,如果左边的值更大

    您的比较函数只返回值 0 和 1,因此左参数不可能更大。您需要添加一个额外的案例来解决这个问题。

    另一个问题是,由于您的数组元素类型是 struct Edge *,传递给比较函数的指针将是 struct Edge ** 类型,因此您需要进行相关更改。

    int comparator_function(const void *v1, const void *v2){
        struct Edge * const *e1 = v1;
        struct Edge * const *e2 = v2;
        if((*e1)->score < (*e2)->score){
            return 1;
        } else if((*e1)->score > (*e2)->score){
            return -1;
        } else {
            return 0;
        }
    }
    

    另外,您没有分配适当的内存量:

    struct Edge* edge = (struct Edge*)malloc(sizeof(struct Edge*));
    

    这只是为指针分配空间,而不是整个结构。你想要:

    struct Edge* edge = malloc(sizeof(struct Edge));
    

    【讨论】:

    • 数组是struct Edge* edges[5];,所以qsort()的第三个参数应该是sizeof(struct Edge*)或者sizeof(*edges),而不是sizeof(struct Edge)
    • @MikeCAT 已修复,但发现了一些其他问题。
    • @dbush,感谢您的快速回复。 qsort 功能现在可以正常工作。但是,如果我没有在 malloc 之前强制转换 struct Edge*,则会显示“从 'void*' 到 'Edge*' 的无效转换”的错误。有没有办法在不强制转换的情况下分配内存?
    • @SaankhyaMondal C 允许在没有演员表的情况下向/从 void * 转换。如果您收到该错误,则意味着您正在使用 C++ 编译器进行编译。请改用 C 编译器。
    猜你喜欢
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 2016-09-02
    • 1970-01-01
    相关资源
    最近更新 更多