I have this really large if statement and it does not look pleasing to the eye as well as not being as efficient as possible.
I'm making a program that (depending on the users input) runs a certain block of code, for example if the user inputs 'a' the program runs a code that adds something to a file etc. By the way this is in a do-while statement(I don't know if this is relevant though).
else if(ansr != 'a' && ansr != 'A' && ansr != 'r' && ansr != 'R' && ansr != 's' && ansr != 'S' && ansr != 'e' && ansr != 'E')
{
printf("Invalid input!\n");
}
As you can see this is a really long if statement and I would like it to be shorter. Thank you
Um, what an example, whatever.
Why don't you use strchr? strchr returns the pointer to a character in a string (if found), NULL otherwise.
else if (strchr("aArRsSeE", ansr) == NULL)
{
printf("Invalid input!\n");
}
I would go with:
switch(tolower(ansr)) {
case 'a':
case 'r':
case 's':
case 'e':
do_stuff();
break;
/* other cases here */
}
Or you can use more library functions such as:
if (strchr("ares", tolower(ansr)) {
do_stuff();
}
strchr function is searching for a given character in the given string and returns NULL if it is not there (or pointer to first occurrence of it, but it is not the use-case which we are interested in here)
This is assuming ansr is in the range of unsigned char or EOF. Otherwise the behavior of tolower is undefined.
To answer your question, I would personally use a switch statement. It is easy to use and easy to read. Another thing which would make your code slightly more readable is using toupper.
Here is an example:
#include <stdio.h>
#include <ctype.h>
int main ()
{
char inp = 'i';
char ansr = toupper(inp);
switch(ansr) {
case 'A' :
// Do something
break;
case 'R' :
// Do something
break;
case 'S' :
// Do something
break;
case 'E' :
// Do something
break;
default :
printf("Invalid input!\n");
}
return 0;
}
It looks like you're trying to write an else if case to catch input characters that you do not support. The else case is perfect for that kind of situation:
...
char input;
//get your input
if (input == 'A' || input == 'a')
DoA();
else if (input == 'R' || input == 'r')
DoR();
else if (input == 'S' || input == 's')
DoS();
else if (input == 'E' || input == 'e')
DoE();
else
DoInvalidInput();
Or if you use tolower() you can put that in a switch statement:
char lowerChar = tolower((unsigned char)input);
switch (lowerChar)
{
case 'a': DoA(); break;
case 'r': DoR(); break;
case 's': DoS(); break;
case 'e': DoE(); break;
default: DoInvalidInput(); break;
}
Depending on if the case of the ansr is important, converting to lowercase before the if statement would half the amount of checks needed.
Related
When the user inputs Yes,Only Maths,Only Science, the compiler executes Default.
I've tried with the same code but with Char replaced with Int it works as intended.. but with char it dosen't..
#include<stdio.h>
int main(){
char a;
printf("Have you passed in both maths and science?[Yes,Only Maths,Only Science]");
scanf(" %c", &a);
switch (a){
case 'Yes':
printf("That's amezing!");
break;
case 'Only Maths':
printf("That's good!");
break;
case 'Only Science':
printf("That's good!");
break;
case 'none':
printf("oof work harder next time!, i hope you will rock on that exam!");
break;
default:
printf("bozo do the typing right!");
break;
}
return 0;
}
A char by itself cannot store a string like "Yes". It will only store the first 'Y' and leave the rest. This is why none of the switch cases will match. Consider using string or char array to store an array of chars which can be compared. However, then the problem becomes that you cannot use switch with strings in C so you must use if, else.
#include <stdio.h>
int main(){
char a[15]; //15 should be a reasonable size
printf("Have you passed in both maths and science?[Yes,Only Maths,Only Science]");
fgets(a, 15, stdin);
if (strcmp(a, "Yes") == 0) printf("That's amezing!");
else if (strcmp(a, "Only Maths") == 0) printf("That's good!");
else if (strcmp(a, "Only Science") == 0) printf("That's good!");
else if (strcmp(a, "none") == 0) printf("oof work harder next time!, i hope you will rock on that exam!");
else printf("bozo do the typing right!");
return 0;
}
It is also recommended to use fgets instead of scanf to read strings.
I'm writing a program to 'encrypt' an inputted string of text by using a switch statement to correlate the given character with a symbol, and output that symbol in the place of the character. I put it in a while loop, the idea being that it would loop the full switch function each time until the received character is EOF. On a guess, I believe it is looping through just the first character, because I don't advance the getchar() statement, but I'm not sure how to do that so any help would be greatly appreciated. I say this because if I use return instead of break, it closes the while loop and only takes that first letter, if I use a break then it spams the first 'encrypted' char.
#include <stdlib.h>
#include <stdio.h>
/* C program to encrypt a given text message, assuming all lowercase */
int main() {
int Input, Encrypted;
printf("Please type your message\n");
Input = getchar();
while (Input != EOF) {
switch (Input) {
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'");break;
return 0;
}
}
return 0;
}
The simplest solution would be to remove the line
Input = getchar();
and to replace the line
while (Input != EOF) {
with:
while ( (Input=getchar()) != EOF && Input != '\n' ) {
Alternatively, if you find this while condition too confusing, you could also use an infinite loop, instead, like this:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
switch ( c )
{
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'"); break;
}
}
return 0;
}
Note that most character sets (such as ASCII) store the characters a to z consecutively. With these character sets, you don't need the long switch statement. Instead, you can simplify it to the following:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
const char map[] = "!##$%^&*`~-_=+[{]};:|,<.>'";
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
if ( 'a' <= c && c <= 'z' )
putchar( map[c-'a'] );
}
return 0;
}
Hi please take a look on this code:
while (cont == 1) {
...
scanf_s("%d", &input);
if (0 < input <= 5){
switch (input) {
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
printf("4");
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input !");
break;
}
}else{
printf("Error, Not a number !");
}
}
If I input something that is not a number, it results in an infinite loop. How do I restrict char inputs?
You can use this:
if(scanf_s("%d", &input) != 1) {
printf("Wrong input !");
break;
}
You should ALWAYS check the return value of scanf_s anyway.
After the scanf_s() fails, you need to read at least one character (the character that it failed on); usually, it makes most sense to discard the rest of the line that the user entered:
while (cont == 1) {
int rc;
...
if ((rc = scanf_s("%d", &input)) < 0)
{
printf("EOF detected\n");
break;
}
if (rc == 0)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
printf("Error, Not a number!\n");
continue;
}
if (0 < input <= 5){
switch (input) {
case 1:
case 2:
case 3:
case 4:
printf("%d", input);
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input (1-5 required)!\n");
break;
}
}
}
If EOF is detected in the 'gobble' loop, you could detect EOF there and repeat the print and break the loop immediately. OTOH, the next scanf_s() should also report EOF, so it isn't 100% necessary. It depends a little on where the prompting occurs; if you get EOF, you probably shouldn't prompt again, so maybe the test after the inner while loop should be:
if (c == EOF)
{
printf("EOF detected\n");
break;
}
else
{
printf("Error, not a number\n");
continue;
}
You can play with variants of the 'gobble' loop that read up to a newline or a digit, and use ungetch(c, stdin); to return the digit to the input stream for the next call to scanf_s() to process — you probably wouldn't prompt for more input if you're going to process the already entered digit (that would confuse).
There are endless other games you can play. One option to consider is limiting the number of failed inputs before you give up — if the user hasn't entered a valid number in 10 tries, they probably aren't going to.
Note how the error processing tells the user what the valid range of numbers is; that helps them get it right. Also notice that the messages have a newline at the end; that's generally a good idea. In contexts outside interactive I/O, the newline can help ensure that the output appears when it is printed, not some arbitrary time later when some other print adds a newline, or the output buffer fills up and the pending data is flushed after all.
While making a asteroid shooter, I came around using _kbhit() and kbhit(). I'm no expert, but here is the problem I think I'm having:
int run = 1;
int main() {
while(run){
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
Sleep(50);
}
}
int GetUserInput(){
if(kbhit()){
char c = _getch();
if(c == 's')
return 2;
if(c == 'w')
return 1;
}
else
return 0;*
}
So, what I think is happening, it does the first check on GetUserInput(), and because of the nature of getch(), the keyboard is read from the buffer and discarded? Anyways, I store the value in c and should return appropriately. But it only does the first check. Is it because there is no more input on the buffer after the first check (in the main() function)?
Your problem is that you're trying to read once for every key you're interested in with this code:
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
For example, I press 'S', you read the key, check if the return value is 2 and it is not. Then you try to read another key, but I haven't pressed one, so the second check for 'S' also fails.
To fix this you need to perform all of your tests on the value you get from GetUserInput().
int val = GetUserInput();
if(val == 2)
printf("W");
else if(val == 1)
printf("S");
You don't need to use else if, but once you've found a match it makes no sense to keep checking if all of your checks are mutually exclusive. You might consider using a switch statement and an enum instead of hardcoded magic values, or even return the key value directly if one is pressed and a sentinel value like 0 that won't match any of the keys you're interested in.
Here is a complete example that works for me:
#include <conio.h>
#include <stdio.h>
int GetUserInput()
{
if (_kbhit())
{
char c = _getch();
switch (c)
{
case 's':
case 'S':
return 2;
case 'w':
case 'W':
return 1;
case 'x':
case 'X':
return -1;
}
}
return 0;
}
int main()
{
for (;;)
{
int c = GetUserInput();
switch (c)
{
case 1:
printf("W");
break;
case 2:
printf("S");
break;
case -1:
return 0;
}
}
return 0;
}
I'm comparing strings character by character.
Here's a part of my code that's causing problems:
switch(line[1]) {
case 'u':
switch(line[2]) {
case 't':
switch(line[3]) {
case 't':
switch(line[4]) {
case 'o':
switch(line[5]) {
case 'n':
switch(line[6]) {
case 's':
printf("buttons\n");
case ' ':
printf("not buttons\n");
break;
}
break;
}
break;
}
break;
}
break;
}
}
For line[6], if an s character exists it should print out "buttons", if there's a space, it should print out "not buttons"
If I have a config file that contains:
buttons 13
button 3
buttons 3
I get:
buttons
not buttons
buttons
not buttons
If I have:
buttons 3
I get:
buttons
not buttons
I get a "buttons" and "not buttons" for every buttons entry and get nothing for the "button 3" entry
thanks
You will always get not buttons when there is buttons because you are not breaking after case 's'.Therefore it won't stop when an line[6] is s.
And you used all these nested switches just to compare a string.Better use strcmp to check if its buttons or button.
Instead of complicating nested switch, use this
FILE * fi; // input file handle
char line[9], c;
while (feof(fi) == 0) {
// Read only required chars
fgets(line, 8, fi);
line[8] = '\0';
while ((c = getc(fi)) != '\n' && c != EOF);
// Simplified comparison
if (strncmp(line, "button", 6) == 0) {
if (line[6] == 's') printf("buttons\n");
else if (line[6] == ' ') printf("not buttons\n");
}
}
Here's a simpler, cleaner version of the code:
if (strncmp(line, "button", 6)==0)
{
if (line[6]=='s')
printf("buttons");
else printf("button");
}