I’m trying to understand how returning a pointer works in the following scenarios:
#include <iostream>
using namespace std;
// Why does this work? I can even pass the return value to another function
// and the contents do not change.
char* StringFromFunction()
{
char* pReturn = "This string was created in the function.";
return pReturn;
}
// I know this is wrong because the memory address where 5 is stored can be
// overwritten.
int* IntegerFromFunction()
{
int returnValue = 5;
return &returnValue;
}
int main()
{
int* pInteger;
char* pString;
pString = StringFromFunction();
pInteger = IntegerFromFunction();
cout << *pInteger << endl << pString << endl;
return 0;
}
The program output is as I expect it to be:
5
This string was created in the function.
The only compiler warning I get in Visual C++ 2010 Express is “c:\vc2010projects\test\main.cpp(14): warning C4172: returning address of local variable or temporary” and it only shows when I use IntegerFromFunction() and not StringFromFunction().
What I think I am understanding from the examples above is the following:
Inside StringFromFunction(), the memory allocation for the text “This string was created in the function.” occurs at execution time and because it is a string literal, the contents persist in memory even after the function returns, and that is why the pointer pString in main() can be passed to another function and the string can be displayed within it.
However, for IntegerFromFunction(), when the function returns the memory allocated is now freed and therefore, that memory address can be overwritten.
I guess my main questions is, can pointers that point to string literals safely be passed around throughout the program?
The easiest way to see the difference is to generate the dissasembly of a simple hello-world-ish example:
This is the diassembly with gcc in FreeBSD with optimization turned off
As you can see, the string literal itself was stored in the .LC0 section, not in the code itself. The test function just return a pointer to the beginning of .LC0 (movl $.LC0, %eax) as this is the first string literal. The location is similar (but not the same) depending the executable format you are compiling to. Read A.out (text segment), or PE.