Odd looping situation, don't know what's causing it - c++

Having some trouble with some code and I cannot get to the bottom of it. This code:
int main()
{
int choice;
while (choice != -1)
{
system("cls");
std::cout << "Main Menu: " << std::endl
<< " 1. Encode." << std::endl
<< " 2. Decode." << std::endl
<< "-1 to exit." << std::endl;
std::cin >> choice;
switch (choice)
{
case 1:
encode();
break;
case 2:
decode();
break;
case -1:
break;
}
}
getchar();
return 0;
}
void encode()
{
std::string plainText;
std::string encText = "Test";
std::cout << "Enter text to be encrypted.\n";
getline(std::cin, plainText);
for (int x = 0; x < plainText.length(); x++)
{
//encText += plainText.substr(x, x + 1);
}
std::cout << encText;
getchar();
return;
}
If I enter '1' at the first cin >> choice, I go into encode(), once there, entering any text causes the program to go back to the while, perform system("cls"), and then jumps right back to "Enter text to be encrypted." down in encode().
Any help? I'm clueless.

If you'd like to exit your while loop after encode() or decode(), you have to satisty the while's condition. You can do this by simple setting choice to -1 after the function calls:
case 1:
encode();
choice = -1;
break;
case 2:
decode();
choice = -1;
break;
Just so you're aware, the return at the end of encode() causes the encode() function to finish, not main. That line of code actually does nothing; since there's nothing after it, it would happen anyway.

Related

How to check if input is valid and keep asking for input if it's not

Can anybody please explain why this while loop is not working properly?
#include <iostream>
using namespace std;
void ask_user(int a, int b){
char choice = ' ';
while(choice != 'q' && choice != 'a' && choice != 's' && choice != 'm'){
cout << "choose operation" << endl;
cout << "a to add, s to subtract, m to multiply and q to quit" << endl;
cout << "----------------------------" << endl;
cin >> choice;
switch(choice){
case 'a' : cout << "a + b = " << a + b;
break;
case 's' : cout << "a - b = " << a + b;
break;
case 'm' : cout << "a * b = " << a + b;
break;
case 'q' : break;
default: cout << "please Enter a valid choice " << endl;
}
}
}
int main(){
ask_user(7, 9);
return 0;
}
If I enter p for exemple which is not valid then it works fine and asks for valid input again,
but if I enter pp that's when it starts bugging and prints the message twice. If I enter ppp it
prints three times etc...
First thing, you have a misunderstanding of how switch works. Each case must end with break statement so that the following one won't get executed.
Which means that a break will break the switch, not the while.
But the main issue is that the logic of your program is wrong.
You should not loop over the validity of the given input, let the switch statement handle that in the default clause.
Instead you should loop over a flag that will be set when the user press the q key.
So considering you have the following functions defined to respectively display the menu and ask for the operands to operate on (defined for code readability):
void display_menu(char & choice)
{
std::cout << "Operation:\na: Addition\nm: Multiplication\ns: Substraction\nq: Quit\n";
std::cin >> choice;
}
void ask_operands(int & a, int & b)
{
std::cout << "\na ?";
std::cin >> a;
std::cout << "\nb ?";
std::cin >> b;
std::cout << '\n';
}
The logic of your code can be then rewritten as:
int main()
{
bool quit = false;
char choice;
int a, b;
ask_operands(a, b); // Ask the user which operands to use
while(!quit) // loop over the flag
{
display_menu(choice);
switch(choice)
{
case 'a': std::cout << (a+b);
break;
case 'm': std::cout << (a*b);
break;
case 's': std::cout << (a-b);
break;
case 'q': std::cout << "Exiting...";
quit = true; // Set the flag to false
break;
default: std::cout << "Invalid choice, try again."; //Here you handle the invalid choices (i.e. let the loop iterate again)
}
std::cout << '\n';
}
return 0;
}
Live example
Note: If you want the user to be able to change the value of the operands at each iteration, just move the ask_operands(a, b); call inside the loop.

Can't get it back to loop. C++

I'm trying to get it back to loop if they enter anything from the choices. everytime I enter 4, it just ends. and if I pick the right one it also ends. Is there anyway I can get it to ask user to input the right one?
void towsoncourse ()
{
cout << "Enter Course: 1 is COSC,2 is ENGL,3 is MATH" << endl;
int course;
bool finish;
bool finishcourse = true;
cin >> course;
while (finishcourse != true)
{
cout << "Enter correct number for course" << endl;
if (course == 1 || course == 2 | course == 3)
{
finish = true;
}
else
{
cout<< "Error: Enter number corresponding to course." << endl;
}
}
switch (course)
{
case 1:
cout << "COSC" << endl;
break;
case 2:
cout << "ENGL" << endl;
break;
case 3:
cout << "MATH" << endl;
break;
default:
cout << "Error: Enter number corresponding to course" << endl;
}
}
int main ()
{
towsoncourse ();
return 0;
}
Not a complete answer, but rather a guide to point the way.
You want to keep reading an input until it is one of 3 possible values. So a good place to read and test the input would be inside a loop, exiting only when the test conditions are met.
while loops test continue criteria before each execution. do loops test continue criteria after each execution. In you case it is necessary to execute at least once.
There were some issues with the code.
1) while (finishcourse != true) condition was wrong. It should be while (finishcourse == true).
2) finish = true; assignment was wrong. It should have been finishcourse = false;
3) cin >> course; should be taken inside the loop. Because if you place it outside, it will lead to infinite loop in case of incorrect entry.
So, Just to ensure readability, I have rewritten the code. I have assumed that it gets back to the loop in case of incorrect entry and in case of correct entry, it terminates.
#include <iostream>
using namespace std;
void towsoncourse ()
{
bool finishcourse = true;
while (finishcourse == true)
{
int course;
cout << "Enter Course: 1 is COSC,2 is ENGL,3 is MATH" << endl;
cin >> course;
switch (course)
{
case 1:
cout << "COSC" << endl;
finishcourse = false;
break;
case 2:
cout << "ENGL" << endl;
finishcourse = false;
break;
case 3:
cout << "MATH" << endl;
finishcourse = false;
break;
default:
cout << "Error: Enter number corresponding to course." << endl;
}
}
}
int main ()
{
towsoncourse ();
return 0;
}

Alternative to goto in nested loops?

This code is working fine, however this whole time I've tried avoiding using the goto statements that you will see in the switch (dice_total) statement.
Without the goto statements, the program will not loop back to the beginning of while (again=='y' || again=='Y'), and instead it keeps looping itself when it reaches the do-while loop.
However, I believe that it is also important to say, that if dice_total is = to the point_total the first time around then the program will function properly, and loop back to the beginning. For example, when the program starts, the first round will generate the point_total, which we will say its 10. Which is a value that will allow the program to continue to the next round, and if the dice_total also gets the same number, 10, the program will say you win, and the loop will work properly. However, if the program reaches the do while loop, and generates a number that isn't 10, but generates a 10 after a few loops, then the program will not loop to the beginning. So what I want to ask, what is wrong with my switch(dice_total) statement, and how can I fix it, to give the program the same effect without using the goto statements?
#include "stdafx.h"
#include <iostream>
#include <random>
#include <string>
using namespace std;
int main()
{
//Declared Variables***********************************
char again = 'y';
int point1;
int point2;
int point_total;
int round_1=1;
int dice1;
int dice2;
int dice_total;
//*****************************************************
//RANDOM SEED******************************************
random_device rd;
mt19937 mt(rd());
uniform_int_distribution<int>dist(1, 6);
//*****************************************************
start://TEMPORARY
while (again == 'y'||again=='Y')
{
int round_1 = 1;
system("CLS");
cout << "WELCOME TO THE CRAPS GAME" << endl;
cout << "THROWING ROUND:" << round_1 << " DICES.............." << endl;
point1 = dist(mt);
point2 = dist(mt);
point_total = point1 + point2;
cout << "ROUND: " << round_1 << " First dice is: " << point1 << " and second dice is: " << point2 <<" and the total is:"<<point_total<< endl;
switch (point_total)
{
case 7:
case 11:
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!" << endl;
cin >> again;
break;
case 2:
case 3:
case 12:
cout << "YOU LOST, PRESS Y TO TRY AGAIN" << endl;
cin >> again;
break;
default:
do
{
++round_1;
cout << "ROUND " << round_1 << endl;
dice1 = dist(mt);
dice2 = dist(mt);
dice_total = dice1 + dice2;
cout << "THROWING ROUND: " << round_1 << " DICES.............." << endl;
cout << "ROUND 1 DICE TOTAL IS: " << point_total << endl;
cout << "ROUND: " << round_1 << " First dice is: " << dice1 << " and second dice is: " << dice2 << " and the total is:" << dice_total << endl;
switch (dice_total)
{
case 11:
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!" << endl;
cin >> again;
goto start;
case 2:
case 3:
case 7:
case 12:
cout << "YOU LOST, PRESS Y TO TRY AGAIN" << endl;
cin >> again;
goto start;
default:
if (dice_total == point_total)
{
cout << "YOU WON CONGRATS PRESS Y TO PLAY AGAIN!!<<endl;
cin >> again;
break;
}//if
else
{
cout << "Going to next round" << endl;
}
}//dice_total
}//do
while (dice_total != point_total);
break;
}//switch point
}//again while
}//main
The problem you're facing is usual when you have too many nested loops in the same function, and is an indicator that you need to refactor parts of your code to be in their own functions.
If you do this, then you have more possibilities to control the flow of your code: in each function you have break and return, and as you can return a custom value, you can use it to determine in the surrounding function if you need to break or return again.
Besides, this gives you the opportunity to put self-explanatory names to your functions, which makes your code clearer for people that look at it for the first time (as it's written, it's so dense that I can't understand it unless I stare at it for some minutes).
An example of what I mean in code:
Before
int main() {
start:
while (a) {
b1();
switch(c) {
case 1:
do {
d();
if (cond) goto start;
} while(e);
break;
}
b2();
}
}
After
int main() {
while (a) {
if (!doStuff1())
break;
}
...
}
bool doStuff1() {
b1();
while (a) {
bool res = doStuff2();
if (res) return true;
}
b2();
...
}
bool doStuff2() {
switch(c) {
case 1:
if (doStuff3()) return true;
}
return false;
}
bool doStuff3() {
do {
d();
if (cond) return true;
} while (e);
return false;
}
How about this design?
bool stop=false;
while(!stop && (again == 'y'||again=='Y'))
{
while(again == 'y'||again=='Y')
{
// ...
break; /* breaks inner while*/
// ...
stop=true;
break; /* breaks inner while, and prevents running outer loop*/
}
}

Functions to check if the user's input is correct not working

I have created some C++ code that is supposed to check to see if a user's input is correct but it isn't quite working how I want it to. Whenever you type an integer first, and then a couple of characters after it, the terminal spams would you like to try again y/n a couple of times. I have tried to limit the amount of times it can output this, but nothing has worked.
#include <iostream>
#include <limits>
using namespace std;
int again()
{
char yorn = 'q';
cout << "\n Would you like to run this program again? y/n: ";
cin >> yorn;
if (cin.fail()) {
int dof1 = 1; // dof1 stands for don't overflow 1
for (int i = 0; i < dof1; i++) {
cout << "ERROR -- You did not enter a valid symbol";
// get rid of failure state
cin.clear();
// discard 'bad' character(s)
cin.ignore(numeric_limits<streamsize>::max(), '\n');
bool check = again();
if (check == true) {
check = false;
return again();
}
else
return 0;
}
}
switch (yorn) {
case 'y':
return true;
break;
case 'n':
return false;
break;
default:
return again();
break;
}
}
int main()
{
int choice = 0;
cout << "\nWelcome to the Weight Tracker! Type 000 at any time to exit\n"
<< "Choose the option you would like to use below \n"
<< "1) \n"
<< "2) \n"
<< "3) \n"
<< "Option selected: ";
cin >> choice;
if (cin.fail()) {
int dof2 = 1; // dof2 stands for don't overflow 2
for (int i = 0; i < dof2; i++) {
cout << "ERROR -- You did not enter an integer";
// get rid of failure state
cin.clear();
// discard 'bad' character(s)
cin.ignore(numeric_limits<streamsize>::max(), '\n');
bool check = again();
if (check == true) {
check = false;
return main();
}
else
return 0;
}
}
switch (choice) {
case 1:
cout << " use later";
break;
case 2:
cout << " use later";
break;
case 3:
cout << " use later";
break;
default:
cout << "ERROR -- Input invalid \n";
bool check = again();
if (check == true) {
check = false;
return main();
}
else
return 0;
break;
}
return 0;
}
You are missing one cin.ingnore
default:
cout << "ERROR -- Input invalid \n";
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // ADD this line
bool check = again();
To be honest. This code is mess. Please remove recursion from it.

C++: Will Not Accept New C-String Input

First off, thanks in advance for your help. This issue is driving me nuts.
I have a program that accepts a c-string, and then can count the number of vowels and consonants. This works without issue. However, I also need to include a function that allows the user to create a new string. The problem is, though, when the user selects "new string" from the menu, it just loops through the newString() method, without waiting for the user's input. It then creates a new, blank screen.
Here is the entire program. The newString() method is at the end.
#include <iostream>
using namespace std;
// function prototype
void printmenu(void);
int vowelCount(char *);
int consCount(char *);
int cons_and_vowelCount(char *);
void newString(char *, const int);
int main() {
const int LENGTH = 101;
char input_string[LENGTH]; //user defined string
char choice; //user menu choice
bool not_done = true; //loop control flag
// create the input_string object
cout << "Enter a string of no more than " << LENGTH-1 << " characters:\n";
cin.getline(input_string, LENGTH);
do {
printmenu();
cin >> choice;
switch(choice)
{
case 'a':
case 'A':
vowelCount(input_string);
break;
case 'b':
case 'B':
consCount(input_string);
break;
case 'c':
case 'C':
cons_and_vowelCount(input_string);
break;
case 'd':
case 'D':
newString(input_string, LENGTH);
break;
case 'e':
case 'E':
exit(0);
default:
cout << endl << "Error: '" << choice << "' is an invalid selection" << endl;
break;
} //close switch
} //close do
while (not_done);
return 0;
} // close main
/* Function printmenu()
* Input:
* none
* Process:
* Prints the menu of query choices
* Output:
* Prints the menu of query choices
*/
void printmenu(void)
{
cout << endl << endl;
cout << "A) Count the number of vowels in the string" << endl;
cout << "B) Count the number of consonants in the string" << endl;
cout << "C) Count both the vowels and consonants in the string" << endl;
cout << "D) Enter another string" << endl;
cout << "E) Exit the program" << endl;
cout << endl << "Enter your selection: ";
return;
}
int vowelCount(char *str) {
char vowels[11] = "aeiouAEIOU";
int vowel_count = 0;
for (int i = 0; i < strlen(str); i++) {
for (int j = 0; j < strlen(vowels); j++) {
if (str[i] == vowels[j]) {
vowel_count++;
}
}
}
cout << "String contains " << vowel_count << " vowels" << endl;
return vowel_count;
} // close vowelCount
int consCount(char *str) {
char cons[43] = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
int cons_count = 0;
for (int i = 0; i < strlen(str); i ++) {
for (int j = 0; j < strlen(cons); j++) {
if (str[i] == cons[j]) {
cons_count++;
}
}
}
cout << "String contains " << cons_count << " consonants" << endl;
return cons_count;
} // close consCount
int cons_and_vowelCount(char *str) {
int cons = consCount(str);
int vowels = vowelCount(str);
int total = cons + vowels;
cout << "The string contains a total of " << total << " vowels and "
"consonants" << endl;
return total;
}
void newString(char *str, int len) {
cout << "Enter a string of no more than " << len-1 << " characters:\n";
cin.getline(str, len);
return;
}
The statement cin >> choice only consumes the character they type, not the carriage return that follows. Thus, the subsequent getline() call reads an empty line. One simple solution is to call getline() instead of cin >> choice and then use the first character as the choice.
BTW, the while (not done) should immediately follow the do { … }, and the return 0 is redundant. Also, you should call newString at the start of the program instead of repeating its contents.
cin >> choice leaves a newline in the input stream.. which cause the next getline() to consume it and return. There are many ways.. one way is to use cin.ignore() right after cin >> choice.
The cin >> choice only consumes one character from the stream (as already mentioned). You should add
cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
right after cin>>choice to ignore all the characters that come into the stream after reading the choice.
p.s. #include <limits>