在C中使用do创建菜单时遇到问题.While和if.else语句



我是编程界的新手。我在学校学习编程。我的老师最近让全班同学制作一个菜单,菜单上的选择有限,最后会有一个哨兵值。下面是我的代码:

#include <stdio.h>
void menu(void);
void choice1();
void choice2();
void choice3();
char choice;
int main() {
    do {
        menu();
        if (choice =='1')
            choice1();
        else if (choice =='2')
            choice2();
        else if (choice =='3')
            choice3();
        else if (choice =='4')
            break;
        else
            printf("Invalid character.");
    } while (choice != '4');
    return 0;
}
void menu(void) {
    printf("nMenu:nn");
    printf("1) Choice 1.n");
    printf("2) Choice 2.n");
    printf("3) Choice 3.n");
    printf("Choose any of the above, or enter 4 to quit.nn");
    scanf("%c", &choice);
}
void choice1() {
    printf("nChoice 1n");
}
void choice2() {
    printf("nChoice 2n");
}
void choice3() {
    printf("nChoice 3n");
}

当我尝试运行它时,通过输入数字1, 2, 3,输出出来,但之后出现了函数menu()和行"无效字符"。至于另一个字符,menu()和"Invalid character"出现了两次。数字4结束程序。我可以做些什么改进来确保menu()和"无效字符"行不会不必要地出现?

在行缓冲输入中,在您读取'choice'的单个字符后,换行字符在缓冲区中徘徊,因此您无意中得到Invalid character.

读取选择

后,需要清空缓冲区
scanf("%c", &choice);
while(getchar()!='n') 
/* Wasting the buffer
 * Hence ensuring that the character you enter
 * is indeed considered for 'choice'
 */
  ;; // Do nothing in particular

作为旁注,你的程序看起来像切换命令的典型用例,也许你的老师希望你使用它。

考虑到@chqrlie在[this]评论中提到的场景,解决方法是在

之后添加
scanf("%c", &choice);

下面的行

int c;
while ((c = getchar()) != EOF && c != 'n') 
    ;; //Wasting the buffer

问题很简单:终端是行缓冲的:您必须按enter键才能使输入对程序可用,第一个scanf("%c", &choice)调用检索键入的字符,第二个调用检索由回车键生成的换行符('n')。

有多种方法可以避免这个问题。您可以在%c: scanf(" %c", &choice); 之前添加scanf格式的空格,或者您可以在第一个字符之后读取字符,直到您得到'n'

注意,必须检查scanf的返回值,以避免用户输入文件结束时出现未定义的行为。还建议避免使用全局变量:函数menu()应该返回指定的选项。使用switch语句也是更惯用的方法。

以下是更正后的版本:

#include <stdio.h>
int menu(void);
void choice1(void);
void choice2(void);
void choice3(void);
int main(void) {
    int ch;
    for (;;) {
        switch (ch = menu()) {
        case '1':  choice1();  continue;
        case '2':  choice2();  continue;
        case '3':  choice3();  continue;
        case '4':
        case EOF:  break;
        default:   printf("Invalid character %cn", ch);  continue;
        }
        break;
    }
    return 0;
}
int menu(void) {
    char choice;
    printf("nMenu:nn");
    printf("1) Choice 1.n");
    printf("2) Choice 2.n");
    printf("3) Choice 3.n");
    printf("Choose any of the above, or enter 4 to quit.nn");
    if (scanf(" %c", &choice) == 1)
        return choice;
    else
        return EOF;
}
void choice1(void) {
    printf("nChoice 1n");
}
void choice2(void) {
    printf("nChoice 2n");
}
void choice3(void) {
    printf("nChoice 3n");
}

正如在其他答案中已经提到的,问题是换行符。

当你按下1然后回车,你会得到两个字符,即1n。所以你的循环运行两次,当n被处理时输出Invalid character

这是你问题的另一个解决方案。只需在%c前加一个空格。
scanf(" %c", &choice);

这可以工作,因为空格将匹配任意数量的空白字符,从而匹配n并删除它。

从手册页:

一组空白字符(空格、制表符、换行符、等等……)。这个指令匹配任何数量的

输入中的空白,包括无空白。

附加评论

您应该始终检查scanf返回的值,以确保您读取的值的正确数量。

 if (scanf(" %c", &choice) != 1)
 {
     // Add error handling ....
     // For instance you could terminate the program like
     exit(1);
 } 

在你的程序中choice是一个全局变量。一般来说,如果可能的话,应该避免使用全局变量。在您的情况下,您可以使choice成为main中的局部变量,并让menu返回char。如:

// char choice;  Remove global variable
int main() {
    char choice; // Add local variable
    do {
        choice = menu();  // Assign to local variable
        .....
}
char menu(void) {    // Make the function return a char
    char choice;     // Add local variable
    printf("nMenu:nn");
    printf("1) Choice 1.n");
    printf("2) Choice 2.n");
    printf("3) Choice 3.n");
    printf("Choose any of the above, or enter 4 to quit.nn");
    if (scanf("%c", &choice) != 1) exit(1); // Assign to local variable
                                            // On failure -> exit
    return choice;  // Return value of local variable
}

可以用scanf(" %c",&choice); (带空格)代替scanf("%c",&choice);

当我尝试运行它时,通过输入数字1,2,3,输出出现了但之后的功能菜单()和行"无效字符。"出现了。

这是因为你在每个数字后面按了一个新的行字符。它本身是一个字符,循环再迭代一次。因为它是一个无效字符,这就是为什么显示" invalid character."

尝试在scanf()之后使用getchar()

编辑:修复我以前的while循环可能不正确退出:

#include <stdio.h>
int main() {
  int choice;
  printf("Menu:nn");
  printf("1) Choice 1.n");
  printf("2) Choice 2.n");
  printf("2) Choice 3.n");
  printf("Choose any of the above, or enter 4 to quit.nn");
  while (1) {
    char c = scanf("%d",&choice);
    if (c == EOF || choice == 4) break;
    if (choice == 1 || choice == 2 || choice == 3) {
      printf("Choice %d.n", choice);
    } else {
      printf("Invalid character.n");
    }
  }
  return 0;
}

如果你愿意,你可以使用function,但在这种情况下不是必须的。您需要了解您的循环实际运行了多少次,并将其与您期望的进行比较。

我之前的代码:

#include <stdio.h>
int main() {
  int choice;
  printf("Menu:nn");
  printf("1) Choice 1.n");
  printf("2) Choice 2.n");
  printf("2) Choice 3.n");
  printf("Choose any of the above, or enter 4 to quit.nn");
  while (scanf("%d", &choice) && choice != 4) {
    if (choice == 1 || choice == 2 || choice == 3) {
      printf("Choice %d.n", choice);
    } else {
      printf("Invalid character.n");
    }
  }
  return 0;
}

最新更新