【问题标题】:C scanf - unknown array sizeC scanf - 未知数组大小
【发布时间】:2014-03-04 07:29:04
【问题描述】:

我想将值(浮点数)读入数组,但我不知道值的数量。

我的意见是这样的

Enter values: 1.24 4.25 1.87 3.45 .... etc

如何将此输入加载到数组中?我知道输入 0 或 EOF 时输入结束。

while(0 or EOF){
   scanf("%f", &variable[i])
   i++;
}

谢谢。

【问题讨论】:

  • 贴出的伪代码哪一部分不起作用?

标签: c scanf


【解决方案1】:

您可以动态分配数组,然后在先前分配的缓冲区已满时为它重新分配内存。请注意,scanf 格式字符串中的转换说明符 %f 读取并丢弃前导空白字符。来自scanf 的手册页 -

scanf 返回成功匹配和分配的项目数 这可能比规定的要少,甚至在发生故障时为零 早期匹配失败。 如果输入结束则返回值 EOF 在第一次成功转换或匹配之前到达 发生故障。

这意味着scanf 仅在遇到EOF 作为第一个输入时才会返回EOF,因为EOF 必须以换行符'\n' 开头,否则它将不起作用(取决于在操作系统上)。这是一个小程序来演示如何做到这一点。

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

int main(void) {
    size_t len = 4;
    float *buf = malloc(len * sizeof *buf);

    if(buf == NULL) {     // check for NULL        
        printf("Not enough memory to allocate.\n");
        return 1;
    }

    size_t i = 0;
    float *temp; // to save buf in case realloc fails

    // read until EOF or matching failure occurs
    // signal the end of input(EOF) by pressing Ctrl+D on *nix
    // and Ctrl+Z on Windows systems

    while(scanf("%f", buf+i) == 1) { 
        i++;
        if(i == len) {               // buf is full
            temp = buf;
            len *= 2;
            buf = realloc(buf, len * sizeof *buf);  // reallocate buf
            if(buf == NULL) {
                printf("Not enough memory to reallocate.\n");
                buf = temp;
                break;
            }
        }
    }

    if(i == 0) {
        printf("No input read\n");
        return 1;
    }

    // process buf

    for(size_t j = 0; j < i; j++) {
        printf("%.2f ", buf[j]);
        // do stuff with buff[j]
    }

    free(buf);
    buf = NULL;

    return 0;
}

【讨论】:

    【解决方案2】:

    我猜你真正关心的是用户要输入的浮点数未知。您可以使用指向浮动的指针,对一些预定义的大小执行 malloc,如果在输入时达到限制,则执行 realloc 以增加内存。在执行 reacloc 时,您需要处理以前接受的数据。

    【讨论】:

      【解决方案3】:

      您需要动态分配数组,因为您在编译时不知道它的大小。

      // INITIAL_SIZE can be the average expected size of your array
      #define INITIAL_SIZE 4
      // size will track the current maximum size of youe array.
      size_t size = INITIAL_SIZE;
      // dynamic allocation for variable
      float* variable = malloc(sizeof(float)*size);
      // check that the allocation happened correctly
      assert(variable != NULL);
      // i contains the current actual size of your array
      int i = 0;
      while (0 or EOF) {
         if (i >= size) {
             // if the array is getting bigger than its max size, resize it.
             size *= 2;
             // This will reallocate enough memory for variable.
             variable = realloc(variable, sizeof(float)*size);
             // check that the allocation happened correctly;
             assert(variable != NULL);
             // (NB: It IS important to affect variable to the result of
             // realloc, you can't simply realloc as in some cases the
             // original pointer will become invalid!)
         }
         scanf("%f", &variable[i])
         i++;
      }
      

      顺便说一句,请注意variable 不是一个很好的变量名。使用描述变量用途的名称。

      EDIT:将 realloc 中的大小更正为 alloc size*2 floats 并避免它严重损坏,正如 unwind 指出的那样。

      【讨论】:

      • -1,请注意size 从“浮点数”转变为“字节数”,这将非常糟糕。检查动态内存分配是否失败也是一个好习惯。此外,将真实代码与明显的伪代码 while(0 or EOF) 行混在一起有点奇怪。
      • 哎呀,已将大小更正为各处的“浮点数”。至于与伪代码的混合,我只是以 OP 的代码为基础,帮助他们找到插入它的位置。
      • 投反对票的人会介意评论他们投反对票的原因吗?
      【解决方案4】:
      i = 0;
      while(scanf("%f", &variable[i])!=-1)
      {   
         i++;
      }
      

      scanfEOF 之后尝试读取时返回-1

      【讨论】:

      • -1,因为如果单次转换失败,它也会返回 0。这将使variable[i] 具有未定义的值,这不是一件令人高兴的事情。
      • 单次转化是什么意思?
      • scanf() 返回成功转换的数量(它处理的%-specifiers 的数量)或EOF。所以你的代码应该期望它返回1,因为在每次调用中都会尝试一次转换。另外,-1 是写EOF 的一种非常糟糕的方式。
      • 好的,知道了。我知道 scanf 返回读取的字节数。感谢您清除它。
      • 不,不是字节。它返回成功的% 转换数。请阅读the manual page
      猜你喜欢
      • 2014-09-14
      • 1970-01-01
      • 1970-01-01
      • 2020-11-13
      • 2013-03-18
      • 1970-01-01
      • 2016-03-03
      • 2014-02-22
      • 2015-04-29
      相关资源
      最近更新 更多