Reputation: 19
int compare (const void * a, const void * b)
{
return ( (int) (*(float*)a - *(float*)b) );
}
When I want to use qsort
function, I should write a compare function in this form as I understood. So, why we are using void before the parameters of compare function?
And, is this compare function standard with its parameters and code in curly braces or can we simply change the code and even parameters through our wishes?
Upvotes: 1
Views: 786
Reputation: 11648
qsort
is using a callback
that allows you to use arbitrary datatypes and then inside the comparator you can sort them any way you please. You just need to adhere to the API.
This provides a lot of flexibility. The code below is a simplified example but it could have been extended to sort arbitrary data structures easily. In all cases the same qsort
function is used ie the very same function at the same address is called.
The following contrived example might help to understand why it's flexible. Note, instead of int
the comparator func_table
could be extended to be a table of structures where each one has a comparator type. To reiterate, the same qsort function is called in each case, its the callback functions address that changes to the correct function required to sort the data at runtime.
The following program sorts an array in a random direction where the sort function is chosen from a table.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int values[] = { 3 , 88 , 52 , 285, 63 , 288 , 576 , 10, 21 , 5,343 , 38 , 55 , 100, 552 , 85 };
typedef int (*comparator)(const void * a, const void * b);
int cmp_reverse(const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}
int cmp_int(const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
static comparator func_table[2];
int main(void) {
srand(time(NULL));
size_t int_arr_size = ARRAY_SIZE(values);
int n = 0;
int i = 0;
func_table[0] = cmp_int;
func_table[1] = cmp_reverse;
while(i++ < 10) {
int order = rand() % 2 == 0;
printf("order: %d %s ", order, order == 0 ? ">" : "<");
qsort(values, int_arr_size, sizeof(int), func_table[order]);
for( n = 0 ; n < int_arr_size; n++ ) {
printf("%d ", values[n]);
}
printf("<\n");
}
return 0;
}
Upvotes: 0
Reputation: 24
The reason why void pointers are used is because they can be cast into other pointer types and then back into void pointers without any issues.
Upvotes: 0
Reputation: 1341
No, you can not change the parameters or the return type. But of course you can change the 'code' of the function. You can compare whatever you want. The only important thing is the return value:
The return value should be <0
if the first passed parameter is 'lower' than the second, == 0
if both are identic or >0
if the first one is 'greater'.
For example you could use a qsort function with strings like this:
int compare (const void * a, const void * b)
{
return strcmp((char *) a, (char *) b);
}
Upvotes: 2
Reputation: 837
In C void *
means that you can store a pointer of any type in it. Imagine that you wanted to sort a list of strings(char *), what would you do? Write one implementation of qsort
for int
data type and one for char *
? Here, qsort
is written using void *
to allow you to compare different stuff with different types.
Yes, the parameter type is standard. See the definition of it in stdlib.h
.
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Upvotes: 1