In the following code, getline() skips reading the first line.
I noted that when commenting the "cin >> T" line, it works normally. But I can't figure out the reason.
I want to read an integer before reading lines! How to fix that?
#include <iostream>
using namespace std;
int main () {
int T, i = 1;
string line;
cin >> T;
while (i <= T) {
getline(cin, line);
cout << i << ": " << line << endl;
i++;
}
return 0;
}
cin >> T;
This consumes the integer you provide on stdin.
The first time you call:
getline(cin, line)
...you consume the newline after your integer.
You can get cin to ignore the newline by adding the following line after cin >> T;:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
(You'll need #include <limits> for std::numeric_limits)
Most likely there is a newline in your input file, and that is being processed immediately, as explained on this page:
http://augustcouncil.com/~tgibson/tutorial/iotips.html
You may want to call cin.ignore() to have it reject one character, but, you may want to read more of the tips, as there are suggestions about how to handle reading in numbers.
This line only reads a number:
cin >> T;
If you want to parse user input you need to take into account they keep hitting <enter> because the input is buffered. To get around this somtimes it is simpler to read interactive input using getline. Then parse the content of the line.
std::string userInput;
std::getline(std::cin, userInput);
std::stringstream(userInput) >> T;
Related
I'm attempting to get a few user-input parameters from the console, two strings, two ints and a double. The relevant code I'm trying to use is this:
#include <string>
#include <iostream>
using namespace std;
// ...
string inputString;
unsigned int inputUInt;
double inputDouble;
// ...
cout << "Title: ";
getline(cin, inputString);
tempDVD.setTitle(inputString);
cout << "Category: ";
getline(cin, inputString);
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
cin >> inputUInt;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
cin >> inputUInt;
tempDVD.setYear(inputUInt);
cout << "Price: $";
cin >> inputDouble;
tempDVD.setPrice(inputDouble);
However, when running the program, instead of waiting for the first inputString to be entered, the code doesn't stop until the second getline() call. Thus the console output looks like this:
Title: Category:
with the cursor appearing after category. If I input now, the program then jumps ahead to the year input, not allowing me to enter more than one string. What's happening here?
The problem is you are mixing calls to getline() with the use of the operator >>.
Remember that operator >> ignored leading white space so will correctly continue across lines boundaries. But stops reading after the input has successfully been retrieved and thus will not swallow trailing '\n' characters. Thus if you use a getline() after a >> you usually get the wrong thing unless you are careful (to first remove the '\n' character that was not read).
The trick is to not use both types of input. Pick the appropriate one and stick to it.
If it is all numbers (or objects that play nice with operator >>) then just use operator >> (Note string is the only fundamental type that is not symmetric with input/output (ie does not play nicely)).
If the input contains strings or a combination of stuff that will require getline() then only use getline() and parse the number out of the string.
std::getline(std::cin, line);
std::stringstream linestream(line);
int value;
linestream >> value;
// Or if you have boost:
std::getline(std::cin, line);
int value = boost::lexical_cast<int>(line);
You need to flush the input buffer. It can be done with cin.clear(); cin.sync();.
You can use
cin.ignore();
or as #kernald mentioned use
cin.clear();
cin.sync();
before using getline()
Use cin.clear() as mentioned and use proper error handling:
cin.clear();
cin.sync();
cout << "Title: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setTitle(inputString);
cout << "Category: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setYear(inputUInt);
cout << "Price: $";
if (!(cin >> inputDouble)) exit 255;
tempDVD.setPrice(inputDouble);
Also works with ws. You can use getline(cin >> ws, inputString)) to eat the whitespaces or the newlines after reading data with cin command.
If user inputs a space before \n in previous cin before getline, only ignore itself wouldn't be enough so you have to use this code instead of ignore() alone. For example 12345 \t \n will not work anymore.
All unprocessed characters must be ignored.
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Use this between cin and getline.
Mixing getline() with input streams in generally a bad thing to do. It's theoretically possible to manually handle the dirty buffers left over by using streams, but it's an unnecessary pain that should definitely be avoided.
You are better off using a console library to grab your input, this way the dirty-work can be abstracted for you.
Take a look at TinyCon. You can just use the static method tinyConsole::getLine() in replace of your getline and stream calls, and you can use it as many times as you'd like.
You can find information here:
https://sourceforge.net/projects/tinycon/
cin.sync();
use this instead of cin.ignore(
works best.
The function_______ will return the last read character and will move the inside pointer one with -1 char.
Getline()
Peek()
3.flush()
4.putback()
#include <iostream>
#include <string>
using namespace std;
struct UserInfo{
string userPhoneNumber;
string userName ;
string userAddress ;
};
int main ()
{
cout << "How many Entries do you want to enter?";
int userAmountSelection;
cin >> userAmountSelection;
UserInfo userOne [userAmountSelection];
for (int i = 0; i < userAmountSelection; i++){
cout << "Please enter your first and last name: ";
cin.ignore(); // possible problem in code
getline (cin, userOne[i].userName, '\n');
cout << "Please Enter your address, " << userOne[i].userName << ":";
cin.ignore(); // possible problem in code
getline (cin, userOne[i].userAddress, '\n');
cout << "Please enter your phone#: ";
cin.ignore (); // possible problem in code
getline (cin, userOne[i].userPhoneNumber);
}
for (int i = 0; i < userAmountSelection; i++){
cout << userOne[i].userName << " " <<
userOne[i].userAddress << " " <<
userOne[i].userPhoneNumber << endl;
}
return 0;
}
As you can see its a simple code for learning structs and experimenting. The problem i run into appears to be from cin.ignore () code. it ignores the first characters of the input strings on output. The code does compile, however input and output are skewed.
For example when i enter a name of Terry, it will output erry.
I have tried removing the cin.ignore (), however when i do that, the output skips over the parts where the user needs to enter data and leaves areas blank.
I have scoured the forums and found suggestions such as adding an argument to the cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');. for example, however this does not solve the problem and only adds to the list of errors I'm experiencing.
The Problem
The problem is with the placement of ignores to prevent the bug outlined in Why does std::getline() skip input after a formatted extraction? The ignores have been placed before the getlines, and while this solves the getline skipping problem, it causes the problem the Asker has encountered. There isn't always something that needs to be ignored.
For example
cin >> userAmountSelection;
will leave a line ending in the stream if the user typed in the amount and then hit enter.
cout << "Please enter your first and last name: ";
cin.ignore(); // possible problem in code
getline (cin, userOne[i].userName, '\n');
inside the for loop Would trip over this line ending if not for the ignore. But getline does not leave a newline in the stream , so the second and subsequent iterations of the loop have no newline to ignore. Part of the requiured data is ignored instead.
After
cin >> userAmountSelection;
rather than before
getline (cin, userOne[i].userName, '\n');
would be a good place to place an ignore so the newline is removed from the stream only after it has been left in the stream, but...
The Solution
The best way to handle this is to always read entire lines with getline and then parse those lines (see option 2 of this answer) into the pieces you want.
std::string line;
std::getline(std::cin, line);
std::istringstream(line) >> userAmountSelection;
This always works (Note: Requires #include <sstream>) and now you only have one type of reading going on, not a game of mix-n-match where you may forget you need an ignore.
Feel free to stop reading now.
The ignore approach requires some extra smarts. It's not as simple as it looks, in addition to fallibility of the human memory. You should place ignores AFTER an operation that leaves unwanted stuff in the stream. If you ignore BEFORE an operation, you often find yourself losing data you wanted because there was nothing to ignore.
std::cin >> userAmountSelection; // read a number
std::cin.ignore(); // discard the next character
Works a lot of the time, but what if the user typed in the amount and then a space and then hit enter or typed in all of the input they needed to type because they new darn well what the next prompt was? You gotta get a bit craftier.
std::cin >> userAmountSelection;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
This ignore annihilates everything until it hits the end of the line or runs out of space in the stream. (Note: Requires #include <limits>)
The problem i run into appears to be from cin.ignore () code. it ignores the first characters of the input strings on output.
Looking at the istream::ignore declaration
istream& ignore (streamsize n = 1, int delim = EOF);
It will discard the first character by default.
I have tried removing the cin.ignore (), however when i do that, the
output skips over the parts where the user needs to enter data and
leaves areas blank.
That's because of the std::cin performed which left a residual newline which was then consumed by the getline. You'll only need ignore between the std::cin and getline calls:
std::cin >> userAmountSelection;
std::cin.ignore(); //---
...
for (int i = 0; i < userAmountSelection; i++) {
...
getline (...);
...
getline (...)
}
Also, there may be instances where you don't know if an std::cin will precede the getline. In that case, you may check if the input stream contains new line before doing ignore:
...
// some I/O operations happening here
...
// ignore if there's white space
if (std::iswspace(std::cin.peek())) std::cin.ignore();
std::getline(std::cin, somestring);
I'm attempting to get a few user-input parameters from the console, two strings, two ints and a double. The relevant code I'm trying to use is this:
#include <string>
#include <iostream>
using namespace std;
// ...
string inputString;
unsigned int inputUInt;
double inputDouble;
// ...
cout << "Title: ";
getline(cin, inputString);
tempDVD.setTitle(inputString);
cout << "Category: ";
getline(cin, inputString);
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
cin >> inputUInt;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
cin >> inputUInt;
tempDVD.setYear(inputUInt);
cout << "Price: $";
cin >> inputDouble;
tempDVD.setPrice(inputDouble);
However, when running the program, instead of waiting for the first inputString to be entered, the code doesn't stop until the second getline() call. Thus the console output looks like this:
Title: Category:
with the cursor appearing after category. If I input now, the program then jumps ahead to the year input, not allowing me to enter more than one string. What's happening here?
The problem is you are mixing calls to getline() with the use of the operator >>.
Remember that operator >> ignored leading white space so will correctly continue across lines boundaries. But stops reading after the input has successfully been retrieved and thus will not swallow trailing '\n' characters. Thus if you use a getline() after a >> you usually get the wrong thing unless you are careful (to first remove the '\n' character that was not read).
The trick is to not use both types of input. Pick the appropriate one and stick to it.
If it is all numbers (or objects that play nice with operator >>) then just use operator >> (Note string is the only fundamental type that is not symmetric with input/output (ie does not play nicely)).
If the input contains strings or a combination of stuff that will require getline() then only use getline() and parse the number out of the string.
std::getline(std::cin, line);
std::stringstream linestream(line);
int value;
linestream >> value;
// Or if you have boost:
std::getline(std::cin, line);
int value = boost::lexical_cast<int>(line);
You need to flush the input buffer. It can be done with cin.clear(); cin.sync();.
You can use
cin.ignore();
or as #kernald mentioned use
cin.clear();
cin.sync();
before using getline()
Use cin.clear() as mentioned and use proper error handling:
cin.clear();
cin.sync();
cout << "Title: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setTitle(inputString);
cout << "Category: ";
if (!getline(cin, inputString)) exit 255;
tempDVD.setCategory(inputString);
cout << "Duration (minutes): ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setDuration(inputUInt);
cout << "Year: ";
if (!(cin >> inputUInt)) exit 255;
tempDVD.setYear(inputUInt);
cout << "Price: $";
if (!(cin >> inputDouble)) exit 255;
tempDVD.setPrice(inputDouble);
Also works with ws. You can use getline(cin >> ws, inputString)) to eat the whitespaces or the newlines after reading data with cin command.
If user inputs a space before \n in previous cin before getline, only ignore itself wouldn't be enough so you have to use this code instead of ignore() alone. For example 12345 \t \n will not work anymore.
All unprocessed characters must be ignored.
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Use this between cin and getline.
Mixing getline() with input streams in generally a bad thing to do. It's theoretically possible to manually handle the dirty buffers left over by using streams, but it's an unnecessary pain that should definitely be avoided.
You are better off using a console library to grab your input, this way the dirty-work can be abstracted for you.
Take a look at TinyCon. You can just use the static method tinyConsole::getLine() in replace of your getline and stream calls, and you can use it as many times as you'd like.
You can find information here:
https://sourceforge.net/projects/tinycon/
cin.sync();
use this instead of cin.ignore(
works best.
The function_______ will return the last read character and will move the inside pointer one with -1 char.
Getline()
Peek()
3.flush()
4.putback()
This question already has answers here:
Need help with getline() [duplicate]
(7 answers)
Closed 7 years ago.
This is probably a very simple problem but forgive me as I am new.
Here is my code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string name;
int i;
string mystr;
float price = 0;
cout << "Hello World!" << endl;
cout << "What is your name? ";
cin >> name;
cout << "Hello " << name << endl;
cout << "How old are you? ";
cin >> i;
cout << "Wow " << i << endl;
cout << "How much is that jacket? ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << price << endl;
system("pause");
return 0;
}
The problem is that when asked how much is that jacket? getline does not ask the user for input and just inputs the initial value of "0". Why is this?
You have to be careful when mixing operator>> with getline. The problem is, when you use operator>>, the user enters their data, then presses the enter key, which puts a newline character into the input buffer. Since operator>> is whitespace delimited, the newline character is not put into the variable, and it stays in the input buffer. Then, when you call getline, a newline character is the only thing it's looking for. Since that's the first thing in the buffer, it finds what it's looking for right away, and never needs to prompt the user.
Fix:
If you're going to call getline after you use operator>>, call ignore in between, or do something else to get rid of that newline character, perhaps a dummy call to getline.
Another option, and this is along the lines of what Martin was talking about, is to not use operator>> at all, and only use getline, then convert your strings to whatever datatype you need. This has a side effect of making your code more safe and robust. I would first write a function like this:
int getInt(std::istream & is)
{
std::string input;
std::getline(is,input);
// C++11 version
return stoi(input); // throws on failure
// C++98 version
/*
std::istringstream iss(input);
int i;
if (!(iss >> i)) {
// handle error somehow
}
return i;
*/
}
You can create a similar function for floats, doubles and other things. Then when you need in int, instead of this:
cin >> i;
You do this:
i = getInt(cin);
Its because you have a '\n' left lying on the input stream from a previous call.
cin >> i; // This reads the number but the '\n' you hit after the number
// is still on the input.
The easiest way to do interactive user input is to make sure each line is processed independently (as the user will hit enter after each prompt).
As a result always read a line, then process the line (until you get familiar with the streams).
std::string line;
std::getline(std::cin, line);
std::stringstream linestream(line);
// Now processes linestream.
std::string garbage;
lienstream >> i >> garbage; // You may want to check for garbage after the number.
if (!garbage.empty())
{
std::cout << "Error\n";
}
Ignore some characters until line feed is reached.
cin.ignore(256, '\n')
getline (cin,mystr);
In the following code, getline() skips reading the first line.
I noted that when commenting the "cin >> T" line, it works normally. But I can't figure out the reason.
I want to read an integer before reading lines! How to fix that?
#include <iostream>
using namespace std;
int main () {
int T, i = 1;
string line;
cin >> T;
while (i <= T) {
getline(cin, line);
cout << i << ": " << line << endl;
i++;
}
return 0;
}
cin >> T;
This consumes the integer you provide on stdin.
The first time you call:
getline(cin, line)
...you consume the newline after your integer.
You can get cin to ignore the newline by adding the following line after cin >> T;:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
(You'll need #include <limits> for std::numeric_limits)
Most likely there is a newline in your input file, and that is being processed immediately, as explained on this page:
http://augustcouncil.com/~tgibson/tutorial/iotips.html
You may want to call cin.ignore() to have it reject one character, but, you may want to read more of the tips, as there are suggestions about how to handle reading in numbers.
This line only reads a number:
cin >> T;
If you want to parse user input you need to take into account they keep hitting <enter> because the input is buffered. To get around this somtimes it is simpler to read interactive input using getline. Then parse the content of the line.
std::string userInput;
std::getline(std::cin, userInput);
std::stringstream(userInput) >> T;