How to move through each line in getline() - c++

Whenever I run my code, I get the first line pulled out of the file, but only the first. Is there something I am missing? I ran into the issue when I implemented stringstream to try and more easily read in the lines of hex from the file and more quickly convert between a string to a hex value. It read in each line accordingly before, but now it is not. Am I missing something in the understanding of how getline() works?
ss is stringstream, fileIn is the file, hexInput is a string, memory[] is an array of short int, instruction is a short int, opCounter is an int...
string hexInput;
stringstream ss;
short int instruction;
ifstream fileIn ("proj1.txt");
if (fileIn.is_open())
{
while ( getline(fileIn, hexInput) )
{
ss << hex << hexInput;
ss >> instruction;
memory[opCounter] = instruction;
cout << hex << memory[opCounter] << '\t';
cout << opCounter << '\n';
ss.str("");
opCounter++;
}
fileIn.close();
}
else cout << "Unable to open file";
Above is the entire function (which was working before using stringstream) and below are the contents of the file.
4000
0033
0132
2033
4321
2137
D036
A00F
B003
C00C
3217
6217
E044
FFFF
6016
1013
FFFF
0
0
0
0
1
2
3
4
5
There are 26 lines and the last opCounter output says "19" in hex which makes me assume the file is being read line-by-line, but the stringstream never updated. This is my first C++ program and am new to a few of these features I am trying to implement.
Thanks for any help...

Your stringstream is created correctly from the first line. After outputting the number into instruction it will be eof though (you can check this with ss.eof()) because there is no data after the first number inside the stringstream.
replace ss.str(""); (which you don't need) by ss.clear(); which will reset the eof flag. Inputting the new line and reading from the stream will then work as expected.
Of course there is absolutely no need for a stringstream in the first place.
while ( fileIn.good() ) {
fileIn >> hex >> instruction;
[...]
}
works fine. It will read short ints in hexadecimal representation until one line cannot be interpreted as such. (Which incidentally is line 7 because D036 is too large to fit inside a short int - admittedly that is different from your current behaviour, but did you really want a silent failure? very useful at this point are again fileIn.eof() to check whether the read failed due to the stream being at the end of the file and fileIn.clear() to reset other fail-bits)
As requested:
The loop is commonly abbreviated as
while ( fileIn >> hex >> instruction ) {
[...]
}
but note, that if you want to check why the read failed, and continue if it was not an eof, the aforementioned loop is more suited to the task.

Related

C++ reading a file into a struct

Using fstreams I have a file opened that contains numerous lines. Each contiguos set of 4 lines are such that: the first line is an int, the second and third are strings and fourth is a double. This sequence continues till EOF.
I'm attempting to load these lines into a struct array:
struct Library {
int id;
string title;
string artist;
double price;
};
and the code I'm trying to implement to load data into the struct is this:
const int LIMIT = 10
Library database[LIMIT];
ifstream file;
file.open("list.txt");
if(file) {
while(!(file.eof()) && counter < LIMIT) {
file >> database[counter].id;
getline(file, database[counter].title;
getline(file, database[counter].artist;
file >> database[counter].price;
}
} else {
...
}
// Using the following to debug output
for(int i = 0; i < counter; i++) {
cout << "ID: " << database[i].id << endl
<< "Title: " << database[i].title << endl
<< "Artist: " << database[i].artist << endl
<< "Price: " << database[i].price << endl
<< "-----------------------" << endl;
}
The file I'm trying to throw at this thing is
1234
Never Gonna Give You Up
Rick Astley
4.5
42
Thriller
Michael Jackson
32.1
The problem I'm having here is that between reading the id and title using file >> ... and getline(...) is that somewhere a newline bite is being introduced screwing up the output, which displays this monstrosity...
ID: 1234
Title:
Artist: Never Gonna Give You Up
Price: 0
--------------------
ID: 0
Title:
Artist:
Price: 0
--------------------
The solution is probably the most basic of solutions, but mainly because I can't figure out exactly what is going on with the newline bite I can't combobulate a phrase to shove into google and do my stuff there, and I'm at the stage where I've been looking at a problem so long, basic knowledge isn't working properly - such as how to handle basic input streams.
Any form of help would be much appreciated! Thanks in advance :)
This happens because the >> operator for the input stream only grabs part of a line, and does not always grab the newline character at the end of the line. When followed by a call to getline, the getline will grab the rest of the line previously parsed, not the line after it. There are a few ways to solve this: you can clear the buffer from the input stream after each read, or you can simply get all your input from getline and just parse the resulting strings into an integer or a double when you need to with calls to stoi or stod.
As a side note, you don't want to detect the end of your file the way you presently are. See why is eof considered wrong inside a loop condition?
You can solve this problem by adding:
fflush(file);
everytime before you use getline(file, ...). Basically this will clear the input buffer before you use the getline() function. And fflush() is declared in the cstdio library.
file >> database[counter].id;
will read, in this case, a whitespace separated sequence of characters that is interpreted as an int. The newline is considered whitespace. You should now be sitting on that newline character, thus the getline() will read nothing -- successfully -- and increment the file position just past that.
You may be better off using getline() for each line and then separately interpreting the lines from the reading. For example, the first line read could be interpreted with a subsequent std::stoi() to get the integer representation from the string.

C++ Read in file with only numbers (doubles)

I'm trying to read in a file that should contain only numbers in it. I can successfully read in the entire file if it meets that criteria, but if it so happened to have a letter in it, I need to return false with an error statement.
The problem is I'm finding it hard for my program to error when it finds this character. It can find it no problem, but when it does, it decides to just skip over it.
My code to read in the file and attempt to read in only numbers:
bool compute::Read (ifstream& stream)
{
double value;
string line;
int lineNumber = 1;
if (stream)
{
while (getline(stream, line))
{
lineNumber++;
istringstream strStream(line);
while (strStream >> value)
{
cout << value << endl;
}
}
}
return true;
}
The input file which I use for this is
70.5 61.2 A8 10.2
2
Notice that there is a non-number character in my input file. It should fail and return false at that point.
Currently, all it does is once it hits the "A", it simply returns to the next line, continuing the getline while loop.
Any help with this would be much appreciated.
The stringstream does catch those errors, but you're doing nothing to stop the enclosing loop from continuing when an error is found. You need to tailor your main loop so that it stops when the stringstream finds an error, which you can't do if the stringstream is being reconstructed on each iteration. You should create a for() loop instead and construct the stringstream in the declaration part. And the condition to the loop should be "as long as the stringstream and stream do not catch an error". For example:
for (std::istringstream iss; iss && std::getline(stream, line);)
{
iss.clear();
iss.str(line);
while (iss >> value)
{
std::cout << value << '\n';
}
}
Futhermore, it doesn't look like you need to use std::getline() or std::istringstream if you just want to print each value. Just do:
while (stream >> value) {
std::cout << value << '\n';
}
The above will stop when it finds an invalid character for a double.
You need the code to stop streaming but return false if it hasn't yet reached the end of the "input".
One way, possibly not the most efficient but still one way, to do that is parse a word at a time.
If you read first into a std::string and if it works (so the string is not empty) create an istringstream from that string, or reuse an existing one, and try streaming that into a double value.
If that fails, you have an invalid character.
Of course you can read a line at a time from the file, then split that into words, so that you can output a meaningful error message showing what line the bad text was found.
The issue of reading straight into doubles is that the stream will fail when it reaches end of file.
However it is possible to workaround that too because the reason for failing has an error status which you can check, i.e. you can check if it eofbit is set. Although the f in eofbit stands for "file" it applies to any stream not just files.
Although this method may sound better than reading words into a string first, I prefer that method in normal circumstances because you want to be able to report the error so you'll want to print in the error what was read.

Missing line of data using Getline with Ifstream

Ok so this is killing me at the moment cause its such a simple part of my program that just doesn't want to work. I'm reading data from a textfile to use in a GA.
The first getline() works perfectly, but the second one doesn't want to write any data into my string. When i cout the string it doesn't show anything.
Here is the code:
ifstream inFile;
inFile.open(fname.c_str());
char pop[20], mut[20];
inFile.getline(pop,20);
cout << pop;
inFile.getline(mut,20);
cout << mut; //this outputs nothing
Thanks for any help in advance.
A sample form my file:
there is no line between them mutation is the line straight after population
Population size: 30
Mutation: 20
Your file's first line is 20 characters long (19+new line) but pop[20] can only contain 19 (because the last one is reserved for the null terminator '\0').
When istream::getline stops because it has extracted 20-1 characters, it doesn't discard the new line delimiter (because it was never read). So the next getline just reads the end of the first line, discarding the new line.
That's why you get nothing in the second string.
Your problem is that the length of your input line exceeds the length of the buffer which must hold it.
The solution is to not use character arrays. This is C++, use std::string!
std::ifstream inFile;
inFile.open(fname.c_str());
std::string pop;
std::getline(inFile, pop);
cout << pop << "\n";
std::string mut;
std::getline(inFile, mut);
cout << mut << "\n";
I think you need to find out what the problem is. Add error checking code to your getline calls, refactor the (simple) code into a (simple) function, with a (simple) unittest. Possibly, your second line is longer than the assumed 20 characters (null-term included!).
For an idea of what I mean, take a look at this snippet.
try something like
while (getline(in,line,'\n')){
//do something with line
}
or try something like
string text;
string temp;
ifstream file;
file.open ("test_text.txt");
while (!file.eof())
{
getline (file, temp);
text.append (temp); // Added this line
}

Why does getline return empty lines if none exist

I have a file containing the following lines:
5556
0 bla.dxf
1 blub.dxf
2 buzz.dxf
The numbers and text are seperated by a singular tab each, there is no whitespace character after 5556. The following code is used for parsing.
int main(int, char**){
std::ifstream file("test.bld");
std::string buildingName;
file >> buildingName;
std::cout << buildingName << std::endl;
std::string buf;
while(getline(file, buf)) {
if(buf.empty()){std::cout << "String was empty"<<std::endl;}
else std::cout << buf << std::endl;
}
return 0;
}
When I parse the file I get an empty line although there obviously is none.
The output reads as follows:
5556
String was empty
0 bla.dxf
1 blub.dxf
2 buzz.dxf
This is only a minimal example. The whole file and the parser is more complex and I would very much like to use direct parsing for the first element and getline for the rest. What am I misunderstanding about line parsing with getline and how do I avoid getting empty lines?
operator>>(istream, string) reads up to but not including the first whitespace character after the extracted token.
To skip the rest of the line after extracting a token, you can either use
std::cin >> std::ws;
(if you know that there is only a newline remaining), or
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
to skip to the end of the line regardless.
I'm assuming because
file >> buildingName;
doesn't move the cursor to the next line, but leaves it at the end of the current line. So when you call getline, you'll read an empty string and then move to the next.

Find the end of stream for cin & ifstream?

I'm running myself through a C++ text book that I have as a refresher to C++ programming. One of the practice problems (without going into too much detail) wants me to define a function that can be passed ifstream or cin (e.g. istream) as an argument. From there, I have to read through the stream. Trouble is, I can't figure out a way to have this one function use cin and ifstream to effectively find the end of the stream. Namely,
while(input_stream.peek() != EOF)
isn't going to work for cin. I could rework the function to look for a certain phrase (like "#End of Stream#" or something), but I think this is a bad idea if the file stream I pass has this exact phrase.
I have thought to use function overloading, but so far the book has mentioned when it wants me to do this. I'm probably putting too much effort into this one practice problem, but I enjoy the creative process and am curious if there's such a way to do this without overloading.
eof() does work for cin. You are doing something wrong; please post your code. One common stumbling block is that eof flag gets set after you try to read behind the end of stream.
Here is a demonstration:
#include <iostream>
#include <string>
int main( int, char*[] )
{
std::string s;
for ( unsigned n = 0; n < 5; ++n )
{
bool before = std::cin.eof();
std::cin >> s;
bool after = std::cin.eof();
std::cout << int(before) << " " << int(after) << " " << s << std::endl;
}
return 0;
}
and its output:
D:>t
aaaaa
0 0 aaaaa
bbbbb
0 0 bbbbb
^Z
0 1 bbbbb
1 1 bbbbb
1 1 bbbbb
(EOF can be generated with Ctrl-Z on Windows and Ctrl-D on many other OSes)
Why won't std::cin.eof() work? cin will signal EOF when stdin closes, which will happen when the user signals it with Ctrl+d (*nix) or Ctrl+z (Windows), or (in the case of a piped input stream) when the piped file ends
If you use a stream in a boolean context then it will convert itself into a value that is equivalent to true if it has not reached the EOF and false if an attempt has been made to read past the EOF (not it is also false if there was a previous error reading from the stream).
Since most IO operations on streams return the stream (so they can be chained). You can do your read operation and use the result in the test (as above).
So a program to read a stream of numbers from a stream:
int main()
{
int x;
// Here we try and read a number from the stream.
// If this fails (because of EOF or other error) an internal flag is set.
// The stream is returned as the result of operator>>
// So the stream is then being used in the boolean context of the while()
// So it will be converted to true if operator>> worked correctly.
// or false if operator>> failed because of EOF
while(std::cin >> x)
{
// The loop is only entered if operator>> worked correctly.
std::cout << "Value: " << x << "\n";
}
// Exit when EOF (or other error).
}