Reputation: 269
Now, I have seen various examples, but I don't get what they mean.
Here's my structure
typedef struct profile{
char gender[1];
double soc;
. . .
} PROFILE;
where soc is social security number that I'm going to be sorting by.
I know you need a compare function, but I don't know how to come up with the exact thing I need.
Upvotes: 25
Views: 92197
Reputation: 441
Here is an example of using qsort
for an array of structs in C
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int price;
int id;
} order;
int compare(const void *a, const void *b) {
order *orderA = (order *)a;
order *orderB = (order *)b;
return (orderB->price - orderA->price);
}
int main() {
order list[6];
srand(time(NULL));
printf("Before sorting\n");
for (int i = 0; i < 6; i++) {
list[i].price = rand() % 10;
list[i].id = i;
printf("Order id = %d Price = %d\n", list[i].id, list[i].price);
}
qsort(list, 6, sizeof(order), compare);
printf("AFTER sorting\n");
for (int n = 0; n < 6; n++) {
printf("Order id = %d Price = %d\n", list[n].id, list[n].price);
}
return 0;
}
Upvotes: 40
Reputation: 300559
Your Soc
should almost certainly not be of type double
, but anyway here's an example of what a compare function needs to return:
int compare(const void *p1, const void *p2)
{
const struct profile *elem1 = p1;
const struct profile *elem2 = p2;
if (elem1->soc < elem2->soc)
return -1;
else if (elem1->soc > elem2->soc)
return 1;
else
return 0;
}
Thanks for pointing out the const void *.
Here is a complete example (archived): Sorting Structures with the C qsort() Function
Upvotes: 14
Reputation: 144750
To sort the array, use qsort()
and pass a comparison function.
Here is one that produces the correct result for all possible values of the price
member:
typedef struct profile {
char gender[1];
double soc;
int price;
...
} PROFILE;
int compare_price(const void *a, const void *b) {
const PROFILE *oa = a;
const PROFILE *ob = b;
return (oa->price > ob->price) - (oa->price < ob->price);
}
int compare_soc(const void *a, const void *b) {
const PROFILE *oa = a;
const PROFILE *ob = b;
return (oa->soc > ob->soc) - (oa->soc < ob->soc);
}
Notes:
the simple subtraction of values produces incorrect results if the difference does not fit in the int
type. For example -2
and INT_MAX
cannot be correctly compared with the subtraction method. It would not work for floating point values either.
the above method can be used for all comparable types, including double
except for NaN
.
If you wish to handle NaN
, here is how to group them at the end:
#include <math.h>
int compare_soc_nan_at_the_end(const void *a, const void *b) {
const PROFILE *oa = a;
const PROFILE *ob = b;
if (isnan(oa->soc)) {
return isnan(ob->soc) ? 0 : 1;
} else
if (isnan(ob->soc)) {
return -1;
} else {
return (oa->soc > ob->soc) - (oa->soc < ob->soc);
}
}
Upvotes: 4
Reputation: 753805
The strict version of a comparator takes two constant void pointers:
int compare(const void *v1, const void *v2)
{
const struct profile *p1 = v1;
const struct profile *p2 = v2;
if (p1->gender > p2->gender)
return(+1);
else if (p1->gender < p2->gender)
return(-1);
else if (p1->soc > p2->soc)
return(+1);
else if (p1->soc < p2->soc)
return(-1);
else
return(0);
}
This compares the gender field first, then the soc field. This is how you handle any multipart comparison.
Upvotes: 8