what's wrong here? [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is iostream::eof inside a loop condition considered wrong?
i used this code to replace the first " with `` and the second one with ''
everything works just fine except it runs through the loop one more time after the last character is read and that makes the program print another character
#include <fstream>
#include <iostream>
using namespace std ;
void main ()
{
ifstream infile;
infile.open("infile.txt");
ofstream outfile;
outfile.open("outfile.txt");
char c ;
int i = 0 ;
while ( !infile.eof() )
{
infile.get(c)
if (c=='\"')
{
i++ ;
if (i%2==0)
outfile<<"\'\'";
else
outfile<<"``";
}
else
outfile<<c;
}
outfile.close();
infile.close();
}

Don't do while ( !infile.eof() ) - this only checks if the previous read hit the end of the file, not if the next one will. So when the last character is read, it loops round again, sees that it hasn't hit the end of file yet and then proceeds to read another character even though there isn't another character to read. Your c will have the same value from the previous iteration.
Instead, do this:
while (infile.get(c))
{
// ...
}
This will read a character from the file and then, if that was succesful, will do something with that character.

Related

C++ Im trying to stream a file, and replace the first letter of every line streamed. It doesn't seem to be working as expected

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>
void add1(std::fstream& files)
{
char c;
int i=0;
int j=0;
int k=0;
int con=0;
string word;
while(files.get(c)&&!files.eof())
{
i++;
j++;
if(c=='\n'||(con>=1&&isspace(c)))
{
con++;
if(con>=2)
{
break;
}
else
{
cout<<j<<"\/"<<i<<endl;
files.seekp(i-j,files.beg);
files.write("h",1);
files.seekg(i);
*seekg ends the loops I tried fstream::clear. I think it would work perfect if seekg worked.
+ without seekg it works but only for 3 lines then its off.
j=0;
word="";
}
}
else
{
con=0;
word=word+c;
}
}
}
*The goal is to be able stream the file, and replace the first letter of every line in the file while streaming.*
You seam to have a logical error and make thinks overcomplicated.
I do not knwow, what you want to do with your variable "word". It is consumed nowhere. So, I will ignore it.
Then you are playing with read and write pointers. That is not necessary. You only need to manipulate the write pointer.
Then, you want to "stream" something. This I do not fully understand. Maybe it means, that you want to write always something to the stream, even, if you do not replace anything. This would in my understanding only make sense, if you would have 2 streams. But in that case it would be brutally simple and no further thinking necessary.
If we use the same stream and do not want to replace a character, then this is already there, existing, and maybe not overwritten by the same character again.
So, if there is nothing to replace, then we will write nothing . . .
Also, and that is very important, we do no replacement operation, if we have an empty line, because then there is nothing to replace. There is now first character in an empty line.
And, most important, we cannot add characters to the same fstream. In that case we would have to shift the rest of the file one to the right. Therefore. 2 streams are always better. Then, this problem would not occur.
So, what's the logic.
Algorithm:
We always look at the previuosly read character. If that was a '\n' and the current character is not, then we are now in a new line and can replace the first character.
That is all.
It will take also into account, if a '\n' is encoded with 2 characters (for example \r\n). It will always work.
And, it is easy to implement. 10 lines of code.
Please see:
#include <iostream>
#include <fstream>
#include <string>
constexpr char ReplacementCharacter{ 'h' };
void replaceFirstCharacterOfLine(std::fstream& fileStream) {
// Here we stor the previously read character. In the beginning, a file always starts
// with a newline. Therefore we pretend that the last read character is a newline
char previouslyReadCharacter{'\n'};
// Here we store the current read character
char currentCharacter{};
// Get characters from file as lon as there are characters, so, until eof
while (fileStream.get(currentCharacter)) {
// No check, if a new line has started. We ignore empty lines!
if ((previouslyReadCharacter == '\n') && (currentCharacter != '\n')) {
// So last charcter was a newline and this is different. So, we are in a new, none empty line
// Set replacement character
currentCharacter = ReplacementCharacter;
// Go one back with the write pointer
fileStream.seekp(-1, std::ios_base::cur);
// Write (an with taht increment file pointer again)
fileStream.put(currentCharacter);
// Write to file
fileStream.flush();
}
else {
// Do not replace the first charcater. So nothing to be done here
}
// Now, set the previouslyReadCharacter to the just read currentCharacter
previouslyReadCharacter = currentCharacter;
}
}
int main() {
const std::string filename{"r:\\replace.txt"};
// Open file
std::fstream fileStream{ filename };
// Check, if file could be opened
if (fileStream)
replaceFirstCharacterOfLine(fileStream);
else
std::cerr << "\n\n*** Error: Could not open file '" << filename << "'\n\n";
return 0;
}

Problems with reading text from a file [duplicate]

This question already has answers here:
Read whole ASCII file into C++ std::string [duplicate]
(9 answers)
Closed 9 years ago.
I have this function that reads the text from a file and adds it to a string, now the weird thing is that it works fine if its a short text. But if its a longer text the string becomes empty, any help solving this problem is appreciated.
string inlasning(string namn)
{
string filString, temp;
ifstream filen(namn.c_str());
if(!filen.good())
{
cout << "Otillganglig fil" << endl;
filString = "ERROR";
return filString;
}
else
{
while(!filen.eof())
getline(filen, temp);
filString.append(temp);
}
filen.close();
return filString;
}
1) Don't use eof() to control the loop. Put getline directly into the loop condition. Search StackOverflow if you have problems doing this.
2) Your while loop has no braces and thus only covers the getline line, despite your misleading indentation.
3) getline discards newlines. Your final string will be wrong.
4) The actual behavior you're observing comes from the fact that you only append the very last thing that getline returns to your string. When your file contains one line of text and doesn't end in a newline, this will seem to work. If it has more lines but doesn't end in a newline, you'll only get the last line. If the file does end in a newline, because of your incorrect loop condition the last call to getline will actually give you an empty string, which will be exactly the contents of your string.
Replace
while(!filen.eof())
getline(filen, temp);
filString.append(temp);
with
while(!filen.eof())
{
getline(filen, temp);
filString.append(temp);
}
Use "is_open()" to check if the file exists:
if( ! filen.is_open() ){...} // you don't need an else clause
...And your while loop must has braces or it will only execute the getline(...) instruction:
while( filen.good() ) {
getline( filen , temp );
filString += ( temp + '\n' );
}
If your file doesn't ends with '\n', remove the last char from the string

Error reading and printing a text file with C++

I have a bug with my code (the code at the end of the question). The purpose of my C++ executable is to read a file that contains numbers, copy it in a std::vector and
then just print the contents in the stdout? Where is the problem? (atoi?)
I have a simple text file that contains the following numbers (each line has one number)
mini01:algorithms ios$ cat numbers.txt
1
2
3
4
5
When I execute the program I receive one more line:
mini01:algorithms ios$ ./a.out
1
2
3
4
5
0
Why I get the 6th line in the stdout?
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void algorithm(std::vector<int>& v) {
for(int i=0; i < v.size(); i++) {
cout << v[i] << endl;
}
}
int main(int argc, char **argv) {
string line;
std::vector<int> vector1;
ifstream myfile("numbers.txt");
if ( myfile.is_open()) {
while( myfile.good() )
{
getline(myfile, line);
vector1.push_back(atoi(line.c_str()));
}
myfile.close();
}
else {
cout << "Unable to open file" << endl;
}
algorithm(vector1);
return 0;
}
You should not use while (myfile.good()), as it will loop once to many.
Instead use
while (getline(...))
The reason you can't use the flags to check for looping, is that they don't get set until after an input/output operation notices the problem (error or end-of-file).
Don't use good() as the condition of your extraction loop. It does not accurately indicate whether the next read will succeed or not. Move your call to getline into the condition:
while(getline(myfile, line))
{
vector1.push_back(atoi(line.c_str()));
}
The reason it is failing in this particular case is because text files typically have an \n at the end of the file (that is not shown by text editors). When the last line is read, this \n is extracted from the stream. Yes, that may be the very last character in the file, but getline doesn't care to look any further than the \n it has extracted. It's done. It does not set the EOF flag or do anything else to cause good() to return false.
So at the next iteration, good() is still true, the loop continues and getline attempts to extract from the file. However, now there's nothing left to extract and you just get line set to an empty string. This then gets converted to an int and pushed into the vector1, giving you the extra value.
In fact, the only robust way to check if there is a problem with extraction is to check the stream's status bits after extracting. The easiest way to do this is to make the extraction itself the condition.
You read one too many lines, since the condition while is false AFTER you had a "bad read".
Welcome to the wonderful world of C++. Before we go to the bug first, I would advise you to drop the std:: namespace resolution before defining or declaring a vector as you already have
using namespace::std;
A second advise would be to use the pre increment operator ++i instead of i++ wherever feasible. You can see more details on that here.
Coming to your problem in itself, the issue is an empty new line being read at the end of file. A simple way to avoid this would be to check the length of line before using it.
getline(myfile, line);
if (line.size()) {
vector1.push_back(atoi(line.c_str()));
}
This would enable your program now to read a file interspersed with empty lines. To be further foolproof you can check the line read for presence of any non numeric characters before using atoi on it. However the best solution as mentioned would be use to read the line read to the loop evaluation.

Function End of file loops extra loop ? C++ [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 9 years ago.
am trying to read characters from file but when I use end of file function it loops more than the number of character inside the file by 1 .. but I don't know why ?
#include <iostream>
#include <fstream>
int main()
{
ifstream file;
char ch1;
file.open("c:\\Downloads\\test.txt" , ios::in);
int i=0;
while(!file.eof())
{ i++;
file>>ch1;
cout<<ch1<<endl;
}
cout <<i<<endl;
file.close();
return 0;
}
file contains
[]
output : [ ] ] 3
Well, when you've read the last character in the file file.eof() is still false, because the stream doesn't yet know that it's reached the end. Only after you attempt to read the already nonexistent character is eof set to true. You should probably do this
char ch;
while(file >> ch)
{
...
}
The reason is because just because you haven't hit the end of the file yet, doesn't mean the next read is going to succeed. Because you are reading characters, the EOF will only be set when you actually attempt to read after the last character.
In fact, even when you are reading strings, integers or other similar things out of a file there is a similar problem. At the end of many text files is an extra \n with no text after it. So when the last line is read, there is still a \n in the stream but EOF has not been set. You then proceed to read the next line which is not there whatever you are extracting into is left with the same contents as before. This results in what appears to be a duplicate reading.

Item at end of text file being read twice [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
ifstream not reading EOF character
(4 answers)
Closed 9 years ago.
The text file contains lines formatted like so:
lSdhmhlN 15479 6694.74 O
szUfGnoI 18760 5275.53 n
I'm reading the file line by line, putting its data into buffer variables, storing those variables in a TopicD object, and inserting that object into a binary search tree. Problem is that the last line of the file is being read twice so that two identical TopicD objects are created and inserted into the tree. Why?
Here's my code:
template<class ItemType>
void read( BinarySearchTree<ItemType> & tree )
{
ifstream read( FILE_NAME.c_str() );
if ( read.fail() )
die( "Error opening the file." );
string strbuff;
double dubbuff;
int intbuff;
char chbuff;
while ( !read.eof() )
{
read >> strbuff;
read >> intbuff;
read >> dubbuff;
read >> chbuff;
TopicD buff( strbuff, dubbuff, intbuff, chbuff );
tree.add(buff);
}
read.close();
}
Consider snipping just a bit out of that loop:
while (read >> strbuff >> intbuff >> dubbuff >> chbuff)
tree.add(TopicD( strbuff, dubbuff, intbuff, chbuff ));
Never rely on .eof() to be true when you reach EOF. Rather, it will be true when, among other things, you try to read again once you are there. Therefore your first read after arriving at EOF is failing, but by that time you've stopped checking for errors (which you were never checking to begin with, by the way) and just blindly insert whatever you have in your variables into your tree.