Need help sorting an array of structures in C using qsort

天涯浪子 提交于 2020-01-05 05:45:08

问题


I have this struct.

struct Transport
{
   int id;
   float Price;
};

Here I read the data into and array of structs.

void read (struct Transport **Car, int *m)
{
    int i;
    printf("Insert total number of cars: ");
    scanf("%d",m);
    *Car=(struct Transport*) malloc ((*m)*3*sizeof(struct Transport));               

    for(i=1; i<=*m; i++)
    {
       (*Car)[i].id=i;
       printf("Price: ");
       scanf("%f",&(*Car)[i].Price);
       printf("\n");
    }
}

And here is the display function.

void display(struct Transport *Car,int m)
{
    int i;
    for(i=1; i<=m; i++)
    {
        printf("Entry #%d: \n",i);
        printf("Price: %2.2f\n",(Car+i)->Price);
        printf("\n");
    }
}

Now here is the problem.I must sort the data by the Price field. So far I've tried this, but it does nothing.

int struct_cmp_by_price(const void *a, const void *b)
{
    struct Transport *ia = (struct Transport *)a;
    struct Transport *ib = (struct Transport *)b;
    return (int)(100.f*ia->Price - 100.f*ib->Price);
}

Here is how the main looks like.

int main()
{
    int m;
    struct Transport *Car;
    read(&Car,&m);
    qsort(Car, m, sizeof(struct Transport), struct_cmp_by_price);
    display(Car,m);
    return 0;
}

Can anyone help me?


回答1:


There are multiple problems in your code:

  • You allocate too much memory in read(), and you do not need to cast the return value of malloc() in C, but you should check for allocation failure. you should instead use:

    *Car = calloc(*m, sizeof(struct Transport));
    if (*Car == NULL) {
        fprintf(stderr, "cannot allocate memory for %d structures\n", *m);
        exit(1);
    }
    
  • You should not use read as a function name because it is the name of a system call and may conflict with the standard library use of that function. Use readTransport.

  • indexes are 0 based in C. Instead of for(i=1; i<=*m; i++), use:

    for (i = 0; i < *m; i++)
    
  • The comparison function cannot use the subtraction trick. As a matter of fact, the subtraction trick can only be used for integer types smaller than int. Use this instead:

    int struct_cmp_by_price(const void *a, const void *b) {
        const struct Transport *ia = a;
        const struct Transport *ib = b;
        return (ia->Price > ib->Price) - (ia->Price < ib->Price);
    }
    
  • You should test the return value of scanf() to detect invalid input. The Price members are left uninitialized in case of conversion failure, which leads to undefined behavior, unless you use calloc(), but the result is still meaningless.




回答2:


You can also try using two separate structs, to make pointer operations easier to handle.

Something like this gives the right idea:

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

typedef struct {
    int id;
    float price;
} transport_t;

typedef struct {
    transport_t *Cars;
    int numcars;
} Cars_t;

Cars_t *initialize_struct(void);
void read(Cars_t *Car);
void display(Cars_t *Car);
int price_cmp(const void *x, const void *y);

int 
main(void) {
    Cars_t *Car;

    Car = initialize_struct();

    read(Car);

    printf("Before:\n");
    display(Car);

    qsort(Car->Cars, Car->numcars, sizeof(transport_t), price_cmp);

    printf("\nAfter:\n");
    display(Car);

    free(Car->Cars);
    free(Car);

    return 0;
}

void
read(Cars_t *Car) {
    int i, count = 0;

    printf("Insert total number of cars: ");
    if (scanf("%d", &(Car->numcars)) != 1) {
        printf("Invalid entry\n");
        exit(EXIT_FAILURE);
    }

    Car->Cars = calloc(Car->numcars, sizeof(transport_t));
    if (Car->Cars == NULL) {
        fprintf(stderr, "Issue allocating memory for %d members", Car->numcars);
        exit(EXIT_FAILURE);
    }

    for (i = 1; i <= Car->numcars; i++) {
        Car->Cars[count].id = i;
        printf("Car id %d\n", Car->Cars[count].id);

        printf("Price: ");
        scanf("%f", &(Car->Cars[count].price));

        count++;

        printf("\n");
    }
}

void
display(Cars_t *Car) {
    int i;

    for (i = 0; i < Car->numcars; i++) {
        printf("Car id: %d, Car price: %2.2f\n", 
                Car->Cars[i].id, Car->Cars[i].price);
    }
}

Cars_t
*initialize_struct(void) {
    Cars_t *Car;

    Car = malloc(sizeof(*Car));
    if (Car == NULL) {
        fprintf(stderr, "%s", "Issue allocating memory for structure");
        exit(EXIT_FAILURE);
    }

    Car->Cars = NULL;
    Car->numcars = 0;

    return Car;
} 

int
price_cmp(const void *x, const void *y) {
    const transport_t *car1 = x;
    const transport_t *car2 = y;

    if (car1->price > car2->price) {
        return +1;
    } else if (car1->price < car2->price) {
        return -1;
    }
    return 0;
}


来源:https://stackoverflow.com/questions/40876657/need-help-sorting-an-array-of-structures-in-c-using-qsort

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!