3

First off, I know this should have been answered somewhere on SO but I just can't seem to find the correct post. So if it is a duplicate please point me to the post that answers this question and I will delete this.

I have a function that copies a string:

static int read_ad_content(json_t * root, char* content)
{

  [.. stuff happens]

  const char* tmp = json_string_value(json_content);
  unsigned int size = strlen(tmp);
  content = (char*)malloc(size + 1);
  memcpy(content, tmp, size);
  content[size] = '\0'; // <= I checked and content is NOT null here!

  return 0;
}

And I call it like this in my main function:

char *ad_content;
if (read_ad_content(ad_json, ad_content) != 0)
  {
     log_err(argv, "Failed to extract information");
  }

  if (ad_content == NULL)
  {
    // <= I always end up here
  }

I know this should be easy but I just don't know how to solve this.

Sören Titze
  • 985
  • 1
  • 12
  • 31
  • You modify a copy of the pointer. `ad_content` on the calling side is never touched. – Mankarse Oct 07 '13 at 22:20
  • That's not how reference semantics work. E.g. [see here](http://stackoverflow.com/a/12449034/596781), or just think about it for a bit. – Kerrek SB Oct 07 '13 at 22:20
  • Here's very similiar question I answered yesterday.[HERE](http://stackoverflow.com/questions/19214293/unable-to-modify-global-variable-in-c/19214332#19214332) – zubergu Oct 07 '13 at 22:27

1 Answers1

3

In C, parameters are passed by value. What you're doing isn't any different from:

void brokenMethod(int a){
    a = 10;
}

int a = 0;
brokenMethod(a);
if(a == 0)
{
    //always end up here!
}

Of course you'll always end up there. a was never modified! The value of a was passed to brokenMethod, which could've done anything it wanted but that's not going to affect the value of a in your outer scope.

If I want the method to fill in an int, I have to pass it a pointer to an int.

void fixedMethod(int* a)
{
    *a = 10; 
    //Remember, you want to modify the thing being pointed at, not the thing doing the pointing!
    //a = something; is going to have the exact same problem as the first example
}

int a = 0;
fixedMethod(&a);
if(a == 0)
{
    //Better
}

The above example sticks a value into an int. In your case, if you want the method to fill in a pointer to an int then you'll have to pass it a pointer to a pointer to an int.

Sidebar: You may also find that methods which return values via parameters are difficult to reason about and more likely to contain bugs. If you're trying to return an pointer to an int, just have a method that returns a pointer to an int.

int* HonestMethod()
{
    return pointer to whatever.
}
Pete Baughman
  • 2,996
  • 2
  • 19
  • 33
  • 1
    The thing why I don't return the pointer is that I want to have a way of checking for errors. Of course one could argue that as long as I return null an error must have happened. I think I will try and use your way of doing it. – Sören Titze Oct 07 '13 at 22:35
  • 1
    Right, if you need a function to set a pointer *and* indicate an error, then - unless you set up a struct for the purpose, which is usually weird - at least one of those things must be modified via a parameter, since functions in C can only return one value. – Crowman Oct 07 '13 at 22:36
  • You're absolutely correct. You have a few options: return an object that holds the return value AND some sort of error indicator, or return null as an indication of error. No matter what you do, make sure that the function's documentation explains it. If you want to return NULL as an error indicator then the documentation should say "Returns NULL if an error happened" – Pete Baughman Oct 07 '13 at 22:37
  • @PaulGriffiths I've found, in my experience, that people rarely bother to check the error code when it's there, and just wait for the null reference to blow up anyway. Given that, I've chosen to push people towards writing methods that are easier to read, vs error checking that everybody ignores anyway. – Pete Baughman Oct 07 '13 at 22:43