cpointerssegmentation-fault

C: why I get segmentation fault?


I have the following code. Calling f1 raises segfault, but not f2.

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

void f1(unsigned char** arr)
{
   unsigned char* p = *arr;
   *p = 'h';
   p++;
   *p = '\0';
}

void f2(unsigned char* arr)
{
   unsigned char* p = arr;
   *p = 'h';
   p++;
   *p = '\0';
}

int main()
{
   unsigned char a[31];
   f1((unsigned char**)&a);
   //f2(a);
   printf("%s\n", a);
}

Solution

  • unsigned char** is a pointer to a pointer to an unsigned char.

    &a returns the address of the array a[]. The type that &a returns is unsigned char (*)[31], not unsigned char**, which is why you can't simply call f1(a) which is a type mismatch. Pay attention to that error, it is important.

    &a does not return the address of a pointer, but you are using a typecast to trick the compiler into thinking it does, thus you are forcing f1() to access an invalid memory address through an invalid pointer, hence the segfault.

    IOW, you are taking a pointer-to-array and typecasting it to a pointer-to-pointer, which it is not. Inside f1(), the *arr dereference is expecting to yield an unsigned char* pointer to a valid unsigned char, but that is not actually the case. arr is pointing at a[] itself, and thus reading *arr will read and misinterpret the 1st 4 bytes (in a 32bit build) or 8 bytes (in a 64bit build) of a[] as being the value of a pointer, which they are not. Then dereferencing that pointer fails.

    Do not blindly use typecasts just to silence compiler errors. They are errors for a reason. Typecasts are useful in certain cases, but this is not one of them. The correct way to call f1() with a[] in your example is like this:

    unsigned char a[31];
    unsigned char *ptr = a; // aka: = &a[0]
    f1(&ptr);
    

    Alternatively, change f1() to accept a pointer-to-array instead of a pointer-to-pointer:

    #include <stdlib.h>
    #include <stdio.h>
    
    void f1(unsigned char (*arr)[31])
    {
       unsigned char* p = *arr;
       *p = 'h';
       p++;
       *p = '\0';
    }
    
    int main()
    {
       unsigned char a[31];
       f1(&a);
       printf("%s\n", a);
    }
    

    As for why calling f2(a) works as-is, that is because an array decays into a pointer to its 1st element, and f2() is using that pointer correctly. That is not the case when you are calling f1(&a).