ccastingvoid-pointerspointer-arithmeticbsearch

Need help understanding typecasting const void pointer in C


I have trouble understanding the first line of code inside this implementation of the bsearch function in C. I understand the search algorithm itself and I have played around with this function to get a good grasp of it but I still do not get what

const char *base = (const char *) base0;

does exactly do, why is it permitted, and why does it have to be char and cannot be some other type. When I used the same function but with typecasting to (const int*) base0; instead and then used the C Tutor to understand what's going on I noticed that the variable p becomes a pointer to invalid memory but I have no idea why it happens and why this function works with both strings and integers.


Solution

  • Within the function you need to find each element in the passed array. However the type of the array is unknown. You only know the size of each element of the array and the starting address of the array that is passed through the parameter base0. of the type const void *..

    To access an element of the array you need to use the pointer arithmetic. But the type void is incomplete type. Its size is unknown/ So you may not use the pointer of the type (const) void *` in expressions with the pointer arithmetic.

    Thus this declaration

    const char *base = (const char *) base0;
    

    introduces the pointer base of the type const char * with which you may use the pointer arithmetic to access elements of the array as in this statement

    p = base + (lim >> 1) * size;
    

    Or example base + size will point to the second element of the array.

    Here is a demonstrative program.

    #include <stdio.h>
    
    void f( const void *base, size_t nmemb, size_t size )
    {
        for ( size_t i = 0; i < nmemb; i++ )
        {
            const char *p = ( const char * )base;
            printf( "The address of the %zu-th element is %p\n", 
                    i, ( const void *)( p + i * size ) );
        }
    }
    
    int main(void) 
    {
        int a[] = { 1, 2, 3 };
        const size_t N = sizeof( a ) / sizeof( *a );
        
        for ( size_t i = 0; i < N; i++ )
        {
            printf( "The address of the %zu-th element is %p\n", 
                    i, ( const void *)( a + i ) );
        }
        
        putchar( '\n' );
        
        f( a, N, sizeof( int ) );
        
        return 0;
    }
    

    The program output might look like

    The address of the 0-th element is 0x7ffc45c6d4dc
    The address of the 1-th element is 0x7ffc45c6d4e0
    The address of the 2-th element is 0x7ffc45c6d4e4
    
    The address of the 0-th element is 0x7ffc45c6d4dc
    The address of the 1-th element is 0x7ffc45c6d4e0
    The address of the 2-th element is 0x7ffc45c6d4e4
    

    Within the main you may use the pointer arithmetic using the expression ( a + i ) because in this expression the array designator is implicitly converted to the type int * and the type int is a complete type (its size is known).

    However within the function f you may not use the expression ( base + i ) because the pointer has the type const void * and the type void is not a complete type (its size is unknown).

    So casting the pointer to the type const char * we can use the pointer arithmetic with this pointer but in this case we need to use the expression ( p + i * size ) to access an element of the passed array.