为什么跳过 scanf()?
Why is the scanf() skipped?
#include <stdio.h>
int main() {
char opt;
scanf(" %c", &opt);
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
printf("Please Enter the Number:");
int number;
scanf("%d", number);
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
}
}
为什么跳过了名字的scanf
?输出看起来像
A
Please Enter a New Name:Please Enter a New Code:
同样当switch()
被移除时,它可以正常工作。问题出在 switch()
上吗?没有其他案例,因为是未完成的代码。
正如 melonduofromage 评论的那样,您的第一个 scanf 在输入流中的 A
之后留下了用户键入的换行符 (\n
)。 Next scanf("%[^\n]s", name)
失败,因为输入流的第一个字节是换行符,所以 scanf
return 立即带有 return 值 0
,你应该不要忽视。然后程序提示输入代码,scanf
跳过初始白色 space,包括待处理的换行符并等待用户输入。
要解决此问题,请在转换说明符前添加 space 以跳过初始白色 space。您还应该限制存储到目标数组中的字符数:在 %
和 [
之间指定此数字。另请注意,"%[^\n]s"
中的尾随 s
是无用的:它不是转换说明符的一部分,scanf()
将尝试将其与输入流匹配。正确的格式是 scanf(" %199[^\n]", name)
,return 值必须是 1
才能成功转换。
还要注意scanf("%d", number)
中少了一个&
:必须传递目标变量的地址:scanf("%d", &number);
这是修改后的版本:
#include <stdio.h>
int invalid_input(void) {
fprintf(stderr, "invalid or missing input\n");
return 1;
}
int main() {
char opt;
if (scanf(" %c", &opt) != 1)
return invalid_input();
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
if (scanf(" %199[^\n]", name) != 1)
return invalid_input();
printf("Please Enter a New Code:");
char code[200];
if (scanf("%199s", code) != 1)
return invalid_input();
printf("Please Enter the Number:");
int number;
if (scanf("%d", &number) != 1)
return invalid_input();
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
//...
}
return 0;
}
当您在此处提示用户第一个 scanf
时
char opt;
scanf(" %c", &opt);
当用户输入一个字符时,比如 A
,“A\n”被放入缓冲区,\n
来自用户按下 return 键。 scanf
根据 " %c"
格式字符串的要求获取一个字符,并将 \n
留在缓冲区中。
当第二个scanf
执行为
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
格式字符串 "%[^\n]s"
要求它读取直到遇到 \n
,请注意,您的缓冲区已经包含 \n
作为第一个字符,因此 scanf
returns 没有读取任何东西,仍然在缓冲区中留下 \n
。
当第三个scanf
执行为:
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
(chqrlie评论后更正)
格式字符串 "%s"
忽略前导白色 space,因此现在 \n
被忽略,并且 scanf
愉快地等待您的输入。
注意格式字符串" %c"
中的前导space,space是为了让scanf
忽略前导的白色space,你可以用你的第二个 scanf
实现相同的逻辑。您可以确保所有连续的 scanf
忽略缓冲区中剩余的 \n
,事实证明大多数格式说明符都会这样做,或者您可以确保没有 scanf
将其从使用开始像 "<...>%*c"
这样的东西来摆脱它。尽管其中 none 是可靠且一致的方法,并且正如无数次所说,scanf
并非旨在执行此类任务,例如获取用户输入,您应该寻求替代方法。
此外,"%[^\n]s"
中的 s
肯定不符合您的预期。 scanf
的手册页指出
An ordinary character (i.e., one other than white space or '%'). This character must exactly match the next character of input.
如果匹配,scanf
将其丢弃并根据剩余的格式说明符继续解析。如果没有,scanf
停在那里然后 returns。由于它位于您的格式字符串的末尾,因此 return 无论哪种方式,都会对您隐藏潜在的错误。
#include <stdio.h>
int main() {
char opt;
scanf(" %c", &opt);
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
printf("Please Enter the Number:");
int number;
scanf("%d", number);
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
}
}
为什么跳过了名字的scanf
?输出看起来像
A
Please Enter a New Name:Please Enter a New Code:
同样当switch()
被移除时,它可以正常工作。问题出在 switch()
上吗?没有其他案例,因为是未完成的代码。
正如 melonduofromage 评论的那样,您的第一个 scanf 在输入流中的 A
之后留下了用户键入的换行符 (\n
)。 Next scanf("%[^\n]s", name)
失败,因为输入流的第一个字节是换行符,所以 scanf
return 立即带有 return 值 0
,你应该不要忽视。然后程序提示输入代码,scanf
跳过初始白色 space,包括待处理的换行符并等待用户输入。
要解决此问题,请在转换说明符前添加 space 以跳过初始白色 space。您还应该限制存储到目标数组中的字符数:在 %
和 [
之间指定此数字。另请注意,"%[^\n]s"
中的尾随 s
是无用的:它不是转换说明符的一部分,scanf()
将尝试将其与输入流匹配。正确的格式是 scanf(" %199[^\n]", name)
,return 值必须是 1
才能成功转换。
还要注意scanf("%d", number)
中少了一个&
:必须传递目标变量的地址:scanf("%d", &number);
这是修改后的版本:
#include <stdio.h>
int invalid_input(void) {
fprintf(stderr, "invalid or missing input\n");
return 1;
}
int main() {
char opt;
if (scanf(" %c", &opt) != 1)
return invalid_input();
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
if (scanf(" %199[^\n]", name) != 1)
return invalid_input();
printf("Please Enter a New Code:");
char code[200];
if (scanf("%199s", code) != 1)
return invalid_input();
printf("Please Enter the Number:");
int number;
if (scanf("%d", &number) != 1)
return invalid_input();
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
//...
}
return 0;
}
当您在此处提示用户第一个 scanf
时
char opt;
scanf(" %c", &opt);
当用户输入一个字符时,比如 A
,“A\n”被放入缓冲区,\n
来自用户按下 return 键。 scanf
根据 " %c"
格式字符串的要求获取一个字符,并将 \n
留在缓冲区中。
当第二个scanf
执行为
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
格式字符串 "%[^\n]s"
要求它读取直到遇到 \n
,请注意,您的缓冲区已经包含 \n
作为第一个字符,因此 scanf
returns 没有读取任何东西,仍然在缓冲区中留下 \n
。
当第三个scanf
执行为:
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
(chqrlie评论后更正)
格式字符串 "%s"
忽略前导白色 space,因此现在 \n
被忽略,并且 scanf
愉快地等待您的输入。
注意格式字符串" %c"
中的前导space,space是为了让scanf
忽略前导的白色space,你可以用你的第二个 scanf
实现相同的逻辑。您可以确保所有连续的 scanf
忽略缓冲区中剩余的 \n
,事实证明大多数格式说明符都会这样做,或者您可以确保没有 scanf
将其从使用开始像 "<...>%*c"
这样的东西来摆脱它。尽管其中 none 是可靠且一致的方法,并且正如无数次所说,scanf
并非旨在执行此类任务,例如获取用户输入,您应该寻求替代方法。
此外,"%[^\n]s"
中的 s
肯定不符合您的预期。 scanf
的手册页指出
An ordinary character (i.e., one other than white space or '%'). This character must exactly match the next character of input.
如果匹配,scanf
将其丢弃并根据剩余的格式说明符继续解析。如果没有,scanf
停在那里然后 returns。由于它位于您的格式字符串的末尾,因此 return 无论哪种方式,都会对您隐藏潜在的错误。