Reading a fixed number of characters from << to istream

I tested several strategies for reading files 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(); 

File contents

  firstfirst firstsecond
 secondfirst secondsecond

When I see the output, it prints like

  firstfirst
 firstsecond
 secondfirst

I expected the result would be something like this:

  fir
 stf
 irs
 tfi
 .....

In addition, I see that β€œsecond of second” was not printed. I think the last read met eof, and cout may not have been executed. But the first behavior is incomprehensible.

+4
source share
5 answers

The extraction operator has no idea about the size of the ifsw1w variable and (by default) is going to extract the characters until it hits spaces, null or eof. They are probably stored in memory after the ifsw1w variable, which can lead to errors if you have additional variables.

To get the desired behavior, you can use

 ifsw1.width(3); 

to limit the number of characters to extract.

+7
source

You are destroying the memory ... reading it behind the 3 characters you defined (reading up to a space or a new line is done).

Read char on char to get the result you mentioned.

Edit: Annoying correctly, this also works (with some fixes, not with the exact result, but with the spirit):

 char ifsw1w[4]; do{ ifsw1.width(4); ifsw1 >> ifsw1w; if(ifsw1.eof()) break; cout << ifsw1w << flush << endl; }while(1); ifsw1.close(); 
+2
source
  • It is almost impossible to use std::istream& operator>>(std::istream&, char *) safely - this is how gets in this regard - you do not need to specify the size of the buffer. The stream simply writes to your buffer, goes to the end. (The above example invokes undefined behavior). Either use overloads that accept std::string , or use std::getline(std::istream&, std::string) .

  • Invalid eof() check. Instead, you want fail() . You really don't care if the stream is at the end of the file, you only care if you were unable to extract the information.

For something like this, it's probably best for you to just read the entire file into a line and use the operations on that line. You can do this with a string stream:

 #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! 
+2
source

The code has undefined behavior. When you do something like this:

 char ifsw1w[3]; ifsw1 >> ifsw1w; 

operator>> gets a pointer to the buffer, but has no idea of ​​the actual size of the buffer. Thus, he cannot know that he should stop reading after two characters (and note that this should be 2, not 3 - to complete the line β€œrequired” for β€œ\ 0”).

Bottom line: When learning how to read data, this code is probably best ignored. What you can learn from code like this, you should avoid. However, as a rule, it is easier to simply follow a few rules of thumb than to try to study all the problems that may arise.

  • Use std :: string to read strings.
  • Use only fixed buffers for fixed size data.
  • When you use fixed buffers, skip their size to limit the number of reads.
  • If you want to read all the data in a file, std::copy can avoid many errors:

    std :: vector strings.
    std :: copy (std :: istream_iterator (Myfile), std :: istream_iterator (), std :: back_inserter (lines));

+2
source

To read spaces, you could use "noskipws", it will not skip spaces.

 ifsw1 >> noskipws >> ifsw1w; 

But if you want to get only 3 characters, I suggest you use the get method:

 ifsw1.get(ifsw1w,3); 
+1
source

Source: https://habr.com/ru/post/1339505/


All Articles