Simple: The first example creates a temporary std::string, and you take its internal data pointer, which points to invalid data as soon as the temporary is destroyed (after the semicolon).
In the second example, you create an explicit std::string, and you take its internal data pointer, which points to valid data as long as your std::string doesn't change.
In the last example, you also create a temporary std::string, and you take its internal data pointer, which was still pointing to valid data since it hasn't been destroyed yet (No semicolon between cout and VShaderStream.str().c_str().
VShaderStream.str() returns a temporary string and hence a pointer to a temporary c-string. As soon as clause ends (line1) the temporary string becomes invalid and so is the pointer. So on line 2 you will have garbage.
Also even if I just do
It's the same: When cout processes the pointer at the end of the stream clause the pointer is invalid.