Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading a fixed number of chars with << on an istream

I was trying out a few file reading strategies in C++ and I came across this.

ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
    ifsw1 >> ifsw1w;
    if (ifsw1.eof())
        break;
    cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();

The content of the file were

firstfirst firstsecond
secondfirst secondsecond

When I see the output it is printed as

 firstfirst
firstsecond
secondfirst

I expected the output to be something like:

fir
stf
irs
tfi
.....

Moreover I see that "secondsecond" has not been printed. I guess that the last read has met the eof and the cout might not have been executed. But the first behavior is not understandable.

like image 404
bsoundra Avatar asked Feb 13 '11 00:02

bsoundra


2 Answers

The extraction operator has no concept of the size of the ifsw1w variable, and (by default) is going to extract characters until it hits whitespace, null, or eof. These are likely being stored in the memory locations after your ifsw1w variable, which would cause bad bugs if you had additional variables defined.

To get the desired behavior, you should be able to use

ifsw1.width(3);

to limit the number of characters to extract.

like image 149
irritate Avatar answered Sep 23 '22 00:09

irritate


  1. It's virtually impossible to use std::istream& operator>>(std::istream&, char *) safely -- it's like gets in this regard -- there's no way for you to specify the buffer size. The stream just writes to your buffer, going off the end. (Your example above invokes undefined behavior). Either use the overloads accepting a std::string, or use std::getline(std::istream&, std::string).

  2. Checking eof() is incorrect. You want fail() instead. You really don't care if the stream is at the end of the file, you care only if you have failed to extract information.

For something like this you're probably better off just reading the whole file into a string and using string operations from that point. You can do that using a stringstream:

#include <string> //For string
#include <sstream> //For stringstream
#include <iostream> //As before

std::ifstream myFile(...);
std::stringstream ss;
ss << myFile.rdbuf(); //Read the file into the stringstream.
std::string fileContents = ss.str(); //Now you have a string, no loops!
like image 45
Billy ONeal Avatar answered Sep 25 '22 00:09

Billy ONeal