0

正如问题所述,这是可行的:

#include <iostream>

int main(int argc, char *argv[])
{
    unsigned short int i;
    std::cin >> i;
    unsigned long long int k[i][i];
}

这里我声明了一个大小为 i x i 的数组,两个维度都是变量。

但不是这个:

#include <iostream>

int main(int argc, char *argv[])
{
    unsigned short int i;
    std::cin >> i;
    unsigned long long int** k = new int[i][i];
    delete[] k;
}

我收到一条编译器消息告诉我

错误:只有分配数组的第一个维度可能具有动态大小

我被迫这样做:

#include <iostream>

int main(int argc, char *argv[])
{
    unsigned short int i;
    std::cin >> i;
    unsigned long long int** k = new unsigned long long int*[i];
    for ( unsigned short int idx = 0 ; idx < i ; ++ i )
        k[idx] = new unsigned long long int[i];
    for ( unsigned short int idx = 0 ; idx < i ; ++ i )
        delete[] k[idx];
    delete[] k;
}

据我了解,new 和 delete 用于在堆上分配一些东西,而不是在堆栈上,当它超出范围时不会被删除,并且对于跨函数和对象传递数据等很有用。

我不明白的是,当我k在第一个示例中声明时会发生什么,我被告知声明的数组应该(并且可以)只有恒定的尺寸,并且当需要一个未知大小的数组时,应该始终考虑new&deletevectors。

我没有得到的这两个解决方案有什么优点和缺点,还是它就是这样?

顺便说一句,我正在使用 Apple 的 LLVM 编译器。

4

3 回答 3

1

这两种形式都不符合 C++ 标准,因为该标准不支持可变长度数组 (VLA)(有趣的是,C99 支持 - 但 C 不是 C++)。但是,一些编译器具有支持此功能的扩展,包括您的编译器:

来自 Clang 的手册

Clang 在非常有限的情况下支持这种可变长度数组,以便与 GNU C 和 C99 程序兼容:

  • 可变长度数组的元素类型必须是 POD(“plain old data”)类型,这意味着它不能有任何用户声明的构造函数或析构函数、任何基类或任何非 POD 类型的成员。所有 C 类型都是 POD 类型。
  • 可变长度数组不能用作非类型模板参数的类型。

但是鉴于扩展程序已经到位,为什么您的第二个片段不起作用?这是因为VLA 仅适用于自动变量——即参数或局部变量。k是自动的,但它只是一个指针 - 数组本身由 定义new int[i][i],它在堆上分配并且绝对不是自动变量。

您可以在相关的 GCC 手册部分阅读更多相关信息。

于 2013-06-02T07:03:43.773 回答
0

本质上,编译器通常对二维数组(固定或可变)执行的操作是:

int arr[x][y] ---> int arr[x*y];

arr[2][4]= something ---> arr[2+4*x]= something;

基本上它们只是一维数组(在堆栈上)的一种更好的表示法。大多数编译器需要固定大小,因此编译器有一种更简单的方法来判断维度是什么(以及乘以什么)。看来您只有一个编译器,即使您使用变量,它也可以跟踪维度(和乘数)。

当然,您也可以自己用 new[] 模仿它,但编译器本身不支持它。

可能出于同样的原因,即因为跟踪尺寸会更加困难,尤其是在移动指针时。

例如,您可以稍后使用新指针编写:

newarr= someotherarray;

并且someotherarray可能是具有不同尺寸的东西。如果编译器进行 2-dim -> one dim 转换,他必须跟踪所有可能的大小转换。

使用上面分配的堆栈arr,这不是必需的,因为至少一旦编译器完成它,它就会保持那个大小。

于 2013-06-01T15:01:19.633 回答
0

我相信您可以轻松找到二维数组功能的实现,但您也可以创建自己的类。最简单的方法是使用std::vector来保存数据并具有一个索引映射函数,该函数获取您的两个坐标并将单个索引返回到向量中。

客户端代码看起来会有些不同,而不是arr[x][y]你有 arr.at(x,y) 但除此之外它也是一样的。您不必摆弄内存管理,因为这是由 完成的std::vector,只需v.resize(N*N)在构造函数或维度设置函数中使用。

于 2013-06-01T14:43:47.520 回答