switches | | |
Is it possible to call a function within a switch? My function call is
bypassed somehow.
int startmenu()
{
exitgame = 0;
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
printf ("Command: ");
int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
} | | | | re: switches
Jonathan H. Justvig wrote: Quote:
Is it possible to call a function within a switch? My function call is
bypassed somehow.
>
Yes and you've made several in your code (puts,printf,scanf).
Unless you post a self contained and compilable example that shows your
problem, we won't be able to help. Quote:
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
}
--
Ian Collins. | | | | re: switches
Jonathan H. Justvig wrote: Quote:
Is it possible to call a function within a switch? My function call is
bypassed somehow.
>
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
}
It's impossible for us to help when we don't know what the "class()"
function does.
What I would recommend is, at the top of the class() function, put in a
line like
printf( "Debug 1\n" );
Then run the program and you can check if it prints "Debug 1" where you
think class() should be called. If not, then indeed class() isn't
getting called (which, given the above code, would be pretty weird).
If so, move the printf line further down, using it to "feel out" where
the problem is. Do this a few times and before you know it you'll find
yourself staring at a for loop followed immediately by a misplaced
semicolon, or something else like that. | | | | re: switches
"Jonathan H. Justvig" <crimson3@cox.netwrites: Quote:
Is it possible to call a function within a switch?
Of course. Quote:
My function call is bypassed somehow.
>
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
getchar() returns the next character from stdin (or EOF if there's no
more input available). If you type 's', the system won't process your
input until you hit the return key, which will then cause getchar() to
return '\n'.
I don't know whether that's your problem, but it might be something
related to that.
To help track it down, add a default case that shows the value of the
character (use "'%c'" if it's printable, "%d" if it isn't). Quote:
switch (c)
{
case ('s'):
[code snipped] --
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this. | | | | re: switches
Ian Collins wrote: Quote:
Jonathan H. Justvig wrote: Quote:
>Is it possible to call a function within a switch? My function call is
>bypassed somehow.
Quote:
Yes and you've made several in your code (puts,printf,scanf).
Quote:
Unless you post a self contained and compilable example that shows your
problem, we won't be able to help.
Here is a very condensed version causing the same problem.
#include <stdio.h>
char c;
char *cclass;
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];
int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}
int main()
{
startmenu();
}
-- Jon | | | | re: switches
"Jonathan H. Justvig" <crimson3@cox.netwrites: Quote:
Ian Collins wrote: Quote:
>Jonathan H. Justvig wrote: Quote:
>>Is it possible to call a function within a switch? My function call is
>>bypassed somehow.
> Quote:
>Yes and you've made several in your code (puts,printf,scanf).
> Quote:
>Unless you post a self contained and compilable example that shows your
>problem, we won't be able to help.
>
Here is a very condensed version causing the same problem.
>
#include <stdio.h>
char c;
char *cclass;
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];
>
int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}
>
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}
>
int main()
{
startmenu();
}
First, I'll point out a few problems in this code that probably aren't
relevant to your problem.
You declare three functions as returning int, but you don't return a
value from any of them.
If a function takes no arguments, it's better to say so explicitly:
int fighter(void)
You mix declarations and statements. This is allowed in C99, but not
in C90 (though some pre-C99 compilers support it as an extension).
You use tolower(), but you don't have a "#include <ctype.h>".
The real problem, I think, is what I guessed previously. getchar()
returns the next character you type. You see the prompt, then you
type 's', then you hit <enter>. The 's' causes getchar() to return
's', and the <entercauses it to return '\n'.
If you type 'sf' *without* pressing <enterafter the 's' (i.e., you
type 'f' before seeing the "Select Class" prompt), you should see the
correct behavior.
After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this. | | | | re: switches
Here it is again with your advice and correction. 'sf' does returns the
correct results. Is the problem because there is a switch within a
switch? I can't seem to get another prompt after I type 's' and fflush
(stdin);
[snip]
#include <stdio.h>
#include <ctype.h>
char c;
char *cclass;
int fighter(void)
{
/* Building Fighter */
cclass = "Fighter";
}
int startmenu(void)
{
puts ("S)tart Game");
printf ("Command: ");
int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter");
printf ("Enter your class: ");
fflush(stdin);
puts ("debug 1");
int c = tolower (getchar());
puts ("debug 2");
switch (c)
{
puts ("debug 3");
case ('f'):
puts ("debug 4");
fighter();
printf ("%s",cclass);
break;
}
default:
printf ("%d", c);
}
}
int main(void)
{
startmenu();
}
[snip]
Keith Thompson wrote: Quote:
You declare three functions as returning int, but you don't return a
value from any of them.
Hopefully, corrected. Quote:
You mix declarations and statements. This is allowed in C99, but not
in C90 (though some pre-C99 compilers support it as an extension).
Is ' int c = tolower (getchar()); ' what you mean? What would you
suggest instead? Quote:
You use tolower(), but you don't have a "#include <ctype.h>".
Now it's been 'included'. Quote:
After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.
I tried fflush(stdin); but that didn't seem to work. I did trying to
print out what was in the variable char 'c' and get strange results
mostly when I use %c or %d.
Thanks for your help thus far.
-- Jon | | | | re: switches
Jonathan H. Justvig wrote:
[snip] [snip] Quote:
I tried fflush(stdin); but that didn't seem to work. I did trying to
print out what was in the variable char 'c' and get strange results
mostly when I use %c or %d.
Hi Jonathan,
fflush() flushes output streams, and should have no effect on input
streams like stdin.
You may just want to add a while loop that reads characters until it
gets the one you want (or until end of file).
-Steve | | | | re: switches
"Jonathan H. Justvig" <crimson3@cox.netwrites: Quote:
Here it is again with your advice and correction. 'sf' does returns
the correct results. Is the problem because there is a switch within
a switch? I can't seem to get another prompt after I type 's' and
fflush (stdin);
No, it's not because you have a switch within a switch. It's because
getchar() does exactly what it's supposed to do. If you type 's'
immediately followed by 'f', the first call to getchar() returns 's'
and the second returns 'f'. If you type 's' immediately followed by
the <enterkey, the first call to getchar() returns 's' and the
second returns '\n'.
It gives you exactly what you typed. You're just not allowing for the
fact that one of the things you typed was '\n' (or the <enterkey,
which is mapped to '\n').
Don't use fflush(stdin); it's not defined.
The system is reading a line at a time; getchar() gets the characters
only after you press <enter>. There are system-specific ways to read
one character at a time, but there's nothing portable; see question
19.1 in the comp.lang.c FAQ, <http://www.c-faq.com/>.
One solution is:
Call getchar() and save the result.
Repeatedly call getchar() and discard the result until you
see a '\n' or EOF.
Another is to read a line at a time using fget() (*not* gets()), and
just use the first character. This is probably simpler than the loop.
[...] Quote: Quote:
>You mix declarations and statements. This is allowed in C99, but not
>in C90 (though some pre-C99 compilers support it as an extension).
>
Is ' int c = tolower (getchar()); ' what you mean? What would you
suggest instead?
In C90, a block (a chunk of code starting with "{" and ending with "}"
needs to contain zero or more declarations followed by zero or more
statements. You can just rearrange your code to meet this
restriction. You might need to separate a variable's initialization
from its declaration to do this; for example:
int c;
/* ... */
c = tolower(getchar());
But this isn't necessary if you're not concerned about portability.
Many compilers, apparently including the one you're using, do allow
mixed declarations and statements. You might consider setting this
issue aside while you work on the other problems.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this. | | | | re: switches
Jonathan H. Justvig (in j3wCg.5501$yO4.437@dukeread02) said:
| I tried fflush(stdin); but that didn't seem to work. I did trying
| to print out what was in the variable char 'c' and get strange
| results mostly when I use %c or %d.
Jonathan...
Sometimes indentation helps to see program structure better. I did a
bit of re-formatting and combined the c definitions in startmenu():
#include <stdio.h>
#include <ctype.h>
char c;
char *cclass;
void fighter(void)
{ /* Building Fighter */
cclass = "Fighter";
}
void startmenu(void)
{ int c;
puts ("S)tart Game");
printf ("Command: ");
c = tolower (getchar());
switch (c)
{ case ('s'):
puts ("Select Class");
puts ("(F)ighter");
printf ("Enter your class: ");
puts ("debug 1");
c = tolower (getchar());
puts ("debug 2");
switch (c)
{ puts ("debug 3");
case ('f'):
puts ("debug 4");
fighter();
printf ("%s",cclass);
break;
}
default:
printf ("%d", c);
}
}
int main(void)
{ startmenu();
return 0;
}
Here's what I got when I ran your program. Note that I put both
expected characters into the stdin stream at first opportunity. The
switches appear to be working just as expected:
C:\WINDOWS\Desktop: jhj
S)tart Game
Command: sf
Select Class
(F)ighter
Enter your class: debug 1
debug 2
debug 4
Fighter102
C:\WINDOWS\Desktop:
--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA http://www.iedu.com/DeSoto | | | | re: switches levis501@yahoo.com writes: Quote:
Jonathan H. Justvig wrote:
[snip] [snip] Quote:
>I tried fflush(stdin); but that didn't seem to work. I did trying to
>print out what was in the variable char 'c' and get strange results
>mostly when I use %c or %d.
>
fflush() flushes output streams, and should have no effect on input
streams like stdin.
You may just want to add a while loop that reads characters until it
gets the one you want (or until end of file).
Correction: fflush() on an input stream invokes undefined behavior.
Some systems define the behavior, but you can't count on it in
portable code.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this. | | | | re: switches
Keith Thompson wrote: Quote:
After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.
Sorry, I'm a little slow. I just now understood that if I issue an
extra getchar() to read the '\n'. It now gives me the prompt for the
next switch. It's probably not the best but it seems to work
regardless. Again, thanks for your help.
-- Jon | | | | re: switches
On 9 Aug 2006 19:02:01 -0700, levis501@yahoo.com wrote: Quote:
>
>Jonathan H. Justvig wrote:
>[snip] >[snip] Quote:
>I tried fflush(stdin); but that didn't seem to work. I did trying to
>print out what was in the variable char 'c' and get strange results
>mostly when I use %c or %d.
>
>Hi Jonathan,
fflush() flushes output streams, and should have no effect on input
>streams like stdin.
fflush is defined only for output streams. Attempting to use it on an
input stream invokes undefined behavior. Quote:
>You may just want to add a while loop that reads characters until it
>gets the one you want (or until end of file).
>
>-Steve
Remove del for email | | | | re: switches
[Others have pretty much picked your code apart, and answered your original
question in the process. But there are one or two points of interest that
remain, which I *think* have not yet been mentioned - so, with your
indulgence...]
Jonathan H. Justvig said: Quote:
#include <stdio.h>
char c;
char *cclass;
Make this const char *cclass because you use it for pointing at string
literals. Quote:
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];
That's a lot of file scope data for such a simple program. Is it really
necessary? (No.) Quote:
int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}
>
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
To ensure that the program produces the prompt before blocking for input,
either make this printf("Command:\n"); or puts("Command:"); or, if you
really want the currently active position to remain on the same line,
fflush(stdout); Quote:
int c = tolower (getchar());
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):
#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])
If so, then your tolower call expands to:
int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);
which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower that way. It knows it's using ASCII, so it takes advantage of
that!"
Okay, so perhaps it uses something like:
#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + ('a' - 'A') : (c))
So your call expands to:
int c = (((getchar()) >= 'A' && (getchar()) <= 'Z') ? (getchar()) + ('a' -
'A') : (getchar()))
which, if sufficient upper case letters are available, calls getchar *three*
times!
Suggested fix: capture it first. Then worry about the case. For example, you
could do:
c = getchar();
switch(tolower(c)) Don't forget case EOF: Quote:
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}
You promised to return an int from startmenu(). Where is it? Quote:
>
int main()
{
startmenu();
You promised to return an int from main(). Where is it?
Incidentally, in your original article you mentioned that you are using:
scanf ("%s", cname);
You didn't specify how much memory cname refers to, but I can assure you it
isn't enough. This is a buffer overrun waiting to happen.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously) | | | | re: switches
Richard Heathfield <invalid@invalid.invalidwrites: Quote:
[Others have pretty much picked your code apart, and answered your original
question in the process. But there are one or two points of interest that
remain, which I *think* have not yet been mentioned - so, with your
indulgence...]
>
Jonathan H. Justvig said:
[...] Quote: Quote:
>int c = tolower (getchar());
>
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):
>
#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])
>
If so, then your tolower call expands to:
>
int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);
>
which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower that way. It knows it's using ASCII, so it takes advantage of
that!"
[snip]
A conforming implementation can't define tolower() that way.
C99 7.1.4p1:
Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.
(C90 has similar or identical wording.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this. | | | | re: switches
Keith Thompson said:
<snip> Quote:
A conforming implementation can't define tolower() that way.
>
C99 7.1.4p1:
>
Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.
Thank you. For some reason I had overlooked that.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously) | | | | re: switches
Richard Heathfield wrote:
<snip> Quote: Quote:
>int c = tolower (getchar());
>
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):
>
#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])
>
If so, then your tolower call expands to:
>
int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);
>
which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower is defined as a function, not a macro, by the standard. I know
the implementation is allowed to provide a macro implementation as well
but that macro is NOT allowed to evaluate the argument more than once.
N1124 includes the text:
| Any invocation of a library function that is implemented as
| a macro shall expand to code that evaluates each of its arguments
| exactly once, fully protected by parentheses where necessary, so it is
| generally safe to use arbitrary expressions as arguments. Quote:
Suggested fix: capture it first. Then worry about the case. For example, you
could do:
>
c = getchar();
switch(tolower(c))
Not required, see above.
<snip>
--
Flash Gordon
Still sigless on this computer. | | | | re: switches
Jonathan H. Justvig wrote: Quote:
Ian Collins wrote: Quote:
Jonathan H. Justvig wrote: Quote:
Is it possible to call a function within a switch? My function
call is bypassed somehow.
> Quote:
Yes and you've made several in your code (puts,printf,scanf).
> Quote:
Unless you post a self contained and compilable example that shows
your problem, we won't be able to help.
>
Here is a very condensed version causing the same problem.
>
#include <stdio.h>
char c;
Quote:
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
>
int c = tolower (getchar());
Besides the other problems people have pointed out, I note that you
have a variable named c and file scope, and another inside a function.
While not technically an error, that's almost always a sign of
something designed improperly, usually the "global" is a fossil left
over from an earlier stage of the program. Many compilers will issue a
diagnostic for this when run at an appropriate warning level.
At the beginning, you should always run at the maximum warning level
your compiler supports (how to do this is implementation-specific).
Treat those warnings as errors that must be corrected.
Brian | | | | re: switches
On Thu, 10 Aug 2006 06:16:41 GMT, Keith Thompson <kst-u@mib.org>
wrote: Quote:
Richard Heathfield <invalid@invalid.invalidwrites:
<snip: tolower() might be macro that multiply evaluates its arg> Quote:
A conforming implementation can't define tolower() that way.
>
C99 7.1.4p1:
>
Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.
>
Except {get,put}[w]c() which have special permission (in 7.19.7.5,8
and 7.23.4.6,8 ) to evaluate the FILE* argument more than once.
Also note that a few library items are specified as function-like
macros, not functions, and thus presumably don't have this guarantee,
particularly setjmp and va_*. In C99 the added IEEE-like operations
(isnan etc.) and tgmath.h generics are specified as macros apparently
because of their not obeying the usual type conversion rules for
function calls, but one hopes shouldn't need to multiply evaluate. Quote:
(C90 has similar or identical wording.)
- David.Thompson1 at worldnet.att.net |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,419 network members.
|