Home > front end >  qsort typ casting pointers in c
qsort typ casting pointers in c

Time:02-26

This is a simple code to practice qsort function in C.

int compareF(const void *a, const void *b) {
    // return (*(int**)a)[0] - (*(int**)b)[0];  
    const int *pr1 = *(const int **)a;
    const int *pr2 = *(const int **)b;
    return pr1[0] - pr2[0];
}

int main() {
    int *array[] = {(int[]){2,2,3}, (int[]){1,2,1},(int[]){1,3,3},(int[]){0,2,3},(int[]){1,2,0}};
    qsort(array, 5, sizeof(int[2]), compareF);
    for (int i = 0; i < 5; i  ) {
        for (int j = 0; j < 3; j  ) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
  return (0);
}

I don't grasp line 3 and 4 of why it is type-casted this way with pointers. This is my understanding. Firstly, it doesn't matter how we use syntax whether we set new variables to save parameters or not like those two return states are just same. Secondly, it needs to be type cased since parameters are void type so function does not know the type. First * is for dereferencing parameter a so that It has an access to the address a. And we use int** because..?

There's 2d integer array in main function. CompareF function only takes array[0] and array[1] as parameter each time in my understanding. So I don't get why it is typed cased with two **.

Do I even make sense?

CodePudding user response:

The compare function passed to qsort is called anytime any two array elements are to be compared, and it is taking the address of each of those array elements.

You have an array of int * that is being sorted, so the address of each of those elements has type int **. That matches the type that the parameters of compareF are casted to. Dereferencing those pointers then gives us a value of type int * which is what is actually contained in the array.

Also, the third parameter to qsort is not correct. The array elements do not have type int[2] but instead have type int *. If an int is 4 bytes and a pointer is 8 bytes then they happen to be the same, but you can't depend on that.

CodePudding user response:

For starters this call of qsort

qsort(array, 5, sizeof(int[2]), compareF);

is incorrect. The third parameter is the size of elements of the array. As the type of elements of the array is int * then the third parameter must be sizeof( int * ) or that is the same sizeof( *array )

qsort(array, 5, sizeof( *array ), compareF);

The function qsort passes pointers to elements of the array to the comparison function compareF as pointers of the type const void *.

As the elements if the array have the type int * then a pointer to an element of the array has the type int **.

So within the function compareF you need to cast the pointers of the type const void * to types const int **. Dereferencing such a pointer you will get an element of the original array.

As the elements of the array point to first elements of compound literals that have the type int[3] then for example the expression pr1[0] within teh comparison function gives the first element of a compound literal, the expression pr1[1] gives the second element of the compound literal and so on.

In general using this return statement

return pr1[0] - pr2[0];

is incorrect because the supplied expression can produce an overflow for the signed integer type int.

It is more interesting to sort the elements (pointers) of the original array comparing all elements of compound literals.

Here is a demonstration program.

#include <stdio.h>
#include <stdlib.h>

enum { M = 3 };

int compareF( const void *a, const void *b ) 
{
    const int *pr1 = *( const int ** )a;
    const int *pr2 = *( const int ** )b;
    
    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] )   i;
    
    return i == M ? 0 : ( pr2[i] < pr1[i] ) - ( pr1[i] < pr2[i] );
}

int main(void) 
{
    int * array[] = 
    {
        (int[M]){2,2,3}, 
        (int[M]){1,2,1},
        (int[M]){1,3,3},
        (int[M]){0,2,3},
        (int[M]){1,2,0}
    };
    
    const size_t N = sizeof( array ) / sizeof( *array );
    
    qsort( array, N, sizeof( *array ), compareF );
    
    for ( size_t i = 0; i < N; i   )
    {
        for ( size_t j = 0; j < M; j   )
        {
            printf( "%d ", array[i][j] );
        }
        
        putchar( '\n' );
    }
}

The program output is

0 2 3 
1 2 0 
1 2 1 
1 3 3 
2 2 3 

As you can see if first elements of two compound literals are equal each other then second elements are compared and so on.

  • Related