Safe operation to clear the empty input buffer in C++ - c++

I was looking at this post and few other. What happens if ignore() is called when input buffer is already empty? I observed in below code that if ignore() is called when buffer is already empty, it will not work and waits for some character to be entered first.
int main(void)
{
char myStr[50];
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
cout<<"Enter the String\n";
cin>>myStr;
// After reading remove unwanted characters from the buffer
// so that next read is not affected
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
}
cin.clear() after ignore() creates further problem if the buffer is already empty it looks. I guess clearing the buffer after cin() is safe. But what if I do not know the status of input buffer and I clear even when it is already empty? Do I have to check first if input buffer is empty using cin.fail() or something similar if any?
Secondly, cin itself may not be safe as space is not allowed. So getline() is suggested by some SO posts as given here. But does getline() also requires clearing input buffer or is it safe always? Does the code below work without any trouble (it works now, but now sure if it is safe code).
void getString(string& str)
{
do
{
cout<<"Enter the String: ";
getline(std::cin,str);
} while (str.empty());
}
Other SO references:
Ref 3

Breaking down main:
int main(void)
{
char myStr[50];
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
A bad idea, but you noticed that already. There must be a newline in the stream or you sit and wait for one. If the user's not expecting this behaviour you can expect to wait a long time and have a frustrated user. That's a bad scene.
cout<<"Enter the String\n";
cin>>myStr;
Also a bad idea, but for a different reason. >> doesn't know it should stop at 49 characters to prevent overflowing myStr. Bad things happen at that 50th character.
// After reading remove unwanted characters from the buffer
// so that next read is not affected
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
This one is safe. >> won't consume the newline, or any other whitespace and in order for the stream to hand over the data from the console someone must have hit enter and provided a newline.
}
A general rule of thumb is to not ignore unless you have reason to ignore, and if you have reason, ignore right away. Do not wait until before the next stream operation to ignore, be cause what if this operation is the first? Or the previous operation did not leave anything to ignore?. ignore after the operation that left what you want ignored in the stream. So
std::string getfirstword()
{
std::string firstword;
if (std::cin >> firstword)
{
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
return firstword;
}
return ""; // or perhaps
// throw std::runtime_error("There is no first word.");
// is more appropriate. Your call.
}
is good, but
std::string getfirstword()
{
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
std::string firstword;
if (std::cin >> firstword)
{
return firstword;
}
return "";
}
is an offence in the eyes of all that is holy. Don't do it.
As for getline, it gets a line. All of it up to the end of the file or the end of the line, whichever comes first. It also eats the end of the line for you so you don't have to worry about a stray newline harshing your mellow later.
If you only want part of the line, you will have to break it down. Typical usage for this is something along the lines of
std::string line;
if (std::getline(std::cin,line))
{
std::istringstream istr(line);
std::string firstword;
if (istr >> firstword)
{
// do something with firstword
}
else
{
// there is no firstword. Do something else.
}
}
getline reads everything up to and including the newline. It's no longer in the stream, so I'd consider this safe. You don't have to worry about garbage hanging around on the end of the line. You may have to worry about the next line, though.

Related

Enter character instead int C++

I am writing a code that tally when an integer data type or character is entered.
int numero,
countInteger = 0;
countCharacter = 0;
while ( 1 ) {
try {
cin >> numero;
cout << numero;
throw numero;
} catch (...) {
countCharacter++;
cout << "Error";
}
}
If I entered Integer, counter in "countInteger" (but not show it in the code). If I enter a character, it is aa exception and recorded in "countCharacter".
But when I run the code generates an infinite loop and does not allow me to re-enter again. They could help me please. Guide me, you may have a bad concept.
When you try to read an integer, and you give something that's not an integer as input, there are two things happening: The first is that the stream gets its failbit set, the second things that happens is that the input is not extracted. So next iteration you read the same input again, and again and again...
I suggest another tactic: Read as a character, then see if it is a digit, an alphabetic character, or something else completely. Optionally, if you need the actual full number, read as a string, and try to convert to an integer.
A clarification: Input using std::cin is buffered. When you use the input operator >> then std::cin extracts characters from the buffer. If you try to read a number, but the first character in the buffer is not a digit, then the input operator will fail, and leave the character in the buffer.
Simple (hopefully) example:
Lets say you have this code
int number;
std::cin >> number;
std::cin >> number;
std::cin >> number;
As input for that part of the code, you enter
123abc
The first input will read 123 from the input, and stop at the letter, leaving the input as
abc
Now we come to the second input, and the code will see that the first character is not a digit, so it will set the failbit in the stream and leave the input as is:
abc
Then with the third input, the exact same thing as in the second happen.
Now imagine this was in a loop instead, the input operator >> will iteration after iteration see the non-digit input an promptly return, effectively giving you an infinite loop.
Now for a clarification of my suggestion... Depending on the goals and requirements of the program, you can instead read into a character and use the character classification functions to see what types you have.
Something like
int countDigit = 0;
int countCharacter = 0;
char ch;
while (std::cin >> ch)
{
if (std::isdigit(ch))
++countDigit;
else if (std::isalpha(ch))
++countCharacter;
else
{
// Not a digit or an alphabetic character
// I.e. newlines, spaces, control characters, etc.
}
}
Finally a note about using exceptions for this: Most people would consider it bad. Exceptions are for exceptions, exceptional cases, not as part of the normal flow of the program. Throwing an exception is expensive and disrupts the normal flow. Only use them for exceptional things, like errors.

What cin.ignore() does exactly?

I've been told by my professor that every time I use cin, I should always follow it with cin.ignore(100, '\n'). But, I never understood why?
Here is an example:
const int MAX = 200;
char input[MAX];
cout << "Enter something: ";
cin.get(input, MAX);
cin.ignore(100, '\n'); //why necessary?!!
You don't need to use ignore every time, but it is good to use after formatted input, or in cases like yours where you only read a specified amount.
In your example, if I were to type in over 200 characters, any future input might be in for a rough surprise.
char input[200];
std::cin.get(input, 200);
After this executes, the first 200 characters were extracted, but anything after that is still left lying in the stream. It also leaves the newline ('\n') character in it. Anytime you want to extract input after this, it'll read in the remaining characters from our previous input.
This happens with formatted input, too. Take this example:
int age;
std::string name;
std::cin >> age;
std::getline(std::cin, name);
What you want is to type in an age, like 32, and a name, like "Bob". What happens is you input the age, and the program skips reading the name. When std::cin uses >> to read into variables, it leaves the '\n' character that was put into the stream by hitting enter. Then, getline reads in that newline character and stops, because it hit a newline and thinks it is done.
ignore solves this problem by discarding everything up to and including the next newline character, so that the extra input doesn't mess with future reads.
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
cin.ignore(100, '\n');
It ignores the first 100 characters, but if the function encounters '\n' before ignoring 100 characters, the function will stop discarding characters. So I assume that your professor wants you to ignore the rest of the data on the line unless it's longer than 100 characters.

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);

getline() does not work if used after some inputs [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Need help with getline()
getline() is not working, if I use it after some inputs, i.e.
#include<iostream>
using namespace std;
main()
{
string date,time;
char journal[23];
cout<<"Date:\t";
cin>>date;
cout<<"Time:\t";
cin>>time;
cout<<"Journal Entry:\t";
cin.getline(journal,23);
cout<<endl;
system("pause");
}
where as if I use getline() on top of inputs, it does work i.e.
cout<<"Journal Entry:\t";
cin.getline(journal,23);
cout<<"Date:\t";
cin>>date;
cout<<"Time:\t";
cin>>time;
What might be the reason?
Characters are extracted until either (n - 1) characters have been
extracted or the delimiting character is found (which is delimiter if this
parameter is specified, or '\n' otherwise). The extraction also stops
if the end of the file is reached in the input sequence or if an error
occurs during the input operation.
When cin.getline() reads from the input, there is a newline character left in the input stream, so it doesn't read your c-string. Use cin.ignore() before calling getline().
cout<<"Journal Entry:\t";
cin.ignore();
cin.getline(journal,23);
Adding to what #DavidHammen said:
The extraction operations leave the trailing '\n' character in the stream. On the other hand, istream::getline() discards it. So when you call getline after an extraction operator, '\n' is the first character it encounters and it stops reading right there.
Put this after before getline call extraction:
cin.ignore()
A more robust way of taking input would be something like this:
while (true) {
cout<<"Time:\t";
if (cin>>time) {
cin.ignore(); // discard the trailing '\n'
break;
} else {
// ignore everything or to the first '\n', whichever comes first
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin.clear(); // clear the error flags
cout << "Invalid input, try again.\n";
}
}
You're not checking stream status. The std::cin stream extraction operator (operator>>) can fail. When it does, the stream is marked as "bad" (failbit, badbit, or eofbit are set). Once "bad", all subsequent stream extractions on that stream will fail unless you clear the status.
Learn to be a paranoid programmer. Always check status of those formatted input operations. You could, for example throw an exception, or print an error message and exit. The one thing you shouldn't do is to simply assume that it worked.

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 */
}