How to pass a comparator to a C function? - c

What is bool (*comparator)(void *, void *)?
I'm trying to use this function from a library, but I don't understand its signature.
The function seems to be expecting some kind of criteria to sort the list (as ASC or DESC in SQL, I think), as a higher order function.
void list_sort(t_list *self, bool (*comparator)(void *, void *)) {
int unsorted_elements = self->elements_count;
if(unsorted_elements < 2) {
return;
}
t_link_element *aux = NULL;
bool sorted = true;
do {
t_link_element *previous_element = self->head, *cursor = previous_element->next;
sorted = true;
int index = 0, last_changed = unsorted_elements;
while(index < unsorted_elements && cursor != NULL) {
if(!comparator(previous_element->data, cursor->data)) {
aux = cursor->data;
cursor->data = previous_element->data;
previous_element->data = aux;
last_changed = index;
sorted = false;
}
previous_element = cursor;
cursor = cursor->next;
index++;
}
unsorted_elements = last_changed;
} while(!sorted);
}
The last definition of the function was in commons/collections/list.h.
I can't figure how to use this function properly after many attempts.
#include <stdio.h>
#include <stdlib.h>
#include <commons/collections/list.h>
/*I added this function thanks to the help of the community,
*and now it works, the list is printed backwards now.*/
bool comparator(void * a, void * b) {
return (int*) a > (int*) b;
}
int main()
{
t_list *list = list_create();
int add[] = {4, 55, 9, 7, 17};
list_add(list, (void*) &add[0]);
list_add(list, (void*) &add[1]);
list_add(list, (void*) &add[2]);
list_add(list, (void*) &add[3]);
list_add(list, (void*) &add[4]);
int size = list_size(list);
int j = 0 ;
while( j++ < 2)
{
for ( int i = 0 ; i < size; i++)
{
int* element = (int*) list_get(list, i);
printf("Found %d\n", *element);
}
//I edited this line, now the second parameter is comparator
list_sort(list, comparator);
}
list_destroy(list);
}
The main() function prints
Found 4 Found 55 Found 9 Found 7 Found 17
Found 17 Found 7 Found 9 Found 55 Found 4
EDIT:
I created the function comparator that actually allows me to run the code
After printing the result I showed before, it prints the same list but backwards.
Thanks everyone who's been nice and helped me fixed this, I still don't know how to print the sorted list. Sorry if my question is useless and/or violates some guideline, I wouldn't ask it this way if I knew it did.

Looking at the code in your last edit, the function is plain wrong. (int*) a > (int*) b compares pointer addresses, not values. If you intend to return true if a is greater than b, then it should be:
bool is_greater (void * a, void * b) {
return *(int*) a > *(int*) b;
}
More readably written as:
bool is_greater (void* a, void* b)
{
const int* ia = a;
const int* ib = b;
return *ia > *ib;
}
The function pointer type used by that API has some code smell, the parameters should have been declared as const void* so that the code can be used on read-only data too, but I guess you can't change that part.

In C++ we would have a predicate - an operator which returns true if the lhs < rhs
So your C function looks like it is following that pattern.
bool myLessInt(void * lhs, void * rhs)
{
// assume input parameters lhs and rhs are pointers into the data.
int intLhs = *((int*)lhs);
int intRhs = *((int*)rhs);
if( intLhs < intRhs ) return true; // lhs was less than rhs
return false; // rhs == or is less than lhs
}
I would look for a function like the one above to solve your problem.

Related

How to pass a designator of which member of a structure to a function in C

I have a lot of records formed by 4 parameters each one (id, field1, field2, field3). Records are contained in a pointer called records. My goal is to create an InsertionSort function in order to sort these records. The sorting will be done for every parameter of the record (through multiple calling). The trouble is that the function must be general.
What can I write in parameters of InsertionSort function so that the pointer works?
main.c
struct fields{
int id;
char field1[20];
int field2;
float field3;
};
int main() {
struct fields *records = malloc(100000 * sizeof *records);
/* Here , I fill *records with values */
InsertionSort(records,field1,100000); // I order by parameter "field1"
InsertionSort(records,id,100000); // I order by parameter "id"
InsertionSort(records,field2,100000); // I order by parameter "field2"
}
InsertionSort function
void InsertionSort(fields *records, char parameter ,int sizeofrecords) {
int i, j;
void* temp;
for (i = 1; i < size; i++) {
temp = records[i].parameter; //this command doesn't work (records[i])
j = i - 1;
while (j >= 0 && records[j].parameter> temp) {
records[j + 1].parameter= records[j].parameter;
j--;
}
records[j + 1].parameter= temp;
}
}
Look at the design of standard C (and POSIX) qsort(). Pass a pointer to a comparator function to your InsertionSort() function in place of the char parameter argument. When you need to compare in the sort function, invoke the comparator on the two records to be compared. Write different comparators to sort on the different fields. A standard (qsort-compatible) comparator has the signature int comparator(const void *p1, const void *p2). You might be able to use const fields * as the argument type, but then you'd not be able to use the standard qsort() function.
Without debugging any other issues in your sort (I'm not sure whether there are any), you might end up with:
void InsertionSort(fields *records, int (*cmp)(const void *p1, const void *p2), int size)
{
for (int i = 1; i < size; i++)
{
void *temp = &records[i];
int j = i - 1;
while (j >= 0 && (*cmp)(&records[j].parameter, temp) > 0)
{
records[j + 1].parameter = records[j].parameter;
j--;
}
records[j + 1].parameter = temp;
}
}
You can write just cmp(records[j].parameter, temp). I learned C long enough ago to prefer the older, more explicit notation for invoking a function via a function pointer. (I learned C in an era when the simpler notation was not an option.)
Your comparator functions might look like these (the other two are trivial variants on cmp_id):
static int cmp_id(const void *p1, const void *p2)
{
const fields *v1 = p1;
const fields *v2 = p2;
// +1 if v1 > v2; -1 if v1 < v2; else 0
return (v1->id > v2->id) - (v1->id < v2->id);
}
static int cmp_field1(const void *p1, const void *p2)
{
const fields *v1 = p1;
const fields *v2 = p2;
return strcmp(v1->field1, v2->field1);
}
The numeric comparator (cmp_id) avoids overflow and branching. You could write:
if (v1->id > v2->id)
return +1;
if (v1->id < v2->id)
return -1;
return 0;
as the body of the function. It is simpler to understand. It can also be extended to deal with tie-breakers, so that if the id values are the same, you can compare the field1 strings or the values in field2 or field3. You simply add extra comparisons after the if statements and before the return 0;.
Warning: this code has not been anywhere near a compiler, much less tested. Caveat Lector.
So Peppino wants to know how to actually do it. Well, kinda. The problem is while we can pass the member, we can't pass the member's type so this will run incorrectly. If we had all the members being the same type instead this would work:
#include <stddef.h>
struct fields{
int id;
char field1[20];
char field2[11];
char field3[20];
};
void InsertionSort(fields *records, size_t parameter ,int size) {
int i, j;
struct fields temp;
for (i = 1; i < size; i++) {
temp = records[i];
j = i - 1;
while (j >= 0 && strnatsort((char *)records[i] + parameter, (char *)records[i] + parameter) > 0) {
records[j + 1] = records[j];
j--;
}
records[j + 1] = temp;
}
}
InsertionSort(records,offsetof(fields, field1),100000);
where strnatsort does natural sort: How to implement a natural sort algorithm in c++?

QuickSort in C library

The Second Param of qsort
Now I want to sort a set of points by x.Following is my code:
typedef struct {
int x;
int y;
} point;
int cmpfunc( const void * a, const void * b){
point *point1 = (point *)(a);
point *point2 = (point *)(b);
if(point1->x < point2->x){
return -1;
}
return 0;
}
int main(){
point *points = (point *)malloc(sizeof(point)*3);
points[0].x = 1;
points[0].y = 2;
points[1].x = 0;
points[1].y = 4;
points[2].x = 4;
points[2].y = 3;
qsort(points,2,(sizeof(points[0])),cmpfunc);
int i=0;
while (i<3){
printf("x=%d",points[i].x);
printf("y=%d\n",points[i].y);
i++;
}
return 0;
}
Please notice qsort(points,2,(sizeof(points[0])),cmpfunc);
The result is correct when I pass the second param value 2 not 3.What's wrong with my code?
To sort on the x axis, you need something like:
static void cmpfunc(const void *a, const void *b)
{
const point *pa = a, *pb = b;
return pa->x < pb->x ? -1 : pa->x > pb->x;
}
It must return less than, equal to, or greater than zero. See the manual page for more.
Oh, and you really shouldn't "drop const" like that, for no reason, and of course you never need to cast from void * to a pointer to struct like we have here. Keep it simple, and learn these things so you don't feel a need to "throw in a cast for good measure".

Create a d-dimensional pointer [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
We use to indicate a pointer with the symbol *. Iterating the procedure, we obtain a "double" pointer **, a "triple" pointer *** and, more generally, a "d-dimensional" pointer (for each d positive natural number).
Problem: given such a d as an input, define S to be a d-dimensional pointer.
Because I started studying dynamic structures only some days ago, I am unfortunately a bit in trouble with this problem.
Does anyone have a suggestion/hint?
Thank you in advance, and my apologies for my probably too basic question.
Ps: I used the word "pointer" without specify its type only for sake of brevity.
This problem has a solution in C as long as two conditions are met:
The value of d is known at compile time, and
d has a pre-defined limit, e.g. 10
You can solve this problem by defining a series of macros and "pasting" the value of d as a token:
#define D_PTR(d,T) D_PTR##d(T)
#define D_PTR0(T) T
#define D_PTR1(T) T*
#define D_PTR2(T) T**
#define D_PTR3(T) T***
...
#define D_PTR10(T) T**********
Now you can declare d-dimension pointers like this:
D_PTR(5,int) ptr5 = NULL;
Demo.
There are three distinct ways to solve this:
Your d is a compile-time constant. For this case, dasblinkenlight has already given the solution.
The hacky-C solution: Just use a cast to get back to the pointer type:
double* dereferenceDLevels(double* pointer, int d) {
for(; d--; ) pointer = *(double**)pointer;
return pointer;
}
I do not recommend this approach, though. It's just too dirty.
You implement your d-level pointers as user defined types:
typedef struct nLevelPointer {
int n;
union {
nLevelPointer* pointer;
double value;
};
} nLevelPointer;
double nLevelPointer_dereference(nLevelPointer* me) {
for(int i = me->n; i--; ) me = me->pointer;
return me->value;
}
I consider this approach the cleanest and most flexible one. However, it has the trade-off of requiring a significant amount of boilerplate code to make it fly.
Basically the number of * represents the number of indirections to reach the variable. So you have to create d indirections. I assume this has no practical application - that's an answer to a recreative problem.
An indirection in C is an address, a pointer. Creating d indirections means the creation of d addresses to reach a variable data (the space allocated to the variable of type T).
p(d) -> p(d-1) -> ... -> p(1) -> variable
To create dynamically such a structure, you could do it via malloc (replace T with any known type), and - since you may not specify the number of * dynamically to a pointer - requires some C hacking.
So, again, this is not something recommended and is a particularly bad design, especially for inexperienced C developers. Purpose is to show it could be done dynamically, whatever the value of d.
Say T is a double
int d = ...; // from input (d >= 1)
double variable;
double **S = malloc(sizeof(double *) * d); // array of pointers to pointer
S[d-1] = &variable; // last address points to target
int i;
for(i=d-2 ; i>=0 ; i--) S[i] = (double *)&S[i+1]; // previous address
// points to next location
There is no way to represent an arbitrary number of indirections in C, so S is only a ** to satisfy the compiler requirements, and is cast when necessary.
Let's try with d set to 4 and applying the algorithm above (say T is a double), having
double variable is at address 0100 (decimal), value 3.14
S address given by malloc at 1000
a pointer size being 4
a double size being 8
variable
v
[8 bytes double value 3.14]
^
0100
S
v
[1004][1008][1012][0100]
^ ^
1000 1012
Now the structure is in place, how to use/test it? You could create a function that returns the type T (double here), take the S value and d, operate the d indirections and return the variable
double getvariable(double **S, int d) {
while (--d > 0) S = (double **)*S; // d-1 iterations
return *(double *)*S;
}
trying it
printf("%lf\n", getvariable(S, d)); // 3.14
to test the above structure without a function, for d == 4, you could create
double ****p = (double ****)*S;
printf("%lf\n", ****p); // 3.14
Problem: given such a d as an input, define S to be a d-dimensional
pointer.
It's possible in C to functionally represent an N dimensional array at run time, if not a pointer with an arbitrary number of levels of indirection. This could be a start (uncompiled, and this utterly ignores any possible alignment issues):
void *allocateArray( unsigned int N, size_t elemSize, unsigned int *dimensions )
{
if ( N == 1U )
{
return( malloc( elemSize * dimensions[ 0 ] ) )
}
void *array = malloc( sizeof( void * ) * dimensions[ 0 ] );
for ( unsigned ii = 0; ii < dimensions[ 0 ]; ii++ )
{
array[ ii ] = allocateArray( N - 1, elemSize, &( dimensions[ 1 ] ) );
}
return( array );
}
Note, that is not a very efficient way of allocating an N-dimensional array.
You could call it like this:
unsigned dims[] = { 5,7,8,9 };
unsigned d = sizeof( dims ) / sizeof( dims[ 0 ] );
size_t elemSize = sizeof( double );
void *array = allocateArray( d, elemSize, dims );
A varargs solution is probably possible, too.
Dereferencing the array would require something similar. This returns the address of the element dereferenced:
void *dereferenceArray( void *array, unsigned int N,
size_t elemSize, unsigned int *element )
{
if ( N == 1U )
{
char *tmp = array;
return( tmp + ( elemSize * element[ 0 ] ) );
}
else
{
void **tmp = array;
return( dereferenceArray( tmp[ element[ 0 ] ],
N - 1, elemSize, &( element[ 1 ] ) ) );
}
}
It'd be much easier in C++ as you could provide a [] operator to your array object and nest them to build N-dimensional arrays.
You could create the runtime equivalent of a d-indirection pointer by chaining as many void ** pointers as you need. A sparse array could then be built this way:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc < 4)
{
printf("Call this passing d (dimensions), n (elements for each dim), u (used elements) as parameters\n");
return 0;
}
int d = atoi(argv[1]);
assert(d > 0);
int n = atoi(argv[2]);
assert(n > 0);
int u = atoi(argv[3]);
assert(u < n * d);
// Creating
void *root = malloc(sizeof(void *) * n);
memset(root, 0, sizeof(void *) * n);
srand(time(NULL));
int i, p, c;
void **cursor;
for (int c = 0; c < u; ++c)
{
cursor = root;
for (i = 0; i < d; ++i)
{
p = rand() % n;
if (cursor[p] == NULL)
{
cursor[p] = malloc(sizeof(void *) * n);
memset(cursor[p], 0, sizeof(void *) * n);
}
cursor = cursor[p];
}
p = rand() % n;
if (cursor[p] == NULL)
cursor[p] = "Hello";
else
--c;
}
// Traversing
struct SE
{
void * *s;
int p;
};
struct SE *stack = malloc(sizeof(struct SE) * (d + 1));
for (cursor = root, p = 0, i = 0; ; ++p)
{
if (p == n)
{
if (i == 0)
break;
cursor = stack[--i].s;
p = stack[i].p;
}
else if (cursor[p] != NULL)
{
if (i < d)
{
stack[i].s = cursor;
stack[i++].p = p;
cursor = cursor[p];
p = -1;
}
else
{
printf("root");
for (c = 0; c < i; ++c)
printf("[%d]->", stack[c].p);
printf("[%d]=\"%s\"\n", p, cursor[p]);
}
}
}
// Tearing down
for (cursor = root, p = 0, i = 0; ; ++p)
{
if (p == n)
{
if (i == 0)
break;
cursor = stack[--i].s;
p = stack[i].p;
free(cursor[p]);
}
else if (cursor[p] != NULL && i < d)
{
stack[i].s = cursor;
stack[i++].p = p;
cursor = cursor[p];
p = -1;
}
}
free(root);
free(stack);
return 0;
}

comparing if void * contains 0 numbytes?

I need generic way to check if void * contains 0 till num_bytes.
I came up with following approach. *p does not contain same type of data everytime hence cant do *(type*)p
bool is_pointer_0(void *p, int num) {
void *cmp;
cmp = (void*)malloc(num);
memset(cmp, 0, num);
if (memcmp(p, cmp, num)) {
free(cmp);
return false;
} else {
free(cmp);
return true;
}
}
The function allocates & frees up num bytes on every call, not pretty I think.
Please suggest faster approaches. Appreciate the help.
Update :
How about this approach ?
bool is_pointer_0(void *p, int num) {
void *a = NULL;
memcpy(&a, p, num);
return a == NULL;
}
This code casts the void pointer to a char pointer. This allows the memory pointed at to be treated as a sequence of bytes. Then cycles through the specified length looking for non zero bytes. I do not know if the standards guarantee that this would work (ie casting a void* to a char* will provide a pointer to the raw bytes), but in real life it works
bool is_pointer_0(void *p, int num) {
char *c = (char *)p;
for(int i = 0; i < num; i++)
if(c[i]) return false;
return true;
}
You can cast the pointer to a char* or unsigned char* and check the values of the elements.
unsigned char* cp = reinterpret_cast<unsigned char*>(p);
for (int i = 0; i < num; ++i )
{
if ( cp[i] != 0 )
{
return false;
}
}
return true;
Note: this approach may be better for long buffers well aligned. Yet this answer is fast due to simplicity.
Since the memory, if all zeros, must compare to itself, use memcmp(): a platform specific optimized function.
int memcmp0(const void *buf, size_t n) {
#define TESTVALUE 0
const char *cbuf = (const char *) buf;
while (n > 0) {
// If odd size, last byte not 0?
if (n % 2 && (cbuf[n - 1] != TESTVALUE)) return 0;
// 1st half matches 2nd half?
size_t half = n / 2;
if(memcmp(cbuf, &cbuf[half], half) != 0) return 0;
n = half;
}
return 1;
}
This is easy to extend to other values other than 0 by changing TESTVALUE.
Note: at most log2(n) iterations.
Another after accept answer:
Since the memory, if all zeros, must compare to itself, use memcmp(): a platform specific optimized function.
Check the first value and then use memcmp() to compare ptr[0],ptr[1], then ptr[1],ptr[2], then ptr[2],ptr[3], etc.
int memcmpfast(const void *ptr, size_t n, char testvalue) {
const char *cptr = (const char *) ptr;
if (n == 0) return 1;
if (cptr[0] != testvalue) return 0;
return memcmp(cptr, cptr + 1, n - 1) == 0;
}
I'd probably go with something like this:
bool is_pointer_0(void* p, int num)
{
return std::search_n((char*)p, (char*)p + num, num, 0) == p;
}
Or this:
bool is_pointer_0(void* p, int num)
{
return std::all_of((char*)p, (char*)p + num, [](char c){return c == 0;});
}

C: Accessing a pointer from outside a function

I have the following code:
int takeEven(int *nums, int numelements, int *newlist) {
newlist = malloc(numelements * sizeof *newlist);
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if (!(*nums % 2)) {
*(newlist++) = *nums;
found++;
}
}
newlist -= found;
printf("First number found %d\n", *newlist); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
The output of the above code:
-1
2088999640
2088857728
If I try printing the first element of the newlist pointer before returning the function (printf("First number found %d\n", *newlist);), it works as intended, but why is it that when I try to access the pointer from outside of the function I get those values from seemingly unmalloced addresses?
You are passing the newList pointer by value, so it will not be modified by your function. You should do instead.
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof *newlist);
...
}
...
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
You need to pass in a pointer to pointer, i.e. int **newlist. Specifically, newlist is being passed into your function by value, so the newlist in main and inside your function are two completely different variables.
There is also a bug in your test for even numbers:
#include <stdio.h>
#include <stdlib.h>
int takeEven(int *nums, int numelements, int **newlist) {
int *list = malloc(numelements * sizeof **newlist);
*newlist = list; // this modifies the value of newlist in main
int i, found = 0;
for(i = 0; i < numelements; ++i, nums++) {
if ((*nums % 2) == 0) {
*(list++) = *nums;
found++;
}
}
list -= found;
printf("First number found %d\n", *list); // <= works correctly
return found;
}
int main()
{
int nums[] = {1,2,3,4,5};
int *evenNums;
int i;
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
for (i = 0; i < n; ++i) {
printf("%d\n", *(evenNums++));
}
return 0;
}
You can also take a look at this question from the C-FAQ which deals with your problem also:
Q: I have a function which accepts, and is supposed to initialize, a pointer:
void f(int *ip)
{
static int dummy = 5;
ip = &dummy;
}
But when I call it like this:
int *ip;
f(ip);
the pointer in the caller remains unchanged.
A: Are you sure the function initialized what you thought it did? Remember that arguments in C are passed by value. In the code above, the called function alters only the passed copy of the pointer. To make it work as you expect, one fix is to pass the address of the pointer (the function ends up accepting a pointer-to-a-pointer; in this case, we're essentially simulating pass by reference):
void f(ipp)
int **ipp;
{
static int dummy = 5;
*ipp = &dummy;
}
...
int *ip;
f(&ip);
Another solution is to have the function return the pointer:
int *f()
{
static int dummy = 5;
return &dummy;
}
...
int *ip = f();
See also questions 4.9 and 4.11.
The newlist you have at the end of the function is not the same as you have when calling the function.
You are passing a copy of a pointer, then malloc changes that pointer(internal to the function) to point to allocated memory, but the outside one is still unmodified.
You need to use a pointer to pointer as a parameter so that you can set where the ourtside one points by double indirection.
int use_pointed_memory(char **pointer){
*pointer = malloc();
}
char *myptr;
use_pointed_memory(&myptr);
So effectively you are giving the function the place where you store the address of what you want and asking the function to store there a valid memory pointer.
You're passing a pointer by value here:
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), evenNums);
Which means that a copy of the pointer is made within that function. You then overwrite that copy:
newlist = malloc(numelements * sizeof *newlist);
Since it is but a copy, the caller won't see the result of your assignment. What you seemingly want here is to pass a pointer by reference - for that, you need a pointer to pointer:
int takeEven(int *nums, int numelements, int **newlist) {
*newlist = malloc(numelements * sizeof **newlist); // apply * to newlist
...
}
int n = takeEven(nums, sizeof(nums) / sizeof(*nums), &evenNums);
And don't forget to free:
free(evenNums);
In C, everything is passed by value. So you are passing a copy of evenNums to the function. Whatever you modify it inside the function doesn't get reflected outside. You need to int** as the third parameter.

Resources