C program calling malloc results in bus error?

96 Views Asked by At

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?

3

There are 3 best solutions below

0
Vlad from Moscow On BEST ANSWER

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.

0
Chris On

In your function foo the argument a is a local variable. You are assigning the result of malloc to that, but this has no effect on the program outside of this function call.

As it stands, you are dereferencing an uninitialized pointer, resulting in undefined behavior. You also have a (in this case short-lived) memory leak if malloc succeeds, because you cannot free this memory later.

To accomplish this you need to pass a pointer to the pointer.

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

int main(void) {
    int *p;
    foo(&p);
    *p = 6;
    printf("%d", *p);
    free(p);

    return 0;
}

You probably also want to get into the habit of checking that malloc succeeeded.

0
Logan MacDougall On

Because you are changing the value of the pointer, you need to pass the address of the pointer. Otherwise, you simply have a copy of the address.

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

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

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