将用户输入存储到数组中并在停止值处终止,而不将该值存储在 C 中

问题描述 投票:0回答:1

我知道如何编写一个 while 循环来读取用户输入,存储到数组中,然后在停止值处终止。但是,该停止值也被存储,我不知道如何让它不这样做。

这是我所拥有的:

printf("Enter temperatures or -100.0 to stop: "); // user input prompt
int i = 0;
while (1) {
  scanf("%f", &temp[i]);     // user input filling array
  if (temp[i] == -100.0) {   // stop loop if input = -100.0
    break;
  }
  i++;
}
c io user-input
1个回答
0
投票

scanf()
man 3 scanf 警告

的联机帮助页

正确使用这些功能是非常困难的,而且 最好使用

fgets(3)
或 getline(3) 读取整行并且 稍后使用
sscanf(3)
或更专业的函数解析它们,例如 作为
strtol(3)

这就是为什么在 StackOverflow 上你会一次又一次地找到 C 语言中用户输入问题的答案,建议

scanf()
不是用户输入的明智选择,使用
fgets()
来阅读整行和从读取的输入行中解析任何需要的值。造成这种情况的原因有很多,但归结为:

  • 如果用户为转换请求类型提供了无效输入,则会发生匹配失败,从
    stdin
    中提取字符将在此时停止,所有导致失败的字符都将留在
    stdin
    中未读,只是等待在您下次尝试输入时咬住您。
  • 即使数字转换成功,
    '\n'
    中也会留下一个
    stdin
    字符,只是等待在下一个输入时再次咬你,不会丢弃前导空格(
    scanf()
    说明符
    "%c"
    "%[..]"
    ,和
    "%n"
    不丢弃前导空格,
    fgets()
    getline()
    - 或任何其他进行输入的系统调用也不丢弃)
  • 必须检查
    scanf()
    的返回来判断输入和转换是否成功
  • 使用
    stdin
    删除剩余字符后,必须清空输入缓冲区 (
    scanf()
    )。
  • 您必须检查
    EOF
    的返回以及检查是否成功以允许用户取消用户输入 - 这也是有效的输入。

使用

fgets()
读取整行用户输入可以避免这些问题,但您仍然需要通过检查
fgets()
返回来进行正确的验证。

除了使用

scanf()
导致的代码问题之外,将 “stopvalue” 包含在
temp[]
数组中的直接问题是因为您使用
scanf()
执行转换为
&temp[i]
,这使得数组中的值,无论它是否是停止值。要解决这个问题,只需声明一个临时变量并用它来保存转换后的值。然后,您可以在将临时值添加到数组之前对照停止值检查临时值。

您遇到的另一个问题是比较停止值的浮点数,例如

if (temp[i] == -100.0)
。距离
-100.0
有多近才算数?您想存储
-100.01
吗?
-100.04
呢?
-99.999
呢?所有这些值都可以比较等于
-100.0
1 通常选择 Magic-Number 作为停止值会出现问题。
fgets()
也为该问题提供了一个简单的解决方案。
fgets()
不使用幻数,而是可以检查无输入,允许用户单独按 Enter 无需输入即可结束输入。这使得所有值都被视为有效温度,而无需制定一个神奇的温度。

使用scanf()

即使有缺点,如果您检查每个所需的条件并注意提取

stdin
中留下的无关字符,您就可以使
scanf()
用于输入。不建议这样做,但你可以这样做:

#include <stdio.h>
#include <math.h>

#define NTEMPS    100   /* if you need a constant, #define one (or more) */
#define STOPV    -100
#define ELIMIT    1.e-4

/* simple function to empty characters left in input stream */
void empty_stdin (void)
{
  int c = getchar();
  
  while (c != '\n' && c != EOF) {
    c = getchar();
  }
}

int main (void) {
  
  float temp[NTEMPS] = { 0 };     /* array to hold temps */
  int i = 0;                      /* counter variable */
  
  /* loop only while space remains in array */
  while (i < NTEMPS) {
    float tmp = 0;                /* temporary value for conversion */
    
    printf ("\nEnter temperatures or %d to stop: ", STOPV);
    fflush (stdout);              /* avoid line-buffering issues */
    
    if (scanf("%f", &tmp) != 1) { /* conversion to float failed */
      
      if (feof (stdin)) {         /* check for manual EOF */
        puts ("  user canceled input.");
        return 0;
      }
      else {  /* othewise empty characters that reamin in stdin unread */
        fputs ("  error: invalid floating-point input.\n", stderr);
        empty_stdin();
      }
      continue;                   /* get next input */
    }
    
    /* check for magic-numer exit condition */
    if (fabs(tmp - STOPV) < ELIMIT) {
      empty_stdin();
      break;
    }
    
    temp[i] = tmp;                /* store converted value in array */
    i++;                          /* increment counter */
  }
  
  /* show output */
  puts ("\nRecorded Temps:\n");
  for (int j = 0; j < i; j++) {
    printf ("temp[%2d] : %.2f\n", j, temp[j]);
  }
}

注意: 使用

-100
周围(在
1.e-4
内)的范围被视为您的神奇止损值。

使用fgets()

不仅建议使用

fgets()
进行用户输入,实际上使用
scanf()
进行所需的所有各种检查和输入缓冲区管理更容易。您所做的不是直接使用
scanf()
进行输入,而是声明一个字符数组来保存用户输入,然后将该数组传递给
sscanf()
,而不是直接使用
scanf()
进行输入。它使事情变得更容易(而且更短),例如

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

#define MAXC    1024    /* if you need a constant, #define one (or more) */
#define NTEMPS   100

int main (void) {
  
  char buf[MAXC] = "";            /* array to hold line of user-input */
  int i = 0;                      /* counter variable */
  float temp[NTEMPS] = { 0 };     /* array to hold temps */
  
  /* loop continually reading input */
  while (1) {
    float tmp;                    /* temporary value for conversion */
    
    /* prompt and flush output (no trailing '\n' in prompt) */
    fputs ("\nEnter temperatures (empty-input to stop) : ", stdout);
    fflush (stdout);
    
    /* read input, check for manual EOF */
    if (fgets (buf, MAXC, stdin) == NULL) {
      puts ("  user canceled input.");
      return 0;
    }
    
    if (buf[0] == '\n') {         /* if Enter pressed with no input */
      break;                      /* done! */
    }
    
    /* validate conversion to float */
    if (sscanf (buf, "%f", &tmp) == 1) {
      temp[i] = tmp;              /* add value to temperature array */
      i++;                        /* increment counter */
    }
    else {  /* otherwise conversion failed, show invalid input */
      buf[strcspn (buf, "\n")] = 0;   /* trim '\n' from string */
      fprintf (stderr, "  error: invalid floating-point input '%s'.\n",
                buf);
    }
  }
  
  /* show output */
  puts ("\nRecorded Temps:\n");
  for (int j = 0; j < i; j++) {
    printf ("temp[%2d] : %.2f\n", j, temp[j]);
  }
}

示例使用/输出

$ ./read-float-arr-fgets

Enter temperatures (empty-input to stop) : 10.8

Enter temperatures (empty-input to stop) : -20.9

Enter temperatures (empty-input to stop) : 59.1

Enter temperatures (empty-input to stop) : 37.4

Enter temperatures (empty-input to stop) : banannas and barbeque sauce
  error: invalid floating-point input 'banannas and barbeque sauce'.

Enter temperatures (empty-input to stop) : -100.2

Enter temperatures (empty-input to stop) : -99.99

Enter temperatures (empty-input to stop) :

Recorded Temps:

temp[ 0] : 10.80
temp[ 1] : -20.90
temp[ 2] : 59.10
temp[ 3] : 37.40
temp[ 4] : -100.20
temp[ 5] : -99.99

尝试在程序中输入

"banannas and barbeque sauce"
,看看会发生什么(提示:手边放 ctrl + c

对于上面的

scanf()
实现,唯一的区别是 stopvalue 行,如下所示:

Enter temperatures or -100 to stop: -100.0001

花时间浏览每个示例并查找所使用的每个函数,并理解为什么需要这样做来创建一个相当强大的输入例程。如果您还有其他问题,请在下面发表评论,我很乐意为您提供进一步帮助。

脚注:

  1. 浮点数学是否被破坏?为什么浮点数不准确?浮点比较
    a != 0.7
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.