Reputation:
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
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
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
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