C++ std::stringstream not accepting chars?

Discussion in 'Computer Programming, Emulation, and Game Modding' started by StackMasher, May 9, 2017.

  1. StackMasher
    OP

    StackMasher GBAtemp Regular

    Member
    111
    54
    Nov 29, 2016
    Here's my function:
    Code:
    const char* getToken(std::ifstream& input) {
        std::stringstream buffer;
        char curChar;
        bool inString = false;
       
        //Get rid of any leading whitespace
        while (input.peek() == ' ') {
            input >> curChar;
        }
       
        //Extract the token
        while (true) {
            input >> curChar;
           
            if (!inString && ( curChar == ' ' || curChar == '\n' || input.eof() == true )) {
                break;
            }
            else if (curChar == '"') {
                inString = !inString;
            }
           
            buffer << curChar;
        }
       
        char* toReturn = new char[buffer.width() + 1];
        buffer.seekg(0,std::ios::beg);
        for (int i{}; i<buffer.width(); ++i) {
            buffer >> toReturn[i];
        }
        toReturn[buffer.width()] = '\0';
        return toReturn;
    }
    the string this function returns is empty, and buffer returns 0 as it's width
     
  2. souler92
    This message by souler92 has been removed from public view by raulpica, May 9, 2017, Reason: Shitposting -rp.
    May 9, 2017
  3. evandixon

    evandixon PMD Researcher

    Member
    1,667
    788
    May 29, 2009
    United States
    Try buffer.str().c_str()
     
  4. StackMasher
    OP

    StackMasher GBAtemp Regular

    Member
    111
    54
    Nov 29, 2016
    nope, same results
    Code:
    char* toReturn = new char[strlen(buffer.str().c_str()) + 1];
    strcpy((char*)buffer.str().c_str(), toReturn);
    return toReturn;
    I've also tried directly returning buffer.str().c_str(), and that doesn't work either
     
  5. GerbilSoft

    GerbilSoft GBAtemp Addict

    Member
    2,063
    2,284
    Mar 8, 2012
    United States
    You may want to change the return type to std::string and return buffer.str().

    stringstream::width() doesn't do what you think it does. That returns the width parameter for the next added object, i.e. for formatting. It doesn't return the length of the string.
     
  6. sarkwalvein

    sarkwalvein Professional asshole at GBATemp

    Member
    GBAtemp Patron
    sarkwalvein is a Patron of GBAtemp and is helping us stay independent!

    Our Patreon
    4,872
    4,925
    Jun 29, 2007
    Germany
    Niedersachsen
    WARNING!!!
    strcpy syntax is strcpy(destination, source)
     
  7. StackMasher
    OP

    StackMasher GBAtemp Regular

    Member
    111
    54
    Nov 29, 2016
    OK i've changed the strcpy to a custom for loop and it works now
    Code:
    int strLen = strlen(buffer.str().c_str()) + 1;
    char* toReturn = new char[strLen];
    for (int i{}; i<strLen; ++i) {
        toReturn[i] = buffer.str().c_str()[i];
    }
    Just out of curiosity, why can't you save or pass the pointer that buffer.str().c_str() returns?

    I remember it with the GAS assembly syntax, first src then dest, though I've probably got that wrong because I haven't done assembly in a while
     
    Last edited by StackMasher, May 9, 2017
  8. GerbilSoft

    GerbilSoft GBAtemp Addict

    Member
    2,063
    2,284
    Mar 8, 2012
    United States
    The original strcpy might have worked; you just had the parameters reversed.

    If you were trying to return buffer.str().c_str(), that's undefined. buffer is a local variable in the function. c_str() returns a pointer to a temporary string created by the stringstream, so you end up returning a pointer to a temporary object, which gets deleted immediately after returning. The pointer ends up pointing to freed memory.

    Here's what you can and can't do in this case.

    Yes:
    Code:
    {
        string str = buffer.str();
        const char *c_str = str.c_str();
        // do stuff with c_str within this function, e.g.:
        cout << "c_str == " << c_str << endl;
    }
    
    You first save the string object to a local variable, then take the c_str() pointer from the str. This works within the same function as long as the original string is in scope. You cannot return c_str, because that will result in a dangling pointer.

    No:
    Code:
    {
        const char *c_str = buffer.str().c_str();
        // BAD! This will result in undefined behavior!
        cout << "c_str might be: " << c_str << endl;
    }
    
    buffer.str() returns a temporary string object. This then calls c_str() to get the C string pointer, but after that's done, the temporary string object is deleted. This results in c_str pointing to nowhere.

    No:
    Code:
    {
        string str = buffer.str();
        const char *c_str = str.c_str();
        return c_str; // BAD: str is deleted after returning
    }
    
    str is deleted after returning, so the returned c_str pointer is pointing nowhere.
     
    Last edited by GerbilSoft, May 9, 2017
    StackMasher likes this.