Loop control inside void function keeps looping - c++

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.

Related

how to eliminate use of goto in switch case

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);
}

Switch statement behavior in C++

I'm having trouble understanding my C++ switch statement.
I have to enter the accepted integer interval twice for the function to return to the switch. And then it falls straight through to case 2.
Inherited Class:
class Fugl : public DyrLuft
{
private:
int alder;
public:
Fugl() : DyrLuft()
{ }
void les()
{
do
{
cout << "\nSkriv inn fuglens alder: ";
cin >> alder;
if(alder < 0 || alder > 130)
cout << "\nDenne alderen virket usannsynlig, prøv igjen!\n";
} while(alder < 0 || alder > 130);
}
};
Main:
int main()
{
char valg = '\q';
cout << "Hvilken dyreart ønsker du å registrere? (Q for å avslutte)"
<< "\n1) - Fugl \n2) - Fisk \n3) - Insekt \n4) - Skalldyr\n";
do
{
cin >> valg;
switch(valg)
{
case '1':
{
Fugl fugl; fugl.les();
} break;
case '2':
{
Fisk fisk; fisk.les();
} break;
case '3':
{
Insekt insekt; insekt.les();
} break;
case '4':
{
Skalldyr skalldyr; skalldyr.les();
} break;
case 'Q': return 0;
case 'q': return 0;
default: cout << "Velg en av ovennevnte!\n";
}
} while(valg != 'Q' || valg != 'q');
return 0;
}
I dont know what is happening in your case, but I ran your code and it works just fine for me. Entered 1,4,Q and program exited as expected....Could be a compiler or a DyrLuft class issue(i just removed the inheritance to make it work, also lines from case 2,3,4).
You have:
case '1':
{
Fugl fugl; fugl.les();
} break;
When you run this you create a Fug1 object and then you call the les() function. When you enter an appropriate age in les() the function returns. Since the break; is outside of the case block it is actually breaking the switch statement and going to the end of the loop. Then it cycles back to the top of the loop and makes you enter a selection again. If you move break inside og the case block it functions as it should. This is the changed loop:
do
{
cout << "Hvilken dyreart ønsker du å registrere? (Q for å avslutte)"
<< "\n1) - Fugl \n2) - Fisk \n3) - Insekt \n4) - Skalldyr\n";
cin >> valg;
switch (valg)
{
case '1':
{
Fugl fugl; fugl.les();
break;
}
case '2':
{
Fisk fisk; fisk.les();
break;
}
case '3':
{
Insekt insekt; insekt.les();
break;
}
case '4':
{
Skalldyr skalldyr; skalldyr.les();
break;
}
case 'Q': return 0;
case 'q': return 0;
default: cout << "Velg en av ovennevnte!\n";
}
} while (valg != 'Q' || valg != 'q');

Switch Case and For Loop C++

Hello I have this code and I cant seem to get it to work. The loop loops for three times and then the addCourse is suppose to add all three selections. The problem is the addCourse function only adds the last bit for all three selections. Example :
If I select 1 2 3 then it is suppose to give out:
Maths
Quantum
Reality
Instead it gives out:
Reality
Reality
Reality
(All three is the case 3 which is selected last)
How do I sort this problem. Thank you. Below is the code.
for(int p = 0; p < 3; p++)
{
cout << "Please select a course:" <<endl;
cout<<"1. Maths\n";
cout<<"2. Quantum\n";
cout<<"3. Reality\n";
cin >> coursepick;
switch (coursepick)
{
case 1: course= "Maths";
case 2: course= "Quantum";
case 3: course= "Reality";
default: break;
}
cout << "Please insert the course mark:" <<endl;
cin >> mark;
cin.ignore();
phys[0]->addCourse(course,mark);
}
switch (coursepick)
{
case 1: course= "Maths"; break;
case 2: course= "Quantum"; break;
case 3: course= "Reality"; break;
default: break;
}
if you don't break at the end of each case, it just continue with the next, and the next, and then until case 3 and break on default.
In C++, case statements automatically move on to the next. You must insert break after each case.
switch (coursepick)
{
case 1: course= "Maths"; break;
case 2: course= "Quantum"; break;
case 3: course= "Reality"; break;
default: break;
}
In your switch statement you need a break statement in each case. Without a break statement C will fall to the next case. You case statement is equivalent to:
course= "Maths";
course= "Quantum";
course= "Reality";
Instead it needs to be:
switch (coursepick)
{
case 1: course= "Maths"; break;
case 2: course= "Quantum"; break;
case 3: course= "Reality"; break;
default: break;
}
As mentioned in the other posts, you need to end each case with the keyword "break;" if you don't want it to trickle down into the next case.
switch (coursepick)
{
case 1: course= "Maths"; break;
case 2: course= "Quantum"; break;
case 3: course= "Reality"; break;
default: break;
}
Switch statements have this behavior because sometimes you want it to filter through multiple cases. This saves you from having to duplicate code when multiple cases have the same result. The following example shows the equivalent of if case 'a' OR case 'A', do this. If case 'b' OR 'B', do this.
switch (input)
{
case 'a':
case 'A': text = "Letter A"; break;
case 'b':
case 'B': text = "Letter B"; break;
default: text = "Not A or B"; break;
}
Dude Can you add Break tag for all the case statements. It Should be like this
switch (coursepick)
{
case 1: course= "Maths";
break;
case 2: course= "Quantum";
break;
case 3: course= "Reality";
break;
default: break;
}
If you don't mention it will be through all the cases and finally in case three course will be over written by Reality.
So break is necessary for case statements
As it was already said you have to use break for any case label.
switch (coursepick)
{
case 1: course= "Maths"; break;
case 2: course= "Quantum"; break;
case 3: course= "Reality"; break;
default: break;
}
But in any case the code is invalid bacause if the user will enter a number outside the acceptable range variable course will not be assigned. However you will use this unassigned variable in statement
phys[0]->addCourse(course,mark);
Also it is not clear why the variable is defined outside the loop.
I would write the loop the following way
enum { Maths = 1, Quantum, Reality };
for ( int p = 0; p < 3; p++ )
{
do
{
cout << "\nPlease select a course:" <<endl;
cout<<"1. Maths\n";
cout<<"2. Quantum\n";
cout<<"3. Reality\n";
cin >> coursepick;
if ( !( Maths <= coursepick && coursepick <= Reality ) )
{
cout << "Error. Invalid input. Please repeat" << std::endl;
}
} while ( !( Maths <= coursepick && coursepick <= Reality ) );
switch (coursepick)
{
case Maths: course= "Maths"; break;
case Quantum: course= "Quantum"; break;
case Reality: course= "Reality"; break;
default: abort();
}
cout << "Please insert the course mark:" << endl;
cin >> mark;
cin.ignore();
phys[0]->addCourse( course, mark );
}

what is EOF key in C++

I am using Windows 7 Ultimate. I am new to C++. Following is my exercise for switch statement.
void GradeBook::inputGrades()
{
int grade;
cout << "Enter Grade: " << endl;
while((grade=cin.get()) != EOF)
{
switch(grade)
{
case 'A':
case 'a':
aCount++;
break;
case 'B':
case 'b':
bCount++;
break;
case 'C':
case'c':
cCount++;
break;
case 'd':
case 'D':
dCount++;
break;
case 'F':
case 'f':
fCount++;
break;
case '\n':
case ' ':
case '\t':
break;
default:
cout << "Incorrect data. Re Enter" << endl;
break;
}
}
}
I run this inside netbeans, and I pressed all the combinations ctrl+c , ctrl+z, ctrl+d but it is not ending!! Why is that? Have I done something wrong? Please help!!
An EOF character is Ctrl+Z followed by a newline character on Windows platforms.
Presumably that will be the same for the console within Netbeans.
cin.get() is pretty low level. The code should use a higher-level interface. It's supposed to read a character at a time, so write it that way:
char grade;
while (cin >> grade)
The stream extractor will fail at end of file, and that will make the while loop terminate.

how to properly create an encryption in c++?

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.