Search code examples
cmallocparameter-passingpass-by-referencepass-by-value

C program calling malloc results in bus error?


I have written this code to declare a pointer, p, and then dynamically allocate 4 bytes of memory for type int to then store some data in it. p should point to an address which holds the data 6 of type int. The program should then print out the data from the pointer variable using the dereferencing operator. I have also included the free() function to release allocated memory from the heap. I don't understand why I'm receiving a bus error. The same code has been executed by a peer and it has worked perfectly fine. I'm using a Mac M2 and running the code on vscode. What could be causing this error?

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

void foo(int *a){
    a = (int*)malloc(sizeof(int));
}

int main(){
    int *p;
    foo(p);
    *p = 6;
    printf("%d",*p);
    free(p);
    return(0);
}

Here's the error message: zsh: bus error

Note that if I were to remove the foo() function and replace the calling line with p = (int*)malloc(sizeof(int)); then the program works perfectly fine. Why is it that having it in the previous method results in a bus error?


Solution

  • In C arguments are passed to functions by value. It means relative to your program that the function foo deals with a copy of the value of the pointer p declared in main.

    So any changes of the copy within the function leave the original pointer unchanged.

    You may imagine the function and its call the following way

    foo(p);
    
    //...
    
    void foo( /*int *a */ ){
        int *a = p;
        a = (int*)malloc(sizeof(int));
    }
    

    As you can see it is the local variable a declared within the function that was changed. The original pointer p stays unchanged. Function parameters are local variables of the function.

    So as the pointer p stays unchanged and is not initialized then dereferencing the pointer like for example

    *p = 6;
    

    results in the bus error.

    To change an object (including a pointer) within a function you need to pass it by reference.

    In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the passed pointer you get a direct access to the object pointed to by the pointer and can change it.

    So your program should look the following way

    #include <stdio.h>
    #include <stdlib.h>
    
    void foo( int **a )
    {
        *a = malloc(sizeof(int));
    }
    
    int main( void )
    {
        int *p;
    
        foo( &p );
    
        if ( p != NULL )
        { 
            *p = 6;
            printf( "%d\n", *p );
        }
    
        free(p);
    
        return 0;
    }
    

    Pay attention to two aspects.

    The first one is that the function main without parameters shall be declared as

    int main( void )
    

    And the second one is that in C (opposite to C++) you need not to cast the pointer returned from the function malloc. That is you may write

    *a = malloc(sizeof(int));
    

    And also you should check whether the pointer p changed within the function is not a null pointer before dereferencing it in main. On the other hand, the function free may be called for a null pointer.