在 C++ 中表示二维数组的最佳方法,其大小在运行时确定

Posted

技术标签:

【中文标题】在 C++ 中表示二维数组的最佳方法,其大小在运行时确定【英文标题】:Best way to represent a 2-D array in C++ with size determined at run time 【发布时间】:2010-09-20 08:32:03 【问题描述】:

在 C++ 中,我想做类似的事情:

int n = get_int_from_user();

char* matrix = new char[n][n];

matrix[0][0] = 'c';
//...
matrix[n][n] = 'a';

delete [][] matrix;

但这当然行不通。做类似事情的最佳方法是什么?我已经看到了一些解决方案,但它们看起来很混乱。

【问题讨论】:

boost::multi_array 手动操作会一团糟。 【参考方案1】:

手动动态方式:

假设你想要一个宽*高的数组,最有效的方法是只使用一维数组:

char *matrix = new char[width*height];

删除它:

delete[] matrix;

要访问它:

char getArrayValue(char *matrix, int row, int col)

  return matrix[row + col*width];

修改它:

void setArrayValue(char *matrix, int row, int col, char val)

  matrix[row + col*width] = val;


提升矩阵:

Consider using boost::matrix,如果你有依赖的话。

然后您可以绑定到 boost linear algebra 库。

这里有一些sample code of boost::matrix:

#include <boost/numeric/ublas/matrix.hpp>
using namespace boost::numeric::ublas;
matrix<char> m (3, 3);
for (unsigned i = 0; i < m.size1 (); ++ i)
    for (unsigned j = 0; j < m.size2 (); ++ j)
        m (i, j) = 3 * i + j;

在某些编译器的堆栈上:

一些编译器实际上允许您在堆栈上创建具有运行时确定大小的数组。 g++ 就是这种编译器的一个例子。但是,默认情况下您不能这样做 VC++。

所以在 g++ 中这是有效的代码:

int width = 10;
int height = 10; 
int matrix[width][height];

Drew Hall 提到这个 C99 功能称为可变长度数组 (VLA),它可能可以在任何现代编译器中启用。

【讨论】:

查看问题标题,“...大小在运行时确定”。所以他不能使用堆栈或常量。 您可以在 g++ 中的堆栈上创建大小确定的数组 这是一个称为可变长度数组 (VLA) 的 C99 功能——它可能可以在任何支持 C 和 C++ 的现代编译器中启用。【参考方案2】:

我通常会这样做:

char *matrix = new char [width * height];

matrix[i + j * width] = 'c'; // same as matrix[i][j] = 'c';

delete [] matrix;

【讨论】:

是的,这可能是一个更好的方法。将访问封装在一个函数中,一切都很好。 我相信这也是在幕后处理多维数组的方式【参考方案3】:

您似乎错过了 C++(带类的 C)的全部要点 :-)。这是一种迫切需要类来实现它的用途。

可以只使用 STL 或其他 3rd 方类库,我相信它们会有您正在寻找的数据结构,但是,如果您需要自己开发,只需创建一个类具有以下属性。

给定 n 的构造函数将创建一个新的 n*n char 数组(例如 charray).. 基于 x.y 获取和设置值的成员函数,它简单地引用 charray[x*n+y]; destructor 其中delete[] 的数组。

【讨论】:

【参考方案4】:

std::vector&lt; std::vector&lt;int&gt; &gt; array2d; 呢?

【讨论】:

性能特征值得注意。向一个方向调整数组大小会很快。但是元素访问会很慢,因为缓存局部性不好(向量可能最终在内存的远处)。另一方面,如果您像大多数其他答案一样使用连续存储,则垂直调整大小会稍慢,水平调整大小会稍快,并且缓存位置要好得多。【参考方案5】:

对于真正的二维数组:

int n = get_int_from_user();

char** matrix = new char*[n];
for (int i = 0; i < n; i++) 
    matrix[i] = new char[n];


// Operations on matrix.

for (int i = 0; i < n; i++) 
    delete [] matrix[i];

delete matrix;

就在我的脑海中。错误,毫无疑问。但是,我认为其他人发布了一种更优雅的方法。

【讨论】:

【参考方案6】:

我喜欢一维数组方法(Brian R. Bondy 选择的答案),它具有将数据成员包装到一个类中的扩展,这样您就不需要单独跟踪宽度:

class Matrix

    int width;
    int height;
    char* data;
public:
    Matrix();
    Matrix(int width, int height);
    ~Matrix();

    char getArrayValue(int row, int col);
    void setArrayValue(int row, int col, char val);

实现是读者的练习。 ;)

【讨论】:

两个潜在的改进。您可以将其设为模板类。您可以用返回引用的 operator()(int,int) 替换 getArrayValue 和 setArrayValue。或者理想情况下,通过代理类模拟 [x][y] 语法 - 但我认为很难确保代理类总是被优化掉。【参考方案7】:

我认为这将是一个很好的。

int n = get_int_from_user();

char **matrix=new (char*)[n];

for(int i=0;i<n;i++)
    matrix[i]=new char[n];

matrix[0][0] = 'c';
//...
matrix[n][n] = 'a';

for(int i=0;i<n;i++)
    delete []matrix;
delete []matrix;

【讨论】:

【参考方案8】:
std::vector<int> m;

然后在运行时调用 m.resize()。

int* matrix = new int[w*h];

如果你想做高斯消元之类的事情,你的矩阵应该是

int** matrix = new int*[h];
for(size_t i(0); i < h; ++i)
    matrix[i] = new int[w];

(在高斯消元法中,我们通常需要将一行与另一行交换,因此最好在恒定时间内交换指向行的指针,而不是通过线性时间复制来交换)。

【讨论】:

以上是关于在 C++ 中表示二维数组的最佳方法,其大小在运行时确定的主要内容,如果未能解决你的问题,请参考以下文章

在数据库中表示“重复事件”的最佳方式是啥?

在固定长度向量中表示文档集合的最佳方法是啥?

在Scala中表示readline循环的最佳方法?

C++中二维数组传参的方法详解

在 C++ 中对结构数组进行排序

如何在 Rust 中表示指向 C 数组的指针?