Is this a good practice to validate menus? - c

i need to show a menu that derive another menu and this derive another menu.
But i'm validating those menus with this form: (Only C standard library)
do{
validOption = 1;
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1: /* Do something */ break;
case 2: /* Do something */ break;
case 3: /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
But at the time of derive a menu i dont know if use the same option variable and validOption flag.
I think that is not a problem since the derived option variable is going to be overwritten and
I will not need the previous option variable since that option variable has been used for its only
purpose that is join in a specific case.
Now, validOption flag is not a problem too, since when a successfully case occurs means that validOption = 1 (will not iterate more)
and it will match with the previous validOption that have a value of 1 (since has been joined in a case). So will not interfere.
Is a good practice to use the same variables (option, validOption) within derived menus?
Also i need to validate with a getint() function, which make me think that if
is even necessary validate menus seeing it in a practical way.
#include<stdio.h>
int main(){
int option;
int validOption;
do{
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1:
validOption = 1;
do{
printf("Option #1\n");
printf("Option #2\n");
printf("Option #3\n");
scanf("%i",&option);
switch(option){
case 1: validOption = 1; /* Another menu with the same option and validOption variables */ break;
case 2: validOption = 1; /* Do something */ break;
case 3: validOption = 1; /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
break;
case 2: validOption = 1; /* Do something */ break;
case 3: validOption = 1; /* Do something */ break;
default: validOption = 0; printf("Invalid Option\n"); break;
}
}while(!validOption);
return 0;
}
//I've put validOption = 1; within all cases just for explaining purposes

I would rather call it nested loop than derived.
Coming to your question: Is it valid to re-use same variable within a loop when the 1st value of the variable is no longer needed? (Am I right in rephrasing your question?)
Yes, it's valid. While there's nothing technically wrong with it, I would say No. Because, it causes unnecessary confusion and makes the code readability difficult especially when you it within the same loop (as you do within your outer loop). It becomes even harder as the code base grows. Hence, I would discourage such a coding practice.
You want to validate your integer: Since, you are only going to do pass-by-value (to getint()), there's no problem in using another variable. You can use option1 and option2
Pass the values to getint() to validate it.

Related

Can this if be added to this switch statement?

Hi so I'm building a hotel management program and I'm trying to make my switch statement short but it's not working. I tried to add a function that had the break inside but I get an error saying break not within a loop or a switch statement:
void goback()
{
char y;
printf("Would you like to go back?(Y/N)");
scanf("%c",&y);
if (y=='Y' || y=='y')
{
break;
}
}
int main(){
do
{
printf (" 1. Add a Room\n 2. Current rooms\n 3. Add a booking\n 4. Current bookings \n 5. Modify a booking\n 6. Print bill\n 7. Exit\n\n");
printf ("Which section would you like to access:");
scanf ("%d",&w);
switch (w){
case 1:
clrscr();
newroom();
goback();
case 2:
clrscr();
roomscan();
goback();
case 3:
clrscr();
addbooking();
goback();
case 4:
clrscr();
currentbooking();
goback();
case 5:
clrscr();
printf("not ready\n");
case 6:
clrscr();
printf("not ready\n");
case 7:
clrscr();
printf("\t\t\t\tLogging out... See you next time!");
exit (1);
break;
default:
printf("try again");
}
}
while (w!=7);
}
of course, you got an error because of the break; statement break you from your goback() function and not from case.
As you know each case block must end with break;.
In your case, you must put the break; statement at the end of each case block and you can make the goback() function returning a boolean to decide if you go back or not, but you must define what to do if the user does not want to go back.
I'm not sure but you might want to add breaks after your statements if they are to be executed separately and not in sequence. here I only see your case 7 contains a break, which means all cases until that one will be executed, if that's what you want it's fine, otherwise maybe try something like this
switch (w){
case 1:
clrscr();
newroom();
goback();
break;
case 2:
clrscr();
roomscan();
goback();
break;
case 3:
...
Here it seems that your goback() function tries to do that break but what it does it's it tries to break from the context where it if called, here an "if" bloc, which can't have a break inside it. That's what the compiler is saying I guess.

C code setjmp declare functions?

I'm absolutely not a coder, but I'm trying to get a very old program to compile from fortran to C, so that I can play a game i've not played in 20+ years (originally created on HP3000 in the late 70s!) on my linux box.
Someone has written a make.sh file, using f2c (fortran to C) so that it can compile using GCC under linux, but that was done many moons ago.
I'm getting the following error message:
stubs.c: In function ‘exexc_’:
stubs.c:76:13: warning: implicit declaration of function ‘mmsa_’; did
you mean ‘memset’? [-Wimplicit-function-declaration]
case 'A': mmsa_(); break;
The relevant piece of code i.e. exexc function in stubs.c is:
#include <setjmp.h>
int setjmp(jmp_buf env);
void exexc_(name, i1, i2, i3, i4, i5, namelen)
char *name;
shortint *i1, *i2, *i3, *i4, *i5;
long namelen;
{
static jmp_buf env;
static int first = 1;
static char segment[6];
ipx[0] = *i1;
ipx[1] = *i2;
ipx[2] = *i3;
ipx[3] = *i4;
ipx[4] = *i5;
strncpy(segment, name, namelen);
if( ! first ) longjmp(env, 1);
if( first )
{
first = 0;
setjmp(env);
switch(segment[3]) {
case 'A': mmsa_(); break;
case 'B': mmsb_(); break;
case 'C': mmsc_(); break;
case 'D': mmsd_(); break;
case 'E': mmse_(); break;
case 'F': mmsf_(); break;
case 'G': mmsg_(); break;
case 'H': mmsh_(); break;
case 'I': mmsi_(); break;
case 'J': mmsj_(); break;
case 'K': mmsk_(); break;
case 'L': mmsl_(); break;
default:
fprintf(stderr, "Whoa, attempted to call segment %s\n", segment);
fflush(stderr);
exit(1);
}
fprintf(stderr, "Oops, segment %s didn't call next segment\n", segment);
fflush(stderr);
exit(2);
}
}
What do i need to change in the stubs.c file, so that 'case 'A': mmsa_()' function is declared? If it helps, then mmsa refers to another file i think mmsa.c in the same local directory.
Happy to give more info if you need it. I've not played this game in over 20+ years(!), so any help would be gratefully received.
this is "just" a warning, and the function call doesn't have any parameters, nor any return value is retrieved, so it should be safe to write:
void mmsa_(void);
void mmsb_(void);
...
and so on.
And if you have header files declaring those functions, it's even better as you can include them instead of declaring them directly.
of course you have to link with libraries or objects containing the code of mmsa_ and other functions, or you'll get a link error (the problem would be just moved to the link phase)
as an aside: consider refactoring your code to remove the K&R old-style parameter declaration which is very much outdated and error prone.

switch-case automatic break

Are there any C compilers with extensions that provide the ability to automatically break at the end of each case statement (similar to what Swift has available) or an alterate switch available in a future C spec?
Mostly interested in this to avoid clutter in extensive switch-case scenarios.
I find this works "ok" but would prefer something clearer about the behavior.
#define case break; { } case
#define switch_break switch
switch_break (action)
{
default: printf ("Unknown action");
case action_none : // Nothing
case action_copy : doCopy ();
case action_paste : doPaste ();
case action_none : break; /* C requires a statement after final case */
}
If you hate writing break everytime, wrap the switch statement inside a function. Then break can be replaced with return statements. For example
int switch_func(char c) {
switch(c) {
case 'a': return 1;
case 'b': return 3;
case 'c': return 5;
case 'd': return 7;
. . .
default: return 0;
}
}
Reduces code only if return values are present.

My book says to make a program that tracks the amount of money a power user owes to the company using only switch statements

It had the same syntax error at all places marked with double forward slash, syntax error was "case label does not reduce to integer constant"
I can't use if statements because my book is dumb and hates if statements (but only in the switch statement chapter)
#include <stdio.h>
int main()
{
double price;
int power;
char user,hrs;
printf("Enter what kind of consumer (R for residential, C for commercial, I for industrial): ");
scanf("%c",user);
printf("Enter amount of kilowatt hours used: ");
scanf("%d",power);
switch(user)
{
case 'R':
case 'r':
price=6.00+.052*power;
break;
case 'C':
case 'c':
switch(power)
{
case (power>1000): //
price=60.00+(power-1000)*.045;
case power<=1000: //
price=60.00;
}
break;
case 'I':
case 'i':
{
printf("Hours (P for peak, O for off-peak):");
scanf("%c",hrs);
switch(hrs)
{
case 'P':
case 'p':
switch(power)
{
case power>1000: //
price=76.00+.065*(power-1000);
break;
case power<=1000: //
price=76.00;
break;
}
case 'O':
case 'o':
switch(power)
{
case power>1000: //
price=40.00+.028*(power-1000);
break;
case power<=1000: //
price=40.00;
break;
}
break;
default:
printf("Business hour ID not recognized; try again");
break;
}
}
break;
default:
printf("Consumer ID not recognized; try again");
break;
}
printf("Price is %f", price);
return(0);
}
The expressions in your case statements must be constants like 'p', not expressions like power>1000.
If you need to do expressions like power>1000, you should use if/else structures to handle all appropriate cases.
The value of a case statement must be a constant integer.
You are free to use chars (e.g. 'a', 'x', etc) because they will be converted to integers by the compiler (using their ASCII code).
Using any other type of constant will yield unexpected and probably unpleasant results.
Besides, the compiler will complain (and rightly so) if you use the same value in two different case statements. This can be trickier than it seems. For instance :
#define WHATEVER 1
switch (xxx)
{
case 1 : return 1;
case WHATEVER : return 10; // error: duplicate case value
}
Frankly I don't think your exercise is such a good illustration of the practical use of a case statement.
99% of the times, the case values will come from an enumerated type, like for instance:
typedef enum {
CMD_START,
CMD_STOP
} Command;
function process_command (Command c)
{
switch (c)
{
case CMD_START:
do_start();
break;
case CMD_STOP:
do_stop();
break;
default:
panic ("unknown command %d", c);
}
}
When you switch on power, the case targets must be constants.
Since you are actually only interested in the binary outcome of power>1000, you can apply the switch to that:
switch(power>1000)
{
case 1:
price=76.00+.065*(power-1000);
break;
default:
price=76.00;
break;
}
The exercise is meant for you to understand that using a switch this way is very close to if-else. However, only do this to satisfy an academic exercise. No one would actually want to maintain code written this way. It is more natural to use if-else:
if(power>1000)
{
price=76.00+.065*(power-1000);
}
else
{
price=76.00;
}

is it possible to do an OR in a case statement?

I want to do something like:
case someenumvalue || someotherenumvalue:
// do some stuff
break;
Is this legal in C?
The variable that I am doing a switch on is an enumerated list data struct.
You can rely on the fact that case statements will fall-through without a break:
case SOME_ENUM_VALUE: // fall-through
case SOME_OTHER_ENUM_VALUE:
doSomeStuff();
break;
You can also use this in a more complicated case, where both values require shared work, but one (or more) of them additionally requires specific work:
case SOME_ENUM_VALUE:
doSpecificStuff();
// fall-through to shared code
case SOME_OTHER_ENUM_VALUE:
doStuffForBothValues();
break;
Yes, you can simply skip the break in the first case to achieve the fall-through effect:
switch (expr) {
case someenumvalue: // no "break" here means fall-through semantic
case someotherenumvalue:
// do some stuff
break;
default:
// do some other stuff
break;
}
Many programmers get into the trap of fall-through inadvertently by forgetting to insert the break. This caused me some headaches in the past, especially in situations when I did not have access to a debugger.
you need:
case someenumvalue:
case someotherenumvalue :
do some stuff
break;
You can use fallthrough to get that effect:
case someenumvalue:
case someotherenumvalue :
do some stuff
break;
A case statement like a goto -- your program will execute everything after it (including other case statements) until you get to the end of the switch block or a break.
As others have specificied, yes you can logically OR things together by using a fall through:
case someenumvalue: //case somenumvalue
case someotherenumvalue : //or case someothernumvalue
do some stuff
break;
But to directly answer your question, yes you can do a logical, or bit-wise or on them as well (it's just a case for the result of the operation), just be careful that you're getting what you'd expect:
enum
{
somenumvalue1 = 0,
somenumvalue2 = 1,
somenumvalue3 = 2
};
int main()
{
int val = somenumvalue2; //this is 1
switch(val) {
case somenumvalue1: //the case for 0
printf("1 %d\n", mval);
break;
case somenumvalue2 || somenumvalue3: //the case for (1||2) == (1), NOT the
printf("2 %d\n", mval); //case for "1" or "2"
break;
case somenumvalue3: //the case for 2
printf("3 %d\n", mval);
break;
}
return 0;
}
If you choose to do the second implementation keep in mind that since you're ||'ing things, you'll either get a 1 or 0, and that's it, as the case.

Resources