我是编程界的新手。我在学校学习编程。我的老师最近让全班同学制作一个菜单,菜单上的选择有限,最后会有一个哨兵值。下面是我的代码:
#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
然后回车,你会得到两个字符,即1
和n
。所以你的循环运行两次,当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;
}