Why does this code keep looping despite no loop? - c++

As the title says, I'm unable to figure out why this code keep on lopping when the input is not of an integer but a string.
Edit: Seems like you misunderstood my question, let me clarify and pase all the code.
I don't want to quit the program after I finished typing the teacher, because there's a case (case 0) that handle that. What I want to know is why the code keep looping if I enter a string in the part where it's asking for birtdate instead of an integer, but work fine if I enter an integer.
In this case, if an interger where to be entered, the program behaves as expected, but when it's a string, the program keep on looping the part where it asks for the birthdate. Even afte removing the if and else, it's still do the same thing, in which it should crash since there's no error handle.
int main()
{
string tempName;
int tempYear;
char input = 't';
bool exit = 0;
do
{
cout << "Please choose one of the following options:" << endl;
cout << "0. Quit" << endl;
cout << "1. Add new Teacher" << endl;
cout << "2. Add new Assistant" << endl;
cout << "3. Add new TA-personel" << endl;
cout << "4. Show all Staff" << endl;
cout << "You chose: ";
cin >> input;
cout << endl;
switch (input)
{
case '0':
exit = 1;
break;
case '1':
cout << "Please enter the name of the teacher: ";
cin >> tempName;
cin.ignore();
cout << "Please enter the birthdate of the teacher: ";
cin >> tempYear;
cin.ignore();
if (!cin.fail())
{
//Nothing
}
else
{
cout << "The input was not a number!";
cout << "1. Please enter the birthdate of the teacher: ";
cin >> tempYear;
}
break;
case '2':
break;
case'3':
break;
case '4':
break;
default:
cout << "Invalid input!" << endl;
break;
}
} while (exit == 0);
getchar();
return 0;
}

This code (or your full MCVE, anyway, which you neglected to share -.-) will always loop, because you never change the value of the poorly-named variable exit.
Update
Remember when you checked for !cin.fail()? That was the right thing to do, but you didn't unset the fail flag for the next attempt.
cin.clear();

You're not modifying the exit variable inside the loop.
So the condition of the while loop is always true if exit was set to 0 before the loop.

First of all the code is incomplete.
1.You need to change the value of the variable name "exit" to a non-zero value in the switch-case to end the loop which corresponds to the user selecting the exit option.
You need to ask for a new choice from the user inside the do-while loop and before the switch statement starts.
Change the variable type of your tempyear to string.
for example:
char choice;
do
{
cin>>choice;
switch(choice)
{
case '0': exit=1;
break;
}
}while(exit==0)
This will end the loop when the user enters 0
UPDATE
The reason that it goes into infinite loop when you enter a string value in the int variable tempyear is that the bad input flag of cin is set after you enter the string.
To fix it you need to use cin.clear() after cin.ignore() so that the bad input flag is reset and it takes input again- as pointed out by #Lightness Races in Orbit

Related

Why do I need to press Enter twice after getline()?

Everything is working fine in this program except when it reaches getline() after cout<<"From Date: ";. At this point no matter if I give input or simply hit enter without input, I have to hit enter twice to proceed further. I tried removing cin.ignore() but it causes more problem by jumping over the first getline(). Here is the snippet which is causing this problem-
int main() {
Date d1;
int choice;
cout << "\nEnter choice: ";
cin >> choice;
cin.ignore(numeric_limits < streamsize > ::max(), '\n');
switch (choice) {
case 1:
d1.diffbw();
break;
default:
cout << "Wrong choice";
}
return 0;
}
void Date::diffbw() {
Date current, ref;
string choice;
cout << "\n Type 'man' to enter date manually else hit Enter to insert current date!";
do {
cout << "From Date:";
getline(cin, choice);
if (choice == "man")
current.getdate(); //getdate() assigns day, month and year in object current
else if (choice.empty())
current = sysDate(); //sysDate returns system date
else {
cout << "\n Wrong Choice!";
cout << "\n Enter Again?(y/n): ";
getline(cin, choice);
}
} while (choice == "y" || choice == "Y");
do {
cout << "To Date:";
getline(cin, choice);
if (choice.empty())
ref = sysDate();
else if (choice == "man")
ref.getdate();
else {
cout << "\n Wrong Choice!";
cout << "\n Enter Again?(y/n): ";
getline(cin, choice);
}
} while (choice == "y" || choice == "Y");
current.calcAge(ref); //calcAge() calculates difference between two given dates.
cout << "\n Difference: ";
cout << abs(current.day) << " day(s) " << abs(current.month) << " month(s) " << abs(current.year) << " year(s)";
}
P.S.- I am using g++ compiler on windows.
Edit: I posted the whole function here as many people are having difficulty in understanding the context here. I also corrected the 'cin.ignore()' syntax as suggested by #john. I am trying to calculate difference between two given dates.
The second 'do while' loop works without any bug although it is completely synonymous with the first one.
It might be because you are first trying to get a value by calling cin.getline() and afterwards the program is done but is waiting for confirmation and it gets the confirmation by you pressing enter.
Basically
Enter Value: 5 //Presses enter
Press any key to exit window.
Your statement
cout<<"\n\n From Date:";
is strange and probably wrong, since the std::cout stream is generally buffered.
You should use std::cout << "From date:" << std::endl; and read a good C++ programming book and check in this C++ reference that you are correctly using every function or feature from the C++ standard library.
If you compile with a recent GCC, I recommend enabling all warnings and debug info, so compiling with g++ -Wall -Wextra -g. Then use your debugger, e.g. GDB.
If your computer runs some Linux or POSIX system, you could be interested in using GNU readline: then the input line becomes user-editable. You might also want to code a graphical application with Qt.
Everything is working fine in this program
How did you check that? What debugger did you use? What test cases do you have? Did you try to type something with spaces, e.g. today's date as the user input? What did happen?
I slightly modified your program to avoid relying on the Date class, which you did not define:
#include <string>
#include <iostream>
#include <limits>
#include <math.h>
#include <stdio.h>
using namespace std;
void diffbw();
int main() {
int choice;
cout << "\nEnter choice: ";
cin >> choice;
cin.ignore(numeric_limits < streamsize > ::max(), '\n');
switch (choice) {
case 1:
diffbw();
break;
default:
cout << "Wrong choice";
}
}
void diffbw() {
string choice;
cout << "\n Type 'man' to enter date manually else hit Enter to insert current date!";
do {
cout << "From Date:";
getline(cin, choice);
cout << "choice";
if (choice == "man") {
}
else if (choice.empty()) {
}
else {
cout << "\n Wrong Choice!";
cout << "\n Enter Again?(y/n): ";
getline(cin, choice);
}
} while (choice == "y" || choice == "Y");
do {
cout << "To Date:";
getline(cin, choice);
if (choice.empty()) {
}
else if (choice == "man") {
}
else {
cout << "\n Wrong Choice!";
cout << "\n Enter Again?(y/n): ";
getline(cin, choice);
}
} while (choice == "y" || choice == "Y");
cout << "\n Difference: ";
}
and I don't see the same phenomenon you describe. That is, I don't need to press Enter twice. Please consider making your problematic program more minimal, and at the same time complete.

Search for a string within an array

I am making a phonebook program for c++ and am having trouble transferring my search function into my main function. When I compile it and search for the name, it crashes the program.
Search Function:
int search(string name){
for(int i=0; i<counter; i++){
if(data[i][0] == name){
return i;
}
else{
cout << "Name not found" << endl;
}
}
}
Main Function:
int main(){
bool done = false;
int choice;
string name;
string areaCode;
string number;
load_contacts("contacts.txt");
cout << "Welcome to AddressBook" << endl;
while(!done){
cout << "What would you like to do?" << endl;
cout << "1) Display all contacts" << endl;
cout << "2) Add a contact" << endl;
cout << "3) Remove a contact" << endl;
cout << "4) Search a contact" << endl;
cout << "5) Exit" << endl;
cin >> choice;
switch (choice){
case 1:
display_contacts();
break;
case 2:
add_contacts(name, areaCode, number);
cout << "Contact Added!";
cout << endl;
break;
case 3:
cout << "Name to remove: ";
cin >> name;
remove_contacts(name);
break;
case 4:
cout << "Name to search: ";
cin >> name;
search(name);
break;
case 5: cout << "Good bye." << endl;
done = true;
break;
}
}
}
There are several issues with the code you posted, mostly due to undefined variables being called.
1: For your search method, counter comes out of nowhere and is being used as a numeric limiter for the loop.
2: Also within your search method, the 2D array data is also undefined, unless it is a global variable set from the load_contacts method that isn't being shown, so currently you're searching a 2D array that doesn't exist.
3: Your "Name not found" message is in an else statement within the for loop in your method, therefore being executed every time a loop doesn't find the name. You may want to move that outside of the loop to print and then return an error number, maybe -1 to handle later.
4: Your search method is a return type of int, however in your main you are not assigning the returned value to any variable to be used, so if there is a successful search, nothing will happen.
If I'm incorrect with any of these, please tell me, but I would focus on the obvious errors first to see if they are causing the crashing.

C++ Program glitch?

I need help debugging my code. So I made a program that adds and subtracts numbers but when I implemented a do-while loop to replay the program, the actual program closes and does not perform the do-while loop and does not replay the program. Is their something wrong with my code?
P.S. I am also using codeblocks IDE
#include <iostream>
using namespace std;
int main()
{
// Addition and Subtraction Calculator
int a_number, number1, number2, sum, number3, number4, subsum, again;
// subsum = subtracted sum
// number1 and number2 are variables that hold the users input for addition
// number3 and number4 are variables that hold the users input for subtraction
do
{
cout << "Addition & Subtraction Calculator" << endl;
cout << "-------------------------------------------" << endl;
cout << "1. Addition" << endl;
cout << "2. Subtraction" << endl;
cout << "Please enter a number [1 or 2]" << endl;
cin >> a_number;
while (a_number < 1 || a_number > 2)
{
cout << "Please enter either 1 or 2" << endl;
cin >> a_number;
}
switch (a_number)
{
case 1:
cout << "Please enter a number" << endl;
cin >> number1;
cout << "Please enter another number" << endl;
cin >> number2;
sum = (number1 + number2);
cout << "The sum is " << sum << endl;
break;
case 2:
cout << "Please enter a number" << endl;
cin >> number3;
cout << "Please enter another number" << endl;
cin >> number4;
subsum = (number3 - number4);
cout << "The answer to the subtraction problem is: " << subsum << endl;
break;
}
cout << "Do you want to try again? [y/n]" << endl;
cin >> again;
}
while (again == 'y' || again == 'n');
return 0;
}
OK. So the OP is using an int where they should have used a char. That covers the immediate problem. int again should be char again.
But there is an important point the other answers have missed.
int again;
cin >> again;
The user input will be converted into an integer as required by again. Inputting y or n fails to convert to an integer as neither y nor n are numbers and cannot be converted. again remains unchanged, keeping whatever junk value happened to be sitting at that spot in memory and might actually be a y or an n, but more importantly cin is now in an error state that needs to be cleared before continuing.
cin would have notified the OP of this if it had been tested. So let's test it.
int again;
if (cin >> again)
{
// got good input. Do something with it.
}
else
{
// got bad input.
cin.clear();
// that bad input is still in the buffer and needs to be removed
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// the above line will wipe out everything to the end of the stream or
// end of line, whichever comes first.
}
Why this is important: Because the OP is doing a lot of numeric input with cin and none of it is checked for validity. For example:
cout << "Please enter a number [1 or 2]" << endl;
cin >> a_number;
The program is broken completely and cannot exit without a kill signal if the user types in anything but a number.
Always check the error state and return codes. They are there to help. Always validate user input before using it. Users are evil and will try to break your program. Don't let them.
use char again; instead of int again;
in your code again is int and when in (again == 'y' || again == 'n')you compare again (an int) with a char, that does not make sense
You need to change the again variable to a char datatype because you need to store text. Something like this:
char again;
You also need to change the while statement to:
while(again != "n");
Or
while(again == "y");

Case inside switch looping non-stop, even though i had break

I just started learning c++, i am making this menu driven program using the switch case.
The problem is, when i enter one of the option it loops infinitely although i already used break.
while (choice != 3)
{
switch(choice)
{
case 1:
{
int TIME;
cout << "Input time: " << endl;
cin >> TIME;
string ACTIVITY;
cout << "Input activity: " << endl;
cin >> ACTIVITY;
todo.addNode(TIME, ACTIVITY);
break;
}
case 2:
{
int DELETE;
cout << "Which activity that you want to delete: " << endl;
cin >> DELETE;
todo.removeIndex(DELETE);
break;
}
default:
{
cout << "Invalid input";
break;
}
}
}
For example, if i pressed 1, the program asks for the time and activity endlessly without breaking. When i pressed any numbers other than 1,2, or 3, it prints the invalid input endlessly.
Am i missing something?
currently your code breaks out of the switch statement, but cannot come out of the while loop as condition is not taken as input inside it.
To come out of the while loop, you need a flag to break outer while loop:
int flag=0;
while (choice != 3)
{
switch(choice)
{
case 1:
{
int TIME;
cout << "Input time: " << endl;
cin >> TIME;
string ACTIVITY;
cout << "Input activity: " << endl;
cin >> ACTIVITY;
todo.addNode(TIME, ACTIVITY);
break;
}
case 2:
{
int DELETE;
cout << "Which activity that you want to delete: " << endl;
cin >> DELETE;
todo.removeIndex(DELETE);
break;
}
default:
{
cout << "Invalid input";
flag=1;
break;
}
}
if(flag == 1)
{
break;
}
}
this is one implementation. your flag=1; statement might be else-where.
Note1: Dont use return in place of break, if there is something else to be processed in the function after this while loop. Otherwise, you can return from the if(flag == 1) condition.
Note2: Another option is to get choice input from the user in the default case. like so cin >> choice; the problem is your while loop does not take choice after it enters the loop because of this choice does not change and hence loops endlessly.

How to insert only numbers and letter should display a message or something

If I enter a letter like "x" I get a message loop "Incorrect option" and it never stops.
int option=0;
while(option != 2)
{
cout << "Select option: ";
cin >> option;
switch (option){
case 1:
cout << "\n Selected option: " << option << endl<<endl;
system("pause");
system("cls");
break;
case 2:
cout << "\n BYE BYE: " << option << endl << endl;
system("pause");
option = 2;
break;
default:
cout << "\n > Incorrect option" << endl<<endl;
option=0;
system("pause");
system("cls");
}
}
I want when I insert a letter when I ask an int number show a message and do something.
You get that infinitely because x is not a valid int, so the cin >> option fails. You need to clear the input buffer and reset the fail bit if the input fails:
while (!(cin >> option))
{
cout << "Enter a valid option!" << endl;
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
...
This will allow you to select a new option.
Change 'int option' to be be 'char option'.
Change 'case 1:' to be 'case '1':'
'1' will return the ASCII value for the character '1' which isn't 1, it's 49. (Do the same for three and two)