void getDay() {
bool repeat;
do
{
cout << "Enter the day code (first 2 letters): ";
cin >> weekDay1;
cin >> weekDay2;
weekDay1 = toupper(weekDay1);
weekDay2 = toupper(weekDay2);
switch (weekDay1)
{
case 'M':
break;
case 'T':
break;
case 'W':
break;
case 'F':
break;
case 'S':
break;
default:
cout << "Invalid input. Please try again.\n";
repeat = true;
break;
}
switch (weekDay2)
{
case 'O':
break;
case 'U':
break;
case 'E':
break;
case 'H':
break;
case 'R':
break;
case 'A':
break;
default:
cout << "Invalid input. Please try again.\n";
repeat = true;
break;
}
}while (repeat == true);
return;
}
I need this function to run once, and loop if the input is not one of the accepted characters. I'm trying to prevent any bad input, but it loops infinitely if the input entered on the initial run is not accepted. It works fine if the input is good on the first run, but I keep getting run-time errors for not initializing bools and I need some help adjusting this control.
The condition in the while loop is always true because you never set it to false in its body. You can do something like this:
void getDay() {
// Initializing while declaring is a good practice.
bool repeat = false;
do {
.
.
repeat = false;
.
switch(...) {
...
}
} while (repeat);
}
Now, repeat = true is only called if one of the switch statements invokes default.
Basically I want to accept a particular character from a user and then using a switch case it passes the string related with that character case to another function .for eg.
case i:strcpy(str,"ice-cream");
other_function(str);
break;
If any default character got printed by the user then it should print default statement and again take character from user and check its case. I did this with goto, but is there any other option available to avoid or replace goto in this code.
p:
{
cout<<"Choose account type:-\n"<<"Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"<<endl;
char c;
cin>>c;
switch(c)
{
char t[20];
case 's':
strcpy(t,"saving");
a[i].setype(t);
break;
case 'c':
strcpy(t,"current");
a[i].setype(t);
break;
case 'f':
strcpy(t,"fixed");
a[i].setype(t);
break;
case 'r':
strcpy(t,"reccurring");
a[i].setype(t);
break;
default:
cout<<"Enter valid account type"<<endl;
goto p;
}
}
The whole switch should be hived off into a function, and its return value used to determine what happens to the loop next.
while (true) {
std::cout << "Choose account type:\n" << std::flush;
char c;
if (cin >> c)
{
const bool result = HandleUserInput(a[i], c);
if (result)
break;
else
std::cout << "Enter valid account type\n";
}
else
{
// Input error - you'll want to do something about that
}
}
And:
// Given a character representing an account type, sets
// the type of 'account' as appropriate. Returns false
// on failure.
bool HandleUserInput(Account& account, const char c)
{
switch (c)
{
case 's':
a[i].setype("saving");
return true;
case 'c':
a[i].setype("current");
return true;
case 'f':
a[i].setype("fixed");
return true;
case 'r':
a[i].setype("recurring");
return true;
default:
return false;
}
}
(Notice how I got rid of the strcpy, which doesn't appear to be necessary? Depends what setype [which is misspelled] does I suppose. Also, for a bonus point, consider using a map instead of the switch, if you don't care about a bit of a performance hit.)
Bathsheba's suggestion is a valid alternative, though I suggest that a return will look much clearer inside a switch than will a continue, since the latter has meaning within other kinds of control flow statements, whereas the former never does.
Also note that, if you decide not to use a function for some good reason, there's actually nothing particularly wrong with your goto, and don't let the cargo cultists tell you otherwise!
Yes there is. Since continue doesn't have a direct meaning in a switch block (cf. break), the presence of the former will apply to an appropriate outer loop control structure.
So something on the lines of
do {
// your code here, starting with "Choose account type".
...
default:
std::cout << "Enter valid account type" << std::endl;
continue; // back to the start of the do loop
} // close the switch
break; // fall out of the loop
} while (true);
will do it, and is fairly idiomatic C++.
Use a boolean flag:
bool isInputSuccessful = false;
while (!isInputSuccessful)
{
cout<<"Choose account type:-\n";
char c;
cin>>c;
isInputSuccessful = true;
switch(c)
{
char t[20];
case 's':strcpy(t,"saving");
a[i].setype(t);
break;
case 'c':strcpy(t,"current");
a[i].setype(t);
break;
case 'f':strcpy(t,"fixed");
a[i].setype(t);
break;
case 'r':strcpy(t,"reccurring");
a[i].setype(t);
break;
default:cout<<"Enter valid account type"<<endl;
isInputSuccessful = false;
}
}
Before inputting from the user, this code sets the success flag to true, and if unsuccessful, returns it to false.
Alternatively, it could just set it to true in each successful case.
I suggest dividing your code into a few functions. That will make it is easier to understand what each function is doing and how it is doing.
bool isValidAccountType(char c)
{
return ( c == 's' || c == 'c' || c == 'f' || c == 'r');
}
char getAccountType()
{
char c;
cout<<"Choose account type:-\n"<<"Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"<<endl;
while ( cin >> c )
{
if ( isValidAccountType(c) )
{
return c;
}
cout<<"Enter valid account type"<<endl;
}
// Wasn't able to get input.
// Exit out of the program.
exit(0);
}
void processAccount(char c)
{
char t[20];
switch(c)
{
case 's':strcpy(t,"saving");
a[i].setype(t);
break;
case 'c':strcpy(t,"current");
a[i].setype(t);
break;
case 'f':strcpy(t,"fixed");
a[i].setype(t);
break;
case 'r':strcpy(t,"reccurring");
a[i].setype(t);
break;
default:cout<<"Invalid account type"<<endl;
return;
}
// Rest of the function.
}
Use the following in main.
char c = getAccountType();
processAccount(c);
If you put this code into a function, you can use a return statement to exit the loop:
const char* enter() {
for (;;) {
std::cout << "Choose account type: ";
char ch;
std::cin >> ch;
switch(ch) {
case 's': return "saving";
case 'c': return "current";
case 'f': return "fixed";
case 'r': return "recurring";
}
std::cout << "Invalid input.\n";
}
}
Now you can call this function and use its result:
char t[20];
strcpy(t, enter());
a[i].set_type(t);
While all the other examples are very interesting, I usually stay away from true in the loop condition wherever it is possible.
In this case it would be correct to move the handling of the cases into a function by itself and use the returning result of the function to continue the actions.
First declare some predefined return results.
enum class Action_Result
{
Ok,
Error,
Invalid_account,
Quit
/*...*/
};
Next make the function return the predefined results. (Notice that instead of break in the case, return is used to break out the function and also return the action result.
Action_Result handle_account_type(char c /*...*/)
{
switch (c)
{
char t[20];
case 's':
strcpy(t, "saving");
a[i].setype(t);
return Action_Result::Ok;
case 'c':
strcpy(t, "current");
a[i].setype(t);
return Action_Result::Ok;
case 'f':
strcpy(t, "fixed");
a[i].setype(t);
return Action_Result::Ok;
case 'r':
strcpy(t, "reccurring");
a[i].setype(t);
return Action_Result::Ok;
default:
return Action_Result::Invalid_account;
}
}
Then in the main loop we can make a decision based on the result of the handling function. Notice how the loop condition is now easy to understand, why the loop will continue to execute, and when it will stop looping. Also all the input and output is in the main function, separate from the actions (adhering better to the Single Responsibility Principle) .
int main()
{
Action_Result account_handled_result = Action_Result::Error;
do
{
cout << "Choose account type:-\n"
<< "Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"
<< endl;
char c;
if (cin >> c)
{
if (c == 'q')
account_handled_result = Action_Result::Quit;
else
account_handled_result = handle_account_type(c);
}
else
{
account_handled_result = Action_Result::Error;
}
if (account_handled_result == Action_Result::Invalid_account)
cout << "Enter valid account type" << endl;
} while (account_handled_result != Action_Result::Quit);
}
scratching my head on this as it was working just fine earlier but when I went to add some other functions suddenly my program freaked out and I can not get it back to what it was.
class has me writing a rock/paper/scissors program to go up against a computer, any help with why the loop keeps terminating itself would be wonderful
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void RPSout(char);
int RPScomp();
int main() {
char choice;
int endit=0;
while (endit == 0)
{
cout << "\n\n\tReady to play Rock/Paper/Scissors against the computer??(please choose R/P/S)(Q to quit)\n";
cin >> choice;
RPSout(choice);
if (choice=='Q'||'q')
{endit=1;}
}
return 0;
}
void RPSout(char choose)
{
int RPS =0;
int comp=0;
switch (choose)
{
case 'R':
case 'r':
{
cout <<"Your choice: Rock";
break;
}
case 'P':
case 'p':
{
cout <<"Your choice: Paper";
break;
}
case 'S':
case 's':
{
cout << "Your choice: Scissors";
break;
}
case 'Q':
case 'q':
{
cout << "Bye Bye Bye";
break;
}
default:
cout<<"You enter nothing!"<<endl;
cout << "The valid choices are R/P/S/Q)";
}
return;
}
int RPScomp()
{
int comp=0;
const int MIN_VALUE =1;
const int MAX_VALUE =3;
unsigned seed = time(0);
srand(seed);
comp =(rand() % (MAX_VALUE - MIN_VALUE +1)) + MIN_VALUE;
return comp;
}
if (choice=='Q'||'q')
This is equivalent to
if ((choice == 'Q') || 'q')
Which is almost certainly not what you want. 'q' is a non-zero char literal, which is "truthy" and so this expression will never be false. It's akin to writing if (choice == 'Q' || true).
The solution is:
if (choice=='Q' || choice=='q')
The statement
if (choice=='Q'||'q')
always tests true and therefore sets your flag to terminate the loop.
Try:
if (choice=='Q'||choice=='q')
I think your if statement should be if (choice=='Q'|| choice=='q')
Your issue if with the if statement
if (choice=='Q'||'q')
{endit=1;}
the || 'q' part will always be true since 'q' in ASCII is not 0
Change your code to
if (choice=='Q'|| choice=='q')
{endit=1;}
I have this function that takes a string from main. The string contains all of the valid characters that a user can input from some menu options. Function will put character input into a variable and be compared to each character of the string. Compare input variable to the string characters until valid input is entered.
My question is, what is the best way to implement this loop? I don't like using while (true) with a return in the middle because it looks like an infinite loop with an exception in the middle, which makes it slightly harder to read, but I'm not sure how else I can do what I want it to do. What's the best practice for achieving my goal? Thanks.
char getValidKey(string validKeys)
{
char letter;
while (true) {
cout << "Operation ? ";
cin >> letter;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
for (int i = 0; i < validKeys.length(); i++) {
if (letter == validKeys[i])
return letter;
}
cout << "Error. Invalid input.\n";
}
}
Also, I have a switch statement with multiple returns. Is it more common/preferred to assign calculations to a variable and have one return at the end or is this way generally okay?
string opStr;
switch (myOperation) {
case 1:
opStr = "RIGHT";
break;
case 2:
opStr = "LEFT";
break;
case 3:
opStr = "CENTER_ONLY";
break;
case 4:
opStr = "CENTER_MISSING";
break;
default:
opStr = "Error. Invalid input.";
break;
}
return opStr;
OR
switch (myOperation) {
case 1:
return "RIGHT";
break;
case 2:
return "LEFT";
break;
case 3:
return "CENTER_ONLY";
break;
case 4:
return "CENTER_MISSING";
break;
default:
return "Error. Invalid input.";
break;
}
For the first case, refactor your code in smaller self-contained functions, and it becomes clear to understand the logic of getValidKey even from a while(true):
char isKeyValid(char x, const string& validKeys)
{
return validKeys.find(x) != string::npos;
}
char readCharFromCin()
{
char letter;
cout << "Operation ? ";
cin >> letter;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return letter;
}
char getValidKey(const string& validKeys)
{
while (true)
{
const char key = readCharFromCin();
if(isKeyValid(key, validKeys)) return letter;
cout << "Error. Invalid input.\n";
}
}
For the second case, avoid break and simply return from your switch. Make the function containing the switch only do one thing.
string switchOperation(int myOperation)
{
switch (myOperation)
{
case 1: return "RIGHT";
case 2: return "LEFT";
case 3: return "CENTER_ONLY";
case 4: return "CENTER_MISSING";
}
return "Error. Invalid input.";
}
Also, try to maximize usage of const and pass string instances you're only reading by const& to avoid unnecessary copies.
I have finished my program about encryption. The problem is, I need a shortcut. The program I have coded is too long and not very suitable. I'm just new to c++ programming. Can someone help me out? thanks! :) Here's my program:
#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int main()
{
c:char crypt[25], cons;
int ctr;
cout<<"Input your 26-character cipherstring below.\n\n";
cout<<"ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";cin>>crypt;
e:char string[65535];
cout<<"\nInput your string (input your spaces as any non-alphabet character).\n";cin>>string;
cout<<"\n\nEncrypted string: "; //std::string
for(ctr=0;ctr<=strlen(string);ctr++)
{
switch(string[ctr])
{
case('a'): cout<<crypt[0]; break;
case('b'): cout<<crypt[1]; break;
case('c'): cout<<crypt[2]; break;
case('d'): cout<<crypt[3]; break;
case('e'): cout<<crypt[4]; break;
case('f'): cout<<crypt[5]; break;
case('g'): cout<<crypt[6]; break;
case('h'): cout<<crypt[7]; break;
case('i'): cout<<crypt[8]; break;
case('j'): cout<<crypt[9]; break;
case('k'): cout<<crypt[10]; break;
case('l'): cout<<crypt[11]; break;
case('m'): cout<<crypt[12]; break;
case('n'): cout<<crypt[13]; break;
case('o'): cout<<crypt[14]; break;
case('p'): cout<<crypt[15]; break;
case('q'): cout<<crypt[16]; break;
case('r'): cout<<crypt[17]; break;
case('s'): cout<<crypt[18]; break;
case('t'): cout<<crypt[19]; break;
case('u'): cout<<crypt[20]; break;
case('v'): cout<<crypt[21]; break;
case('w'): cout<<crypt[22]; break;
case('x'): cout<<crypt[23]; break;
case('y'): cout<<crypt[24]; break;
case('z'): cout<<crypt[25]; break;
case('A'): cout<<crypt[0]; break;
case('B'): cout<<crypt[1]; break;
case('C'): cout<<crypt[2]; break;
case('D'): cout<<crypt[3]; break;
case('E'): cout<<crypt[4]; break;
case('F'): cout<<crypt[5]; break;
case('G'): cout<<crypt[6]; break;
case('H'): cout<<crypt[7]; break;
case('I'): cout<<crypt[8]; break;
case('J'): cout<<crypt[9]; break;
case('K'): cout<<crypt[10]; break;
case('L'): cout<<crypt[11]; break;
case('M'): cout<<crypt[12]; break;
case('N'): cout<<crypt[13]; break;
case('O'): cout<<crypt[14]; break;
case('P'): cout<<crypt[15]; break;
case('Q'): cout<<crypt[16]; break;
case('R'): cout<<crypt[17]; break;
case('S'): cout<<crypt[18]; break;
case('T'): cout<<crypt[19]; break;
case('U'): cout<<crypt[20]; break;
case('V'): cout<<crypt[21]; break;
case('W'): cout<<crypt[22]; break;
case('X'): cout<<crypt[23]; break;
case('Y'): cout<<crypt[24]; break;
case('Z'): cout<<crypt[25]; break;
default: cout<<" "; break;
}
}
cout<<"\n\n";
/*cout<<"Input 'c' to re-input your cipherstring.\n 'e' to reuse your cipherstring.\n 'q' to quit. ";
comm:cout<<"\nCommand: "; cin>>cons;
switch (cons)
{
case('c'): cout<<endl; goto c; break;
case('C'): goto c; break;
case('e'): goto e; break;
case('E'): goto e; break;
case('q'): break;
case('Q'): break;
default: cout<<"Invalid command. Please refer to the command list above.\n";goto comm;
}*/
system("PAUSE"); return 0;
}
You can replace that huge switch statement with this:
if (isalpha(string[ctr]))
{
int index = toupper(string[ctr]) - 'A';
cout << crypt[index];
}
else
cout << " ";
Also, do not call strlen for every iteration of the for loop, just do it once:
for(int ctr=0, len=strlen(string); ctr<len; ctr++)
{
....
}
A few other things of note:
crypt is too small, it should have size 27
If you use getline instead of operator>>, you can have the user enter spaces properly
Your code is prone to buffer overflows. Use std::string and you can pretty much forget about those.
Note, that as Kerrek says, this assumes that in the character set you are using, the uppercase letters A-Z are in sequence. But I think that the cases where this is not true are so exceedingly rare, that you can safely ignore them.