Since I can't return a local variable, what's the best way to return a string from a C or C++ function?

As a follow-up to this question:

From what I've seen, this should work as expected:

void greet(){
  char c[] = "Hello";
  greetWith(c);
  return;
}

but this will cause undefined behavior:

char *greet(){ 
  char c[] = "Hello";
  return c;
}

If I'm right, what's the best way to fix the second greet function? In an embedded environment? On a desktop?


Solution 1:

You're absolutely right. Your c array in the second example is being allocated on the stack, and thus the memory will get reused immediately following. In particular, if you had code like

 printf("%s\n",greet());

you'd get weird results, because the call to printf would have reused some of the space of your array.

The solution is to allocate the memory somewhere else. For expample:

char c[] = "Hello";

char * greet() {
    return c;
}

Would work. Another choice would be to allocate it statically in scope:

char * greet() {
    static char c[] = "Hello";
    return c;
}

because static memory is allocated separately from the stack in data space.

Your third choice is to allocate it on the heap via malloc:

char * greet() {
   char * c = (char *) malloc(strlen("Hello")+1);  /* +1 for the null */
   strcpy(c, "Hello");
   return c;
}

but now you have to make sure that memory is freed somehow, or else you have a memory leak.

Update

One of those things that seems more confusing than I expect is what exactly a "memory leak" is. A leak is when you allocate memory dynamically, but lose the address so it can't be freed. None of these examples necessarily has a leak, but only the third one even potentially has a leak, because it's the only one that allocates memory dynamically. So, assuming the third implementation, you could write this code:

{
    /* stuff happens */
    printf("%s\n", greet());
}

This has a leak; the pointer to the malloc'ed memory is returned, the printf uses it, and then it's lost; you can't free it any longer. On the other hand,

{
    char * cp ;
    /* stuff happens */
    cp = greet();
    printf("%s\n", cp);
    free(cp);
}

doesn't leak, because the pointer is saved in an auto variable cp long enough to call free() on it. Now, even though cp disappears as soon as execution passes he end brace, since free has been called, the memory is reclaimed and didn't leak.

Solution 2:

If you are using C++, then you may want to consider using std::string to return strings from your second function:

std::string greet() {
    char c[] = "Hello";
    return std::string(c); // note the use of the constructor call is redundant here
}

Or, in a single threaded environment you can do:

char *greet() {
    static char c[] = "Hello";
    return c;
}

The static here allocates space in the global memory area, which never disappears. This static method is fraught with peril, though.

Solution 3:

Depends if the embedded environment has a heap or not, if so, you should malloc as follows:

char* greet()
{
  char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition
  strcpy(ret,"hello");
  return ret;
}

Note that you should later call free() to clean up. If you don't have access to dynamic allocation, you will need to make it a global, or a variable on the stack, but further up the call stack.