非const数组声明

8

我自学编程已经有几年了,我曾确信如果需要声明变量数量的数组,需要使用mallocnew

但今天我发现,在g++版本4.4.4下,这段代码可以编译通过,没有任何警告或错误:

#include <iostream>
using namespace std;

int main()
{
    int size_array;
    cin >> size_array;
    int iTable[size_array];

    for(int i=0;i < size_array;i++)
        iTable[i]=i*i;
    for(int i=0;i < size_array;i++)
        cout << iTable[i] << endl;

    return 0;
}

如果你使用gcc(在将coutcin更改为printfscanf后),它可以完全编译通过。

在Visual Studio下,由于size_array不是常量,该代码无法编译通过。

这个问题是什么时候改变的?这种方法是否安全?


C标签已被删除,因为这段代码与C语言毫无关系。 - Puppy
可能是重复的问题: https://dev59.com/SnE95IYBdhLWcg3wKqyq - Mihran Hovsepyan
1
@DeadMG,Soltys 指出,即使您使用 printf 和 scanf,此问题仍然适用。示例是 c++,问题更为一般化。 - Tom
8个回答

12

这是C99的一个特性 - VLA - 它并不属于标准的c++。如果编译器支持它且您不需要可移植性,可以使用它。如果编译器支持它,使用它是完全安全的 - 但使用非标准特性是个坏习惯。


如果我在循环中放置一个size_array++,那么这仍然是安全的吗?肯定不是吧? - Tom
1
@Tom:是的,没错。不过这样做不会改变数组的大小。 - Puppy
2
@Tom:当然。VLA的堆栈只分配一次,不会改变,sizeof将提供实际大小。如果您更改用于指示数组大小的变量,则无论是VLA还是其他类型的数组都无关紧要-这是逻辑错误。 - Erik
@Erik:由于C++0x基于C99,您是否知道他们是否将VLA集成到C++0x中?快速搜索标准并没有产生有用的结果。 - Matthieu M.
1
@Erik:我必须承认我很喜欢它们,尽管实现起来很棘手,特别是当你想要在对象内使用VLA时:D 这可能也与vector是STL的一部分有关,所以他们可能没有像在C中那样感到强制。 - Matthieu M.
显示剩余3条评论

5

2

不,那毫不安全。它可能会破坏您的堆栈。


它可能会发生什么?如果他输入了“-1”? - Daniel A. White
刚刚测试了一下,当我开始分配负数时,出现了内存损坏。在初始化之前需要检查是否大于0。 - DavidMFrey

2

0

这取决于你是写C还是C++。我会假设你在写C,因为如果你使用std::vector而不是数组,那么使用C++会更好。

在C中,这取决于你使用的版本。只有当你使用C99标准编译器时,数组才能在运行时从变量获取大小,就像你在这里所做的那样;否则,大小必须在编译时定义。Visual Studio不支持动态数组-请参见MSDN

C++使用C89标准,因此需要在编译时设置大小。

因此,在你的情况下,你需要查看你向编译器传递了哪些标志。

如@Eric所指出的那样,代码是C++,因此工作编译器正在使用非标准扩展,因此对于gnu,我会添加flags来强制执行一个标准,例如-ansi或-std=c++98和-pedantic。


0

有一个扩展的GCC模拟C99可变长度数组。这不是标准的C++。

然而,即使你关闭了这个扩展,发布的代码仍然可以编译。标准不要求对这种情况进行诊断:它是未定义行为,不是错误。

在非常明显的情况下,编译器可能会选择阻止您编写此内容,但否则,它可以让您安心失败。

结论:不要被编译所迷惑。这仍然是不好的和错误的。


0

您可以在C或C++中使用alloca(Windows上的_alloca)获得此功能。 std::vector不是替代品:它在堆上分配,使用new调用malloc,这可能是昂贵的。

您可能希望在运行时确定长度的数组分配在堆栈上:这非常快速。 假设您有一个频繁执行但具有取决于运行时某些内容的数组的循环(例如,画布小部件的大小)。 您无法仅硬编码数字:当我们都拥有36 "300dpi Retina显示器且pixels [2400]不再安全时,您的程序将崩溃。 但您不想使用new,否则您的循环会触发malloc并变得缓慢。

尽管对于大型数组,最好具有仅在必要时进行调整大小(更大)的静态std :: vector,因为您的堆栈具有有限的大小。

(请参见http://msdn.microsoft.com/en-us/library/wb1s57t5(VS.71).aspx


0

如果您正在使用c99,则可以使用该功能。

关于size的值,您必须非常小心。一个大的值将会溢出您的堆栈,导致您的进程可能会失控。


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