Problem with istream::tellg()? - c++

I'm reading data.txt:
//////////////////////////////////////////////////
data.txt:
//////////////////////////////////////////////////
MissionImpossible3
3
TomCruise
MaggieQ
JeffChase
Here's code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream fin("data.txt");
string FilmName, ActorName;
getline(fin,FilmName,'\n');
cout << FilmName << endl;
// cout << fin.tellg() << endl; //if I add this line to
// get current reading position of data.txt, the program just
// can't work as if tellg() triggered some error. So I removed
// all tellg(). What's the reason for this and what shall I do
// if I want to get current reading position?
int a;
fin >> a;
cout << a << endl;
// cout << fin.tellg() << endl;
getline(fin,ActorName,'\n');
// cout << fin.tellg() << endl;
for(int i=0;i<a;i++)
{
getline(fin,ActorName,'\n');
cout << ActorName << endl;
// cout << fin.tellg() << endl;
}
getchar();
}
Unexpected output is:
MissionImpossible3240-1-1
I'm using Dev-c++ and Windows XP. I'll appreciate it if you guys give it a try and paste your results and environment. Maybe there is some problem with my system or compiler.
Another version of input/output:
data.txt:
MissionImpossible3
3
TomCruise
MaggieQ
JeffChase
WarOfTheWorlds
2
TomCruise
DakotaFanning
SharkTale
3
JackBlack
RobertDeNiro
WillSmith
HideAndSeek
2
DakotaFanning
RobertDeNiro
TheAdventureOfPlutoNash
2
WillSmith
EddieMurphy
ShowTime
2
RobertDeNiro
EddieMurphy
output:
MissionImpossible3
49
0
-1
-1

It says it consumed 24 characters after the first line, then failed to get a number. However, MissionImpossible3 only has 18 characters.
I suspect you have a line encoding incompatiblity. Your file is saved with \n endings, while Windows iostreams expects \r\n. The 3 in the input gets thrown away as the system expects a \n. Then the next input is non-numeric and it enters an error state.
Try copy-pasting the input data to a new file in Notepad.

Try opening the file in binary mode:
ifstream fin("data.txt", ios::binary);

Creating the ifstream with std::ios::binary fixed the tellg so it returned the correct position in the file in my code as well (Win 7 64-bit).
As L.Lawliets asks - Why??!

I compiled and ran your code with the tellg lines re-enabled, and it seemed to work fine. The output I got was:
MissionImpossible3
20
3
21
23
TomCruise
34
MaggieQ
43
JeffChase
52
What exact result do you get when you try to run it? [Yes, this is really more of a comment than an answer, but it won't fit in a comment.]

Related

Why does C++ fstream require call to clear() after calling std::getline in a loop

In the following code I do a read from a file containing simply "12345" using std::getline, and immediately after attempt to write "67890" to the file. This write will fail unless I first call myfile.clear(). Why is this? What exactly is breaking? Is there a way to still use std::getline in a loop but prevent an error from occurring when the last line is read? What is correct?
#include <fstream>
#include <iostream>
#include <string>
using std::cout;
using std::fstream;
using std::string;
void printStats(fstream&);
int main(int argc, char* argv[])
{
// textfile.txt:
// 1234
fstream myfile("textfile.txt", std::fstream::in | std::fstream::out);
string line;
cout << "\n"
<< "Before reading lines in a loop.\n";
printStats(myfile);
cout << "\n"
<< "Reading lines in the loop.\n";
while (myfile.eof() != true)
{
std::getline(myfile, line); // Last call here causes EOF and FAIL bit to be set
cout << "line=" << line << "\n";
}
cout << "\n"
<< "After reading lines in a loop.\n";
printStats(myfile);
myfile.clear(); // If I comment this out the write below fails
myfile << "67890\n";
myfile.close();
return 0;
}
void printStats(fstream& fileStream)
{
int position = fileStream.tellp();
cout << "position = " << position << "\n";
if (fileStream.eof() == true)
cout << "EOF bit = 1\n";
else
cout << "EOF bit = 0\n";
if (fileStream.fail() == true)
cout << "FAIL bit = 1\n";
else
cout << "FAIL bit = 0\n";
if (fileStream.bad() == true)
cout << "BAD bit = 1\n";
else
cout << "BAD bit = 0\n";
}
Here are the results from execution with myfile.clear() commented out:
user#Ubuntu:~/example/test$ cat textfile.txt ; ./test ; cat textfile.txt
12345
Before reading lines in a loop.
position = 0
EOF bit = 0
FAIL bit = 0
BAD bit = 0
Reading lines in the loop.
line=12345
line=
After reading lines in a loop.
position = -1
EOF bit = 1
FAIL bit = 1
BAD bit = 0
12345
Here are the results from execution with myfile.clear() included in the code:
user#Ubuntu:~/example/test$ cat textfile.txt ; ./test ; cat textfile.txt
12345
Before reading lines in a loop.
position = 0
EOF bit = 0
FAIL bit = 0
BAD bit = 0
Reading lines in the loop.
line=12345
line=
After reading lines in a loop.
position = -1
EOF bit = 1
FAIL bit = 1
BAD bit = 0
12345
67890
This is compiled with g++ on Ubuntu Linux 20.04
user#Ubuntu:~/example/test$ /usr/bin/g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
I did find this similar result below but it does not clearly explain the answers to my questions.
c++ getline() looping when used in file with a read in int array?
Looks like you're running into the issue of why while(!in.eof()) is usually wrong. The eofbit isn't set until after you've attempted to read past the end of the file, which because you're doing so with getline causes the failbit to be set as well. Then the stream refuses to write while myfile.fail() is true, which it is until you clear it.

Garbage value when getting integer value from binary file in c++

I am studying binary file of C++ nowadays. I made a example code for it, but it does not work well.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream writeFile;
ifstream readFile;
int temp = 1;
writeFile.open("file.dat", ios::binary);
for (int i = 5; i <= 10 ; i++) // range 5 to 10
writeFile.write((char*)(&i), sizeof(i));
writeFile.close();
readFile.open("file.dat", ios::binary);
readFile.seekg(0);
while (!readFile.eof()) {
readFile.read((char*)(&temp), sizeof(temp));
cout << "temp: " << temp << endl;
readFile >> ws;
}
readFile.close();
system("pause");
return 0;
}
Here is the result:
temp: 5
temp: 6
temp: 7
temp: 8
temp: 167772160
temp: 167772160
When I change the range not to include 9 (for example, 5 to 8), it works well. Also, When I make the same code with double type, it works well. So I think the integer 9 is problem. Can you tell me why?
readFile >> ws; discards white space, which is non-sense for a binary stream. In this case, the character value 9 (which is '\t') is skipped, corrupting your stream. Simply remove that line.
The second problem is you are not checking the state of the stream between reading and displaying the value. EOF is only detected after a read would exceed the end of the file. This is why you get your invalid value twice, the second time the read fails and simply leaves temp with it's previous value. See this question for a more details.
The answer by François Andrieux already has the answer to the question of why your code behaves the way it does.
Here are couple of methods to fix the problem.
Use a for loop to read the numbers. It mirrors the loop used to write to it.
readFile.open("file.dat", ios::binary);
for (int i = 5; i <= 10 ; i++)
{
readFile.read((char*)(&temp), sizeof(temp));
cout << "temp: " << temp << endl;
}
readFile.close();
Use the while loop correctly.
readFile.open("file.dat", ios::binary);
while (readFile.read((char*)(&temp), sizeof(temp)))
{
cout << "temp: " << temp << endl;
}
readFile.close();

Reading Input Error

I am working on NOV14 on COdechef contest problems. and i stuck at this problem.
http://www.codechef.com/NOV14/problems/RBTREE
My algorithm working well, but i cant take the input correctly. the problem is i don't know how many number of inputs are given. but i need to store in multiple variables.
Take a look at here..
5
Qb 4 5
Qr 4 5
Qi
Qb 4 5
Qr 4 5
where 5 is the number of test cases,
can i read every test cases into variables.
if i take First test case I can take Qb to one variable, 4 to other and 5 to another.
But the problem is How to read a line which start with Qi.
Well, first of all, if you write C++, you should use C++ streams. Here's the code for input (which you can adjust for your own needs):
#include <iostream>
#include <fstream>
int main() {
std::ifstream file;
file.open("data.in");
int lines = 0;
file >> lines;
std::string query_type;
for (int i = 0; i < lines; i++) {
file >> query_type;
if (query_type == "Qi") {
std::cout << query_type << std::endl;
} else {
int x = 0;
int y = 0;
file >> x >> y;
std::cout << query_type << " " << x << " " << y << std::endl;
}
}
file.close();
return 0;
}
You'll need to check what you've read at each step, and then determine whether or not you need to read the numbers in.
So read two characters, and if the characters you've read are "Q" and "i", you don't need to read any numbers, and you can just step on to the next line. Otherwise, you should read the two numbers before going to the next line.

I'm Having Trouble Skipping Certain Characters from an Input Text File (C++)

(I apologize that this is so low level compared to most of the questions I have seen on this website, but I have run out of ideas and I do not know who else to ask.)
I am working on a school project that requires me to read basketball statistics from a file named in06.txt. The file in06.txt looks exactly as follows:
5
P 17 24 9 31 28
R 4 5 1 10 7
A 9 2 3 6 8
S 3 4 0 5 4
I am required to read and store the first number, 5, into a variable called "games." From there, I must read the numbers from the second line and determine the high, the low, and the average. I must do the same thing for lines 3, 4, and 5. (FYI, the letters P, R, A, and S are there to indicate "Points," "Rebounds," "Assists," and "Steals.")
Since I only have been learning about programming for a few weeks, I do not want to overwhelm myself by jumping right into dealing with every aspect of the project. So, I am first working on determining the average from each line. My plan is to keep a running total of each line and then divide the running total by the number of games, which is 5 in this case.
This is my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
int games;
int points_high, points_low, points_total;
int rebounds_high, rebounds_low, rebounds_total;
int assists_high, assists_low, assists_total;
int steals_high, steals_low, steals_total;
double points_average, rebounds_average, assists_average, steals_average;
ifstream fin;
ofstream fout;
fin.open("in06.txt");
if( fin.fail() ) {
cout << "\nInput file opening failed.\n";
exit(1);
}
else
cout << "\nInput file was read successfully.\n";
int tempint1, tempint2, tempint3, tempint4;
char tempchar;
fin >> games;
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character P from the text file.
while( fin >> tempint1 ) {
points_total += tempint1;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character R from the text file.
while( fin >> tempint2 ) {
rebounds_total += tempint2;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character A from the text file.
while( fin >> tempint3 ) {
assists_total += tempint3;
}
fin.get(tempchar); // Takes the endl; from the text file.
fin.get(tempchar); // Takes the character S from the text file.
while( fin >> tempint4 ) {
steals_total += tempint4;
}
cout << "The total number of games is " << games << endl;
cout << "The value of total points is " << points_total << endl;
cout << "The value of total rebounds is " << rebounds_total << endl;
cout << "The value of total assists is " << assists_total << endl;
cout << "The value of total steals is " << steals_total << endl;
return 0;
}
And this is the (incorrect) output:
Input file was read successfully.
The total number of games is 5
The value of total points is 111
The value of total rebounds is 134522076
The value of total assists is 134515888
The value of total steals is 673677934
I have been reading about file input in my textbook for hours, hoping that I will find something that will indicate why my program is outputting the incorrect values. However, I have found nothing. I have also researched similar problems on this forum as well as other forums, but the solutions use methods that I have not yet learned about and thus, my teacher would not allow them in my project code. Some of the methods I saw were arrays and the getline function. We have not yet learned about either.
Note: My teacher does not want us to store every integer from the input file. He wants us to open the file a single time and store the number of games, and then use loops and if statements for determining the high, average, and low numbers from each line.
If anyone could help me out, I would GREATLY appreciate it!
Thanks!
You have all these variables declared:
int games;
int points_high, points_low, points_total;
int rebounds_high, rebounds_low, rebounds_total;
int assists_high, assists_low, assists_total;
int steals_high, steals_low, steals_total;
double points_average, rebounds_average, assists_average, steals_average;
And then you increment them:
points_total += tempint1;
Those variables were never initialzed to a known value (0), so they have garbage in them. You need to initialize them.
Besides what OldProgrammer said, you've approached the reading of integers incorrectly. A loop like this
while( fin >> tempint2 ) {
rebounds_total += tempint2;
}
will stop when an error occurs. That is, either it reaches EOF or the extraction encounters data that cannot be formatted as an integer - or in other words, good() returns false. It does not, as you seem to think, stop reading at the end of a line. Once an error flag is set, all further extractions will fail until you clear the flags. In your case, a loop starts reading after P, extracts five intergers, but then it encounters the R from the next line and errors out.
Change this to a loop that reads a fixed number of integers or alternatively, read a whole line using std::getline into a std::string, put it into a std::stringstream and read from there.
In any case, learn to write robust code. Check for success of extractions and count how many elements you get.
An example of a loop that reads at most 5 integers:
int i;
int counter = 0;
while (counter < 5 && file >> i) {
++counter;
// do something with i
}
if (counter < 5) {
// hm, got less than 5 ints...
}

String.at() returning funky numbers

when I am trying to run this snippet of code I am getting some malfunctions I have not been able to pinpoint the cause of. The first two "cout" lines display the numbers 7 and 3, however, the last "cout" line displays numbers ranging from 50-60 usually (At the moment when I run it I get 55 and 51, which seems to somehow correlate a bit with the numbers I am trying to read). As far as I can tell from some googling and the books I have at hand this should be valid, but there's obviously something I am missing. Thank you for your time.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string text = "73";
int one=0, two=0;
cout << text.at(0) << endl;
cout << text.at(1) << endl;
one = text.at(0);
two = text.at(1);
cout << one << endl << two << endl;
return 0;
}
the program functions correctly: text.at() returns a char, which you implicitly convert to an int. Then you print the value of that int, which are respectively 55 for "7" and 51 for "3" (look here).