Reputation: 45
Here is a simplified C code of the problem I am working on. In the actual function I am passing a pointer as a parameter to have it be "returned" as something is already being returned by foo(). Why does this give a segmentation fault? How do I fix it?
#include <stdio.h>
void foo(int* num_rows){
int row_scan;
printf("enter:\n ");
scanf("%d", &row_scan);
num_rows = &row_scan;
}
int main(void) {
int *num_rows;
foo(num_rows);
printf("%d", *num_rows);
return 0;
}
Here is a link to the code online: https://repl.it/repls/SilentFreshProperties#main.c
Upvotes: 1
Views: 55
Reputation: 123558
The immediate cause of your segfault is that num_rows
in main
is not actually being updated to point to anything meaningful.
The num_rows
parameter in foo
is a different object than the num_rows
variable in main
. When you write
num_rows = &row_scan;
this does not affect the num_rows
variable in main
- it only affects the formal argument, which is local to foo
and ceases to exist when foo
exits. So when you write
int main(void) {
int *num_rows; // contains an *indeterminate* value
foo(num_rows); // does not update num_rows
printf("%d", *num_rows); // dereferencing that indeterminate value
return 0;
}
num_rows
starts out with an indeterminate value that may or may not correspond to a writable memory address. It is not updated by the call to foo
, and
attempting to dereference that invalid pointer value leads to a segfault.
So how do you fix this? Well, you start by declaring num_rows
as an int
, not an int *
, and you pass the address of num_rows
to foo
:
int main(void) {
int num_rows;
foo(&num_rows);
printf("%d", num_rows);
return 0;
}
Look at the scanf
call in your foo
function, you're basically doing the exact same thing - you define an object that will store the integer value, and you pass the address of that object to the function so that the function can update it.
You will need to make the following changes to foo
:
void foo(int* num_rows){
int row_scan;
printf("enter:\n ");
scanf("%d", &row_scan);
*num_rows = row_scan;
}
Instead of writing the address of row_scan
to num_rows
(which will be invalid once the function returns), you write the value of row_scan
to *num_rows
, which is the int
object that num_rows
points to.
You could dispense with the row_scan
variable altogether and just write
scanf( "%d", num_rows ); // no &, num_rows is already a pointer
but, if you want to do additional validation, then it's a good idea to write to a local variable and not update num_rows
unless you know the input is good, like:
int items_read = scanf( "%d", &row_scan );
if ( items_read == 1 )
{
*num_rows = row_scan;
}
else if ( items_read == 0 )
{
fprintf( stderr, "Input was not an integer value, num_rows not updated\n" );
}
else
{
fprintf( sterr, "EOF or error on input stream\n" );
}
Upvotes: 0
Reputation: 67765
In your code you return pointer to the variable which stops to exists when function returns. This is wrong and it is called an Undefined Behaviour
You need to change your logic - pass the reserence to the variable defined in the calling function (in your case main
)
#include <stdio.h>
void foo(int* num_rows){
int row_scan;
printf("enter:\n ");
scanf("%d", &row_scan);
*num_rows = row_scan;
}
int main(void) {
int num_rows;
foo(&num_rows);
printf("%d", num_rows);
return 0;
}
Upvotes: 1