Ifstream.getline() - Only reading first line? - c++

I'm just trying to run a simple c++ program that will format a .txt file with data entries. I have run it with many different text files of the exact same format, and now it just won't work. I'm sure the solution is simple.
Here is a simplified version of the program (I trimmed down everything to only show the parts that are giving me trouble).
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
int main(){
ifstream filei("in.txt");
ofstream fileo("comlab.txt");
double a, b;
string s;
stringstream ss;
while (getline(filei,s)){
ss<<s;
ss>>a>>b;
fileo<<setw(10)<<a<<setw(10)<<b<<'\n';
}
fileo.close();
}
Here is a sample input for in.txt:
1 11
2 22
3 33
4 44
5 55
Now here is what I want to show up (exactly the same as input):
1 11
2 22
3 33
4 44
5 55
But here is what actually shows up:
1 11
1 11
1 11
1 11
1 11
What is going on? I'm compiling with g++ and following the C++11 standard.

When you execute
ss>>a>>b;
in the first round of execution of the loop. ss is already at the end of the stream. i.e. ss.eof() == true. You need to clear its state and reset state to start reading from the beginning.
while (getline(filei,s)){
ss<<s;
ss>>a>>b;
ss.clear();
ss.seakg(0);
fileo<<setw(10)<<a<<setw(10)<<b<<'\n';
}
A better alternative is to create the object within the scope of the loop.
while (getline(filei,s)){
stringstream ss;
ss<<s;
ss>>a>>b;
fileo<<setw(10)<<a<<setw(10)<<b<<'\n';
}
or even simpler (Thanks to #vsoftco for the suggestion)
while (getline(filei,s)){
stringstream ss(s);
ss>>a>>b;
fileo<<setw(10)<<a<<setw(10)<<b<<'\n';
}

Related

Reading text fies with inconsistent format

I am trying to perform some operations on a text file containing a repetition of a C based string and some numbers. My code successfully carried out the operation on the first set but it would not get to the remaining sets.
Please see the content of the text file below:
Max Scherzer 2017
6.2 4 2 2 2 7
6.0 4 3 1 2 10
mod Cameron 2018
6.4 4 1 2 1 3
6.0 4 3 5 2 8
John Brandonso 2019
6.1 1 3 5 2 7
6.5 4 7 3 4 10
I have used .eof() and it completely messed up what i am doing.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
char playername [25];
int season;
ifstream gamefilein;
gamefilein.open("C:\\Users\\troy\\Desktop\\GAME_SCORE\\gameinfo.txt");
if(!gamefilein)
{
cout<<"unable to open file";
}
double IP;
int H,R,ER,BB,K;
int counter=0;
double totalscore=0;
while(!gamefilein.fail())
{
gamefilein.get(playername,25);
gamefilein>>season;
cout<<playername<<season<<endl;
cout<<"Game Scores:"<<endl;
while(gamefilein>>IP>>H>>R>>ER>>BB>>K)
{
int IPa=IP;
int IPb=(IP-IPa)*10;
int IPc=0;
if(IPa>4)
{
IPc=IPa-4;
}
int score=50+(IPa*3)+(IPb*1)+(IPc*2)+(K*1)-(H*2)-(ER*4)-((R-ER)*2)-(BB*1);
cout<<score<<endl;
counter++;
totalscore+=score;
}
cout<<"Number of Games Started: "<<counter<<endl;
cout<<fixed<<setprecision(2)<<"Average Game Score:
<<(totalscore/counter)<<endl<<endl;
}
gamefilein.close();
return 0;
}
I get the below result, but I want the same result for the rest of the information in the text file, for example, I am expecting two more results like the one I have below.
Max Scherzer 2017
Game Scores:
63
64
Number of Games Started: 2
Average Game Score: 63.50
Aren't you reading the file as a char array?
If I read this correctly you try to shift an int and double over a char array with numbers in a STRING right?
e.g. "6.2" string is different than a 6.2 double number in your memory, hence why it cant work.
You also seem to have a lot of spaces which should not forget as well.
Where do you get that string to begin with? I would recommend you change the creation of that file to a more convenient format e.g. cv or json
I just solved my problem myself. The problem occurred when the loop operating on the integers and double completes its run and sees the character-based string that is in the next dataset. So i inserted a clear member function just at the point where i check for end of file
(gamefilein.clear())
and that solved my problem.
Thanks for attempting to help

Misunderstood the usage of cin.unget() while handling I/O files C++

For example, I have a file named Bjarne.txt and in it there's the integers:
16 2 3 4
I have made a program to read the integers available inside the file and output them to me in the console window , however , I'm trying to use cin.unget() and by that get understanding of what it does actually , here's the source code:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ifstream ifs("Bjarne.txt");
int a;
for(int i = 0;i<4;++i){
ifs>>a;
cout<<endl<<a;
if(i==0){
ifs.unget();
}
}
And the output is:
16 6 2 3
Why is the output like that? ( it should be 16 2 3 4 ) , it only occurs when I put ifs.unget() in the program , so my questions are , what is the purpose of cin.unget() while using I/O files and why is the number 6 ( as part of 16 ) getting outputted?
Thanks in advance for any help.
Something wrong with the documentation?
Makes the most recently extracted character available again.
At the end of your first loop iteration, 6 was the last extracted character (as the final digit of the extracted formatted int with value 16).
Unget does exactly that: it un-gets it.
The next operation has the 6 to work with. So, surprise, you get 6 next time.

Reading an ASCII file with fstream

Have an ASCII text file with some integer numbers in it, each separated by a space, and sometimes the numbers go on to a new line. For example:
// my_file.txt
23 45 973 49
44 1032 33 99
43 8 4 90824
I want to read 100 of these numbers into an array of "ints". Thus far, I have the following code:
int x[100];
fstream file_in("my_file.txt", ios::in);
for (int i = 0; i < 100; i++)
{
file_in >> x[i];
}
However, I now want to do a couple of other things that I am not sure about.
What if I want to just read the entire file in, without having to go through the loop? If this was binary data, I know that I can just write file_in.read((char*)&x[0], 100 * sizeof(int)). But how can I do this with an ASCII file?
What if I want to skip the first 3 numbers in the file, and start reading from the fourth? Again, if this was binary data, I could just use file_in.seekg(3 * sizeof(char)). But I don't know how to skip in an ASCII file.
No raw loops!
Reading the entire file:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream f("data.txt");
std::vector<int> v(std::istream_iterator<int>(f), {});
Skipping over the first three:
v.erase(v.begin(), v.begin() + 3);

Stopping file input when a certain word is encountered

I'm working on a c++ program that is supposed to eventually create a cross-reference table from a paragraph of words read in from a file using hashing. Right now I'm mainly working on reading in the input from the file and making sure the hash function is working properly.
Here a little more specifics on this portion of the problem:
The program is supposed to read in a paragraph from a file one word at a time until it reaches a "word" consisting of 10 "*"s. Below this line of *s are a few more lines of words that will be used to test the program later on.
With the code I have written, everything appears to be working properly (I've used the formula to calculate the index of a couple of the words and am getting the same answer as is being displayed), however, I'm not sure how to get the input to stop when I reach the line of 10 *s. So while this seems to be reading the file in correctly and performing the right calculations, it's performing these calculations for every word in the file.
Here's the code I've written:
#include <iostream>
#include <fstream>
using namespace std;
int hash(string word) {
int firstOff = word[0];
int lastOff = word[word.size() - 1];
int index = (firstOff * 256 + lastOff) % 23;
cout << index << endl;
return index;
}
int main() {
ifstream file;
file.open("prog7.dat");
if(!file.is_open()) {
cerr << "Error opening " << file << endl;
}
string word;
while(file >> word) {
hash(word);
}
}
Here's the output I'm getting:
12
6
17
21
1
21
12
14
11
12
7
14
16
10
2
22
19
21
22
7
7
12
21
21
3
9
3
12
14
14
0
3
21
7
6
7
12
7
17
6
2
16
21
7
14
And in case it helps, here's the file I'm using for the input:
the relative lack of acceptance
of these products in the
corporate marketplace is
due less to technical than
to political factors the
availability of this technology
threatens the perks privileges
and traditions of corporate
management
**********
the
political
lack
relative
less
forgive
tradition
factors
more
Can anyone help me out? I'd really appreciate it.
You can simply check for the word in the while condition:
while(file >> word && word != "**********") {
hash(word);
}
You could also break the loop when you reach the word (if you prefer how it looks).
while(file >> word) {
if (word == "**********") break;
hash(word);
}
Can also use an istream_iterator such as
#include <iostream>
#include <string>
#include <iterator>
#include <fstream>
using namespace std;
int main()
{
ifstream file("prog7.dat");
istream_iterator<string> it(file);
while(*it != "**********")
hash(*it++);
}

Sorting 200 lines in text file by 4 numbers that occur at same spot on each line [duplicate]

This question already has answers here:
Processing lines from one text file to another
(2 answers)
Closed 8 years ago.
I am trying to read a text file that has 200 lines looking like these four examples:
1 4:48:08 Orvar Steingrimsson 1979 30 - 39 ara IS200
2 4:52:25 Gudni Pall Palsson 1987 18 - 29 ara IS870
3 5:14:24 Ryan Paavola 1984 18 - 29 ara USA
4 5:18:43 Hendrik Sporing 1990 18 - 29 ara GER
Currently, the lines are organised by their time, as you can see, but I wish to organise them by the birthyear of each contestant, so that in this case, these four lines would look like this:
4 5:18:43 Hendrik Sporing 1990 18 - 29 ara GER
2 4:52:25 Gudni Pall Palsson 1987 18 - 29 ara IS870
3 5:14:24 Ryan Paavola 1984 18 - 29 ara USA
1 4:48:08 Orvar Steingrimsson 1979 30 - 39 ara IS200
I am supposed to rearrange the lines according to the birthyear, and the input file is "laugavegurinn.txt" and the output file is "laugavegurinn2.txt"
Can anyone point out the problem with my code and/or suggest a better way to do this? Heads up, not very skilled with C++ and would appreciate any help at all. This is my code:
#include <iostream> //for basic functions
#include <fstream> //for basic file operations
#include <string> //for string operations
#include <map> //for multimap functions
using namespace std;
void process (istream &in, ostream &out) {
multimap<int, string> data_by_year;
string str;
while (getline(in,str)) {
int year = stoi(str.substr(54, 4));
data_by_year.insert(make_pair(year, str));
}
for (auto v : data_by_year) {
out << v.second << "\n";
}
}
int main () {
ifstream in;
ofstream out;
in.open("laugavegurinn.txt");
out.open("laugavegurinn2.txt");
process(in, out);
}
This is working right? You're just looking for improvements.
The usual way to do this would be to add all the lines unsorted to a std::vector<std::string> and then call std::sort with a custom ordering to sort into the desired order, then print out.
Should be a little more efficient than your solution (which is pretty good anyway).
As an alternative to using str.substr(54 ,4), you could have used the following method (using character positions is error prone if the format ever changes):
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
using namespace std;
int main() {
string myString = "Three separate tokens";
istringstream iss(myString);
auto it = istream_iterator<string>(iss);
string thirdToken = *(it ++ ++);
cout << thirdToken;
}
This directly reads the third word, regardless of its position or length.