A decision condition is triggered without input - c++

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;

Related

C++ How can i create Object automatically via program directly

Ok I searched for questions but couldn't get my answer, or was not using appropriate term.
if(choice == 2){
string tempName, tempAddress; int tempNic,tempContact;
cout << "\n\t\t*\tWelcome to Our Sponsor Registeration Section\t*\n\n";
cout << "Please enter your name : "; cin>>tempName;
cout << "Please enter your National Identity Card Number : "; cin>>tempNic;
cout << "Please enter your Contact Number : "; cin>>tempContact;
cout << "Please enter your Address : "; cin>>tempAddress;
// prototype Sponsor(string n, string add, int nic_n, int phone) constructor
Sponsor (Constructor goes here) // how to make many objects now?
}
the code is pasted here https://codeshare.io/aVxl42
check line 69 where i am going to use a constructor to add the values, by this i can add 1 object, but what shall i do such that if a person who is using program wants to add more objects do it?
I know i need to encapsulate something between 61 and 70.
Please help me how i work this out.
I'm guessing you want to make it loop? I'd suggest a while-loop.
I haven't used vectors in forever(professors forbid it) so I may make some mistake, but you'll get the overall point.
bool stop = false; //This is to check after each loop if it should continue or not
char contChoice;
vector<Sponsor> sponsors;
while(!stop){
if(choice == 2){
string tempName, tempAddress; int tempNic,tempContact;
cout << "\n\t\t*\tWelcome to Our Sponsor Registeration Section\t*\n\n";
cout << "Please enter your name : "; cin>>tempName;
cout << "Please enter your National Identity Card Number : "; cin>>tempNic;
cout << "Please enter your Contact Number : "; cin>>tempContact;
cout << "Please enter your Address : "; cin>>tempAddress;
// prototype Sponsor(string n, string add, int nic_n, int phone) constructor
sponsors.push_back(Sponsor(tempName, tempAddress, tempContact, tempNic));
//Add whatever other arguments you want to pass in, in whatever order
cout << "Do you want to continue? [Y/N]: "; cin>>contChoice;
if(contChoice == 'N' || contChoice == 'n')
stop = true;
else stop = false; //This isn't really necessary since it is false by default
}
}
But I would also suggest that you make set-member functions in Sponsor at least. You can also use a dynamic array and make it expand, which is trickier than a vector, way trickier in fact.

C++ mystical infinite loop

I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?
my code:
#include <iostream>
using namespace std;
struct dataT {
int numOfVoters = -1;
float preSpread = -1;
float votingError = -1;
};
void getUserInfo() {
dataT data;
while (data.numOfVoters == -1) {
cout << "enter the number of voters" << endl;
cin >> data.numOfVoters;
if (data.numOfVoters <= 0) {
data.numOfVoters = -1;
cout << "Invalid entry, please enter a number larger than zero." << endl;
}
}
while (data.votingError == -1) {
cout << "enter the percentage spread between candidates" << endl;
cin >> data.votingError;
if (data.votingError <= 0 || data.votingError >= 1) {
data.votingError = -1;
cout << "Invalid entry. Enter a number between 0 to 1." << endl;
}
}
while (data.preSpread == -1) {
cout << "Enter the precentage spread between the two candidates." << endl;
cin >> data.preSpread;
if (data.preSpread <= 0 || data.preSpread >= 1) {
data.preSpread = -1;
cout << "Invalid input. Enter a number between 0 and 1." << endl;
}
}
}
int main() {
getUserInfo();
return 0;
}
Console:
enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.
a proper check can be
while(integervariable has not good value)
{
cout << "prompt the user: ";
cin >> integervariable;
if(!cin) //something wrong in the input format
{
cin.clear(); //clear the error flag
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
cout << "prompt error message \n";
}
}
Your if statements are always true, you want something more like:
if (data.votingError < 0 || data.votingError > 1) {
...
then data.votingError can take on a value different from -1 and exit your loop.
The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.
As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.

getline() and reading data from text files

The program I code below should
List all payment made by each student, show amount paid and outstanding
I need some help with the following section:
void payment()
{
// Display message asking for the user input
std::cout << "List all payment made by each student, show amount paid and outstanding." << std::endl;
// Read from text file and Display list of payment
std::ifstream infile; // enable to open, read in and close a text file
float StudentCode; // to store the student enrolment number
float Amount; // to store the amount of money
float Type; // to store information on type of payment made
float Outstanding; // to store amount of money is due
infile.open("Payment.txt"); // open a text file called Payment
if (!infile)
{
std::cout << "Item list is empty" << std::endl; // if the file is empty it output the message
}
else
{
std::cout << "List of Payment: " << std::endl;
std::cout << "" << std::endl;
std::cout << "Enrolment No." << "Amount" << "Outstanding" << std::endl;
// If there is Student Code that has the same number, it need to combined the amount it paid
// For an example
// Student Code: 12 Amount: 25
// Student Code: 12 Amount: 50
// so it should display the following when the program runs:
// Student Code: 12 Amount: 75
while(!infile.eof()) // output the description of the text file onto the screen
{
getline(infile,StudentCode,Amount);
Outstanding = Amount - 100;
std::cout << StudentCode << Amount << "$" << Outstanding << std::endl;
//iter++;
}
std::cout << "End of list\n" << std::endl;
}
infile.close(); // close the text file
}
What is wrong with the getline part:
getline(infile,StudentCode, Amount);
Also the program should not display repeated Student Code but combine the amount it paid.
Where I explain in the comment section
// If there is Student Code that has the same number .....
How do I do this?
getline reads a line from a stream into a string. What you're trying to do, is more like this
while (infile >> StudentCode >> Amount) {
// process values
}
If you want to sum up all amounts, you must first accumulate and afterwards loop through the collected values and print them
std::map<int, float> amountsPaid;
int studentCode;
float amount;
// accumulate amounts
while (infile >> studentCode >> amount) {
amountsPaid[studentCode] += amount;
}
// loop through map and print all entries
for (auto i = amountsPaid.begin(); i != amountsPaid.end(); ++i) {
float outstanding = i->second - 100;
std::cout << i->first << ": " << i->second << "$, " << outstanding << '\n';
}
There are several problems here. One is that getline reads one line of text into a single std::string variable, not multiple float fields.
For that you might try
infile >> StudentCode >> Amount;
A second problem is that
while(!infile.eof())
will not check if the next input is going to work but if the previous input attempt failed beause it reached end-of-file.
The standard method is to combine these into
while (infile >> StudentCode >> Amount)
{
// do something with the code and amount
}
Your call to getline doesn't seem correct.
The documentation states
istream& getline ( istream& is, string& str, char delim );
But your giving it
getline(istream&, float, float);
You should be trying to read the line as a string and then parse out the 2 floats.
Since your using c++, if the file is well formatted you could just redirect cin and it'll be easier. You could just do something like
while (infile >> StudentCode) {
infile >> Amount;
}

Not handling user input correctly

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.

Else statement crashes when i enter a letter for a cin << int value

Alright, I have a question, I veered away from using strings for selection so now I use an integer. When the user enters a number then the game progresses. If they enter a wrong character it SHOULD give the else statement, however if I enter a letter or character the system goes into an endless loop effect then crashes. Is there a way to give the else statement even if the user defines the variable's type.
// action variable;
int c_action:
if (c_action == 1){
// enemy attack and user attack with added effect buffer.
///////////////////////////////////////////////////////
u_attack = userAttack(userAtk, weapons);
enemyHP = enemyHP - u_attack;
cout << " charging at the enemy you do " << u_attack << "damage" << endl;
e_attack = enemyAttack(enemyAtk);
userHP = userHP - e_attack;
cout << "however he lashes back causing you to have " << userHP << "health left " << endl << endl << endl << endl;
//end of ATTACK ACTION
}else{
cout << "invalid actions" << endl;
goto ACTIONS;
}
You haven't shown how you are reading the integer. But in general you want to do something like this:
int answer;
if (cin >> answer)
{
// the user input a valid integer, process it
}
else
{
// the user didn't enter a valid integer
// now you probably want to consume the rest of the input until newline and
// re-prompt the user
}
The problem is that your cin is grabbing the character and then failing, which leaves the character in the input buffer. You need to check whether the cin worked:
if( cin >> k) { ... }
or
cin >>k;
if(!cin.fail()) { ... }
and if it fails, clear the buffer and the fail bit:
cin.clear(); // clears the fail bit
cin.ignore(numeric_limits<streamsize>::max()); // ignore all the characters currently in the stream
EDIT: numeric_limits is found in the limits header file, which you include as per usual:
#include <limits>
Your problem is not with the else-statement, but with your input. If you do something like
cin >> i;
and enter a character, the streams error state is set and any subsequent try to read from the stream will fail unless you reset the error state first.
You should read a string instead and convert the strings contents to integer.