What cin.ignore() does exactly? - c++

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.

Related

cin is not accepting input with space in them in C++?

#include <iostream>
using namespace std;
int main(){
string doi, name, address, phone;
cout<<"Please provide these credentials:\n";
cout<<"1.Date of issue\n";
cin>>doi;
cout<<"2.Name\n";
cin>>name;
cout<<"3.Address\n";
cin>>address;
cout<<"4.Phone Number\n\n";
cin>>phone;
return 0;
}
When I am giving name input with spaces, for eg ("John Doe"), instead of storing this value is name it split value by space and store "John" in name and "Doe" in address.
If you have spaces in the string you want to read, you could use std::getline like this:
std::getline(std::cin, name);
instead of the line:
std::cin >> name;
Note that the getline will read all characters up to a newline character.
Also, please avoid using namespace std;.
You should use getline() in place of cin when you need to input strings with spaces.
In your case the syntax will be
string name;
getline(cin,name);
for more info on getline https://www.geeksforgeeks.org/getline-string-c/
There's a lot of muddled terminology in the comments and the answers. std::cin is an object; it doesn't do anything on its own.
Functions that read from input streams fit into one of two categories: they do formatted input or unformatted input. Formatted input functions translate the text that they get from the input stream (here, std::cin) into the data type that they're trying to read:
int i;
std::cin >> i; // operator>> reads text and translates it into an integer value
Formatted input functions begin by skipping whitespace, then they read characters and translate them; when the function encounters a character that isn't valid for the type that they're reading, or when they see whitespace, they stop. So in the example above, if you typed " 32 ", the stream extractor would skip the leading space, read the 3 and the 2, see the following space, and stop reading. The value stored into i would be 32.
std::string data;
std::cin >> data;
Here, if you type "Hello, world", the stream extractor (operator>>) will read up to the space, and store "Hello," in data.
If you want to read whitespace as well as non-whitespace you need an unformatted input function:
std::string data;
std::getline(std::cin, data);
Here, the call to getline reads text from std::cin up to the first newline character or to the end of the input stream. So if you typed " 32 " for this code, data would hold the text " 32 ". If you typed "Hello, world", data would hold the text "Hello, world".
And note that if you mix formatted input functions with unformatted input functions you have to be careful about leftover whitespace:
int i;
std::string data;
std::cin >> i;
std::getline(std::cin, data);
If you typed "32 Hello, world" on a single line, i would get the 32, and data would get " Hello, world".
On the other hand, if you type two lines of input, the first with "32" and the second with "Hello, world", you'll get 32 in i, but data will be empty. That's because the stream extractor read the 3 and the 2, then saw a newline character, and stopped, leaving the newline in the input buffer. std::getline then read that newline character and it, too, stopped. But it read the entire line: it swallowed the newline character.
So when your code switches from formatted input to unformatted you have to deal with whitespace characters remaining in the input buffer. If you want to read them, fine; but if you don't, you need to remove them:
int i;
std::string data;
std::cin >> i;
std::getline(std::cin, data); // read the rest of the line
std::getline(std::cin, data); // read the next line of text
A better approach is to do that cleanup with something like std::cin.ignore(42, '\n');. std::ignore is an unformatted input function; in this call it reads up to 42 characters, looking for a newline character. It stops reading when it has read 42 characters, sees a newline character, or hits the end of the input. That's better than using std::getline(std::cin, data) because it doesn't store the text into data, which could require a bunch of resizing if there's a lot of text in the remainder of the line. The more usual form for that call is to pass std::numeric_limits<int>::max() as the size argument; that's a special case, and it puts no limit on the number of characters to be read. So std::cin.ignore(std::numeric_limits<int>::max(), '\n'); will read characters until it finds a newline or hits the end of the input.
int i;
std::string data;
std::cin >> i;
std::cin.ignore(std::numeric_limits<int>::max(), '\n'); // flush the rest of the line
std::getline(std::cin, data); // read the next line of text

Safe operation to clear the empty input buffer in 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.

Ignoring the input character

So, I want to use the cin.ignore(200,'\n') to input a line and save it into a string without saving the \n as the string. But when I do:
cin.ignore(200,'\n');
getline(cin,name);
It asks me to input something twice, but I just want to ask me once and save it into name.
I've read something about the cin.clear(), but I think it's not what I need, or perhaps, I missunderstood what that clear does.
Thanks!
cin.ignore(n, ch) discards characters from the stream associated with std::cin until either n characters have been skipped, or until ch is seen. The cin.ignore(200, '\n'); is discarding the first input, up to the newline character. You're then getting a line, which will accept your second input.
You may need to use the cin.ignore(n, ch); construct if you want to read a line immediately after you perform a whitespace-delimited input operation, like
int i = 0;
std::cin >> i; // reads an integer, possibly leaving a '\n' in the stream
std::cin.ignore(200, '\n'); // reads and discards until a newline is seen
std::string name;
std::getline(std::cin, name); // reads a full line
In your case, if you haven't done any whitespace-delimited input, the cin.ignore is skipping over the first attempt to provide your line input. You should simply use std::getline immediately. The newline character at the end of the line is not appended to the string, but it is removed from the input stream.
The documentation for std::getline explains this in the "Notes" section.
For a more robust line input function, where you cannot be sure whether the previous input operation left a newline character (or whatever delimiter you're using) on the stream, you can do something like:
char ch;
std::cin.peek(ch);
if (ch == '\n') {
std::cin.ignore(1, '\n'); // or std::cin.get(ch);
}
std::string line;
std::getline(std::cin, line);
The peek member function will return the next character to be read, without removing it from the stream. If it's a newline, you can go ahead and ignore it. Otherwise, the getline call will read the entire line, including the character you just peeked at.
Alternatively, if you only want to consume whitespace, you can use the std::ws manipulator.
You don't need to use ignore() in this case. getline() will not put the new line character to the string.
The reason its asking you for an input twice is because the ignore() function is removing until your first 200 input characters or up to the newline(your deliminator) so the next getline() probably will not have anything to read thus asking you for input(unless of course your first input contains more than 200 characters,in that case it will read the remaining characters in the buffer).
std::getline() will not add the delimiter character to the string that is read, which is the newline character by default.

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.

why does my program skip steps using getline()?

I think my program skips steps because I use getline() inside While and For loops without using cin.clear() and cin.ignore(). If I'm right, where will I have to insert them?
I tried to write the code with cin.clear() and cin.ignore(10000, '\n') after each getline() (really I don't know how these functions work properly, I found them surfing on Google) and the code doesn't work correctly.
The code is :
main.cpp
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <utility>
using namespace std;
int main(){
string S;
cout<<"insert test....input exaple: test 1"<<endl;
getline(cin, S);
while(S!="-1"){
cout<<"START WHILE"<<endl;
int nB = 0; //number of Lego Bricks;
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
for(int i=0; i<nB; i++){
cout<<"START FOR"<<endl;
cout<<"insert Lego brick (the number of faces must be even)....input example: NameBrick -> face1 face2 face3 face4...."<<endl;
getline(cin, S);
}
getline(cin, S);
}
return 0;
}
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
This is the problem. getLine() keeps reading until the next newline character. Let us say that '|' is our newline symbol.
When you write something into the terminal or when you are reading from file you have many lines to work through.
Example input(Greeting, name, age and hobby):
Hello.|
Magnus Elden|
24|
Tennis|
GetLine() will give you the entire line. The first call to getLine() will return the string "Hello." and stop since it reached a newline character, '|'.
The important part is that it stops AFTER the newline character.
Thus, the next time the first character it reads is the 'M' in "Magnus Elden".
When you get to the age part of the input, you use cin which only read the first item, be it a string or a number. As such it will stop BEFORE the newline character. The next time you call getLine() it reads until a newline character comes, but since the newline character still remains in the buffer getLine() returns immediately with "" as its return value.
That is why it seems to skip a step.
Step by step breakdown:
You input your greeting "Hello." and the buffer will then look like this:
Buffer:Hello.|
Let us say that the start of the reading is denoted by a ^. These are the steps.
Step 1.
Input:Hello.
Buffer:Hello.|
^
Function call:getLine()
Return value:"Hello."
Buffer:
Step 2.
Input:Magnus Elden
Buffer:Magnus Elden.|
^
Function call: getLine()
Return value:"Magnus Elden"
Buffer:
Step 3.
Input:24
Buffer:24|
^
Function call: cin
Return value:24
Buffer:|
Step 4.
Input:Tennis.
Buffer:|Tennis.|
^
Function call: getLine() //Remember that it runs until the first newline '|'.
Return value:""
Buffer:Tennis|
Just change the code bit to:
cout<<"insert number of Lego bricks"<<endl;
getLine(cin, s);
nB = atoi(s.c_str());
I hope this helps.
getline(cin,s) will do what you expect. The rest of the line (except the newline itself) is stored in s. And, crucially, the newline itself will be extracted and discarded.
So, if you call getline(cin,s) multiple times, each line will be read once, as you expect.
Similarly, assuming x in an int, cin >> x will read an integer. Multiple consecutive calls to cin >> x will read numbers from the input into x. Each time you call cin>>x it will skip over any whitespace before the number, then read the number. So, if you have a set of numbers, perhaps on the same line separated by spaces, or perhaps on different lines separated by newlines, then cin>>x will read them for you.
But it will not read-and-discard any whitespace after the number. Whitespace is discarded at the start of each call to cin>>x (i.e. before the number itself is read), but not after the number is read.
The problem occurs if you have a cin>>x followed by a getline. Imagine you type a number and then press enter. cin>>x will consume the number. but cin>>x will not consume the newline. Then, the getline will attempt to read the rest of the line. It will not try to read the next line. We're are still stuck on the same line as the number. You probably hit Enter immediately after entering the number, therefore the "rest of the line" is just an empty string.
There's a difference between "typing a number" and "typing a number followed by hitting the Enter key"
Thanks to all.
I solved replacing cin>> with getline how many of you suggested.
precisely:
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
with
cout<<"insert number of Lego bricks"<<endl;
getLine(cin, s);
nB = atoi(s.c_str());