Getting char* array from c++ stringstream ostringstream

JavaFan picture JavaFan · Apr 22, 2015 · Viewed 12.7k times · Source

I am trying to copy ostringstream to a char* array and am hoping someone can help me with understanding where my mistake lies. I looked on the forum, found some things that are similar and unfortunately am still am unable to get property copy from ostringstream to char*. In short I am trying to copy into the char* via:

ostringstream bld
bld<<"test"<<"is"<<"good"
const char * result = bld.str().c_str();

The complete code to reproduce an error is below. In this code I am having two functions that essentially build strings via ostringstream. In the makeFilePath() function I build a complete file path (ie /path/file.txt). In the add() function, I simply add two more char* arrays to an argument to get prefix /path/file.txt suffix.

The problem is for some unknown reason to me the fullFilePath also changes to look like prefix /path/file.txt suffix. Last three lines of a code will exhibit that.

I spent hours on this, thinking maybe this is a referencing issue or something else. However, none that I attemped worked. Any ideas how to get over this problem?

Thanks!!

#include <iostream>
#include <sstream>
#include <string>

using std::cout;
using std::endl;
using std::string;

using std::ostringstream;

const char* add(const char *fileName) {
    ostringstream bld;
    const char *prefix = "prefix";
    const char *suffix = "suffix";
    bld << prefix << " " << fileName << " " << suffix;
    string temp = bld.str();
    cout << "in add(): \n\t" << temp << endl;
    return temp.c_str();
}

const char * makeFilePath(const char *path, const char *name, const char *ext =
        ".txt") {
    ostringstream bld;
    bld << path << name << ext;
    cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
    string temp = bld.str();
    return temp.c_str();

}

int main(int argc, char **argv) {
    cout << "=== PROJECT START ===" << endl;

    const char * filePath = "\\Path\\";
    const char *fileName = "FILENAME";
    const char *fullFilePath = makeFilePath(filePath, fileName);

    cout << fullFilePath before calling add():\n\t" << fullFilePath << endl;    
    const char* str = add(fullFilePath);
    cout << fullFilePath after calling add():\n\t" << fullFilePath << endl;

    return 1;
}

Answer

Abhijit picture Abhijit · Apr 22, 2015

stringstream.str() returns a expiring value a temporary string object whose lifetime is restricted to the end of the expression. A pointer to a temporary expiring value when deleted would simply dangle and accessing it beyond the expression is an Undefined behaviour possibly a crash or some garbage value.

One option would be to fetch the string object to a persistent string and then get the constant pointer to the character array buffer.

const std::string bld= stringstream.str();
const char* result= bld.c_str();

Alternatively you may also consider to bind the expiring rvalue to a constant reference (Note some compilers might be lenient to bind to a reference which is possibly incorrect) and then fetch the pointer to the buffer. This will simply extend the lifetime of the temporary object.

But that would not resolve all you pain. As I have missed your function implementation

const char * makeFilePath(const char *path, const char *name, const char *ext =
        ".txt") {
    ostringstream bld;
    bld << path << name << ext;
    cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
    string temp = bld.str();
    return temp.c_str();

}

You are returning a pointer to a local object the scope of which is not extended beyond the function scope. A better suggestion would be to return a string object from your function and then on the caller scope convert the string object to a const C null terminated string.

std::string makeFilePath(const char *path, const char *name, const char *ext =
        ".txt") {
    ostringstream bld;
    bld << path << name << ext;
    cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
    return bld.str();

}

Alternatively you may want to duplicate the string using strdup, but the caller should be aware to release the resource for the allocated buffer.