I wanted to validate a string that will be inputted by the user which follows two conditions. The condition would be whether the string is empty or the string has a space char. My current problem is that I can validate the string but it would require me to press enter once more time to reiterate my question "2. Enter Product Name: ".
while (true) {
cout << "2. Enter Product Name: ";
if(getline(cin, newNode->product_name)) {
if ((newNode->product_name).empty() || (newNode->product_name) == " ") {
cout << "Please enter a valid product name!\n";
cin.clear();
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
}
else {
break;
}
}
}
Being inside the if statement if(getline(cin, newNode->product_name)) { means that the reading of a line succeeded. Therefore, you don't need the lines
cin.clear();
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
They will request an extra line to ignore, so remove that lines.
Related
I am currently working on a very simple project and I found a problem in the testing phase when I tried to enter his name for the new employee and the decision condition was suddenly triggered, I am not sure why this happened. Based on my limited coding experience, in general, a statement in an output judgment statement needs to fulfil a judgment condition, but why would a judgment condition be triggered if I didn't do any input? Thank you all for your help.
Here is a part of the code.
void Management::Add_Staff() {
std::cout << "Please enter the number of staffs you want to add: " << std::endl;
int addNum = 0; // saves the amount entered by the user
std::cin >> addNum;
while (addNum <= 0 || addNum >= 50) {
std::cout << "Invaild number. Please try again" << std::endl;
std::cout << "Please enter the number of staffs you want to add: " << std::endl;
std::cin.clear(); // clear error enter
std::cin.ignore(INT_MAX, '\n'); // INT_MAX means an extremely large number,'\n' means empty space
std::cin >> addNum;
}
int new_Size = this->_StaffNumber + addNum; // The number of existing employees plus
// the number of new employees
Person** new_Space = new Person*[new_Size]; // Open up new space
if (this->_StaffArray !=
NULL) // if the data of the original pointer is not null
{
for (int i = 0; i < this->_StaffNumber;
i++) // data of the original pointer is added to the new pointer
{
new_Space[i] = this->_StaffArray[i];
}
}
for (int i = 0; i < addNum; i++) {
int ID; // create an variable nameed id to store the staff number entered
// from users
std::cout << "Please enter pure and positive number as the staff number of " << i + 1 << " staff: " << std::endl;
std::cin >> ID;
while (ID <= 0) {
std::cout << "Invalid staff number, please enter again: " << std::endl;
std::cin.clear();
std::cin.ignore(INT_MAX, '\n');
std::cin >> ID;
}
std::string NAME; // create an variable nameed id to store the staff
// number entered from users
std::cout << "Please enter the name: " << std::endl;
// std::cin >> NAME;
while (std::getline(std::cin, NAME)) {
if (NAME.length() == 0)
{
std::cout << "Your input is not correct. Please re-enter your name" <<
std::endl;
}
// This will check if the NAME contains only characters.
else if (std::all_of(NAME.begin(), NAME.end(), isalpha)) // isalpha: The function returns a non-zero value if the argument is an alphabetic character, or zero otherwise.
{
break;
}
else {
std::cout << "Only characters are allowed:" << std::endl;
}
}
That is my test case.
*********************************************************
********Welcome to the employee management system********
***********0.Exit the management page********************
***********1.Add the employee information****************
***********2.Display the employee information************
***********3.Delete the employee information*************
***********4.Modify the employee information************
***********5.Search the employee information************
***********6.Sort by number*****************************
Please enter the numbers 0 through 6 as your next step
1
Please enter the number of staffs you want to add:
1
Please enter pure and positive number as the staff number of 1 staff:
12
Please enter the name:
Your input is not correct. Please re-enter your name
After I entered the employee number, the judgment condition was triggered before I entered the name, but I didn't enter a space, I didn't even have time to enter something, and the judgment condition was triggered.
When you get input form the user using std::cin the input from the user does not go directly into the program. Instead that input sits in a buffer, which temperately stores that user entered data so you can later tie that data to a variable or perform some other task with that data. However, if that buffer does not get cleared and you use std::getline then std::getline will read the buffer instead of the new user input that you actually wanted. This is why its important to make use of the std::cin.ignore() function, which will clear the buffer of unwanted int and characters. If you want a more en-depth overview of std::cin.ignore() check out this link .
The Fix:
Looking at your code you do make use of cin.ignore() to clear the buffer but only the user enters something other then a number which will drop them into that while loop.
This is what you currently have:
while (ID <= 0) {
std::cout << "Invalid staff number, please enter again: " << std::endl;
std::cin.clear();
std::cin.ignore(INT_MAX, '\n');
std::cin >> ID;
}
std::string NAME; // create an variable named id to store the staff
// number entered from users
std::cout << "Please enter the name: " << std::endl;
To correct this you will need that std::cin.ignore() call out side of the while loop so that it always happens whether there is an error or not. I have a comment that says NEW CODE LINE for where I made the change.
while (ID <= 0) {
std::cout << "Invalid staff number, please enter again: " << std::endl;
std::cin.clear();
std::cin.ignore(INT_MAX, '\n');
std::cin >> ID;
}
std::cin.ignore(INT_MAX, '\n');//NEW CODE LINE
std::string NAME; // create an variable named id to store the staff
//number entered from users
std::cout << "Please enter the name: " << std::endl;
I want to ask the user for input, which I get with cin like this
void AskForGroundstate() {
cout << "Please enter an groundstate potential value in Volt:" << endl;
if (!(cin >> _VGroundstate)) {
cin.clear();
cin.ignore();
cout << "Groundstate potential not valid." << endl;
AskForGroundstate();
}
}
_VGroundstate is a double, so if the user enters an String with not numbers, it should ask him again for a better input. But the problem is, that when the input is for example "AA", than the program executes AskForGroundstate two times, with "AAA" three times etc. Did I use the clear wrong?
The problem is that cin.ignore() drops one character; you want to drop all characters to end of line:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
This ensures that all invalid input is dropped before end-users are prompted for input again.
I am trying to get a C++ program to output user inputs into an empty file. However, when after inputting a float, the program ends the current session of input by calling up the next session. Below is the code of the function for the user inputs.
vector<Item> insertProducts()
{
vector<Item> products;
string name;
string code;
float price;
string unit;
bool repeat = true;
while(repeat) // program will keep asking for another round of input after one session ends
{
cout << "Enter product description: ";
getline(cin, name);
if(name.compare("#") != 0) // program stop asking for input if # is entered
{
cout << "Enter product code: ";
getline(cin, code);
cout << "Enter product unit price: ";
cin >> price;
cout << "Enter product unit phrase: ";
getline(cin, unit);
cout << "" << endl;
Item newProduct = Item(code, name, price, unit);
products.push_back(newProduct);
}
else
{
repeat = false;
printCatalog(products);
}
}
return products;
}
Below is the result after inputting a float for price whereby the program skipped input of unit phrase and go right into another round of input.
Enter product description: Potato Chips
Enter product code: P3487
Enter product unit price: 1.9
Enter product unit phrase: Enter product description:
May I know what causes this problem and how can I solve it?
Your problem is that after cin >> price;, the newline character which the user used to terminate the input of the price is still in the input buffer—it's the next character to be read. The following std::getline then reads it and returns an empty line.
The most robust way of clearing such a trailing newline is to tell the stream to ignore everything up to and including the next newline:
cin >> price;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Use
cin.ignore();
before calling the getline() function
Alternatively, you can try using
cin.clear();
cin.sync();
at the beginning of your code
This will flush the input buffer.
i'm totally new to C++ and this forum. I tried searching the codes and found a piece of code but it doesn't work as what I wanted. I want a login that check every line of the txt file and grant access to the system if the username and password is correct.
string line = " ";
ifstream readfile("Login.txt");
string username, password, adminname, adminpass;
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
cout << "\nLOGIN SUCCESSFUL!";
}
}
//Login Fail Function
{
int fail = 5;
while (fail > 0)
{
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
fail--;
}
cout << "\nACCESS DENIED!";
}
The txt file consists of 1st line (admin123 password123), 2nd line (admin admin).
The login worked fine if I entered correctly however, if I enter wrong username or password I just stuck in the while loop until it shows access denied even if I enter correct username and password for the second try.
Can anyone help me to fix this? If possible please include the comments(the //) so that I am able to learn from it. Thanks in advance.
Since you mention in the comments that this is an assignment, I'm going to keep this pretty general.
In your program, you prompt once for username and password, then read through the file to see if there is a match.
If there is no match, you then prompt for username and password again in a loop, but do not check to see if they are valid. This is what the problem is. Each time you get a new username and password, check to see if they are valid.
There are (at least) two possible approaches:
Include the "fail" and re-prompt logic around the code that reads the file. So you get a username and password, then read the file checking for a match. If no match, do it again. In this case, you would be reading the file each time. For a large data-set, this could get slow. For this problem, it should be fine.
Read the file once and save the values (Have you studied arrays, vectors, or other data structures? You need at least some of those things to do this). I would use a std::map here because it is direct access and would be the smallest amount of code, but there are many other ways to do this as well.
Here is a possible way to do it with re-reading the file. Note that this mostly just re-organizing the code you already have:
bool success = false; //use this as part of our loop condition
int fail = 5;
while (!success && fail > 0) //loop until we succeed or failed too much
{
//get the username and password
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
//open the file and see if we have a match
ifstream readfile("Login.txt");
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
//we have a match, so set success to true so we exit the loop
success = true;
}
}
if (!success) //we did not find a match in the file
{
//so we output the message
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
fail--;
}
}
//now we know if we had success or not, so report it
if (success)
{
cout << "\nLOGIN SUCCESSFUL!";
}
else
{
cout << "\nACCESS DENIED!";
}
So, this program I am working on is not handling incorrect user input the way I want it to. The user should only be able to enter a 3-digit number for use later in a HotelRoom object constructor. Unfortunately, my instructor doesn't allow the use of string objects in his class (otherwise, I wouldn't have any problems, I think). Also, I am passing the roomNumBuffer to the constructor to create a const char pointer. I am currently using the iostream, iomanip, string.h, and limits preprocessor directives. The problem occurs after trying to enter too many chars for the roomNumBuffer. The following screenshot shows what happens:
The relevant code for this problem follows:
cout << endl << "Please enter the 3-digit room number: ";
do { //loop to check user input
badInput = false;
cin.width(4);
cin >> roomNumBuffer;
for(int x = 0; x < 3; x++) {
if(!isdigit(roomNumBuffer[x])) { //check all chars entered are digits
badInput = true;
}
}
if(badInput) {
cout << endl << "You did not enter a valid room number. Please try again: ";
}
cin.get(); //Trying to dum- any extra chars the user might enter
} while(badInput);
for(;;) { //Infinite loop broken when correct input obtained
cin.get(); //Same as above
cout << "Please enter the room capacity: ";
if(cin >> roomCap) {
break;
} else {
cout << "Please enter a valid integer" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
for(;;) { //Infinite loop broken when correct input obtained
cout << "Please enter the nightly room rate: ";
if(cin >> roomRt) {
break;
} else {
cout << "Please enter a valid rate" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
Any ideas would be greatly appreciated. Thanks in advance.
Read an integer and test whether it's in the desired range:
int n;
if (!(std::cin >> n && n >= 100 && n < 1000))
{
/* input error! */
}
Although Kerrek SB provide an approach how to address the problem, just to explain what when wrong with your approach: the integer array could successfully be read. The stream was in good state but you didn't reach a space. That is, to use your approach, you'd need to also test that the character following the last digit, i.e., the next character in the stream, is a whitespace of some sort:
if (std::isspace(std::cin.peek())) {
// deal with funny input
}
It seems the error recovery for the first value isn't quite right, though. You probably also want to ignore() all characters until the end of the line.