【问题标题】:Changing the size of 1D and 2D variable length array更改一维和二维可变长度数组的大小
【发布时间】:2019-03-01 12:32:29
【问题描述】:

由于包含可变长度数组,在 C99 和下一个版本中,以下程序可以工作。

#include <stdio.h>

int main(void)
{
    int i, numFibs;
    printf ("How many Fibonacci numbers do you want (between 1 and 75)? ");
    scanf ("%i", &numFibs);
    if (numFibs < 1 || numFibs > 75) 
    {
        printf ("Bad number, sorry!\n");
        return 1;
    }
    unsigned long long int   Fibonacci[numFibs];
    Fibonacci[0] = 0;          // by definition
    Fibonacci[1] = 1;          // ditto
    for ( i = 2;  i < numFibs;  ++i )
    {
        Fibonacci[i] = Fibonacci[i-2] + Fibonacci[i-1];
    }
    for ( i = 0;  i < numFibs;  ++i )
    {
        printf ("%llu  ", Fibonacci[i]);
        printf ("\n");
    }
    return 0;
}

但是当我尝试实现以下程序时,它可以正常工作,直到 a9 的任何值,该程序在数组中占用的元素不超过 9 个。

为什么?

#include <stdio.h>

int main()
{
    int a=0;
    int arr[a];
    printf("Enter number of rows: ");
    scanf("%d", &a);
    printf("\nNo of rows to be entered: %d\n", a);
    for(int j=0; j<a; j++)
    {
        printf("Enter array element[%d]: ", j);
        scanf("%d", &arr[j]);
    }
    for(int j=0; j<a; j++)
    {
        printf("Entered array element [%d]: %d", j, arr[j]);
        printf("\n");
    }
    return 0;
}

下面是一个二维数组的示例,它可以正常工作,直到 b

#include <stdio.h>

int main()
{
    int b=0;
    int arr[b][2];
    printf("Enter number of rows: ");
    scanf("%d", &b);
    printf("No of rows to be entered: %d", b);
    for(int i=0; i<b; i++)
    {
        for(int j=0; j<2; j++)
        {
            printf("Enter array element[%d][%d]: ", i, j);
            scanf("%d", &arr[i][j]);
        }
    }
    printf("\n");
    for(int i=0; i<b; i++)
    {
        for(int j=0; j<2; j++)
        {
            printf("Enter array element[%d][%d]: %d", i, j, arr[i][j]);
            printf("\n");
        }
    }
    return 0;
}

在上面的示例中,动态获取行和列是错误的,但是动态获取行是可行的。如果你动态地取列,它也会失败。

有没有其他方法可以在没有 malloc() 的情况下解决这些问题?

机器上运行的GCC版本:-

C:\Users\gahlot>gcc -v 使用内置规范。 COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe 目标:mingw32 配置:../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with- pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime -libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nls 线程模型:win32 gcc版本6.3.0 (MinGW.org GCC-6.3.0-1)

【问题讨论】:

  • 我很确定这不是 VLA 的工作方式。我不认为他们改变大小。只允许您在知道大小后声明数组。您的第二个和第三个示例正在创建大小为 0 的数组
  • 在第一个示例中,我也在更改数组的大小。 numFibs 是用户设置的数组大小。
  • 在第三个示例中,动态获取行和列是错误的,但是动态获取行是有效的。如果你动态地取列,它也会失败。
  • No 在第一个示例中,您在知道 numFibs 之后声明了斐波那契。从那时起,它就是那个大小。同样,如果您对其进行了 malloc,它将是您 malloc 的大小,直到您重新分配
  • 将您的int arr... 移动到您的第一个scanf 下方并查看

标签: c c99 c11


【解决方案1】:

这并不像你认为的那样:

int a=0;
int arr[a];
printf("Enter number of rows: ");
scanf("%d", &a);

一旦以给定大小定义数组,即使该大小不是常量表达式,数组的大小也是固定的。大小a 的当前值绑定。创建大小为 0 的数组也是无效的。

这在 C 标准的第 6.7.6.2p5 节中有详细说明:

如果大小是一个不是整数的表达式 常量表达式:如果它出现在函数的声明中 原型范围,它被视为被替换为 * ;否则,每次对其进行评估时,它的值都应大于零。可变长度数组的每个实例的大小 类型在其生命周期内不会改变。

在这种情况下,数组的大小由单个变量指定,但是大小可以由任何表达式确定。例如:

int f()
{
    int a, b, c;
    scanf("%d", &a);
    b=3;
    c=9;
    return sqrt(a) * (b - c) + sin(b);
}

...

int arr[f()];

如果您这样定义arr,即使您可以更改大小,您希望如何实现?

至于为什么您的第二和第三段代码有时有效而有时无效,这意味着您正在调用undefined behavior。在这两种情况下,这都是由于创建了一个至少一维为 0 的数组并随后尝试使用它造成的。

【讨论】:

    【解决方案2】:

    VLA 的大小在遇到声明时确定。

    • 之后您无法更改它们的大小
    • 大小表达式不能有值0,甚至不能为负数。

    【讨论】:

    • 详细解释这一点,例如为什么会这样,将非常有帮助。还是我应该认为 C 就是这样构建的??
    • 如果声明是早期的,它仍然有效。这有点奇怪,它应该失败而不是为某些值工作。你怎么看?
    • @Gahlot int n[0]; n[1] = 123; 可能看似工作,但实际上它表现出未定义的行为(谷歌该术语)。未定义的行为包括“显然工作正常”。
    • @Gahlot ...是的,C 就是这样工作的。无论如何,您将如何更改 VLA 的大小?
    • 如果您可以像我尝试的那样更改 C 中的大小,我也有同样的想法,那么您为什么还需要 malloc() 之类的其他东西?所以想知道这背后的“原因”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多