【问题标题】:Trouble: C Declaration of integer array of unknown size问题:C 声明未知大小的整数数组
【发布时间】:2016-10-22 14:11:38
【问题描述】:

我需要使用scanf 函数读取用户输入的未知数量的各种数字。这仅仅意味着各种整数的数量由用户通过发送尽可能多的数字来确定。请注意,我直接读取数字(我必须),如以下代码所述:

int main(void)
{
    int numbers[];
    int error = 0;

    int i = 0;
    while(scanf("%i", &numbers[i++]) == 1);

    for(int i = 0; i < sizeof(numbers) - 1; ++i) {
        if(numbers[i] < -10000 || numbers[i] > 10000)
        {
            printf("%i%s", numbers[i], ", ");
        }
        else
        {
            printf("%s", "\b\b\nError: Error: Vstup je mimo interval!\n");
            // Means "Input is out of range!".
            // We have to write exact output to terminal as stated in HW.
            i = sizeof(numbers);
            error = 1;
        }
    }

    ...
}

int error实际上是一个布尔值,但是我懒得实现布尔库,所以我将它定义为整数:D

但是,问题出在其他地方。编译器给我一个错误:

main.c:7:9: error: array size missing in ‘numbers’
     int numbers[];
                ^

看起来 C 程序需要知道数组的可分配大小。我已经查看了其他人在那里共享的一些代码,以找出我需要实现的基础知识,在搜索数组大小问题时,我发现了这个问题:

C - Declaring an array with an undefined value

但是,对于直接输入未知数量的数字,它并不能解决数组大小未知的问题。我没有找到我需要解决的地方。我试图定义数组的最大大小以容纳最多 999 个数字,但是编译器向我抛出了这个异常:

main.c:50:23: error: iteration 999u invokes undefined behavior [-Werror=aggressive-loop-optimizations]
             if(numbers[j] > 0)
                       ^
main.c:48:9: note: containing loop
         for(int j = 0; j < sizeof(numbers); ++j)
         ^

用于数字统计的每个循环都相同(总数、最大值、最小值、赔率、偶数、正数、负数、它们的百分比和平均值)。这意味着该数组的大小严格为 999 个数字,其余数字为零。我发现了一个malloc 函数,但不明白它的用法:(

【问题讨论】:

  • 另外,C99 在stdbool.h 中提供了布尔类型_Bool
  • @JohnBode:严格来说,C99 提供了_Bool 类型,即使没有&lt;stdbool.h&gt; 标头;标头提供booltruefalse(和__bool_true_false_are_defined)。但您的主要观点是 C99 支持布尔类型,这是正确的。
  • 请注意,sizeof() 返回一个以字节为单位的大小。如果它适用于您的数组(如果您的数组定义有效),那么or(int j = 0; j &lt; sizeof(numbers); ++j) 将尝试将sizeof(int) 索引到数组中的时间太远。如果您显示第二批代码会更好,但您似乎定义了 int numbers[999]; 只能使用值 0..998 进行索引,但如果 sizeof(int) == 4 (最常见的大小),那么您的循环会尝试索引元素 999 .. 3995,但数组中都不存在这些元素。因此编译器警告。
  • C 中没有机制可以在单个 I/O 操作中读取不定数量的整数。您必须提前知道该数字,或者一次迭代读取一些适当的较小数字集(例如,一次一个)。您可以编写一个函数来完成这项工作。除了 EOF 之外,还应该如何检测输入的结尾?有几种方法可以告诉您何时需要退出循环:EOF、非数字输入、先前计数——我错过了吗?我想,哨兵值(例如 -999999)是“非数字输入”的变体——它是数字但具有特殊含义。
  • 这正是动态分配的用途,在 C 中,您使用 malloc()(或 calloc())来执行动态分配。你能解释一下你对malloc()的不理解吗?

标签: c arrays compiler-errors


【解决方案1】:

“我需要使用 scanf 函数读取用户输入的未知数量的各种数字。”是一个糟糕的设计目标。

任何允许外部接口无限制地输入任意量输入的程序都是黑客攻击。

健壮的代码将用户输入限制在慷慨但合理的输入量。好的代码会将上限编码为常量或宏。

使用scanf() 并不是读取用户输入的最佳工具。
推荐fgets() 阅读。 (此处未显示。)

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

// find the next character without consuming it.
int peek_ch(void) {
  unsigned char ch;
  if (scanf("%c", &ch) == 1) {
    ungetc(ch, stdin);
    return ch;
  }
  return EOF;
}

#define INPUT_N 1000
void foo(void) {
  int input[INPUT_N];
  size_t n = 0;

  // Read 1 _line_ of input using `scanf("%d", ....)` to read one `int` at a time
  for (n = 0; n < INPUT_N; n++) {
    int ch;
    while (((ch = peek_ch()) != '\n') && isspace(ch))
      ;
    // %d consume leading white-space including \n, hence the above code to find it.
    if (scanf("%d", &input[n]) != 1) {
      break;
    }
  }

  // TBD: Add code to handle case when n == N

  for (size_t i = 0; i < n; i++) {
    printf("%zu: %d\n", i, input[i]);
  }
}

【讨论】:

    【解决方案2】:

    根据您在 cmets 中的描述,您将不得不使用 malloc 动态分配内存,并根据需要使用 realloc 扩展它。

    这是一个示例的基本框架:

    #define INITIAL_SIZE 1024
    
    #include <stdlib.h>
    #include <stdio.h>
    
    int main( void )
    {
      size_t arraySize = 0;
      size_t i = 0;
    
      // initially allocate numbers array
      int *numbers = malloc( sizeof *numbers * INITIAL_SIZE );
      if ( !numbers )
      {
        fprintf( stderr, "Error allocating memory...exiting\n" );
        exit( EXIT_FAILURE );
      }
    
      arraySize = INITIAL_SIZE;
      int input;
      while ( scanf( "%d", &input ) == 1 )
      { 
        if ( i == arraySize )
        {
          // double the size of the numbers array
          int *tmp = realloc( numbers, sizeof *numbers * (2 * arraySize) );
          if ( !tmp )
          {
            fprintf( stderr, "Could not extend array size...no more inputs allowed\n" );
            break;
          }
          numbers = tmp;
          arraySize *= 2;
        }
        numbers[i++] = input;
      }
    
      // process numbers
      ...
      // clean up after ourselves
      free( numbers );
    

    【讨论】:

      【解决方案3】:

      感谢大家的帮助,我真的很感激。它帮助了我,虽然我真正需要的不是一个解决方案,而是略有不同。如上面评论所述,我只需要满足作业输入和输出要求。我联系了我的教授,他建议我摆脱整数数组并将初始数字列表输出和所有计算进度包含在 while 循环中。如果在所有最终输出中未发生错误,则百分比和平均总和的最终计算将包含在if 条件测试中。但是,这不会被标记为解决问题的答案,因为它在这里确实对我有很大帮助。但是我将 chux 标记为答案,因为它非常合乎逻辑,并且任何程序都应该通过缓冲区溢出来防止恶意软件利用。再次感谢大家的帮助,我真的很感激:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-17
        • 1970-01-01
        相关资源
        最近更新 更多