如何在C语言中使用scanf读取单个字符

139

在C语言中:

我正在尝试使用scanf从用户获取字符,但运行程序时它不等待用户输入任何内容...

这是代码:

char ch;
printf("Enter one char");
scanf("%c", &ch);
printf("%c\n",ch);

为什么它不起作用?


2
仅澄清一下,如果C程序仅包含上述代码,则它将按预期工作。像OP提到的那样可能出现的问题只有在与其他I/O代码一起使用时才会出现,原因在P.P的答案中提到。 - forumulator
11个回答

304

%c转换说明符不会自动跳过任何前导空格,因此如果输入流中有任何杂散的换行符(例如来自先前输入的条目),则scanf调用将立即将其消耗掉。

解决这个问题的一种方法是在格式字符串中在转换说明符之前放置一个空格:

scanf(" %c", &c);

在格式字符串中的空格会告诉 scanf 跳过前导空格,而第一个非空白字符将由 %c 转换说明符读入。


37
首先,避免使用 scanf()。使用它是不值得的痛苦。
参见:为什么大家都说不要使用 scanf?应该使用什么代替?scanf() 中使用空格字符将忽略输入流中剩余的任意数量的空格字符,如果您需要读取更多的输入,怎么办?考虑以下情况:
#include <stdio.h>

int main(void)
{
   char ch1, ch2;

   scanf("%c", &ch1);  /* Leaves the newline in the input */
   scanf(" %c", &ch2); /* The leading whitespace ensures it's the
                          previous newline is ignored */
   printf("ch1: %c, ch2: %c\n", ch1, ch2);

   /* All good so far */

   char ch3;
   scanf("%c", &ch3); /* Doesn't read input due to the same problem */
   printf("ch3: %c\n", ch3);

   return 0;
}

虽然第3个scanf()可以通过在前面加一个空格来解决,但并不总是像上面那样简单。 另一个主要问题是,scanf()如果输入不符合格式,则不会丢弃输入流中的任何内容。例如,如果您为像scanf("%d", &int_var);这样的int输入了abc,那么必须读取并丢弃abc。请考虑:

#include <stdio.h>

int main(void)
{
    int i;

    while(1) {
        if (scanf("%d", &i) != 1) { /* Input "abc" */
            printf("Invalid input. Try again\n");
        } else {
            break;
        }
    }

    printf("Int read: %d\n", i);
    return 0;
}

另一个常见的问题是混合使用scanf()fgets()。请考虑以下代码:

#include <stdio.h>

int main(void)
{
    int age;
    char name[256];
    printf("Input your age:");
    scanf("%d", &age); /* Input 10 */
    printf("Input your full name [firstname lastname]");
    fgets(name, sizeof name, stdin); /* Doesn't read! */
    return 0;
}

由于上一次 scanf() 调用留下的换行符被读取,所以调用 fgets() 不会等待输入。当遇到换行符时,fgets() 终止输入读取。

scanf() 存在许多类似的问题。这就是为什么通常建议避免使用它的原因。

那么,有什么替代方法吗?请使用以下方式使用fgets()函数来读取单个字符:

#include <stdio.h>

int main(void)
{
    char line[256];
    char ch;

    if (fgets(line, sizeof line, stdin) == NULL) {
        printf("Input error.\n");
        exit(1);
    }

    ch = line[0];
    printf("Character read: %c\n", ch);
    return 0;
}

使用 fgets() 时需要注意一点,如果输入缓冲区有足够的空间,它将读入换行符。 如果不希望出现此情况,则可以将其删除:

char line[256];

if (fgets(line, sizeof line, stdin) == NULL) {
    printf("Input error.\n");
    exit(1);
}

line[strcpsn(line, "\n")] = 0; /* removes the trailing newline, if present */

11

这对我来说有效,请尝试一下

int main(){
char c;
scanf(" %c",&c);
printf("%c",c);
return 0;
}

2
现在这很疯狂!你能解释一下为什么在%c前面加空格会有所不同吗? - Max Coplan
2
已解决:查看 这些 内容 - Max Coplan
3
这似乎没有比2012年被接受的答案提供更多信息。 - domsson

5

我想分享一个类似的事情,

在使用Visual Studio时可能会遇到以下错误:

'scanf':函数或变量可能不安全。考虑改用 scanf_s。要禁用过时警告,请使用 _CRT_SECURE_NO_WARNINGS

为了避免这种情况,您应该按照以下格式编写代码:

读入单个字符的代码示例如下:

char c;
scanf_s("%c", &c, 1);

当读取非空结尾字符串的多个字符时,使用整数作为宽度规范和缓冲区大小。

char c[4];
scanf_s("%4c", &c, _countof(c));

似乎对我不起作用。 在Deitel0805.exe中未处理的异常0x799AF2F6(ucrtbased.dll):向将无效参数视为致命错误的函数传递了无效参数。#include <stdio.h> #include <ctype.h>int main() { char c; printf("%s", "请输入一个字符:"); scanf_s("%c", &c, 1);return 0;} - Besuglov Sergey

3

无论是fgets还是getchar都不能解决这个问题。唯一的解决办法是在使用scanf时,在%c之前保留一个空格。

以下示例中,即使使用fgets也不起作用。

scanf(" %c",ch); //可以正常工作
char line[256];
char ch;
int i;

printf("Enter a num : ");
scanf("%d",&i);
printf("Enter a char : ");

if (fgets(line, sizeof line, stdin) == NULL) {
    printf("Input error.\n");
    exit(1);
}

ch = line[0];
printf("Character read: %c\n", ch);

2

对我有效的唯一代码是:

scanf(" %c",&c);

我也遇到了同样的问题,只有单个字符有这个问题。经过一个小时的随机测试,我还没有报告任何问题。人们会认为C语言现在应该有一种防弹函数来从键盘中检索单个字符,而不是一堆可能的变通方法...只是说说而已...


4
这个问题实际上想要表达的是,这个回答试图如何比旧的、已有的回答更有价值? - tripleee
1
实际上,在阅读整个线程后,我不得不得出结论,这里没有明确的答案...只有解决方法。 - edmanicom

1

尝试使用 getchar(); 替代

语法:

void main() {
    char ch;
    ch = getchar();
}

-1
在使用scanf之前,加上fflush(stdin);以清除缓冲区。

14
根据C标准,fflush(stdin);未定义行为 - P.P
这不是正确的,fflush(stdin) 是 UB,在许多 SO 的问题中提到。 - danglingpointer
它可以与微软编译器一起使用,但仅限于此。 - WENDYN

-2
使用字符串(string)代替字符(char),例如:
char c[10];
scanf ("%s", c);

我相信它工作得很好。


6
这个回答并没有解答问题,因为原帖作者想要使用 scanf 函数读取_单个字符_,而不是一串字符。 - ForceBru

-3

在%c转换说明符之前提供一个空格,以便编译器忽略空格。程序可以编写如下:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char ch;
    printf("Enter one char");
    scanf(" %c", &ch); /*Space is given before %c*/
    printf("%c\n",ch);
return 0;
}

20
这是两年前John Bode提出的同样建议。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接