Search code examples
c++streamifstreamofstream

C++ streams can't tell where one string ends and the next begins?


I'm writing a string and an int to an ofstream, then trying to read that back with an ifstream. I would expect the string to be null terminated, so the stream should know where the string stops and where the int begins. But that's not happening -- when I read it back in, it treats the int as part of the string. How do I avoid that?

#include <fstream>
#include <string>

int main()
{
    std::string tempFile("tempfile.out");
    std::ofstream outStream(tempFile); //Tried this both with text 
    //and with ::bin but get same results

    std::string outStr1("Hello");
    int outInt1 = 5;
    std::string outStr2("Goodbye");

    outStream << outStr1 << outInt1 << outStr2;
    outStream.close();

    std::ifstream inStream(tempFile);  //Tried this both with text 
    //and with ::bin but get same results
    std::string inStr1, inStr2;
    int inInt1;
    inStream >> inStr1; //this reads a string that concats all 
    //my prev values together!
    inStream >> inInt1; //doesn't do what I want since the int was 
    //already read as part of the string
    inStream >> inStr2; //doesn't do what I want 
}

How can I make it separate the string and the int instead of combining them into a single string?


Solution

  • You can simply add newline to separate the strings

    outStream << outStr1 << std::endl << outInt1 << std::endl << outStr2;
    

    But why is the newline needed? The string is null-terminated, so shouldn't c++ write that null character to the byte stream? If so, then why is a newline needed?

    It doesn't have to be newline though newline would work for you...

    std::string doesn't necessarily have to be nul terminated. It has size and should be treated like an array/vector of characters. You can write the nul to the stream if the str is constructed as:

    std::string outStr1{'H', 'e', 'l', 'l', 'o', 0};
    

    while

     std::string s("OK");
    

    constructs a string with size 2.

    When you read data from a stream, it needs to know the rule to extract bytes and convert to the type expected. Basically if you read a string from the stream it needs to know when to end the string. The simple rule is if it reaches a space(std::isspace()), the string terminates. Here space means whitespace, tab, line break, etc.

    Say if you want to extract an integer, it should stop when reaching a char that is not legal in a integer notation, like 'z'.

    To fully understand this, http://en.cppreference.com/w/cpp/concept/FormattedInputFunction is a good start.