why does my program skip steps using getline()? - c++

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

Related

While loop with getline doesn't end for user input

I thought getline stops at a newline character, but the while loop does not end? it returns the correct data but it just sits in the terminal window. For example:
Enter an expression: #5+4#5+4
(blinking cursor)
(can enter data forever and press enter forever and it wont exit)
my code, (main.cpp):
int main()
{
string exp;
cout << "Enter an Infix Expression:";
while (getline(cin, exp, '#'))
{
string token = exp;
string post;
cout << token << endl;
IntoPost *infix = new IntoPost(token.length());
post = infix->inToPost(token);
cout << post << endl;
}
cin.get();
}
The Solution Using EOF
Your current program is looping endlessly because getline returns std::basic_istream, so while(getline()) will never equate to 'false'.
As #0x499602D2 has stated, your program is working as intended, but the extraction from getline can only end in two ways, as indicated by the reference here:
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n', for when no delimiter is specified).
The extraction also stops if the end of file is reached in is or if some other error occurs during the input operation.
The first condition is difficult to pull off, as inputs on console are triggered by the \n character.
As for the second condition, as per #DavidC.Rankin:
You can also generate a manual EOF on Linux with [Ctrl+d] or windows with [Ctrl+z] (generally twice is required)
This means the solution is to use [Ctrl+d] or [Ctrl+z] to trigger the second condition to end your while loop at any time.
Alternative Using a Break Statement
One alternative way you can try to end the loop instead is breaking on input of an 'exit' string:
(1)
#include <algorithm>
//...
while (getline(cin, exp, '#'))
{
// removes meaningless endline chars from input
exp.erase(std::remove(exp.begin(), exp.end(), '\n'), exp.end());
if (exp == "exit"){
break;
}
//... Your While Block Code Here!
}
To break out of your while loop, you can simply use:
exit#
# Note, the endls from your couts in the loop will bleed into your inputs on your next while (getline(cin, exp, '#')), giving us unwanted newlines. To prevent this, we can get rid of the endlines from the inputs by using std::erase(). If you wish to keep those endlines in your input, simply set string token = exp; in front of the erase() line.
That's right, getline blocks the execution of the loop until a line separator is received and returns while that all is well, in the next step everything is repeated. If you want the loop not to be infinite - then put the Boolean variable key in the loop condition, and from the input check if the last character is an exit symbol and if so switch the variable key

why does this C++ program works for the first line of input but not second or third?

I want to write a program which prints Real Fancy if the given string contains "NOT" or "not" and regularly fancy if it doesn't contain not.
Ex: "this is not a string"
o/p: Real Fancy
"this is nothing"
o/p: regularly fancy
The problem is it prints Real Fancy if my first testcase input is "not is this line". But if the same line is given as input in second or above testcase it is not working and printing regularly fancy.Why? Any help?
Here is the code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;//No.of test cases
cin>>t;
while(t--)
{
string quote;//the input from user
string found="not";//word to be found
string temp="";
int not_found=0;
cin.ignore();
getline(cin,quote);
//Splitting the given line into words and store in a vector
vector<string> words;
istringstream iss(quote);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(words));
//Scan for "not" and if found break from for loop
for(int i=0;i<words.size();i++)
{
temp=words[i];
transform(temp.begin(),temp.end(),temp.begin(),::tolower);
if(temp==found)
{
cout<<"Real Fancy"<<endl;
not_found=1;
break;
}
}
if(not_found==0)
cout<<"regularly fancy"<<endl;
}
return 0;
}
The input pattern looks like
t
quote
quote
quote
...
The reading of t
cin>>t;
stops as soon as it finds an input that cannot possibly be an integer. This includes the newline character representing the end of the line, leaving the newline character in the stream to be consumed later (see Why does std::getline() skip input after a formatted extraction? for more on that problem). The skipping problem has been resolved with a
cin.ignore();
getline(cin,quote);
in the while loop, but that traded one bug for another. If there was no preceding formatted input to leave unwanted characters in the stream, cin.ignore(); will be throwing out the legitimate first character of the input.
This will happen on the second and subsequent reads. The input will wind up looking like
t //newline consumed by ignore
quote //newline consumed by getline. ignore consumes first character of next line
uote //newline consumed by getline. ignore consumes first character of next line
uote //newline consumed by getline. ignore consumes first character of next line
..
Solution:
Move it to after the input that leaves the unwanted character in the stream
cin>>t;
cin.ignore();
A better alternative is to the ignore so that you can make certain you get rid of all potential garbage on the end of the line
cin>>t;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
This will read from the stream up to the maximum possible length of the stream or a newline is found and discarded, whichever comes first.
Always clean up after an operation rather than before the next. It keeps the related code closer together, aiding in readability, and protects you from cases where there is nothing from before to clean up.

Issue When Clearing cin Buffer After Using cin.getline()

I am using getline (the cin.getline() one) to get a string from cin and finding an issue with a special case. If a user inputs more characters than the the streamsize argument (in this case, 50), the cin buffer holds them and puts them into the next cin call. If I use cin.clear() and cin.ignore() and the user enters in fewer characters than the streamsize argument, then the program waits for the user to press enter again before it continues. So I use strlen to check the size of the string and only use cin.clear() and cin.ignore() if the string has 50 characters. This chops off the extra characters that the user entered after the 49th character. The problem is that when the user enters exactly 49 characters, then there are no extra characters in the buffer to chop off with the cin.clear() and cin.ignore() calls and therefore the program will sit and wait for the user to press enter another time.
A couple of questions:
1) Is there a flag I can check to see if there are characters in the buffer so I can clear() and ignore() only when this flag is true?
2) Is there any other way I can call this same getline function that cuts off all characters after the streamsize argument?
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
#define SIZE 50
void getString(char*);
int main() {
char words[SIZE];
getString(words);
return 0;
}
void getString(char* words) {
cout << "Enter your string: ";
cin.getline(words, SIZE);
if (strlen(words) == SIZE - 1) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
A sample 49 character input that would cause the issue:
abcdefghijklmnopqrstuvwxysabcdefghijklmnopqrstuvw
Erase or add one letter to see the program's normal performance.
You can use istream::gcount() to decide whether there are any more characters other than '\n' left in the line still.
Here are the cases you need to think about.
The return value of cin.gcount() is less than SIZE-1. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.
The return value of cin.gcount() is SIZE-1. This could be due to two scenarios.
The user enters SIZE-2 characters followed by a newline. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.
The user enters SIZE or more number of characters followed by a newline. In this case, there are still some characters left in the line. You will want to ignore the rest of the line.
The return value of cin.gcount() is SIZE. This can happens only when the user enteres SIZE-1 characters followed by a newline. All the characters from the line are read into the argument provided to the function. The newline character is read and discarded. You don't have to worry about ignoring the rest of the line.
Give the above cases, the only time you have to worry about ignoring the rest of the line is when you run into case 2.2. That condition is met when cin.gcount() == SIZE-1 and strlen(words) == SIZE-1.
void getString(char* words) {
cout << "Enter your string: ";
cin.getline(words, SIZE);
if (cin.gcount() == SIZE-1 && strlen(words) == SIZE-1)
{
// There are characters in the stream before the \n.
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}

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.

Repeating code for N cases error [duplicate]

I have the following code:
std::vector<std::string> final_output;
std::string input;
int tries = 0;
std::cin >> tries;
int counter = 0;
while(counter < tries) {
std::getline(std::cin, input);
final_output.push_back(input);
++counter;
}
Given the input:
3
Here Goes
Here Goes 2
The output is:
<blank line>
Here Goes
Here Goes 2
Weirdly, it seems to enter a blank line as input for the first time it runs.
However, if I have the code as:
int tries = 3; // explicitly specifying the number of tries
int counter = 0;
while(counter < tries) {}
It works as expected. Why is the std::cin >> tries causing the code to fail?
I have tested it with VC++ 2010 and g++ 4.4.3
When you enter the number for tries, you hit the return key. After you read tries, the carriage return from hitting the return key is still sitting in the input buffer. That carriage return will normally be translated to a new-line character. Your next call to getline reads everything in the input buffer up to the next new-line. Since the first character is a new-line, it reads that as a line of zero length (i.e., zero characters before the new-line).
The newline of the first entry is still in the input buffer.
You can call std::cin.ignore(); just after reading tries from cin.
This way the newline gets discarded.
I found a good link that explains plenty of things regarding the use of I/O:
http://www.augustcouncil.com/~tgibson/tutorial/iotips.html
You have nothing to absorb the '\n' from the first line in your standalone std::cin >> tries.