char * gives garbage value when pointing to a variable of a function in C

72 Views Asked by At

When i pass a pointer to a function and then change the pointer to a another location of the memory, I get SIGSEV or garbage values. Where is a code to demonstrate that:

#include <stdio.h>

void fn(char *n) {
  /*
   * imagine this variable 'b' is
   * a part of a structure of
   * some library
   */
  char *b = "hello, world!";

  n = b;
}

int main() {
  char *a = NULL;
  fn(a);

  /* it throws garbage or SIGSEV */
  printf("%s\n", a);
}

I know what's the reason for this problem. The function fn, when called creates a variable b but when fn ends, b is deleted. And therefore, a is pointing to a memory that the program doesn't own. What do I do to fix this program. I know, I can solve the issue just by using C++ with it's std::string. But I have to do it in C. Thanks.

4

There are 4 best solutions below

0
Vlad from Moscow On BEST ANSWER

It means that you need to pass the pointer a defined in main to the function fn by reference. In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the passed pointer the function will have a direct access to the object pointed to by the pointer and can change it.

void fn(char **n) {
  /*
   * imagine this variable 'b' is
   * a part of a structure of
   * some library
   */
  char *b = "hello, world!";

  *n = b;
}

And in main you need to write

fn( &a );

Pay attention to that the pointer a will be valid after the function call because it points to a string literal used in fn and string literals have static storage duration.

0
Mathieu On

You want to modify n value itself, not the data pointed by it.

So

  • fn prototype should be void fn(char ** n)
  • the assignment should be *n = b or better n* = strddup (...);
  • the call sholud be fn(&a);
3
tahzibi.jafar On

I think the best way is to malloc a in main function and pass it to the fn function.

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

void fn(char *n) {
  /*
   * imagine this variable 'b' is
   * a part of a structure of
   * some library
   */
    
   char *b = "Hello, world";
   memcpy(n, b, strlen(b));

}

int main() {
  char *a = malloc(100);   // 100 is a sample
  fn(a);

  /* it throws garbage or SIGSEV */
  printf("%s\n", a);
}

Also, you can avoid memcpy, by assigning the struture variable to n, instead of b

0
John Bode On

Your function isn't updating a to point to the string; in your main function a is still NULL after the call to fn.

Remember that C passes all function arguments by value; when you call fn the argument a is evaluated and the result of that evaluation (NULL) is copied to the formal argument n. a and n are completely different objects in memory and changes to one are not reflected in the other.

In order for fn to write a new value to a you must pass a pointer to a:

void fn( char **n )
{
  *n = "hello, world"; // no need for a separate variable
}

int main( void )
{
  ...
  fn( &a );
  ...
}

Alternately, you can have fn return the new pointer value and assign it to a:

char *fn( void )
{
  return "hello, world";
}

int main( void )
{
  char *a = fn();
  ...
}

although this only works if you return a pointer to a string literal, static variable, or the result of a function that returns a pointer like malloc or fopen or something like that; you can't return a pointer to a local variable like

char *fn( void )
{
  char buf[] = "hello, world";
  return buf;
}

because the local variable buf ceases to exist once the function returns and that pointer value is now invalid.

General rule:

void update( T *ptr ) // for any non-array type T
{
  *ptr = new_T_value(); // writes a new value to the thing
}                       // ptr points to

int main( void )
{
  T var;
  update( &var ); // write a new value to var
  ...
}

If we replace T with a pointer type P *, we get

void update( P **ptr )
{
  *ptr = new_Pstar_value(); 

int main( void )
{
  P *var;
  update( &var ); 
  ...
}

The semantics are exactly the same; ptr still has an extra layer of indirection, we still use &var as the argument, etc.