I am making C dynamic array library, kind of. Note that I'm doing it for fun in my free time, so please do not recommend million of existing libraries.
I started implementing sorting. The array is of arbitrary element size, defined as struct:
typedef struct {
//[PRIVATE] Pointer to array data
void *array;
//[READONLY] How many elements are in array
size_t length;
//[PRIVATE] How many elements can further fit in array (allocated memory)
size_t size;
//[PRIVATE] Bytes per element
size_t elm_size;
} Array;
I originally prepared this to start with the sort function:
/** sorts the array using provided comparator method
* if metod not provided, memcmp is used
* Comparator signature
* int my_comparator ( const void * ptr1, const void * ptr2, size_t type_size );
**/
void array_sort(Array* a, int(*comparator)(const void*, const void*, size_t)) {
if(comparator == NULL)
comparator = &memcmp;
// Sorting algorithm should follow
}
However I learned about qsort
:
void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
Apparently, I could just pass my internal array to qsort
. I could just call that:
qsort (a->array, a->length, a->elm_size, comparator_callback);
But there's a catch - qsort
's comparator signature reads as:
int (*compar)(const void*,const void*)
While memcmp
's signature is:
int memcmp ( const void * ptr1, const void * ptr2, size_t type_size );
The element size is missing in qsort
's callback, meaning I can no longer have a generic comparator function when NULL
is passed as callback. I could manually generate comparators up to X bytes of element size, but that sounds ugly.
Can I use qsort
(or other sorting built-in) along with memcpy
? Or do I have to chose between built-in comparator and built-in sorting function?
C11 provides you with an (admittedly optional) qsort_s
function, which is intended to deal with this specific situation. It allows you to pass-through a user-provided void *
value - a context pointer - from the calling code to the comparator function. The comparator callback in this case has the following signature
int (*compar)(const void *x, const void *y, void *context)
In the simplest case you can pass a pointer to the size value as context
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdlib.h>
...
int comparator_callback(const void *x, const void *y, void *context)
{
size_t elm_size = *(const size_t *) context;
return memcmp(x, y, elm_size);
}
...
qsort_s(a->array, a->length, a->elm_size, comparator_callback, &a->elm_size);
Or it might make sense to pass a pointer to your entire array object as context.
Some *nix-based implementations have been providing a similar qsort_r
function for a while, although it is non-standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With