首页 文章

如何声明未定义或没有初始大小的数组?

提问于
浏览
27

我知道可以使用malloc完成,但我还不知道如何使用它 .

例如,我希望用户使用带有哨兵的无限循环来输入几个数字以阻止它(即-1),但由于我不知道他/她将输入多少,我必须声明一个没有初始大小的数组,但我也知道它不会像这样的int arr [];在编译时,因为它必须有一定数量的元素 .

用夸张的大小来声明它像int arr [1000];会工作,但感觉愚蠢(并浪费内存,因为它会将1000个整数字节分配到内存中),我想知道更优雅的方式来做到这一点 .

7 回答

  • 1

    malloc() (及其朋友 free()realloc() )是用C做到这一点的方法 .

  • 1

    这可以通过使用指针,并使用 malloc 在堆上分配内存来完成 . 请注意,以后无法询问内存块有多大 . 您必须自己跟踪阵列大小 .

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char** argv)
    {
      /* declare a pointer do an integer */
      int *data; 
      /* we also have to keep track of how big our array is - I use 50 as an example*/
      const int datacount = 50;
      data = malloc(sizeof(int) * datacount); /* allocate memory for 50 int's */
      if (!data) { /* If data == 0 after the call to malloc, allocation failed for some reason */
        perror("Error allocating memory");
        abort();
      }
      /* at this point, we know that data points to a valid block of memory.
         Remember, however, that this memory is not initialized in any way -- it contains garbage.
         Let's start by clearing it. */
      memset(data, 0, sizeof(int)*datacount);
      /* now our array contains all zeroes. */
      data[0] = 1;
      data[2] = 15;
      data[49] = 66; /* the last element in our array, since we start counting from 0 */
      /* Loop through the array, printing out the values (mostly zeroes, but even so) */
      for(int i = 0; i < datacount; ++i) {
        printf("Element %d: %d\n", i, data[i]);
      }
    }
    

    而已 . 接下来是一个更为复杂的解释为什么这个工作:)

    我不知道你对C指针的了解程度如何,但C中的数组访问(如 array[2] )实际上是通过指针访问内存的简写 . 要访问 data 指向的内存,请编写 *data . 这称为解除引用指针 . 由于 data 的类型为 int * ,因此 *data 的类型为 int . 现在来看一条重要的信息: (data + 2) 表示“将2个字节的字节大小添加到 data 指向的地址” .

    C中的数组只是相邻内存中的一系列值 . array[1] 紧挨着 array[0] . 因此,当我们分配一大块内存并希望将其用作数组时,我们需要一种简单的方法来获取内部每个元素的直接地址 . 幸运的是,C允许我们在指针上使用数组表示法 . data[0] 表示与 *(data+0) 相同的内容,即“访问 data 指向的内存” . data[2] 表示 *(data+2) ,并访问内存块中的第三个 int .

  • 30

    它经常做的方式如下:

    • 分配一些初始(相当小)的数组;

    • 读入此数组,跟踪您已阅读的元素数量;

    • 一旦数组已满,重新分配,大小加倍并保留(即复制)内容;

    • 重复直到完成 .

    我发现这种模式经常出现 .

    这个方法的有趣之处在于它允许人们在摊销的 O(N) 时间内逐个将 N 元素插入到一个空数组中而不事先知道 N .

  • 2

    现代C,又名C99,有variable length arrays,VLA . 不幸的是,并非所有的编译器都支持这一点,但如果你的确支持这一点,那么这将是另

  • 5

    这是一个示例程序,它将 stdin 读入一个根据需要增长的内存缓冲区 . 在实际程序中,'s simple enough that it should give some insight in how you might handle this kind of thing. One thing that'可能会有不同的做法,即每次分配时数组必须如何增长 - 如果你想在调试器中逐步完成,我会在这里保持较小的数据以帮助保持简单 . 一个真正的程序可能会使用一个更大的分配增量(通常,分配大小加倍,但如果你在某个合理的大小上限 - 增加 - 当你进入数百兆字节时加倍分配可能没有意义) .

    此外,我在这里使用了对缓冲区的索引访问作为示例,但在实际程序中我可能不会这样做 .

    #include <stdlib.h>
    #include <stdio.h>
    
    
    void fatal_error(void);
    
    int main( int argc, char** argv)
    {
        int buf_size = 0;
        int buf_used = 0;
    
        char* buf = NULL;
        char* tmp = NULL;    
    
        char c;
        int i = 0;
    
        while ((c = getchar()) != EOF) {
            if (buf_used == buf_size) {
                 //need more space in the array
    
                 buf_size += 20;
                 tmp = realloc(buf, buf_size); // get a new larger array
                 if (!tmp) fatal_error();
    
                 buf = tmp;
            }
    
            buf[buf_used] = c; // pointer can be indexed like an array
            ++buf_used;
        }
    
        puts("\n\n*** Dump of stdin ***\n");
    
        for (i = 0; i < buf_used; ++i) {
            putchar(buf[i]);
        }
    
        free(buf);
    
        return 0;
    }
    
    void fatal_error(void)
    {
        fputs("fatal error - out of memory\n", stderr);
        exit(1);
    }
    

    此示例与其他答案中的示例相结合,可以让您了解如何在较低级别处理此类事物 .

  • 12

    我可以想象的一种方法是使用链表来实现这样的场景,如果你需要在用户输入指示循环终止的东西之前输入的所有数字 . (作为第一个选项发布,因为从来没有为用户输入做过这个,它似乎很有趣. Wasteful but artistic

    另一种方法是进行缓冲输入 . 如果循环继续,则分配缓冲区,填充,重新分配( not elegant, but the most rational for the given use-case ) .

    我不认为所描述的是优雅的 . 可能,我会更改用例( the most rational ) .

  • 0

    尝试实现动态数据结构,例如linked list

相关问题