我不知道应该用scanf输入多少个数字

时间:2015-05-06 13:41:12

标签: c scanf

我无法确定在主程序中输入多少个数字。 例如,我可能在数组中输入一个或两个数字。

float p[1];
for (int z = 0 ; z <=1 ; z++)
{
    scanf("%f",&p[z]);
}

在这段代码中,如果我只输入一个数字,for循环将继续运行,直到我输入另一个数字。 我该怎么办?

1 个答案:

答案 0 :(得分:3)

通常,用户必须告诉程序没有更多输入,通常是通过执行以下操作之一:

  • 输入一个超出预期值范围的值(例如,如果您希望所有输入都大于0,则输入值0可能表示结束输入)。这通常不是最实用的方法,特别是对于浮点输入。

  • 从键盘发出文件结束信号。在Linux上,通过键入Ctrl-D来完成此操作,而在Windows上则通过键入Ctrl-Z来完成。这种方法的优点是它适用于交互式输入和基于文件的输入。

scanf函数返回成功转换和分配的次数;如果输入与转换说明符不匹配,则返回0,在文件结束或错误时返回EOF。这导致了如下逻辑:

float p[N]; // for some number N
size_t z = 0;

while ( z < N && scanf( "%f", &p[z] ) == 1 )
  z++;

首先检查以确保z小于N;如果是这样,它将尝试将下一个输入读入p[z]。如果读取成功(1次成功转换和分配),它将递增z并再次循环。

如果读取失败(由于EOF或输入错误),它将退出循环。

修改

如果您在一行上输入多个值,另一种方法是将输入作为一行文本读取,然后解析出单个数字。这是一个例子:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main( void )
{
  char input[SIZE+1]; // for some size SIZE, single line of text input, 
                      // +1 for 0 terminator
  float p[N];         // for some size N
  size_t z = 0;

  /** 
   * Instead of scanf, use fgets to read a line of input
   * from the input stream.  Go until z == N or 
   * there's no more input.
   */
  while( z < N && fgets( input, sizeof input, stdin ) != NULL )
  {
    const char *delimiter = " \t";

    /**
     * Break the input line into *tokens* separated by spaces or tabs
     * (note that this modifies the input buffer by overwriting
     * space and tab characters with 0)
     */
    char *token = strtok( input, delimiter );

    /**
     * Loop while z < N and token is not NULL.
     */
    while ( z < N && token )
    {
      char *chk = NULL;

      /**
       * Convert the token (which is a string) to the 
       * equivalent floating-point value.  If the token
       * contains any characters that don't belong in a
       * floating-point constant, the chk variable will be
       * set to point to that character.
       */
      double val = strtod( token, &chk );

      /**
       * On a successful conversion, chk should point to either
       * a whitespace character or the 0 terminator. 
       */
      if ( *chk != 0 && !isspace( *chk ))
      {
        /**
         * For this example we simply discard the bad input and keep processing
         */
        fprintf( stderr, "%s is not a valid float value - discarding\n", token );
      }
      else
      {
        p[z++] = value;
      }
      /**
       * NULL tells strtok to keep reading from the end of the
       * previous token in the buffer
       */
      token = strtok( NULL, delimiter );
    }
  }
  /**
   * Do something interesting with your p array
   */

  return 0;
}

这样,如果您输入数据

1.0 2.0 3.0 4.0 ...

此代码将处理每个输入,直到它到达输入的末尾。

在此示例中未处理的一个边缘条件是,如果输入行大于SIZE个字符,则最终会拆分标记。换句话说,您的缓冲区大小可以容纳80个字符,但最终输入90个字符,并且您的一个输入跨越了该边界。有几种方法可以解决这个问题,但我试图让这个例子尽可能简单。

如果你因为C中的交互式输入处理繁琐且容易出错而留下这个印象,那么你是对的。它是。我之前应该提到的一点是scanf不是处理交互式输入的好工具;它缺少上面代码中的一些错误处理能力。