I am trying to input a string. It's working fine when I input something like John.
But if I input something like John Smite I end up in an endless loop and a terminal crash.
string fullname;
do{
cout << "Please input the Full Name of the user: ";
cin >> fullname;
}while(fullname=="");
The space is throwing cin off. You should use getline.
You can try this one:
do{
cout << "Please input the Full Name of the user: ";
cin >> fullname;
}
while(fullname.length() == 0);
As to why you get an infinite loop - operator>> overload for std::string will first discard any leading whitespace and then read up to either next whitespace or the end of avaliable input.
When you enter "John Smite", first iteration reads "John", second iteration reads "Smite" and then there's no more input for subsequent iterations. The problem is that your implementation seems to clear fullname before it attempts a read. But because the stream is not in good state anymore, no more reads are possible and there's your infinite loop.
You could do something like this instead:
string temp;
string fullname;
do {
cin.clear(); // clear any error flags
do {
if (cin >> temp) fullname += temp + ' ';
} while (cin.good());
} while (fullname.empty());
This has a (good) side effect that it collapses multiple adjacent whitespace characters, but it's still pretty clunky.
Much better way would be to just say
do std::getline(std::cin, fullname); while (fullname.empty());
Related
#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 wrote a very basic program in C++ which asked the user to input a number and then a string. To my surprise, when running the program it never stopped to ask for the string. It just skipped over it. After doing some reading on StackOverflow, I found out that I needed to add a line that said:
cin.ignore(256, '\n');
before the line that gets the string input. Adding that fixed the problem and made the program work. My question is why does C++ need this cin.ignore() line and how can I predict when I will need to use cin.ignore()?
Here is the program I wrote:
#include <iostream>
#include <string>
using namespace std;
int main()
{
double num;
string mystr;
cout << "Please enter a number: " << "\n";
cin >> num;
cout << "Your number is: " << num << "\n";
cin.ignore(256, '\n'); // Why do I need this line?
cout << "Please enter your name: \n";
getline (cin, mystr);
cout << "So your name is " << mystr << "?\n";
cout << "Have a nice day. \n";
}
ignore does exactly what the name implies.
It doesn't "throw away" something you don't need. Instead, it ignores the number of characters you specify when you call it, up to the char you specify as a delimiter.
It works with both input and output buffers.
Essentially, for std::cin statements you use ignore before you do a getline call, because when a user inputs something with std::cin, they hit enter and a '\n' char gets into the cin buffer. Then if you use getline, it gets the newline char instead of the string you want. So you do a std::cin.ignore(1000,'\n') and that should clear the buffer up to the string that you want. (The 1000 is put there to skip over a specific number of chars before the specified delimiter, in this case, the '\n' newline character.)
You're thinking about this the wrong way. You're thinking in logical steps each time cin or getline is used. Ex. First ask for a number, then ask for a name. That is the wrong way to think about cin. So you run into a race condition because you assume the stream is clear each time you ask for a input.
If you write your program purely for input you'll find the problem:
int main()
{
double num;
string mystr;
cin >> num;
getline(cin, mystr);
cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}
In the above, you are thinking, "first get a number." So you type in 123 press enter, and your output will be num=123,mystr=''. Why is that? It's because in the stream you have 123\n and the 123 is parsed into the num variable while \n is still in the stream. Reading the doc for getline function by default it will look in the istream until a \n is encountered. In this example, since \n is in the stream, it looks like it "skipped" it but it worked properly.
For the above to work, you'll have to enter 123Hello World which will properly output num=123,mystr='Hello World'. That, or you put a cin.ignore between the cin and getline so that it'll break into logical steps that you expect.
This is why you need the ignore command. Because you are thinking of it in logical steps rather than in a stream form so you run into a race condition.
Take another code example that is commonly found in schools:
int main()
{
int age;
string firstName;
string lastName;
cout << "First name: ";
cin >> firstName;
cout << "Last name: ";
cin >> lastName;
cout << "Age: ";
cin >> age;
cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
}
The above seems to be in logical steps. First ask for first name, last name, then age. So if you did John enter, then Doe enter, then 19 enter, the application works each logic step. If you think of it in "streams" you can simply enter John Doe 19 on the "First name:" question and it would work as well and appear to skip the remaining questions. For the above to work in logical steps, you would need to ignore the remaining stream for each logical break in questions.
Just remember to think of your program input as it is reading from a "stream" and not in logical steps. Each time you call cin it is being read from a stream. This creates a rather buggy application if the user enters the wrong input. For example, if you entered a character where a cin >> double is expected, the application will produce a seemingly bizarre output.
Short answer
Why? Because there is still whitespace (carriage returns, tabs, spaces, newline) left in the input stream.
When? When you are using some function which does not on their own ignores the leading whitespaces. Cin by default ignores and removes the leading whitespace but getline does not ignore the leading whitespace on its own.
Now a detailed answer.
Everything you input in the console is read from the standard stream stdin. When you enter something, let's say 256 in your case and press enter, the contents of the stream become 256\n. Now cin picks up 256 and removes it from the stream and \n still remaining in the stream.
Now next when you enter your name, let's say Raddicus, the new contents of the stream is \nRaddicus.
Now here comes the catch.
When you try to read a line using getline, if not provided any delimiter as the third argument, getline by default reads till the newline character and removes the newline character from the stream.
So on calling new line, getline reads and discards \n from the stream and resulting in an empty string read in mystr which appears like getline is skipped (but it's not) because there was already an newline in the stream, getline will not prompt for input as it has already read what it was supposed to read.
Now, how does cin.ignore help here?
According to the ignore documentation extract from cplusplus.com-
istream& ignore (streamsize n = 1, int delim = EOF);
Extracts characters from the input sequence and discards them, until
either n characters have been extracted, or one compares equal to
delim.
The function also stops extracting characters if the end-of-file is
reached. If this is reached prematurely (before either extracting n
characters or finding delim), the function sets the eofbit flag.
So, cin.ignore(256, '\n');, ignores first 256 characters or all the character untill it encounters delimeter (here \n in your case), whichever comes first (here \n is the first character, so it ignores until \n is encountered).
Just for your reference, If you don't exactly know how many characters to skip and your sole purpose is to clear the stream to prepare for reading a string using getline or cin you should use cin.ignore(numeric_limits<streamsize>::max(),'\n').
Quick explanation: It ignores the characters equal to maximum size of stream or until a '\n' is encountered, whichever case happens first.
When you want to throw away a specific number of characters from the input stream manually.
A very common use case is using this to safely ignore newline characters since cin will sometimes leave newline characters that you will have to go over to get to the next line of input.
Long story short it gives you flexibility when handling stream input.
Ignore function is used to skip(discard/throw away) characters in the input stream. Ignore file is associated with the file istream.
Consider the function below
ex: cin.ignore(120,'/n');
the particular function skips the next 120 input character or to skip the characters until a newline character is read.
As pointed right by many other users. It's because there may be whitespace or a newline character.
Consider the following code, it removes all the duplicate characters from a given string.
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
cin>>t;
cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
while(t--){
vector<int> v(256,0);
string s;
getline(cin,s);
string s2;
for(int i=0;i<s.size();i++){
if (v[s[i]]) continue;
else{
s2.push_back(s[i]);
v[s[i]]++;
}
}
cout<<s2<<endl;
}
return 0;
}
So, You get the point that it will ignore those unwanted inputs and will get the job done.
It is better to use scanf(" %[^\n]",str) in c++ than cin.ignore() after cin>> statement.To do that first you have to include < cstdio > header.
I have a database class that is an array that will hold a number of objects.
The function will take a couple of inputs from the user which include both strings and ints
For example:
std::cout << "Enter first name: ";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(std::cin, first_name);
std::cout << "Enter last name: ";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(std::cin, last_name);
std::cout << "Enter age: ";
std::cin >> age;
When I run the code, after I hit enter after entering the last name, it just starts a new line and I have to enter another input before it asks for the age input.
I heard it was bad to mix getline and cin, and that it's better to use one or the other. What can I do to make this work and what would be good practice moving forward?
Edit: I added in the ignores when I initially searched for solutions because without them, the code wouldn't bother waiting for user input. The output would be "Enter first name: Enter last name: "
Edit2: RESOLVED. Problem was I had used "cin >>" earlier in my code for user to input an int variable and needed the first cin.ignore statement, but not the other. Did not include that part of the code because I didn't know that was affecting it. Still new to all this so thanks everyone for their help!
Your std::cin::ignore calls are not helping you. They are only needed after an input that does not extract the end-of-line character (>>).
std::string first_name;
std::string last_name;
int age;
std::cout << "Enter first name: ";
std::getline(std::cin, first_name); // end of line is removed
std::cout << "Enter last name: ";
std::getline(std::cin, last_name); // end of line is removed
std::cout << "Enter age: ";
std::cin >> age; // doesn't remove end of line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // this does
// input can proceed as normal
You only need the std::cin::ignore call after std::cin >> age; because that doesn't remove the end of line character whereas the std::getline calls do.
According to the documentation of std::basic_istream::ignore(), this function behaves as an Unformatted Input Function which mean it is going to block and wait for user input if there is nothing to skip in the buffer.
In your case both of your ignore statments are not neccessary since std::getline() will not leave the new line character in the buffer. So what is actually happening is:
std::cout << "Enter first name: ";
/*your first input is skipped by the next ignore line because its going to block until
input is provided since there is nothing to skip in the buffer*/
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
/* the next getline waits for input, reads a line from the buffer and also removes the
new line character from the buffer*/
std::getline(std::cin, first_name);
std::cout << "Enter last name: ";
/*your second input is skipped by the next ignore line because its going to block until
input is provided since there is nothing to skip in the buffer*/
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
/* the next getline waits for input and this is why it seems you need to provide
another input before it ask you to enter the age*/
std::getline(std::cin, last_name);
You need to remove the ignore statments to make this work. You may also want to read When and why do I need to use cin.ignore() in C++
I recommend removing the ignore function calls:
std::string name;
std::cout << "Enter name: ";
std::getline(cin, name);
unsigned int age;
std::cout << "Enter age: ";
std::cin >> age;
I have a problem using getline method to get a message that user types, I'm using something like:
string messageVar;
cout << "Type your message: ";
getline(cin, messageVar);
However, it's not stopping to get the output value, what's wrong with this?
If you're using getline() after cin >> something, you need to flush the newline character out of the buffer in between. You can do it by using cin.ignore().
It would be something like this:
string messageVar;
cout << "Type your message: ";
cin.ignore();
getline(cin, messageVar);
This happens because the >> operator leaves a newline \n character in the input buffer. This may become a problem when you do unformatted input, like getline(), which reads input until a newline character is found. This happening, it will stop reading immediately, because of that \n that was left hanging there in your previous operation.
If you only have a single newline in the input, just doing
std::cin.ignore();
will work fine. It reads and discards the next character from the input.
But if you have anything else still in the input, besides the newline (for example, you read one word but the user entered two words), then you have to do
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
See e.g. this reference of the ignore function.
To be even more safe, do the second alternative above in a loop until gcount returns zero.
I had similar problems. The one downside is that with cin.ignore(), you have to press enter 1 more time, which messes with the program.
int main(){
.... example with file
//input is a file
if(input.is_open()){
cin.ignore(1,'\n'); //it ignores everything after new line
cin.getline(buffer,255); // save it in buffer
input<<buffer; //save it in input(it's a file)
input.close();
}
}
I know I'm late but I hope this is useful.
Logic is for taking one line at a time if the user wants to enter many lines
int main()
{
int t; // no of lines user wants to enter
cin>>t;
string str;
cin.ignore(); // for clearing newline in cin
while(t--)
{
getline(cin,str); // accepting one line, getline is teminated when newline is found
cout<<str<<endl;
}
return 0;
}
input :
3
Government collage Berhampore
Serampore textile collage
Berhampore Serampore
output :
Government collage Berhampore
Serampore textile collage
Berhampore Serampore
i think you are not pausing the program before it ended so the output you are putting after getting the inpus is not seeing on the screen right?
do:
getchar();
before the end of the program
The code is correct. The problem must lie somewhere else. Try the minimalistic example from the std::getline documentation.
main ()
{
std::string name;
std::cout << "Please, enter your full name: ";
std::getline (std::cin,name);
std::cout << "Hello, " << name << "!\n";
return 0;
}
So I have a function that keeps skipping over the first getline and straight to the second one. I tried to clear the buffer but still no luck, what's going on?
void getData(char* strA, char* strB)
{
cout << "Enter String 1: "; // Shows this line
cin.clear();
cin.getline(strA, 50); // 50 is the character limit, Skipping Input
cout << endl << "Enter String 2: "; // Showing This Line
cin.clear();
cin.getline(strB, 50); // Jumps Straight to this line
}
Make sure you didn't use cin >> str. before calling the function. If you use cin >> str and then want to use getline(cin, str), you must call cin.ignore() before.
string str;
cin >> str;
cin.ignore(); // ignores \n that cin >> str has lefted (if user pressed enter key)
getline(cin, str);
In case of using c-strings:
char buff[50];
cin.get(buff, 50, ' ');
cin.ignore();
cin.getline(buff, 50);
ADD: Your wrong is not probably in the function itself, but rather before calling the function. The stream cin have to read only a new line character \n' in first cin.getline.
cin.clear(); clears any error bits on the stream - it does not consume any data that may be pending.
You want to use cin.ignore() to consume data from the stream.
After you read something there is still 'RETURN' character inside bufor so you have to cin.ignore() after each read.
You can also use cin.sync() to clear the stream.
Actualy clear method only clears flags.
There is also option that you can go to the end of stream, with nothing left to read you should write without problems.
std::cin.seekg(0, std::ios::end);
It is up to you what will you use.
use cin.ignore(-1);It will not remove the first character of the input string
after a bigger input using get line, a cin causes errors. So using this code after getline returns the input queue and fall bit to normal.
cin.getline(a,5);
while(getchar()!='\n');
cin.clear();
that is run a while loop to remove all characters from the queue
cin.ignore() causes problem for further inputs and
cin.clear() is just to reset the fallbit