Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a string literal from a function

I am always confused about return a string literal or a string from a function. I was told that there might be memory leak because you don't know when the memory will be deleted?

For example, in the code below, how to implement foo() so as to make the output of the code is "Hello World"?

void foo (       )              // you can add parameters here.
{

}

int main ()
{
    char *c;
    foo (    );
    printf ("%s",c);
    return 0;
}

Also, if the return type of foo() is not void, but you can return char*, what should it be?

like image 947
skydoor Avatar asked Mar 20 '10 01:03

skydoor


3 Answers

I'm assuming we cannot modify main. To get your program working without a leak, you need something to have static storage:

void foo(char*& pC)  // reference
{
    static char theString[] = "thingadongdong";

    pC = theString;
}

But really, this isn't very conventional C++ code. You'd be using std::string and std::cout, so you don't have to worry about memory:

std::string foo(void)
{
    return "better thingadongdong";
}

int main(void)
{
    // memory management is done
    std::cout << foo() << std::endl;
}

If you're wondering if something needs to be manually deallocated, it's being done wrong.

like image 183
GManNickG Avatar answered Oct 02 '22 17:10

GManNickG


Since the old use of char* is being deprecated, can you not simply use a string?

const char* func1 () {return "string literal";}

string func2 () {return "another string literal";}

Both of these work fine, with no compiler warnings.

However

char* func3 () {return "yet another string literal";}

will not compile at all. Nor will

char* func4 () {return &"a ref to a string literal?";}

Stroustrup says in "The C++ Programming Language" (Third Edition):

"A string literal is statically allocated so that it is safe to return one from a function.

const char* error_message (int i)`
{
//...
return "range error";
}

The memory holding range error will not go away after a call of error_messages()."

So every string literal in a program is allocated in its own little piece of memory that lasts for the duration of the program (i.e. is statically allocated). Putting the const in front of the char* lets the compiler know that you do not intend (and cannot) alter that string literal's little piece of memory which could be dangerous, so they let this assignment slide despite that conversion from string literal to char* is deprecated.

Returning instead to a string must copy the string literal into an object of type string, memory that the caller is responsible for.

Either way there are no memory leaks: every string literal gets its own piece of memory that is cleaned up on program termination; return to const char* returns a pointer to a literal's piece of memory (knowing you cannot alter it); and return to a string makes a copy into a string object existing in the caller's code which is cleaned up by the caller.

Though it seems a little ugly notation-wise, I'm guessing they left the const char* to keep the cheap alternative (involving no copies).

like image 41
RMS Avatar answered Oct 02 '22 18:10

RMS


I am always confused about return a string literal or a string from a function.

Immutable, literal string

As I understand it, you are safe to return a string literal directly if the return type is declared const, to declare that the string is not intended to be altered. This means you needn't worry about the lifespan of the string / memory leaks.

Mutable, non-literal string

However, if you need a string that you can change in-place, you need to consider the lifespan of the string and the size of the memory allocation in which it is stored. This becomes an issue, since you can no longer blithely return the same memory containing string for each invocation of the function, since a previous use could have altered the contents of that memory, and/or may still be in use. Hence a new piece of memory must be allocated to hold the string returned.

This is where the potential for a leak occurs, and where the choice needs to be made about where the allocation and de-allocation should occur. You could have the function itself allocate the memory and state in the documentation that this happens and stipulate therein that the caller has to free the memory when it is no longer required (preventing a leak). This means the function can simply return a char *.

The other option is to pass in some memory to the function that was allocated by the caller, and have the function place the string inside that memory. In this case, the caller both allocates and is responsible for freeing that memory.

Finally, I mentioned that the size of the memory and string need to be managed when using a mutable string. The allocation needs to be both large enough for the string initially set by the function and also for any changed that are made after the function, before the memory is freed. Failing to do this correctly can cause a buffer overflow by writing a string to long to fit in the memory initially allocated; this is extremely dangerous to the health and security of your program. It can cause bugs and security holes that are extremely hard to spot (since the source of the error - the overflow - can be far removed from the symptoms seen when the program fails).

like image 33
Mike Tunnicliffe Avatar answered Oct 02 '22 18:10

Mike Tunnicliffe