Try to use in cin,peek() - c++

I try to get from the user inputs till blank line
so I wrote this:
while (c != '\n')
{
c = cin.peek();
cin >> check;
if (check == "Test")
{
cin >> ID >> One >> Two >> Three;
Test[i++] = Test(ID, One, Two, Three);
}
}
to example, I get from the user Test 12 45 56 78 99 now, check=test, id=45, one, 56, two=78, three=99
and when I enter empty line, why the while loop isn't stopped?

It's not clear what you're trying to do; you don't use the
results of cin.peek() until far later, after having done
significantly more input, without testing whether it succeeded
or not. Given the code, my first question is: do you understand
how while works? Modifying the value of a control variable
within the loop will not cause you to break out of the loop; the
test is only done at the top of the loop. And you must always
verify that input has succeeded before using the variables
you've input.
If your input is line oriented, the classical solution would
be:
std::string line;
while ( std::getline( std::cin, line ) && !isEmpty( line ) ) {
std::istringstream parser( line );
if ( parser >> check >> ID >> One >> Two >> Three >> std::ws
&& parser.get() == EOF ) {
// Data is good, can be used...
} else {
// Some sort of format error in the line...
}
}
I've put the test for an empty line in a separate function,
because you probably want to treat a line with just white space
as empty. (Users may accidentally hit the space bar before
enter, and what they see will still look like an empty line.)
That's also why I >> into std::ws before checking that
there's no garbage at the end of line when parsing.

cin >> check;
is a formatted input function, meaning it will discard leading white space. A blank line is just leading white space, it will be discarded and the extraction operator will keep reading until non-whitespace data arrives, or an I/O error occurs.

Related

Using successive cin >> input loops

I have to loops to gather input, the first gathers input into a vector of doubles...
double input;
while (cin >> input)
{
list.push_back(input);
}
and the second gathers input into a vector of ints...
int input;
while (cin >> input)
{
list.push_back(input);
}
The second loop keeps auto-exiting and so I added the following two lines...
cin.clear();
cin.ignore(INT_MAX,'\n'); // I've also tried cin.ignore()
However this has occurred in my output being discarded in the second loop. How can I get both of these to work the way they need to?
The first loop reads until the stream goes bad because there isn't any double to read from. When the stream has gone bad it won't become good again unless you do something, e.g., using std::cin.clear() to clear the state flags.
Of course, just clearing the state flags won't make much of a difference because it would have read all viable numbers: the format of valid doubles is a superset of the format of valid ints (well, OK, unless they are using base 16). That is, you'll need some sort of separator, probably a non-space, non-digit character. Your use of ignore() should skip over a separator and up to the next newline (although the magic value isn't INT_MAX but std::numeric_limits<std::streamsize>::max()).
It is unclear what you are trying to input but if you use something like
1 2 3 exit 4 5 6
the first three values would be read as double and everything else would be ignored. That is, you may want to be ignore characters a bit more careful, e.g., clear the input and keep trying to read an int and clear() and ignore() until this is successful:
// skip separator:
std::cin.clear();
int input;
while (!(std::cin >> input)) {
std::cin.clear();
std::cin.ignore(); // ignore the next character only
}
do {
list.push_back(input);
} while (std::cin >> input);

How do I break out of a getline with a file?

I have code where I am inputting stuff from a file. My txt file looks like this:
file.txt
hello world
...
1 2
The numbers at the bottom are supposed to be read into variables. As for "hello world", it should be picked up by getline. But I don't know how many lines there will be in the txt file so I don't know how to break out of it. Here is my code:
while (getline(file, line))
{
std::cout << line << std::endl;
// ...
}
file >> a >> b; // 1 2
If I was doing this with cin I could just do Ctrl+Z to stop getline loop from running. How do I break out of the while loop at the right time before I get to 1 2?
For each line string line, you can put it into an istringstream iss. And then try to stream it into a and b using iss >> a >> b, if it can be done successfully, it means you enter the right line. Otherwise, you go on checking the next line.
int a, b;
while (getline(file, line))
{
istringstream iss(line);
if (iss >> a >> b)
{
// you are in the right line, and a,b has the values e.g. 1 2
}
}
It should also work for other strings besides "hello world", like "aaa bbb cc" etc. as long as they are not the numbers you are looking for.
P.S.: you can also take use of regex if you use C++11 to check if given line has/matches the pattern you are looking for.
Use a condition, and a break; statement.
E.g.:
while (getline(file, line))
{
std::cout << line << std::endl;
// ...
if(line == "hello world"/){
break;//Exits the loop
}
}
A break statement makes your code exit the most inner loop it's used in. In this case, it exits the while loop.
EDIT:
If you don't want to break on a specific line, then you'll better use regular expression or another mechanism (like std::stringstream) to find a match of the string you're looking for, and capture the part you're interested in. I suggest you take a look at Boost.Regex for this.
The idea is to loop on the lines, i.e. just as you do. As soon as you have a match, you can break (the same way) and capture from the string you're currently reading (which in your code would be in the line variable).
It's not too clear how you determine that you want to break out
of the loop. What is the criterion? If you want to read all
lines but the last, the simplest solution is to simply read all
of the lines into an std::vector<std::string>, and then
process that; you can iterate over a vector until the next to
the last element (which you can't do on a stream). If it's some
pattern your looking to match (say "\\d+\\s+\\d+"), then you
can add this to the condition:
std::string line;
std::regex matchNumbers( "\\d+\\s+\\d+" );
while ( std::getline( file, line ) && ! regex_match( line, matchNumbers ) ) {
// ...
}
std::istringstream numbers( line );
numbers >> a >> b;
And so on.

Cin from stdin when it his the end of a line

I have a file for example
M
4
2
//comments
.#..
It is given to the program via stdin. I can't use fstream, just iostream.
If I want to read the whole thing character by character could I do?
char first_letter, first_num, second_num;
cin >> first_letter;
cin >> first_num;
cin >> second_num;
Or would the end of the line mess up cin? As in, does cin know after it reads M for first_letter, that it needs to go to the end line?
Secondly I dont want to read the comment lines. My plan is that if I see a / I will use getline to "trash" the line then move to the . # . . and store those in my array. Would that be the best way to do that?
Firstly, streams skip whitespace (space, tabs, newlines) by default, so that part is easy.
Now, concerning the comment lines, this is a bit more complicated. You can use std::getline() to read one line. This will store the line in a string and discard the trailing newline. However, if you e.g. read the first letter in your code above, the newline remains in the stream, so getline() will read an empty string. In short, don't mix line-based and token-based input.
In practice, you read a line and either parse the it manually or you create a stream for that:
while(getline(in, line)) {
if(line.empty()) continue; // empty line
if(line[0] == '#') continue; // comment line
// parse line
std::stringstream s(line);
char c;
s >> c;
}

reading and filling separate variables from file

I am doing a homework assignment where we are to read company data from a file and then process it for errors.
What I have so far I think will work with the first line, but I'm not sure how to make it read each line after. Each line is a record with ID, name, and payments. Basically I want to know how I can skip to the next line after I've processed the first. I haven't included the error checking yet but I think it will be in the last do while loop after 1 record is read. If the information read into each variable is wrong I can check it and output it to either the summary file or error file.
void processFile()
{
string filename;
ifstream recordFile;
ofstream summary("summary.dat");
ofstream error("error.dat");
cout << "Please enter a filename\n";
do
{
cin >> filename;
recordFile.open(filename);
if (!recordFile.is_open())
cout << "No file by that name. Please enter another filename\n";
}
while(!recordFile.is_open());
int ID = 0;
string firstName;
string lastName;
double payment1, payment2, payment3 = (0.00, 0.00, 0.00);
string numberOfRecords;
getline(recordFile, numberOfRecords);
do
{
ws(recordFile);
recordFile >> ID;
recordFile >> firstName;
recordFile >> lastName;
recordFile >> payment1;
recordFile >> payment2;
recordFile >> payment3;
}
while(!recordFile.eof());
}
*edit : I found part of my problem, I actually need to skip the first line and read on from that point. The first line in each file has useless data in it.
Use the getline function on the ifstream object
Two things. The first is if you're going to have to read multiple
records, and each record is a new line, the best solution is almost
always to read line by line, using std::getline, and then use
std::istringstream to break up the line (record) into the desired
fields. This has the advantage of keeping your input synchronized, even
in case of errors; you don't have to worry about how much to skp ahead
or ignore.
The second point is that you're checking for eof(). This is almost
always an error; sometimes, it will lead you to reading one line too
many, and in other cases, of ignoring the last line or field. If the
input is successful (and you can only check for end of file after
trying to input beyond it), the stream will behave as true in a
conditional context; if not, it will behave as false. So your loop
should be:
std::string line;
while ( std::getline( recordFile, line ) ) {
std::istringstream record( line );
record >> ID;
if ( ! record ) ...
// ...
}
And one final comment: all of the >> operators strip leading spaces,
so you don't need your call to ws. On the other hand, with the above
schema, you might want to do something like:
if ( record >> ws && record.get() != EOF ) {
// Unexpected garbage at end of line...
}
at the very end of your loop, to verify that there isn't extra text.

How to read from std::cin until the end of the stream?

My problem is, that I want to read the input from std::cin but don't know how long the input is. Also I have to char and can't use std::string.
There are two ways I have to handle:
a) The user inputs text and when he hits [ENTER] the program stops reading.
b) The user redirects std::cin to a file (like .\a.oput < file) which can hold multiple lines.
Edit: Just noticed that std::cin.eof() is always false also in the case of reading form a file.
For a) I could read until \n occures. For b) Edit: No (I could read until std::cin.eof() occures.)
But when I don't know whether I'm getting an a) or a b) problem, how can I break the reading process?
This is what I have for a) ...
char buffer = ' ';
while(std::cin >> std::noskipws >> buffer && buffer != '\n')
{
// do some stuff with buffer
}
... and b)
char buffer = ' ';
while(std::cin >> std::noskipws >> buffer)
{
// do some stuff with buffer
}
Also I know there is std::cin.tellg() to get the current position in the stream.
Edit: So it seems like in case of the file the input streams gets terminated, in the way that std::cin >> std::noskipws >> buffer gets false.
What the code above does for a):
It waits for the user to make an input and press [ENTER]
Then it loops through every char entered by the user on the last line.
Then it waits again for the user to make an input and press [ENTER]
Infinite-waiting-processing-loop
So how do I do it?
You could require the input to always end EOF (meaning from commmand line requiring ^D to be pressed) and then use the process for b as always. This would then enable multiline input from cmdline as well
You could use the (old) getline function, which takes a pointer to a char array and can use a delimiter. But you wont be able to ensure that in every case it will read to the eof (as the char buffer might be too small), but using a char-array and not paying attention to the size of it is a very dangerous (and from the point of security catastrophic) thing anyways as it can lead to buffer-overflows which can be easily exploited.
This code should enable you to extract line by line from the input:
char buffer[256];
while(getline(buffer,256,'\n')) { //get a line
/* do something with the line */
}
This to read a maximum amount of chars:
char buffer[256];
while(getline(buffer,256)) {//get a maximum amount out of the input
/* do something with the line */
}