【问题标题】:can size of array be determined at run time in c?可以在c中的运行时确定数组的大小吗?
【发布时间】:2010-12-13 05:25:09
【问题描述】:

据我所知,在 c 中编译时间之前,数组需要具有特定的大小。

我想知道为什么这段代码仍然有效?

int s;
printf("enter the array size: ");
scanf("%d",&s);

int a[s]; // Isn't s value determined at run time?

【问题讨论】:

    标签: c arrays memory-management size definition


    【解决方案1】:

    如果你需要分配一个动态大小的数组,你必须使用 malloc() 从堆中获取它。

    int *a = malloc(sizeof(int) * s)
    

    【讨论】:

    • 如果您放弃(int*) 演员表,如果您忘记包含定义malloc 的文件,编译器将生成错误。因此,最好不要包含演员表。
    • int *a = malloc(s * sizeof *a)
    【解决方案2】:

    Variable Length ArraysC99 以来一直是 C 语言的一部分。 但它们已在C11 中作为可选功能提供 - 这意味着符合 C11 的实现不需要提供它(尽管实际上所有支持 C99 的实现都肯定在 C11 中提供 VLA)。

    您可以使用宏 __STDC_NO_VLA__ 来检查您的实现是否不提供 VLA(如果它是在 C99 或 C11 编译模式下定义的,那么您的实现不支持 VLA)。

    因此,在现代 C (>= C99) 中可以在运行时确定数组大小,并且类似下面的代码很好:

    int s;
    printf("Enter the array size: ");
    scanf("%d", &s);
    int a[s];
    

    VLA 的一个明显缺点是,如果s 很大,a 的分配可能会失败。更糟糕的是,无法检查分配是否失败,并且您会遇到运行时错误(例如,segfault)。它本质上是undefined behaviour。所以如果数组太大,你要避免使用 VLA。基本上,如果有疑问,请使用动态内存分配(见下文)。

    另一个问题,与其他相比,VLA 的严重性要小得多,是它们具有自动存储持续时间(也称为“堆栈分配”)。因此,如果您想要持续更长时间的东西,然后是声明 VLA 的 块范围,那么 VLA 没有帮助。

    同样相关的是C89 中没有 VLA。所以使用动态内存分配是唯一的方法。虽然,有一些非标准的扩展,例如alloca(),它类似于VLA,并且与VLA有相同的缺点)。

    int s;
    printf("enter the array size: ");
    scanf("%d",&s);
    int *a = malloc(s * sizeof *a);
    ...
    free(a);
    

    【讨论】:

      【解决方案3】:

      了解编译器如何将内存分配给变量以正确回答您的问题非常重要。内存分配给变量有两种模式,可以在堆上,也可以在栈上。堆上的内存是动态分配的。因此,在堆上分配内存的变量可以在运行时指定其大小。

      在 C 的情况下,数组在堆栈上被赋予内存。为了在堆栈上提供内存,编译器在编译期间应该知道内存的大小。因此,在运行期间,可以为堆栈上的变量留出大量内存。这就是就 C 语言而言,您无法在运行时决定数组大小的原因。

      【讨论】:

      • 在堆栈上分配内存只是调整堆栈指针的问题 - 堆栈指针只能通过编译时已知的值来调整的根本原因是no .事实上,最新的 C 标准允许自动变量的大小在运行时确定,并且还有一个公共扩展 alloca()那个 之前的几年中提供了相同的东西。
      【解决方案4】:

      此代码受 C99 语言规范支持。 C89/90 模式下的 GCC 编译器也支持此代码作为扩展。

      因此,您的问题(为什么“有效”)的答案取决于您如何编译它。在一般情况下,这甚至不会被 C89/90 编译器编译。

      【讨论】:

        【解决方案5】:

        你在这里混淆了两件事。

        1) 确定已分配数组的大小(您的标题暗示):将 sizeof() 的总数除以一个(例如,第一个)元素的大小:

         sizeof(a)/sizeof(a[0])
        

        2) 根据您的问题动态分配内存:

         int *a = (int*)malloc( s * sizeof(int) );
        

        【讨论】:

        • sizeof(a)/sizeof(a[0]) 在编译时确定数组的大小,而不是在运行时确定数组的大小,如果它像数组声明一样在堆栈上分配。
        【解决方案6】:

        数组大小需要知道 ANSI 89 C。99 版本的规范消除了这个限制并允许可变大小的数组。

        这是该功能的 GNU 版本的文档

        【讨论】:

        • 哦,我明白了。谢谢。所以数组的所有元素仍然位于堆栈上?
        • 是的,他们是。如果这不好,请按照其他答案中的建议使用 malloc。
        • @JaredPar 链接已损坏。
        猜你喜欢
        • 1970-01-01
        • 2013-12-04
        • 2010-12-08
        • 1970-01-01
        • 2015-11-19
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        • 2016-07-15
        相关资源
        最近更新 更多