views:

214

answers:

3

Hi, 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?

+4  A: 

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.

GMan
Not always. After all, std::string does the allocation manually.
George Edison
Eh, when you're not in "library writing mode" I should say. :)
GMan
There we go. Much better. My opinion exactly.
George Edison
I'm not sure what is wrong with using char *foo() { return "Hello World"; }, am I missing something?
fd
I would use std::string as far as possible. All memory allocation taken care of. And if you do want formating like printf(), try boost::format together with std::cout.
jpyllman
@fd, you can't change the string literal and it triggers the deprecated conversion in '03 and is ill-formed in c++0x. `char*` indicates the OP wants to change the returned string. We can't be sure.
Johannes Schaub - litb
@Johannes, ah, as I see the question description didn't seem to show the need for a mutable string. I note your entirely correct comment about const-ness on the question, but I wonder if the OP didn't intend that restriction. The question seemed to be more concerned with worrying about a memory leak from returning a literal, I suspect the informative answer is to explain the difference between returning a literal (with const declaration) and returning a mutable string whose length and/or lifespan should be managed.
fd
+2  A: 

Something like this:

void foo(char ** pChar)
{
    // Make sure the string is shorter
    // than the buffer
    *pChar = new char[256];
    strcpy(*pChar,"Hello World!");
}

Then call it like this:

foo(&c);

As mentioned in the comment, be careful the string you are storing is smaller than the buffer or you will get a... stack overflow! (Pun intended)

George Edison
And if I do `foo(0)`?
GMan
You can't dereference `0` That'll crash your program.
George Edison
why pointer to pointer is needed? Why not just pointer?
skydoor
Because the allocation is being done in `foo` When `foo` returns, the memory allocated will be dangling. (And there will be no way to free it.)
George Edison
@George: That's the point. Don't take a pointer, take a reference. This is C++.
GMan
@GMan that's like saying "and if i do string(0)?" or "and if i do printf(0)?". He forbids null pointers as a precondition, so passing `0` is not allowed.
Johannes Schaub - litb
I know. This is just an example. I could change it to a reference if you want...
George Edison
@litb: But a reference enforces that, rather than just saying "don't do it".
GMan
@GMan ah, i see. Yeah references seem the better tool here.
Johannes Schaub - litb
+1  A: 

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).

fd