user2070408
user2070408

Reputation:

Why does this simple C example end in a segfault?

The following simple example results in a segmentation fault when attempting to access the first element of m inside main.

Why does this happen?

How can I fix it, but still keep the overall structure of the code the same?

Thanks.

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

double *array(int cols) {
  return malloc(cols*sizeof(double));
}

void create_and_modify_array(double *m) {
  m = array(10);
  m[0] = 123;
}

void main() {
  double *m;
  create_and_modify_array(m);
  printf("%f\n", m[0]);
}

Upvotes: 1

Views: 520

Answers (3)

iain
iain

Reputation: 5683

It segfaults because m inside create_and_modify_array is a local variable, so m inside main is still uninitialised.

To be more explicit the code flow is:

at the start of main m is a random, unassigned memory address. Then it calls create_and_modify_array with that memory address. Inside create_and_modify_array a new variable called m is created, and it has that random, unassigned memory address that was passed in. Then you call array and the variable m inside create_and_modify_array is assigned to your allocated memory.

The problem is that that value of m never gets passed back to the m in main.

To do that you need to pass a pointer to main's m into create_and_modify_array:

void create_and_modify_array (double **m) {
    double *tmp = array(10);
    tmp[0] = 123;
    *m = tmp; // This passes the value of tmp back to the main function.
              // As m in this function is actually the address of m in main
              // this line means put tmp into the thing that is at this address
}

void main () {
    double *m;
    create_and_modify_array (&m); // This passes the address of the variable m
                                  // into create_and_modify_array
    printf ("%f\n", m[0]);
}

Upvotes: 1

Timothy Jones
Timothy Jones

Reputation: 22135

The problem here is that C is always pass by value. Pass by value means that function arguments are copies of the variables they were called with. This means when you do this:

m = array(10);

inside create_and_modify_array(double *m), you are only changing where the function's local copy of m points. The m pointer from the main method is unaffected (and stays uninitialised, hence the crash).

To fix this, you can pass a pointer to the main()'s m pointer:

void create_and_modify_array(double **m) {
  *m = array(10); // change the pointer that `m` points to
  (*m)[0] = 123;  // assign something to the first element of what `m` points to
}

And pass the address of main()'s m in:

void main() {
  double *m; // make a pointer to a double
  create_and_modify_array(&m); // pass a pointer to the pointer to the double
                               // or, in alternative wording: 
                               // pass the address of the pointer to the double

Upvotes: 6

CharlesB
CharlesB

Reputation: 90336

Because the pointer created in create_and_modify_array is a different address than the one declared and used in main(). You can do this instead

double *create_and_modify_array(double *m) {
  m = array(10);
  m[0] = 123;
  return m;
}

void main() {
  double *m = create_and_modify_array(m);
  printf("%f\n", m[0]);
  free (m);
}

Upvotes: 2

Related Questions