简体   繁体   中英

From an if statement to a switch statement?

I have to write a program that translates from english to pig latin and vice versa for an intro class, and I'm not understanding why after validating that alphabetical inputs are not accepted, it won't continue on to my switch statement. Here's a part of my code:

int main()
{

    char choice;

    while (1) {

        printf("Press 1 to translate from English to pig Latin.\nPress 2 to translate from pig Latin to English.\nPress 3 to terminate the program.\nEnter your choice.\n");

        scanf("%s",&choice);

        if (isalpha (choice)) {
            printf ("ERROR: Please enter a valid input\n");
            continue;
        }

        switch (choice) {
            case 1:
                printf("Enter the English sentence.\n");
                scanf("%s",str);
                englishToPig();
                break;
            case 2:
                printf("Enter the pig Latin sentence.\n");
                scanf("%s",str);
                pigToEnglish();
                break;
            case 3:
                return 0;
            default:
                printf("Wrong Choice\n");
                break;
        }

    }

    return 0;
}

Edit: the switch technically does work, but whenever I enter 1, 2, or 3 it immediately defaults to "wrong choice" instead of calling my translating functions (or exiting the program)

我认为您应该使用int choice而不是char choice ,然后将您的scanf%s更改为%d

You have used String token %s instead use %c ,Better use int instead of char . Hope it helps !

Set datatype of choice as int and change the scanf("%d",&choice); like this

While you can use scanf for taking user-input, you shouldn't. There are a multitude of pitfalls just waiting to trap new C programmers associated with its use. To use it correctly, you must always validate its return and handle the cases where:

  1. You receive valid input (the return is the number of conversions requested);
  2. A matching or input failure occurs (return is less than number requested, no further characters are read, leaving all invalid input in the input buffer, eg stdin ); and
  3. The user cancels input with a manual EOF (the return is EOF ); and
  4. You must always account for any characters left in the input buffer by a previous I/O call.

You must do this with every input. This is further complicated by how the differing conversion specifiers handle leading-whitespace (numeric and %s ignore leading-whitespace, character and character-class (eg %[..] ) don't)

That is why the preferred method of taking user input is with fgets (or POSIX getline ). Both are line-oriented input functions that read up to (and including) the trailing '\\n' (generated by the user pressing Enter). You must still validate the return of both and handle the trailing '\\n' , as required, but the potential for falling into a trap due to failing to account for characters left unread is significantly reduced.

Taking the above into consideration, and using a fixed-buffer for both choice and str (to pass to the functions englishToPig , etc...), you could do something simple like the following.

First, any time you need a constant in your code #define one (or more). Don't use magic numbers in your code. Also, don't leave lines of text scrawling off the side of your page, the preprocessor will combine all string literals separated by nothing by whitespace. This allows the output of your menu prompt to be tidied up quite a bit:

#define MAXC 256    /* if you need a constant, define one */

int main (void) {

    char choice[MAXC] = "", /* initialize choice and str all zero */
        str[BUFSIZ] = "";   /* BUFSIZ is 8092 Linux (512 windows) */
    size_t len = 0;         /* variable for string length tests */

    while (1) {

        printf ("\nPress 1 to translate from English to pig Latin.\n"
                "Press 2 to translate from pig Latin to English.\n"
                "Press 3 to terminate the program.\n\n"
                "Enter your choice: ");
        ...

Reading with fgets is simple, fgets (buffer, size, FILE* stream) . To validate you have good input in your buffer, you only need check that the return is not NULL . You then proceed to check the length and make sure the input fit in size characters and that the final character is '\\n' (otherwise characters remain unread). If you were storing the string or not otherwise accounting for the last character being '\\n' , you could simply remove it by overwriting it with 0 (the same as '\\0' - the nul-character)

Reading choice is as simple as:

            /* read choice (up to 255-chars + nul-terminating char */
        if (fgets (choice, MAXC, stdin) == NULL) {
            fprintf (stderr, "(user canceled input)\n");
            break;
        }
        len = strlen (choice);  /* test all chars fit in choice */
        if (len == MAXC - 1 && choice[len - 1] != '\n') {
            fprintf (stderr, "warning: characters remain unread.\n");
            while (fgets (str, BUFSIZ, stdin)) {}  /* read/discard chars */
        }

Now that you have the user input in choice , you can simply compare the first-character as each case in your switch statement. This is as easy as passing the dereferenced choice to switch (ie choice is just a pointer to the first character, so dereferncing returns the first character itself, *choice being equivalent to choice[0] )

        switch (*choice) {  /* *choice is the same as choice[0] */
            case '1':
                printf ("Enter the English sentence.\n");
                /* read input in BUFSIZ chunks, passing str to englishToPig */
                while (fgets (str, BUFSIZ, stdin)) {
                    puts ("calling englishToPig (str)");
                    // englishToPig (str);
                    if (str[strlen (str) - 1] == '\n')  /* all read, break */
                        break;
                }
                break;
            case '2':
                printf ("Enter the pig Latin sentence.\n");
                /* read input in BUFSIZ chunks, passing str to pigtoEnglish */
                while (fgets (str, BUFSIZ, stdin)) {
                    puts ("calling pigtoEnglish (str)");
                    // pigtoEnglish (str);
                    if (str[strlen (str) - 1] == '\n')  /* all read, break */
                        break;
                }
                break;
            case '3':
                return 0;
            default:
                fprintf (stderr, "error: invalid choice.\n");
                break;
        }

( note: above, even if the size of the user input exceeds BUFSIZ , the entire input will be passed to your functions in BUFSIZ chunks).

Turning the above into a short example just takes adding the headers and the return , eg

#include <stdio.h>
#include <string.h>

#define MAXC 256    /* if you need a constant, define one */

int main (void) {

    char choice[MAXC] = "", /* initialize choice and str all zero */
        str[BUFSIZ] = "";   /* BUFSIZ is 8092 Linux (512 windows) */
    size_t len = 0;         /* variable for string length tests */

    while (1) {

        printf ("\nPress 1 to translate from English to pig Latin.\n"
                "Press 2 to translate from pig Latin to English.\n"
                "Press 3 to terminate the program.\n\n"
                "Enter your choice: ");

        /* read choice (up to 255-chars + nul-terminating char */
        if (fgets (choice, MAXC, stdin) == NULL) {
            fprintf (stderr, "(user canceled input)\n");
            break;
        }
        len = strlen (choice);  /* test all chars fit in choice */
        if (len == MAXC - 1 && choice[len - 1] != '\n') {
            fprintf (stderr, "warning: characters remain unread.\n");
            while (fgets (str, BUFSIZ, stdin)) {}  /* read/discard chars */
        }

        switch (*choice) {  /* *choice is the same as choice[0] */
            case '1':
                printf ("Enter the English sentence.\n");
                /* read input in BUFSIZ chunks, passing str to englishToPig */
                while (fgets (str, BUFSIZ, stdin)) {
                    puts ("calling englishToPig (str)");
                    // englishToPig (str);
                    if (str[strlen (str) - 1] == '\n')  /* all read, break */
                        break;
                }
                break;
            case '2':
                printf ("Enter the pig Latin sentence.\n");
                /* read input in BUFSIZ chunks, passing str to pigtoEnglish */
                while (fgets (str, BUFSIZ, stdin)) {
                    puts ("calling pigtoEnglish (str)");
                    // pigtoEnglish (str);
                    if (str[strlen (str) - 1] == '\n')  /* all read, break */
                        break;
                }
                break;
            case '3':
                return 0;
            default:
                fprintf (stderr, "error: invalid choice.\n");
                break;
        }
    }

    return 0;
}

The above handles all cases of proper or invalid input and handles the user generating a manual EOF at each stage (it will exit at choice , and simply reprompt if at str )

Example Use/Output

With valid input:

$ ./bin/fgetspig

Press 1 to translate from English to pig Latin.
Press 2 to translate from pig Latin to English.
Press 3 to terminate the program.

Enter your choice: 1
Enter the English sentence.
My dog has two fleas and my cat has none :)
calling englishToPig (str)

Press 1 to translate from English to pig Latin.
Press 2 to translate from pig Latin to English.
Press 3 to terminate the program.

Enter your choice: 2
Enter the pig Latin sentence.
yMa atca owna asha wota easlfa, uckyla ogda.
calling pigtoEnglish (str)

Press 1 to translate from English to pig Latin.
Press 2 to translate from pig Latin to English.
Press 3 to terminate the program.

Enter your choice: 3

With invalid input and user canceling by generating a manual EOF by pressing Ctrl+d ( Ctrl+z on windows with legacy mode enabled on Win10 ):

$ ./bin/fgetspig

Press 1 to translate from English to pig Latin.
Press 2 to translate from pig Latin to English.
Press 3 to terminate the program.

Enter your choice: No!
error: invalid choice.

Press 1 to translate from English to pig Latin.
Press 2 to translate from pig Latin to English.
Press 3 to terminate the program.

Enter your choice: (user canceled input)

Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM