C全局未定长数组?

6

我们有一个学校项目,需要使用C语言编写任何信息系统。为了维护一个动态大小的学生记录列表,我选择了链表数据结构。今天早上我的朋友让我看了他的系统。我对他的记录列表感到惊讶:

#include <stdio.h>
/* and the rest of the includes */

/* global unsized array */
int array[];

int main()
{
    int n;
    for (n=0; n < 5; n ++) {
         array[n] = n;
    }


    for (n=0; n < 5; n ++) {
         printf("array[%d] = %d\n", n, array[n]);
    }
    return 0;
}

与代码类似,他声明了一个未定义大小的全局数组(在bss段),供整个程序使用。他可以通过用非零值覆盖后续内存块来向数组添加新条目,以便可以这样遍历该数组:
for (n=0; array[n]; n++) {
    /* do something */
}

他使用的是Turbo C v1(我也测试了一下)。我在Linux上尝试过,也可以工作。
因为我以前从未遇到过这种技术,所以我认为它存在问题。所以,是的,我想知道为什么这是一个不好的主意,为什么要选择它而不是链表。

1
这与写入任何越界数组一样 - 未定义。 - teppic
这应该是C99吗? - Hayri Uğur Koltuk
请查看teppic所更新的答案。并打开codepad链接,您可以观察到您代码中C语言的未定义行为。 - Grijesh Chauhan
3个回答

7
int array[];

技术上称为不完全类型的数组。简单地说,这相当于:

int array[1];

这样做并不好,原因如下:

  1. 它会产生未定义行为。使用不完整类型的数组的主要用途是在结构体欺骗(Struct Hack)中。请注意,在C99标准化之前,不完整的数组类型是非法的。

这不就是未定义行为吗?因为GCC提示source.c:4:5: warning: array 'array' assumed to have one element [enabled by default],这意味着如果超过1个元素,他将会在数组范围之外进行写操作。 - Tony The Lion
2
这不是VLA,而只是在内存中写入随机地址。 - teppic
你好,真的吗?int array[];int array[1];是相同的吗?请给我阅读链接。 - Grijesh Chauhan

4
这是未定义行为。你正在写入未分配的内存(超出数组范围)。为了编译它,编译器至少会分配一个元素,然后你就在那之后进行写入。尝试使用更大的数字范围。例如,如果我在Linux上运行你的代码,它可以工作,但如果我将循环更改为50,000,它就会崩溃。 编辑:代码在小值的n情况下可能有效,但对于更大的值则会失败。为了证明这一点,我已经编写了你的代码,并测试了n = 1000
这是CODEPAD的链接,你可以看到当n = 1000时,发生了分段错误
而对于相同的代码和编译器,当n = 10时,它是可以工作的,参见这个链接CODEPAD。所以这被称为未定义行为

我在你的答案中添加了更多细节,以展示代码的未定义行为。希望你喜欢。如果不喜欢,你可以回到你的版本。 - Grijesh Chauhan

0
如果您使用链表,可以检查内存是否正确分配。
int *ptr;
ptr = (int *)malloc(sizeof(int))
if(ptr==NULL)
{
  printf("No Memory!!!");
}

但是使用您的代码,如果测试数组具有很大的边界,程序就会崩溃。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接