This is from a 'magic' array library that I'm using.
void
sort(magic_list *l, int (*compare)(const void **a, const void **b))
{
qsort(l->list, l->num_used, sizeof(void*),
(int (*)(const void *,const void *))compare);
}
My question is: what on earth is the last argument to qsort doing?
(int (*)(const void *, const void*))compare)
qsort takes int (*comp_fn)(const void *,const void *) as it's comparator argument, but this sort function takes a comparator with double pointers. Somehow, the line above converts the double pointer version to a single pointer version. Can someone help explain?
That's exactly what the cast you quoted does: it converts a pointer of type
int (*)(const void **, const void **)
to a pointer of type
int (*)(const void *, const void *)
The latter is what is expected by qsort.
Thing like this are encountered rather often in bad quality code. For example, when someone wants to sort an array of ints, they often write a comparison function that accepts pointers to int *
int compare_ints(const int *a, const int *b) {
return (*a > *b) - (*a < *b);
}
and when the time comes to actually call qsort they forcefully cast it to the proper type to suppress the compiler's complaints
qsort(array, n, sizeof *array, (int (*)(const void *,const void *)) compare_ints);
This is a "hack", which leads to undefined behavior. It is, obviously, a bad practice. What you see in your example is just a less direct version of the same "hack".
The proper approach in such cases would be to declare the comparison function as
int compare_ints(const void *a, const void *b) {
int a = *(const int *) a;
int b = *(const int *) b;
return (a > b) - (a < b);
}
and then use it without any casts
qsort(array, n, sizeof *array, compare_ints);
In general, if one expects their comparison functions to be used as comparators in qsort (and similar functions), one should implemnent them with const void * parameters.
The last argument to qsort is casting a function pointer taking double pointers, to one taking single pointers that qsort will accept. It's simply a cast.
On most hardware you can assume that pointers all look the same at the hardware level. For example, in a system with flat 64bit addressing pointers will always be a 64bit integer quantity. The same is true of pointers to pointers or pointers to pointers to pointers to pointers.
Therefore, whatever method is used to invoke a function with two pointers will work with any function that takes two pointers. The specific type of the pointers doesn't matter.
qsort treats pointers generically, as though each is opaque. So it doesn't know or care how they're dereferenced. It knows what order they're currently in and uses the compare argument to work out what order they should be in.
The library you're using presumably keeps lists of pointers to pointers about. It has a compare function that can compare two pointers to pointers. So it casts that across to pass to qsort. It's just syntactically nicer than, e.g.
qsort(l->list, l->num_used, sizeof(void*), compare);
/* elsewhere */
int compare(const void *ptr1, const void *ptr2)
{
// these are really pointers to pointers, so cast them across
const void **real_ptr1 = (const void **)ptr1;
const void **real_ptr2 = (const void **)ptr2;
// do whatever with real_ptr1 and 2 here, e.g.
return (*real_ptr2)->sort_key - (*real_ptr1)->sort_key;
}
It is casting a function pointer. I imagine that the reason is so that compare can be applied to the pointers that are dereferenced rather than whatever they are pointing to.
(int (*)(const void *,const void *))compare is a C style cast to cast the function pointer compare to a function pointer with two const void * args.
The last argument is a function pointer. It specifies that it takes a pointer to a function that returns an int and takes two const void ** arguments.
Related
int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *ptr);
return 0;
}
I expected for this code to print 12, but it does not.
if instead of void pointer, we define int pointer it would work.
I wanted to know how can we use void pointer and print the address allocated to it and the amount saved in it?
Dereferencing a void * doesn't make sense because it has no way of knowing the type of the memory it points to.
You would need to cast to pointer to a int * and then dereference it.
printf("%d", *((int *)ptr));
void pointers cannot be dereferenced.it will give this warning
Compiler Error: 'void' is not a pointer-to-object type*
so, you have to do it like this.
#include<stdio.h>
int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *(int *)ptr);
return 0;
}
If p has type void *, then the expression *p has type void, which means "no value". You can't pass a void expression to printf for the %d conversion specifier (or any other conversion specifier).
In order to dereference a void *, you must first convert it to a pointer of the appropriate type. You can do it with a cast:
printf( "%d\n", *(int *) ptr );
or assign it to a pointer of the appropriate type:
int *p = ptr;
printf( "%d\n", *p );
The rules around void pointers are special such that they can be assigned to other pointer types without an explicit cast - this allows them to be used as a "generic" pointer type. However, you cannot directly examine the thing a void pointer points to.
A schoolbook example of when void pointers are useful is qsort.
This is the signature:
void qsort(void *base,
size_t nitems,
size_t size,
int (*compar)(const void *, const void*)
);
base is just a pointer to the first element. The reason it's a void pointer is because qsort can be used for any list, regardless of type. nitems is number of items (doh) in the list, and size is the size of each element. Nothing strange so far.
But it does also take a fourth argument, which is a function pointer. You're supposed to write a custom compare function and pass a pointer to this function. This is what makes qsort able to sort any list. But since it's supposed to be generic, it takes two void pointers as argument. Here is an example of such a compare function, which is a bit bloated for clarity:
int cmpfloat(const void *a, const void *b) {
const float *aa = (float*) a;
const float *bb = (float*) b;
if(*aa == *bb) {
return 0;
} else if(*aa > *bb) {
return 1;
} else {
return -1;
}
}
Pretty clear what is going on. It returns positive number if a>b, zero if they are equal and negative if b>a, which is the requirements. In reality, I'd just write it like this:
int cmpfloat(const void *a, const void *b) {
return *(float*)a - *(float*)b;
}
What you do with this is something like:
float arr[5] = {5.1, 3.4, 8.9, 3.4, 1.3};
qsort(arr, 5, sizeof *arr, cmpfloat);
Maybe it's not completely accurate to say that void pointers are used instead of templates, generic functions, overloaded functions and such, but they have similarities.
I'm taking a specialization on Coursera and in a lesson it explains the qsort() function that sorts a given array:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
where we should provide qsort() with four parameters - the array to sort, number of elements in the array, size of each element of the array, and a pointer to a function (compar) which takes two const void *s and returns an int. The lesson says that we need to write the compar function to be compatible with the qsort function, so if we would like to compare two strings the function should look like:
int compareStrings(const void * s1vp, const void * s2vp) {
// first const: s1vp actually points at (const char *)
// second const: cannot change *s1vp (is a const void *)
const char * const * s1ptr = s1vp;
const char * const * s2ptr = s2vp;
return strcmp(*s1ptr, *s2ptr);
}
void sortStringArray(const char ** array, size_t nelements) {
qsort(array, nelements, sizeof(const char *), compareStrings);
}
It says: Note that the pointers passed in are pointers to the elements in the array (that is, they point at the boxes in the array), even though those elements are themselves pointers (since they are strings). When we convert them from void *s, we must take care to convert them to the correct type—here, const char * const *—and use them appropriately, or our function will be broken in some way. For example, consider the following broken code:
// BROKEN DO NOT DO THIS!
int compareStrings(const void * s1vp, const void * s2vp) {
const char * s1 = s1vp;
const char * s2 = s2vp;
return strcmp(s1, s2);
}
The thing that I can't really get is why didn't we consider s1vp and s2vp as pointers to pointers? I mean, since the arguments passed to the function compareStrings are addresses of pointers pointing to strings (address of pointer), shouldn't we have declared s1vp and s2vp as int compareStrings(const void ** s1vp, const void ** s2vp) since they are receiving addresses of pointers?
In other words, I'm passing, for example, the address of the first element of the array of strings, which is actually a pointer, to s1vp. So now s1vp is receiving address of pointer not a variable, so We should declare it as pointer to pointer, right? It gives me warning when I try to do so...
A void * can point to any datatype. The fact that the datatype in question is also a pointer doesn't change things.
Also, you can't change the signature of the comparison function, otherwise it would be incompatible with what qsort is expecting and can lead to undefined behavior.
This question already has answers here:
Swapping objects using pointers
(10 answers)
Closed 7 years ago.
I want to make a swap function that can be generically used for any data type. I know that the following function works for ints:
void swap(void *a, void *b)
{
int temp;
temp = *(int*)a;
*(int*)a = *(int*)b;
*(int*)b = temp;
}
and this works for strings:
void swap(void *a, void *b)
{
void *temp;
temp = *(void**)a;
*(void**)a = *(void**)b;
*(void**)b = temp;
}
If you pass the size of the pointee along, too (like in qsort), then you can do it:
void swap(void * a, void * b, size_t len)
{
unsigned char * p = a, * q = b, tmp;
for (size_t i = 0; i != len; ++i)
{
tmp = p[i];
p[i] = q[i];
q[i] = tmp;
}
}
Usage:
struct Qux x, y;
swap(&x, &y, sizeof(Qux));
(You might want to add restrict qualifiers to the pointers, or otherwise a test for self-swapping.)
You should read the C FAQ list at least once. It is good to see what people have pondered over time.
Why can't I perform arithmetic on a void * pointer? is relevant to your question:
The compiler doesn't know the size of the pointed-to objects. (Remember that pointer arithmetic is always in terms of the pointed-to size; see also question 4.4.) Therefore, arithmetic on void *'s is disallowed (though some compilers allow it as an extension). Before performing arithmetic, convert the pointer either to char * or to the pointer type you're trying to manipulate (but see also questions 4.5 and 16.7).
Also relevant is Suppose I want to write a function that takes a generic pointer as an argument and I want to simulate passing it by reference. Can I give the formal parameter type void ** ...:
There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void *'s; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void *. When you make use of a void ** pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.
Here's another answer:
void swap(void *a, void *b, size_t width)
{
void *temp = malloc(width);
memcpy(temp, b, width);
memcpy(b, a, width);
memcpy(a, temp, width);
free(temp);
}
I am a beginner programmer in C who wants to get used to terminology and pointers.
I have found the following working function prototype while searching for a way to sort the elements of a numerical array. The function was qsort and it utilized pointers. Now what I understood is that the word "const" ensures that the values a and b are unchanged but not the pointers. Correct me if I am wrong here. My questions are:
Why do we use void * the function can we not use int * from the
start?
How does the construction *(int*)a in the return part
work?
Why does the qsort algorithm needs this many arguments?
int compare (const void *a, const void *b)
{
return ( *(int*)a - *(int*)b );
}
Many thanks for the answers.
PS: That is a pretty complicated task for me.
qsort was made this way so it could be used as a generic sorter. If it would use int from the start it could only be used to compare integers. This way you could also, for example, sort strings by passing strcmp as the compare function to qsort.
*(int*)a casts a to a pointer-to-int and then dereferences it, so you get the integer stored at a. Note that this doesn't change a or the value that a points to.
qsort requires 4 arguments: the array to sort, the number of elements in that array and the size of the elements and finally the compare function. It needs all this information, because again, it is made to be as generic as possible.
It needs the number of elements because in C pointers don't carry information about the size of the buffer that follows them. And it needs to know the size of each element so it can pass the elements to the compare function correctly. For examle, to compare ints you would pass sizeof(int) as the size parameter. To compare strings you would use sizeof(char *).
ADDIT as suggested by H2CO3 the reason for using const void * is to indicate that the compare function may not change the value pointed to by a and b. This, of course, to ensure that sorting the array doesn't suddenly change the values in the array. And, as H2CO3 said, it would be cleaner to cast to (const int *) so that you cannot accidentally change the value after casting it:
return *(const int *)a - *(const int *)b;
You could also get rid of the cast with:
int compare(const void * a, const void * b){
const int * ia = a;
const int * ib = b;
return *ia - *ib;
}
depending on your tastes regarding casts. (I prefer to avoid them)
Finally, to clarify the asterisks:
*(int *)a
^ ^
| └ cast to integer pointer
└ dereference (integer) pointer
Now what I understood is that the word "const" ensures that the values a and b are unchanged but not the pointers
You understood wrong.
const int *a;
declare a as pointer to constant int type. This means that the word const ensures that you can't modify the value of the variable a points to by modifying *a.
Why do we use void * the function can we not use int * from the start?
void * is used to point any type of variable.
How does the construction *(int*)a in the return part work?
*(int *) is used to cast a as a pointer to int and then dereferencing it to get the value stored at location it points to.
The other answers are excellent. I just want to add that it's ofter easier to read if you are very clear in your callback function.
int compare (const void *a, const void *b)
{
return ( *(int*)a - *(int*)b );
}
becomes
int compare (const void *a, const void *b)
{
int ia = *(int *)a;
int ib = *(int *)b;
return ia - ib;
}
In this case it's not too important but as your compare funcion gets complex, you may want to get your variables to "your type" before doing the compare.
Since you asked in the comment below, here is a very step by step version:
int compare (const void *a, const void *b)
{
int *pa = (int *)a;
int *pb = (int *)b;
int ia = *pa;
int ib = *pb;
return ia - ib;
}
qsort() function is an example of a generic algorithm that was implemented as a general-purpose routine. The idea is to make it useful for sorting arbitrary objects, not just int or float. Because of that (and because of the C language design), qsort() resorts to taking a comparison function as a parameter that accepts two generic (in C sense) pointers. It is up to that function (provided by qsort() user) to cast these pointers to correct type, perform correct comparison and return an indication of ordering.
Similarly, since qsort() doesn't know beforehand how large objects are, it takes the object size as a parameter. As far as qsort() is concerned, the objects are blobs of bytes of equal size contiguously arranged in memory.
Finally, since neither of the operations qsort() performs can cause an error, it doesn't return an error code. Actually there is a situation where qsort() might fail, which is illegal parameters passed to it, but in a tradition of many other standard C library routines, it does not guarantee any error checking on parameters promising undefined behavior in such a case.
I'm beginning to learn C and read following code:
public void** list_to_array(List* thiz){
int size = list_size(thiz);
void **array = malloc2(sizeof(void *) * size);
int i=0;
list_rewind(thiz);
for(i=0; i<size; i++){
array[i] = list_next(thiz);
}
list_rewind(thiz);
return array;
}
I don't understand the meaning of void**. Could someone explain it with some examples?
void** is a pointer to a pointer to void (unspecified type). It means that the variable (memory location) contains an address to a memory location, that contains an address to another memory location, and what is stored there is not specified. In this question's case it is a pointer to an array of void* pointers.
Sidenote: A void pointer can't be dereferenced, but a void** can.
void *a[100];
void **aa = a;
By doing this one should be able to do e.g. aa[17] to get at the 18th element of the array a.
To understand such declarations you can use this tool and might as well check a related question or two.
void** is a pointer to void*, or a pointer to a void pointer if you prefer!
This notation is traditionally used in C to implement a matrix, for example. So, in the matrix case, that would be a pointer to an array of pointers.
Normally void * pointers are used to denote a pointer to an unknown data type. In this case your function returns an array of such pointers thus the double star.
In C, a pointer is often used to reference an array. Eg the following assignment is perfectly legal:
char str1[10];
char *str2 = str1;
Now when void is used, it means that instead of char you have a variable of unknown type.
Pointers to an unknown data type are useful for writing generic algorithms. Eg. the qsort function in standard C library is defined as:
void qsort ( void * base,
size_t num,
size_t size,
int ( * comparator )
( const void *, const void * ) );
The sorting algorithm itself is generic, but has no knowledge of the contents of the data. Thus the user has to provide an implementation of a comparator that can deal with it. The algorithm will call the comparator with two pointers to the elements to be compared. These pointers are of void * type, because there is now information about the type of data being sorted.
Take a look at this thread for more examples
http://forums.fedoraforum.org/showthread.php?t=138213
void pointers are used to hold address of any data type. void** means pointer to void pointer. Void pointers are used in a place where we want a function should receive different types of data as function argument. Please check the below example
void func_for_int(void *int_arg)
{
int *ptr = (int *)int_arg;
//some code
}
void func_for_char(void *char_arg)
{
char *ptr = (char *)char_arg;
//some code
}
int common_func(void * arg, void (*func)(void *arg))
{
func(arg);
}
int main()
{
int a = 10;
char b = 5;
common_func((void *)&a, func_for_int);
common_func((void *)&b, func_for_char);
return 0;
}