Scanf被忽略了,如何预防?

时间:2014-10-03 19:04:44

标签: c

我收到了这段代码:

#include <stdio.h>

int main(void){
    char ordet;
    int again = 1;

    while(again == 1){
        printf("Write a name: \n");

        while (ordet!='\n'){
            scanf("%c",&ordet);
            if('A'<= ordet && ordet <='W')
            {
                printf("%c",ordet+3);
            }

            else if('W'<=ordet){
                printf("%c", ordet-22);
            }
        }
        printf("\nDo you want to write a new name? 1/0");
        scanf("%d", &again);
    }
    return 0;
}

它第一次运行正常但是只要你按1来写一个新名字你就永远没有机会写它,它只是不断询问&#34;你想写一个新名字吗?&#34 ;并忽略&#34;写一个名字:&#34;。我已经测试了fflush(stdin),!= EFO和%c前面的空间,但没有任何效果。我怎么能解决这个问题,因为我真的不知道,几天前从C开始。

3 个答案:

答案 0 :(得分:3)

您的代码有两个问题:

  1. ordet在首次使用之前未初始化。这是未定义的行为。

  2. 您不会在内循环之外的任何位置重置ordet。也就是说,一旦ordet变得等于\n,内循环的主体就再也不会被执行。

  3. 要解决此问题,您可以在内循环之前编写类似ordet = 0的内容。并且在阅读again变量后,不要忘记跳过缓冲区中留下的新行字符。

答案 1 :(得分:3)

    while (ordet!='\n'){

ordet在没有初始化的情况下使用。 Not quite UB(如果您的实施使用未签名的char或签名的char没有陷阱表示),但已经足够糟糕了。

        scanf("%c",&ordet);

以上行是唯一可能设置ordet 的行。请注意,仅当ordet不是'\n'时才会输入以它开头的循环 您可能希望在进入内循环之前重置它,或使用do-while-loop 实际上,将两个循环更改为do-while-loops都会很好。

    scanf("%d", &again);

以上一行从stdin开头读取一个数字,但保留换行符

这必须通过重复使用所有空格来处理 幸运的是,当内循环忽略空格时,这很容易完成 将"%c"更改为" %c"

此外,您的所有scanf - 调用都可能失败。检查一下!

答案 2 :(得分:1)

您从键盘在控制台中写入的所有输入都放在缓冲区中,scanf从此缓冲区读取,但是如果缓冲区中的字符数多于格式说明符指定的那些字符将保留在缓冲区中。

e.g。

scanf( "%d", &n );

当你输入一个数字值100然后按ENTER键时,当你在缓冲区(stdin)上执行scanf时,将ENTER字符放在缓冲区中“100 \ n”,从缓冲区中提取100但是n仍然存在。

下次你写scanf(“%d”,&amp; n); \ n仍然在那里,%d不会读取,因为它不是%d号。

IMO处理此问题的最佳方法是使用fgets从键盘读取,然后在读取内容后使用sscanf提取所需信息:

char buffer[128];
fgets( buffer, sizeof(buffer), stdin );
sscanf( buffer, "%d", &n );

然后您还可以进行其他错误检查:

if (fgets( buffer, sizeof(buffer), stdin ) != NULL )
{
  if (sscanf( buffer, "%d", &n ) ==1)
  {
  ...
  }
}

现在代码:

如果你想从键盘上逐个字符地阅读,请使用fgetc()而不是scanf() 使用C运行时函数isalpha()/ toupper()来识别字符。 在C中,一个字符是一个int,这就是为什么大多数函数如fgetc返回一个int而不是一个char。

一般情况下,我建议使用fgets(),而不是一次只读一个字符。