使用scanf接受用户输入

时间:2010-01-27 03:54:05

标签: c

gcc 4.4.2

我正在阅读一篇关于scanf的文章。我个人从未检查过scanf的返回码。

#include <stdio.h>

int main(void)
{
  char buf[64];
  if(1 == scanf("%63s", buf))
  {
    printf("Hello %s\n", buf);
  }
  else
  {
    fprintf(stderr, "Input error.\n");
  }
  return 0;
}

我只是想知道当程序员在想要获得用户输入时使用scanf时会遇到的其他技术?或者他们是使用其他功能还是自己编写?

感谢您的任何建议,

编辑=========

#include <stdio.h>

int main(void)
{
    char input_buf[64] = {0};
    char data[64] = {0};

    printf("Enter something: ");
    while( fgets(input_buf, sizeof(input_buf), stdin) == NULL )
    {
    /* parse the input entered */
    sscanf(input_buf, "%s", data);
    }

    printf("Input [ %s ]\n", data);

    return 0;
}

我认为大多数程序员都认为scanf很糟糕,大多数人同意使用fgets和sscanf。但是,我可以使用fgets来读取输入。但是,如果我不知道用户将输入什么,我怎么知道要解析什么。例如,如果用户输入的地址包含数字和字符,并且按任何顺序?

5 个答案:

答案 0 :(得分:6)

请勿直接使用scanf。使用起来非常困难。最好读取整行输入然后解析它(可能使用sscanf)。

从comp.lang.c FAQ中读取此条目(以及它引用的条目): http://c-faq.com/stdio/scanfprobs.html

编辑: 好的,要从您自己的编辑中解决您的其他问题:如果您允许非结构化输入,那么您将不得不尝试以多种方式解析字符串,直到找到有效的字符串。如果找不到有效匹配,则应拒绝输入并再次提示用户,可能会解释您希望输入的格式。

对于任何更复杂的事情,你可能最好使用正则表达式库,甚至使用专用词法分析器/解析器工具包(例如flex和bison)。

答案 1 :(得分:5)

我不使用scanf()进行交互式用户输入;我使用fgets()将所有内容都作为文本阅读,然后根据需要解析输入,使用strtol()strtod()将文本转换为数字值。

scanf()落入的一个例子是当用户输入错误的数字值,但其初始部分有效时,如下所示:

if (scanf("%d", &num) == 1)
{
  // process num
}
else
{
  // handle error
}

如果用户输入“12e4”,scanf()将成功转换并将“12”分配给num,在输入流中留下“e4”以填写将来的读数。 整个输入应被视为伪造,但scanf()无法捕获此类错误。 OTOH,如果我做的话:

if (fgets(buffer, sizeof buffer, stdin))
{
  int val;
  char *chk;
  val = (int) strtol(buffer, &chk, 10);
  if (!isspace(*chk) && *chk != 0)
  {
    // non-numeric character in input; reject it completely
  }
  else
  {
    // process val
  }
}

我可以捕获输入中的错误并在使用它的任何部分之前拒绝它。这也可以更好地避免在输入流中留下垃圾。

scanf()是一个很棒的工具,如果,您可以保证您的输入始终是格式良好的。

答案 2 :(得分:2)

scanf()有问题,因为如果要求用户键入一个整数,并输入一个字符串,那么程序通常会发生炸弹。这可以通过将所有输入作为字符串读取(使用getchar()),然后将字符串转换为正确的数据类型来克服。

/* example one, to read a word at a time */
#include <stdio.h>
#include <ctype.h>
#define MAXBUFFERSIZE   80

void cleartoendofline( void );  /* ANSI function prototype */

void cleartoendofline( void )
{
    char ch;
    ch = getchar();
    while( ch != '\n' )
        ch = getchar();
}

main()
{
    char    ch;                     /* handles user input */
    char    buffer[MAXBUFFERSIZE];  /* sufficient to handle one line */
    int     char_count;             /* number of characters read for this line */
    int     exit_flag = 0;
    int     valid_choice;

    while( exit_flag  == 0 ) {
        printf("Enter a line of text (<80 chars)\n");
        ch = getchar();
        char_count = 0;
        while( (ch != '\n')  &&  (char_count < MAXBUFFERSIZE)) {
            buffer[char_count++] = ch;
            ch = getchar();
        }
        buffer[char_count] = 0x00;      /* null terminate buffer */
        printf("\nThe line you entered was:\n");
        printf("%s\n", buffer);

        valid_choice = 0;
        while( valid_choice == 0 ) {
            printf("Continue (Y/N)?\n");
            scanf(" %c", &ch );
            ch = toupper( ch );
            if((ch == 'Y') || (ch == 'N') )
                valid_choice = 1;
            else
                printf("\007Error: Invalid choice\n");
            cleartoendofline();
        }
        if( ch == 'N' ) exit_flag = 1;
    }
}

答案 3 :(得分:1)

我循环调用fgets直到读取行的末尾,然后调用sscanf来解析数据。检查sscanf是否到达输入行的末尾是个好主意。

答案 4 :(得分:1)

我很少使用scanf。大多数时候,我使用fgets()将数据作为字符串读取。然后,根据需要,我可以使用sscanf()或其他函数,例如strto*函数族,str*chr()等,从字符串中获取数据。

如果我使用scanf()fgets() + sscanf(),我总是检查函数的返回值,以确保它们执行我想要的操作做。我也不使用strtok()来标记字符串,因为我认为strtok()的界面已被破坏。