为什么跳过 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 无论哪种方式,都会对您隐藏潜在的错误。