Declaring variables in Switch Statement - c++

I have a function that declares two object from two different classes :
void car (){
int choice;
cout << " What type of car ? ";
cout <<" 1- Fast . 2- Slow.";
cin >> choice;
switch(choice)
{
case 1:
Fast obj1;
obj1.print();
break;
case 2:
Slow obj2;
obj.print();
break;
default:
cout << "No type";
}
}
The compiler shows error at:
switch(choice)
This is the error
(error: transfer of control bypasses initialization of:
variable "obj1" (declared at line 179)
variable "obj2" (declared at line 181)
Can you please tell me what I am doing wrong

As the error message says, the jump to each switch label passes the initialisation of one or more variables declared inside the switch block, which isn't allowed.
You can fix this by scoping each variable inside a block within the switch block:
switch(choice)
{
case 1:
{
Fast obj;
obj.print();
break;
}
case 2:
{
Slow obj;
obj.print();
break;
}
default: cout << "No type";
}

You have to use blocks in each case Statement if you want to declare variables there:
switch(choice)
{
case 1:
{
Fast obj1;
obj1.print();
}
break;
case 2:
{
Slow obj2;
obj.print();
}
break;
default:
cout << "No type";
}

Related

C++ switch statement error (variable not declared in this scope)

I'm currently learning about switches in C++, so I created a grading program that will output a specific message based on the grade entered. Below is the code:
#include <iostream>
using namespace std;
int main()
{
char student_grade;
cout << "Enter student's grade:" << "\n";
cin >> student_grade;
// switch statement for a simple grading system
switch(student_grade)
{
case A:
cout << "You have passed with a distinction!";
break;
case B:
cout << "You have a grade B,congrats.";
break;
case C:
cout << "Average grade,you can do better.";
break;
default:
cout<<"NIL grade";
break;
}
return 0;
}
I get this error once I run it, what did I do wrong?
/root/Desktop/practise.cpp: In function ‘int main()’:
/root/Desktop/practise.cpp:14:6: error: ‘A’ was not declared in this scope
14 | case A:
| ^
/root/Desktop/practise.cpp:17:6: error: ‘B’ was not declared in this scope
17 | case B:
| ^
/root/Desktop/practise.cpp:20:6: error: ‘C’ was not declared in this scope
20 | case C:
| ^
In the switch case, the character cases should be written in ' '. E.g. 'A', 'B'. There is a difference between A and 'A', 'A' is a character literal. It's of char type with value 97 on most of the systems.
The corrected code will be:-
#include<iostream>
using namespace std;
int main()
{
char student_grade;
cout<<"Enter student's grade:"<<"\n";
cin>>student_grade;
// switch statement for a simple grading system
switch(student_grade)
{
case 'A':
cout<<"You have passed with a distinction!";
break;
case 'B':
cout<<"You have a grade B,congrats.";
break;
case 'C':
cout<<"Average grade,you can do better.";
break;
default:
cout<<"NIL grade";
break;
}
return 0;
}
Simpe put it in ' ' because thats necessary for chars than it will compile.
Without that its just a variable.
#include<iostream>
using namespace std;
int main()
{
char student_grade;
cout<<"Enter student's grade:"<<"\n";
cin>>student_grade;
// switch statement for a simple grading system
switch(student_grade)
{
case 'A':
cout<<"You have passed with a distinction!";
break;
case 'B':
cout<<"You have a grade B,congrats.";
break;
case 'C':
cout<<"Average grade,you can do better.";
break;
default:
cout<<"NIL grade";
break;
}
return 0;
}

Using object when out of scope?

I'm working on a school assignment require to create a char LinkedList from user string input based on a menu of options:
Enter new string and store as linked list character of in an LinkedList class.
Get current length from the LinkedList.
Find index of character in this linked list.
Append another LinkedList to this LinkedList.
I have everything working fine, but now I'm stuck at the menu option part.
So let's say I choose option 1 to enter a string, and then I decide to use that object for case 2 and 3 to get the size and find index. That would not work because the object will be destroyed when out of scope. Is there any proper way that I can use to implement this ?
Simple Code Below
switch(option){
case 1:
LinkedList ls1(getInput());
ls1.printList();
break;
}
case 2:
cout << "Size of LinkedList: " <<ls1.getSize() << endl; //wouldn't work because ls1 got destroyed when out of scope.
}
If you want to expand the scope of an object, you declare it at a higher scope. You probably have a while loop asking for input, and then switching on that input? If you want your LinkedList to survive successive iterations of the loop, you'll need to declare it before the loop starts.
LinkedList ls1; // required default constructor
int option = 3;
do
{
std::cout << "Enter 1 to create new list. 2 to print current list. 3 to quit: ";
std::cin >> option;
switch(option)
{
case 1:
ls1 = getInput(); // requires conversion from getInput()'s return type and copy (or preferably move) assignment operators
ls1.printList();
break;
case 2:
std::cout << "Size of LinkedList: " <<ls1.getSize() << std::endl;
break;
}
} while(option != 3);
Try to initiate the object outside the switch statement and after that you could use that object within any switch case.
Example:
ClassName ObjectName(getInput());
switch(option){
case 1: ObjectName.printList();
break;
case 2: cout << "Size of LinkedList: " <<ObjectName.getSize() << endl;
break;
default: break;
}
Declare the object outside the switch statement.
LinkedList ls1(getInput());
switch(option){
case 1:
ls1.printList();
break;
case 2:
cout << "Size of LinkedList: " <<ls1.getSize() << endl;
break;
default:
break;
}

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

A few coding convention/standard practice questions

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.

Case command for checking two values

Look at this code please:
char o,t; cin >> o >> t;
switch (o,t)
{
case 's','g': cout << "Finish"; break;
default: cout << "Nothing";
}
as you can see switch is set for two values, but in case command I can not check for both of them at the same time. What should I do? is there any way?
it's not proper syntax use instead
case 's':
case 'g':
cout << "Finish"; break;
You can't switch on multiple values in C++.
switch (o,t)
uses the comma operator (it looks a lot like a pair would in some other languages, but it isn't).
The comma operator evaluates its left operand (o), ignores the value of that, and then returns the value of its right operand (t).
In other words, your switch only looks at t.
There is no way around this.
Your particular case is better written as
if (o == 's' && t == 'g')
{
cout << "Finish";
}
else
{
cout << "Nothing";
}
You cannot do switch for two expressions at the same time. The switch part only compiles because there is a comma operator (which simply evaluates to the second value, in this case t).
Use plain old if statements.
char o,t; cin >> o >> t;
switch (o,t)
{
case 's':
case 'g': cout << "Finish"; break;
default: cout << "Nothing";
}
In switch when matched case is found, all operator after that are executed. That's why you should write break; operator after case-es to exit switch. So if you want to do the same in several cases you should just put them one after another.
You have some syntax error, the correct code is
char o,t; cin >> o >> t;
switch (o)
{
case 's':case 'g': cout << "Finish"; break;
default: cout << "Nothing";
}
switch (t)
{
case 's':case 'g': cout << "Finish"; break;
default: cout << "Nothing";
}