al512
al512

Reputation: 45

Pointers in C, Returning Extra Parameters in C

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

Answers (2)

John Bode
John Bode

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

0___________
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;  
}

https://godbolt.org/z/xxo4Pr

Upvotes: 1

Related Questions