difference between input using ignore and so on - c++

I wanted to clear some doubt regarding the function
cin.ignore(1,'\n');
code:
char x[80];
cin>>x;
cin.ignore(1,'\n');
If user input the word: paul Smith
does the program looks for the first space in the word and ignores/delete the rest of the characters?
Hence the program takes paul only and discards Smith?
Am I right?
I'm getting confused! Please explain in really simple words because I cannot understand the explanation on google regarding this issue.

cin.ignore(1,'\n');
is not very useful. It will ignore only one character.
cin.ignore(100,'\n');
will ignore up to 100 characters but will stop after it encounters a '\n'.
In your case,
cin>>x;
will read paul into x. The line
cin.ignore(1,'\n');
will consume the space after paul. Hence, Smith will be left on the input stream.
Hence the program takes paul only and discards Smith?
No. I hope that is clear from the above.

cin >> x;
Since x is a string or char array, this reads one word (everything up to the first whitespace character) from the input, and stores it in x.
cin.ignore(1, '\n');
reads and ignores one character from the input. It won't read the whole rest of the line. More generally:
cin.ignore(n, delim);
reads and ignores characters until it has either read n characters or reached a character equal to delim. If you want to ignore until the end of the line, no matter how many characters that is, do:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Related

C++ Beginner: std::cin to std::string

Just started learning C++ and encountered an issue with strings while doing an exercise.
So I initialized std::string phrase; while allowing the user to input and save the phrase to the string with std::cin >> phrase;. Now my issue comes when the inputed phrase has spaces, I noticed that the computer will only save the characters up till the first word only.
With the phrase "sunsets are great", the phrase.size() only came out to 7, so the following words after the first space were not saved.
The entire exercise is supposed to compare all of the letters in the whole inputted string with another set of values. Should I be using a different function for this?
Any help would be appreciated! :)
I have also had this problem when i was first starting out.
whenever you want to read a string i would use the getline.
ie
string phase
cout << "enter phase" <<endl;
getline(cin,phase);
If you want to take an entire line including space(s), you may use the following code:
string str; // declaration
getline(cin, str);
Remember: cin.get and cin will trim all the inputted characters just after first space.
Enjoy.

When to use a blank cin.get()?

As the title says - when should I use a blank cin.get() ?
I encountered situations when the program acted strange until I added a few blank cin.get()s between reading lines. (e.g. in a struct when reading its fields I had to enter a cin.get() between each non-blank cin.get())
So what does a blank cin.get() do and when should I use it?
Thanks.
There are two broad categories of stream input operations: formatted and unformatted. Formatted operations expect input in a particular form; they start out by skipping whitespace, then looking for text that matches what they expect. They typically are written as extractors; that's the >> that you see so often:
int i;
std::cin >> i; // formatted input operation
Here, the extractor is looking for digits, and will translate the digits that it sees into an integer value. When it sees something that isn't a digit it stops looking.
Unformatted input operations just do something, without regard to any rules about what the input should look like. basic_istream::get() is one of those: it simply reads a character or a sequence of characters. If you ask it to read a sequence it doesn't care what's in that sequence, except that the form that takes a delimiter looks for that delimiter. Other than that, it just copies text.
When you mix formatted and unformatted operations they fight with each other.
int i;
std::cin >> i;
If std::cin is reading from the console (that is, you haven't redirected it at the command line), you'll typically type in some digits followed by the "Enter" key. The extractor reads the digits, and when it hits the newline character (that's what the "Enter" key looks like on input) it stops reading, and leaves the newline character alone. That's fine, if the next operation on that stream is also a formatted extractor: it skips the newline character and any other whitespace until it hits something that isn't whitespace, and then it starts translating the text into the appropriate value.
There's a problem, though, if you use a formatted operation followed by an unformatted operation. This is a common problem when folks mix extractors (>>) with getline(): the extractor reads up to the newline, and the call to getline() reads the newline character, says "Hey, I've got an empty line", and returns an empty string.
Same thing for the version of basic_istream::get() that reads a sequence of characters: when it hits the delimiter (newline if you haven't specified something else) it stops reading. If that newline was a leftover from an immediately preceding formatted extractor, it's probably not what you're looking for.
One (really really ugly) solution is the brute force cin.ignore(256, '\n');, which ignores up to 256 sequential newline characters.
A more delicate solution is to not create the problem in the first place. If you need to read lines, read lines. If you need to read lines and sometimes extract values from the text in a line, read the line, then create a std::stringstream object and extract from that.

istringstream ignores first letter

I am trying to access different words in a string using std::istringstream and I am also doing so with multiple test cases.
int t;
cin>>t;
while(t--)
{
string arr;
cin.ignore();
getline(cin,arr);
istringstream iss(arr);
string word;
while(iss>>word)
{
cout<<word;
}
}
For the first test case, everything is perfect (i.e. it outputs the correct words). But for every subsequent test case, the first letter of the first word is left out.
Example:
Input:
4
hey there hey
hi hi hi
my name is xyz
girl eats banana
And I'm getting:
Output:
hey there hey
i hi hi
y name is xyz
irl eats banana
Can anyone please suggest me what to do and why is this error occurring?
Your problem is that formatted input, i.e., something like in >> value conventionally skips leading whitespace before attempting to read. Unformatted input, on the other hand, doesn't skip leading whitespace. With the std::cin.ignore(); in your loop you make the assumption that std::getline(std::cin, arr) would leave the newline in the input like the input of t does. That is not so. std::getline() extracts and stores all characters up to the first newline where it stop, still extracting the newline. So, you'd remove the cin.ignore(); from the loop.
The key question becomes how to switch between formatted input and unformatted input. Since the newline upon entry of a numeric value may be preceded with arbitrary spaces which you probably also want to ignore, there are essentially to ways:
std::cin >> std::ws; skips all leading whitespace. That may include multiple newlines and spaces at the beginning of the line. Skipping those may not necessarily desirable.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); ignores all characters up to and including the first newline. That would allow for empty lines to follow up as well as lines starting with leading whitespace.
This line is the culprit: cin.ignore();.
When std::basic_istream::ignore is called without any arguments, it ignores exactly 1 character.
In your case, std::cin.ignore() will ignore the first letter, but not for the first test case, because at that point std::cin is empty, so there is nothing to ignore. But then, std::cin has the other words in it, so it ignores 1 character from the first word.
According to the documentation of std::basic_istream::ignore:
Extracts and discards characters from the input stream until and
including delim. ignore behaves as an UnformattedInputFunction
Its worth to mention that std::basic_istream::ignore will block and wait for user input if there is nothing to ignore in the stream.
With this in mind, lets break down what your code does:
the first time you call this function in your loop, it is going to
ignore the new line character that is still in the buffer from the
previous cin>>t operation. Then the getline statment will wait and read a line from the user.
The next time around, since there is nothing in the buffer to
ignore(as std::getline doesn't leave the new line character in the
buffer), it is going to block and wait for input to ignore. So
the next time the program block and waits for input, it is because
of the ignore() function,not the getline function as you would
have hoped, and the moment you provide an input(i.e you second test
case),one character from the input is going to be ignored.
The next getline function will not block since there is something
in the buffer left by the previous ignore function after it
ignores the first character of the input so getline will read the
remaining string which will happen to be one character short.
The process continues from step 2 until your loop terminates.
int t;
cin>>t;//this leaves new line character in the buffer
while(t--)
{
string arr;
cin.ignore();//this will ignore one character from the buffer,so the first time
//it will ignore the new line character from the previous cin input
//but next time it will block and wait for input to ignore
getline(cin,arr);//this will not block if there is something in the buffer
//to read
...
}
The solution would be to move the ignore statement out of the loop and next to your cin>>t statement. It's also better write ignore(INT_MAX,'\n'); in this case. You might also want to read this answer to see when and how to use ignore.

Reading whole line with std::cin

I would like to figure out how to read a whole line (including spaces) with std::cin. I am aware of the existence of std::getline, I would just like to figure out how to do it with std::cin so I can better understand iostream in C++. I've tried using a for loop with std::cin, however it keeps reading past the end of the line. Any help would be greatly appreciated.
Also the cin << only allows us to enter one word into a string.
However, there is a cin function that reads text containing blanks.
std::cin.get(name, MAX);
get will read all characters including spaces until Max characters have been read or the end of line character (ā€˜\nā€™) is reached and will put them into the name variable.
You should decide what is MAX.

Splitting user input by one space for the first two words, then storing the remaining phrase (C++)

Right now I'm trying to, and as the title says, find a way to split a string in a weird way.
Lets say the input looks like:
1234.5/N 1222.2/W Taco Tuesday
And the input given for the first two words separated by spaces will always be in the format #.#/(N/S/W/E)
The problem I'm having is with the last word. This word can be as many spaces as it wants to be and is only "terminated" by a newline.
My first try was doing:
std::string input1; // number/Letter
std::string input2; // number/Letter
std::string input3; // word
std::cin >> input1 >> input2 >> input3;
The problem is, obviously is that if input 3 has a space in it, cin won't capture anything past that last space.
I thought about using getline(cin, input), but I realized I would get a single string with everything in it, instead of 3 separate strings. I believe this would be more challenging to extract the numbers out of the first two (probably by using find(/)), somehow keeping the letter after the slash, then moving to the next number, extracting that, keeping the letter after, and finally getting the rest of the phrase, minus the letter after the slash.
Also I would have to store the numbers in separate variable for calculations, take note of the letter used, and keep the last phrase.
Is there any reasonably elegant way to do this using std::string or at the very least is there just some way to at least extract the first two words and then store the remaining phrase into a string?
You can try to read first two words with cin and then use getline:
cin >> input1 >> input2;
getline(cin, input3);