Search code examples
cpointerscastingdereference

Why dereferencing after casting void pointer to pointer to char pointer makes problem?


I've learned pointer to pointer. I am curious about dereferencing after casting "integer to pointer" (char*)(int) and "void pointer to pointer to char pointer." (char**)(void*)

Now there are some issues when I want to dereference to void pointer to pointer to char pointer.(char**)(void*)

I tried 2 cases.

integer to pointer (char*)(int)

#include <stdio.h>
int main()

{
    
    int a = 10;
    int b;
    void* ptr = &a;

    b = ptr;
    printf("%d\n", *(unsigned int*)b);
    printf("%d\n", *(void**)(b));
    printf("%p\n", *(char**)(b));

    return 0;
}

*(unsigned int*)b 
*(void**)(b)
*(char**)(b)**

These three read 10 which is in address.

But the code below is problem. (Please watch ptr_speacial) "void pointer to pointer to char pointer." (char**)(void*)

#include <stdio.h>
int main()
{
    
    int arr[5] = { 1,2,3,4,5 };
    char arr2[5] = { 1,2,3,4,5 };
    

    void* ptr_arr;
    void* ptr_arr2;

    void* ptr_special;

    ptr_arr = arr;
    ptr_arr2 = arr2;

    ptr_special = (char*)ptr_arr2 + 4;


    printf("address : %p: value : %d\n", ptr_special, *(char**)ptr_special);
    printf("%d\n", *(char**)ptr_arr);

    return 0;
}

*(char**)ptr_special did not read 5 which is in address but -858993659

I'm not sure but I think this is overflow problem. What happend in this case? Please help me!


Solution

  • Take a look at this:

    #include <stdio.h>
    int main()
    {
        char arr2[] = { 1,2,3,4,5 };
        char arr3[] = { 1,2,3,4,5 };
        
        void* ptr_special2 = arr2 + 4;
        void* ptr_special3 = arr3 + 4;
    
        printf("address : %p: value : %d\n", ptr_special2, *(char**)ptr_special2);
        printf("address : %p: value : %d\n", ptr_special2, *(char**)ptr_special3);
    
        return 0;
    }
    

    output (may vary):

    address : 0x7ffc5841755a: value : 50462981
    address : 0x7ffc5841755a: value : 1074892805
    

    Now try this:

        char arr2[] = { 1,2,3,4,5,0,0,0 };
        char arr3[] = { 1,2,3,4,5,1,0,0 };
    

    output:

    address : 0x7fffecb291fc: value : 5
    address : 0x7fffecb291fc: value : 261
    

    Try to work out what's happening before reading the ...

    Explanation:

    On my system, a "pointer to a pointer to a char" is 4 bytes long. So - when you take the address of the 5 in arr2, cast it to a char**, and dereference it - the system reads 4 bytes, starting at the 5.

    In arr2, those 4 bytes are 5 0 0 0, which in a little-endian system is interpreted as 5.

    In arr3, those 4 bytes are 5 1 0 0, which in a little-endian system is interpreted as 5 + 256 = 261.

    In your code, the three bytes after the 5 are unknown. You don't know what the compiler has placed there (if anything). You are reading beyond the end of the array because you are trying to read 4 bytes (or whatever sizeof(char**) is on your system) from an array that only has 1 valid byte at that address.

    This is undefined behaviour, which means the standard allows literally anything to happen - but typically, you could expect:

    1. "random garbage" bytes
    2. The beginning of the next local variable
    3. An access violation