如何在C/ c++中最好地处理动态多维数组?

时间:2021-08-10 02:30:06

What is the accepted/most commonly used way to manipulate dynamic (with all dimensions not known until runtime) multi-dimensional arrays in C and/or C++.

在C和/或c++中操作动态(所有维度直到运行时才知道)多维数组的公认/最常用方法是什么?

I'm trying to find the cleanest way to accomplish what this Java code does:

我正在寻找最干净的方法来完成这个Java代码的工作:

public static void main(String[] args){
 Scanner sc=new Scanner(System.in);
 int rows=sc.nextInt();
 int cols=sc.nextInt();
 int[][] data=new int[rows][cols];
 manipulate(data);
}

public static void manipulate(int[][] data){
   for(int i=0;i<data.length;i++)
   for(int j=0;j<data[0].length.j++){
         System.out.print(data[i][j]);       
   }    
}

(reads from std_in just to clarify that dimensions aren't known until runtime).

(读取std_in,只是为了澄清直到运行时才知道维度)。

Edit:I noticed that this question is pretty popular even though it's pretty old. I don't actually agree with the top voted answer. I think the best choice for C is to use a single-dimensional array as Guge said below "You can alloc rowscolssizeof(int) and access it by table[row*cols+col].".

编辑:我注意到这个问题很流行,尽管它很古老。我不同意上面的投票结果。我认为C的最佳选择是使用一维数组,正如Guge下面所说:“您可以alloc rowscolssizeof(int)并通过table[row*cols+col]访问它。”

There is a number of choices with C++, if you really like boost or stl then the answers below might be preferable, but the simplest and probably fastest choice is to use a single dimensional array as in C.

使用c++有很多选择,如果你真的喜欢boost或stl,下面的答案可能更好,但是最简单、可能也是最快的选择是使用一个一维数组,就像在C中那样。

Another viable choice in C and C++ if you want the [][] syntax is lillq's answer down at the bottom is manually building the array with lots of malloc's.

C和c++中另一个可行的选择(如果你想要[][]]语法的话)是lillq在底部的答案是用大量的malloc手工构建数组。

10 个解决方案

#1


21  

Use boost::multi_array.

使用boost::multi_array。

As in your example, the only thing you need to know at compile time is the number of dimensions. Here is the first example in the documentation :

在您的示例中,在编译时惟一需要知道的是维度的数量。以下是文件中的第一个例子:

#include "boost/multi_array.hpp"
#include <cassert>

int 
main () {
  // Create a 3D array that is 3 x 4 x 2
  typedef boost::multi_array<double, 3> array_type;
  typedef array_type::index index;
  array_type A(boost::extents[3][4][2]);

  // Assign values to the elements
  int values = 0;
  for(index i = 0; i != 3; ++i) 
    for(index j = 0; j != 4; ++j)
      for(index k = 0; k != 2; ++k)
        A[i][j][k] = values++;

  // Verify values
  int verify = 0;
  for(index i = 0; i != 3; ++i) 
    for(index j = 0; j != 4; ++j)
      for(index k = 0; k != 2; ++k)
        assert(A[i][j][k] == verify++);

  return 0;
}

Edit: As suggested in the comments, here is a "simple" example application that let you define the multi-dimensional array size at runtime, asking from the console input. Here is an example output of this example application (compiled with the constant saying it's 3 dimensions) :

编辑:正如评论中所建议的,这里有一个“简单”的示例应用程序,它允许您在运行时根据控制台输入定义多维数组大小。下面是这个示例应用程序的示例输出(用常量表示为3维):

Multi-Array test!
Please enter the size of the dimension 0 : 4

Please enter the size of the dimension 1 : 6

Please enter the size of the dimension 2 : 2

Text matrix with 3 dimensions of size (4,6,2) have been created.

Ready!
Type 'help' for the command list.

>read 0.0.0
Text at (0,0,0) :
  ""

>write 0.0.0 "This is a nice test!"
Text "This is a nice test!" written at position (0,0,0)

>read 0.0.0
Text at (0,0,0) :
  "This is a nice test!"

>write 0,0,1 "What a nice day!"
Text "What a nice day!" written at position (0,0,1)

>read 0.0.0
Text at (0,0,0) :
  "This is a nice test!"

>read 0.0.1
Text at (0,0,1) :
  "What a nice day!"

>write 3,5,1 "This is the last text!"
Text "This is the last text!" written at position (3,5,1)

>read 3,5,1
Text at (3,5,1) :
  "This is the last text!"

>exit

The important parts in the code are the main function where we get the dimensions from the user and create the array with :

代码中重要的部分是我们从用户那里获取尺寸并创建数组的主要功能:

const unsigned int DIMENSION_COUNT = 3; // dimension count for this test application, change it at will :)

// here is the type of the multi-dimensional (DIMENSION_COUNT dimensions here) array we want to use
// for this example, it own texts
typedef boost::multi_array< std::string , DIMENSION_COUNT > TextMatrix;

// this provide size/index based position for a TextMatrix entry.
typedef std::tr1::array<TextMatrix::index, DIMENSION_COUNT> Position; // note that it can be a boost::array or a simple array

/*  This function will allow the user to manipulate the created array
    by managing it's commands.
    Returns true if the exit command have been called.
*/
bool process_command( const std::string& entry, TextMatrix& text_matrix );

/* Print the position values in the standard output. */
void display_position( const Position& position );

int main()
{
    std::cout << "Multi-Array test!" << std::endl;

    // get the dimension informations from the user
    Position dimensions; // this array will hold the size of each dimension 

    for( int dimension_idx = 0; dimension_idx < DIMENSION_COUNT; ++dimension_idx )
    {
        std::cout << "Please enter the size of the dimension "<< dimension_idx <<" : ";
        // note that here we should check the type of the entry, but it's a simple example so lets assume we take good numbers
        std::cin >> dimensions[dimension_idx]; 
        std::cout << std::endl;

    }

    // now create the multi-dimensional array with the previously collected informations
    TextMatrix text_matrix( dimensions );

    std::cout << "Text matrix with " << DIMENSION_COUNT << " dimensions of size ";
    display_position( dimensions );
    std::cout << " have been created."<< std::endl;
    std::cout << std::endl;
    std::cout << "Ready!" << std::endl;
    std::cout << "Type 'help' for the command list." << std::endl;
    std::cin.sync();


    // we can now play with it as long as we want
    bool wants_to_exit = false;
    while( !wants_to_exit )
    {
        std::cout << std::endl << ">" ;
        std::tr1::array< char, 256 > entry_buffer; 
        std::cin.getline(entry_buffer.data(), entry_buffer.size());

        const std::string entry( entry_buffer.data() );
        wants_to_exit = process_command( entry, text_matrix );
    }

    return 0;
}

And you can see that to accede an element in the array, it's really easy : you just use the operator() as in the following functions :

可以看到,要在数组中加入元素,非常简单:您只需使用操作符(),如下所示:

void write_in_text_matrix( TextMatrix& text_matrix, const Position& position, const std::string& text )
{
    text_matrix( position ) = text;
    std::cout << "Text \"" << text << "\" written at position ";
    display_position( position );
    std::cout << std::endl;
}

void read_from_text_matrix( const TextMatrix& text_matrix, const Position& position )
{
    const std::string& text = text_matrix( position );
    std::cout << "Text at ";
    display_position(position);
    std::cout << " : "<< std::endl;
    std::cout << "  \"" << text << "\"" << std::endl;
}

Note : I compiled this application in VC9 + SP1 - got just some forgettable warnings.

注意:我在VC9 + SP1中编译了这个应用程序,只是得到了一些被遗忘的警告。

#2


7  

There are two ways to represent a 2-dimension array in C++. One being more flexible than the other.

用c++表示二维数组有两种方法。一个比另一个更灵活。

Array of arrays

数组的数组

First make an array of pointers, then initialize each pointer with another array.

首先创建一个指针数组,然后用另一个数组初始化每个指针。

// First dimension
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
    // Second dimension
    array[i] = new int[4];
}

// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
    for( int j = 0; j < 4; ++j )
    {
        std::cout << array[i][j];
    }
}

THe problem with this method is that your second dimension is allocated as many arrays, so does not ease the work of the memory allocator. Your memory is likely to be fragmented resulting in poorer performance. It provides more flexibility though since each array in the second dimension could have a different size.

这种方法的问题是,您的第二个维度被分配了相同数量的数组,因此不能简化内存分配器的工作。你的记忆可能会支离破碎,导致性能下降。它提供了更大的灵活性,因为第二个维度中的每个数组可能有不同的大小。

Big array to hold all values

包含所有值的大数组

The trick here is to create a massive array to hold every data you need. The hard part is that you still need the first array of pointers if you want to be able to access the data using the array[i][j] syntax.

这里的诀窍是创建一个大型数组来保存所需的所有数据。难点在于,如果您希望能够使用数组[i][j]语法访问数据,仍然需要第一个指针数组。

int* buffer = new int[3*4];   
int** array = new int*[3];

for( int i = 0; i < 3; ++i )
{
    array[i] = array + i * 4;
}

The int* array is not mandatory as you could access your data directly in buffer by computing the index in the buffer from the 2-dimension coordinates of the value.

int*数组不是必需的,因为您可以通过从值的二维坐标计算缓冲区中的索引来直接访问缓冲区中的数据。

// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
    for( int j = 0; j < 4; ++j )
    {
        const int index = i * 4 + j;
        std::cout << buffer[index];
    }
}

The RULE to keep in mind

记住这条规则

Computer memory is linear and will still be for a long time. Keep in mind that 2-dimension arrays are not natively supported on a computer so the only way is to "linearize" the array into a 1-dimension array.

计算机内存是线性的,而且还会持续很长一段时间。请记住,在计算机上没有本机支持二维数组,因此唯一的方法是将数组“线性化”为一维数组。

#3


5  

You can alloc rowscolssizeof(int) and access it by table[row*cols+col].

您可以alloc rowscolssizeof(int)并通过table[row*cols+col]访问它。

#4


4  

The standard way without using boost is to use std::vector :

不使用boost的标准方法是使用std::vector:

std::vector< std::vector<int> > v;
v.resize(rows, std::vector<int>(cols, 42)); // init value is 42
v[row][col] = ...;

That will take care of new / delete the memory you need automatically. But it's rather slow, since std::vector is not primarily designed for using it like that (nesting std::vector into each other). For example, all the memory is not allocated in one block, but separate for each column. Also the rows don't have to be all of the same width. Faster is using a normal vector, and then doing index calculation like col_count * row + col to get at a certain row and col:

这将自动处理新的/删除您需要的内存。但是它的速度很慢,因为std::vector并不是为这样使用它而设计的(将std:::vector嵌套在一起)。例如,不是将所有内存分配到一个块中,而是为每个列分配单独的内存。而且行不必都是相同的宽度。Faster使用法向量,然后进行col_count * row + col等索引计算,得到某一行和col:

std::vector<int> v(col_count * row_count, 42);
v[col_count * row + col) = ...;

But this will loose the capability to index the vector using [x][y]. You also have to store the amount of rows and cols somewhere, while using the nested solution you can get the amount of rows using v.size() and the amount of cols using v[0].size().

但这将削弱使用[x][y]索引向量的能力。您还必须在某处存储行和cols的数量,在使用嵌套解决方案时,您可以使用v.size()获得行数量,使用v[0].size()获得cols数量。

Using boost, you can use boost::multi_array, which does exactly what you want (see the other answer).

使用boost,您可以使用boost::multi_array,它可以实现您想要的效果(请参见另一个答案)。


There is also the raw way using native C++ arrays. This envolves quite some work and is in no way better than the nested vector solution:

还有使用本机c++数组的原始方法。这需要做很多工作,而且并不比嵌套向量解决方案更好:

int ** rows = new int*[row_count];
for(std::size_t i = 0; i < row_count; i++) {
    rows[i] = new int[cols_count];
    std::fill(rows[i], rows[i] + cols_count, 42);
}

// use it... rows[row][col] then free it...

for(std::size_t i = 0; i < row_count; i++) {
    delete[] rows[i];
}

delete[] rows;

You have to store the amount of columns and rows you created somewhere since you can't receive them from the pointer.

您必须存储在某处创建的列和行数量,因为您无法从指针接收它们。

#5


4  

Here is the easy way to do this in C:

这里有一个简单的方法,在C:

void manipulate(int rows, int cols, int (*data)[cols]) {
    for(int i=0; i < rows; i++) {
        for(int j=0; j < cols; j++) {
            printf("%d ", data[i][j]);       
        }
        printf("\n");
    }
}

int main() {
    int rows = ...;
    int cols = ...;
    int (*data)[cols] = malloc(rows*sizeof(*data));
    manipulate(rows, cols, data);
    free(data);
}

This is perfectly valid since C99, however it is not C++ of any standard: C++ requires the sizes of array types to be compile times constants. In that respect, C++ is now fifteen years behind C. And this situation is not going to change any time soon (the variable length array proposal for C++17 does not come close to the functionality of C99 variable length arrays).

这是完全有效的,因为C99,但是它不是任何标准的c++: c++需要数组类型的大小来编译时间常量。在这方面,c++现在比C晚了15年,而且这种情况不会很快改变(c++ 17的可变长度数组建议没有接近C99可变长度数组的功能)。

#6


3  

2D C-style arrays in C and C++ are a block of memory of size rows * columns * sizeof(datatype) bytes.

C和c++中的2D C样式数组是一个大小为行*列* sizeof(数据类型)字节的内存块。

The actual [row][column] dimensions exist only statically at compile time. There's nothing there dynamically at runtime!

实际的[row][列]维度仅在编译时静态存在。在运行时没有动态的东西!

So, as others have mentioned, you can implement

因此,正如其他人提到的,您可以实现

  int array [ rows ] [ columns ];

As:

为:

 int  array [ rows * columns ]

Or as:

或者为:

 int * array = malloc ( rows * columns * sizeof(int) );

Next: Declaring a variably sized array. In C this is possible:

接下来:声明一个可变大小的数组。在C中,这是可能的:

int main( int argc, char ** argv )
{
  assert( argc > 2 );

  int rows    = atoi( argv[1] );
  int columns = atoi( argv[2] );

  assert(rows > 0 && columns > 0);
  int data [ rows ] [ columns ];  // Yes, legal!

  memset( &data, 0, sizeof(data) );

  print( rows, columns, data );
  manipulate( rows, columns, data );
  print( rows, columns, data );
}

In C you can just pass the variably-sized array around the same as a non-variably-sized array:

在C中,你可以将不同大小的数组与非不同大小的数组一样传递给它:

void manipulate( int theRows, int theColumns, int theData[theRows][theColumns] )
{
  for (   int r = 0; r < theRows;    r ++ )
    for ( int c = 0; c < theColumns; c ++  )
      theData[r][c] = r*10 + c;
}

However, in C++ that is not possible. You need to allocate the array using dynamic allocation, e.g.:

但是,在c++中,这是不可能的。您需要使用动态分配来分配数组,例如:

int *array = new int[rows * cols]();

or preferably (with automated memory management)

或者更好(使用自动内存管理)

std::vector<int> array(rows * cols);

Then the functions must be modified to accept 1-dimensional data:

然后对函数进行修改,接受一维数据:

void manipulate( int theRows, int theColumns, int *theData )
{
  for (   int r = 0; r < theRows;    r ++ )
    for ( int c = 0; c < theColumns; c ++  )
      theData[r * theColumns + c] = r*10 + c;
}

#7


2  

If you're using C instead of C++ you might want to look at the Array_T abstraction in Dave Hanson's library C Interfaces and Implementations. It's exceptionally clean and well designed. I have my students do a two-dimensional version as an exercise. You could do that or simply write an additional function that does an index mapping, e.g.,

如果您使用的是C而不是c++,您可能想看看Dave Hanson的库C接口和实现中的Array_T抽象。它特别干净,设计得很好。我让我的学生做一个二维的版本作为练习。你可以这样做,或者简单地写一个做索引映射的函数,例如,

void *Array_get_2d(Array_T a, int width, int height, int i, int j) {
    return Array_get(a, j * width, i, j);
}

It is a bit cleaner to have a separate structure where you store the width, the height, and a pointer to the elements.

有一个单独的结构来存储宽度、高度和指向元素的指针会更简洁一些。

#8


1  

I recently came across a similar problem. I did not have Boost available. Vectors of vectors turned out to be pretty slow in comparison to plain arrays. Having an array of pointers makes the initialization a lot more laborious, because you have to iterate through every dimension and initialize the pointers, possibly having some pretty unwieldy, cascaded types in the process, possibly with lots of typedefs.

我最近遇到了一个类似的问题。我没有Boost。向量的向量与普通数组相比是非常慢的。拥有一个指针数组会使初始化变得更加困难,因为您必须遍历每个维度并初始化指针,可能在过程中有一些非常笨拙的级联类型,可能有大量的typedef。

DISCLAIMER: I was not sure if I should post this as an answer, because it only answers part of your question. My apologies for the following:

免责声明:我不确定是否应该把这个作为答案,因为它只回答了你问题的一部分。以下是我的歉意:

  • I did not cover how to read the dimensions from standard input, as other commentators had remarked.
  • 正如其他评论员所说,我没有涉及如何从标准输入中读取维度。
  • This is primarily for C++.
  • 这主要是为了c++。
  • I have only coded this solution for two dimensions.
  • 我只把这个解写成了二维的形式。

I decided to post this anyway, because I see vectors of vectors brought up frequently in reply to questions about multi-dimensional arrays in C++, without anyone mentioning the performance aspects of it (if you care about it).

无论如何,我决定发布这篇文章,因为我看到了在c++中频繁地回答关于多维数组的问题的向量,没有人提到它的性能方面(如果您关心它的话)。

I also interpreted the core issue of this question to be about how to get dynamic multi-dimensional arrays that can be used with the same ease as the Java example from the question, i.e. without the hassle of having to calculate the indices with a pseudo-multi-dimensional one-dimensional array.

我还将这个问题的核心问题解释为:如何获得动态多维数组,以便与问题中的Java示例一样轻松地使用它们,即不需要使用伪多维一维数组来计算索引。

I didn't see compiler extensions mentioned in the other answers, like the ones provided by GCC/G++ to declare multi-dimensional arrays with dynamic bounds the same way you do with static bounds. From what I understand, the question does not restrict the answers to standard C/C++. ISO C99 apparently does support them, but in C++ and prior versions of C they appear to be compiler-specific extensions. See this question: Dynamic arrays in C without malloc?

我没有看到在其他答案中提到的编译器扩展,比如GCC/G++提供的用于声明具有动态边界的多维数组的扩展,就像使用静态边界一样。根据我的理解,这个问题并不局限于标准的C/ c++。ISO C99显然支持它们,但是在c++和以前的C版本中,它们似乎是特定于编译器的扩展。看到这个问题了吗:没有malloc的C中的动态数组?

I came up with a way that people might like for C++, because it's little code, has the ease of use of the built-in static multi-dimensional arrays, and is just as fast.

我想到了一种人们可能喜欢使用c++的方式,因为它的代码很少,具有内置静态多维数组的易用性,而且速度也很快。

template <typename T> 
class Array2D {
private:
    std::unique_ptr<T> managed_array_;
    T* array_;
    size_t x_, y_;

public:
    Array2D(size_t x, size_t y) {
        managed_array_.reset(new T[x * y]);
        array_ = managed_array_.get();
        y_ = y;
    }
    T* operator[](size_t x) const {
        return &array_[x * y_];
    }
};

You can use it like this. The dimensions do not

你可以这样使用它。尺寸不

auto a = Array2D<int>(x, y);
a[xi][yi] = 42;

You can add an assertion, at least to all but the last dimension and extend the idea to to more than two dimensions. I have made a post on my blog about alternative ways to get multi-dimensional arrays. I am also much more specific on the relative performance and coding effort there.

您可以添加一个断言,至少可以添加到最后一个维度,并将其扩展到两个以上的维度。我在博客上发表了一篇关于获取多维数组的替代方法的文章。我还更具体地介绍了相关性能和编码工作。

Performance of Dynamic Multi-Dimensional Arrays in C++

c++中动态多维数组的性能

#9


0  

There is no way to determine the length of a given array in C++. The best way would probably be to pass in the length of each dimension of the array, and use that instead of the .length property of the array itself.

在c++中,无法确定给定数组的长度。最好的方法可能是传入数组的每个维度的长度,而不是使用数组本身的.length属性。

#10


0  

You could use malloc to accomplish this and still have it accessible through normal array[][] mean, verses the array[rows * cols + cols] method.

您可以使用malloc来实现这一点,并且仍然可以通过普通数组[][][]来访问它,而不是通过数组[row * cols + cols]方法。

main()
{
   int i;
   int rows;
   int cols;
   int **array = NULL;

   array = malloc(sizeof(int*) * rows);
   if (array == NULL)
       return 0;  // check for malloc fail

   for (i = 0; i < rows; i++)
   {
       array[i] = malloc(sizeof(int) * cols)
       if (array[i] == NULL)
           return 0;  // check for malloc fail
   }

   // and now you have a dynamically sized array
}

#1


21  

Use boost::multi_array.

使用boost::multi_array。

As in your example, the only thing you need to know at compile time is the number of dimensions. Here is the first example in the documentation :

在您的示例中,在编译时惟一需要知道的是维度的数量。以下是文件中的第一个例子:

#include "boost/multi_array.hpp"
#include <cassert>

int 
main () {
  // Create a 3D array that is 3 x 4 x 2
  typedef boost::multi_array<double, 3> array_type;
  typedef array_type::index index;
  array_type A(boost::extents[3][4][2]);

  // Assign values to the elements
  int values = 0;
  for(index i = 0; i != 3; ++i) 
    for(index j = 0; j != 4; ++j)
      for(index k = 0; k != 2; ++k)
        A[i][j][k] = values++;

  // Verify values
  int verify = 0;
  for(index i = 0; i != 3; ++i) 
    for(index j = 0; j != 4; ++j)
      for(index k = 0; k != 2; ++k)
        assert(A[i][j][k] == verify++);

  return 0;
}

Edit: As suggested in the comments, here is a "simple" example application that let you define the multi-dimensional array size at runtime, asking from the console input. Here is an example output of this example application (compiled with the constant saying it's 3 dimensions) :

编辑:正如评论中所建议的,这里有一个“简单”的示例应用程序,它允许您在运行时根据控制台输入定义多维数组大小。下面是这个示例应用程序的示例输出(用常量表示为3维):

Multi-Array test!
Please enter the size of the dimension 0 : 4

Please enter the size of the dimension 1 : 6

Please enter the size of the dimension 2 : 2

Text matrix with 3 dimensions of size (4,6,2) have been created.

Ready!
Type 'help' for the command list.

>read 0.0.0
Text at (0,0,0) :
  ""

>write 0.0.0 "This is a nice test!"
Text "This is a nice test!" written at position (0,0,0)

>read 0.0.0
Text at (0,0,0) :
  "This is a nice test!"

>write 0,0,1 "What a nice day!"
Text "What a nice day!" written at position (0,0,1)

>read 0.0.0
Text at (0,0,0) :
  "This is a nice test!"

>read 0.0.1
Text at (0,0,1) :
  "What a nice day!"

>write 3,5,1 "This is the last text!"
Text "This is the last text!" written at position (3,5,1)

>read 3,5,1
Text at (3,5,1) :
  "This is the last text!"

>exit

The important parts in the code are the main function where we get the dimensions from the user and create the array with :

代码中重要的部分是我们从用户那里获取尺寸并创建数组的主要功能:

const unsigned int DIMENSION_COUNT = 3; // dimension count for this test application, change it at will :)

// here is the type of the multi-dimensional (DIMENSION_COUNT dimensions here) array we want to use
// for this example, it own texts
typedef boost::multi_array< std::string , DIMENSION_COUNT > TextMatrix;

// this provide size/index based position for a TextMatrix entry.
typedef std::tr1::array<TextMatrix::index, DIMENSION_COUNT> Position; // note that it can be a boost::array or a simple array

/*  This function will allow the user to manipulate the created array
    by managing it's commands.
    Returns true if the exit command have been called.
*/
bool process_command( const std::string& entry, TextMatrix& text_matrix );

/* Print the position values in the standard output. */
void display_position( const Position& position );

int main()
{
    std::cout << "Multi-Array test!" << std::endl;

    // get the dimension informations from the user
    Position dimensions; // this array will hold the size of each dimension 

    for( int dimension_idx = 0; dimension_idx < DIMENSION_COUNT; ++dimension_idx )
    {
        std::cout << "Please enter the size of the dimension "<< dimension_idx <<" : ";
        // note that here we should check the type of the entry, but it's a simple example so lets assume we take good numbers
        std::cin >> dimensions[dimension_idx]; 
        std::cout << std::endl;

    }

    // now create the multi-dimensional array with the previously collected informations
    TextMatrix text_matrix( dimensions );

    std::cout << "Text matrix with " << DIMENSION_COUNT << " dimensions of size ";
    display_position( dimensions );
    std::cout << " have been created."<< std::endl;
    std::cout << std::endl;
    std::cout << "Ready!" << std::endl;
    std::cout << "Type 'help' for the command list." << std::endl;
    std::cin.sync();


    // we can now play with it as long as we want
    bool wants_to_exit = false;
    while( !wants_to_exit )
    {
        std::cout << std::endl << ">" ;
        std::tr1::array< char, 256 > entry_buffer; 
        std::cin.getline(entry_buffer.data(), entry_buffer.size());

        const std::string entry( entry_buffer.data() );
        wants_to_exit = process_command( entry, text_matrix );
    }

    return 0;
}

And you can see that to accede an element in the array, it's really easy : you just use the operator() as in the following functions :

可以看到,要在数组中加入元素,非常简单:您只需使用操作符(),如下所示:

void write_in_text_matrix( TextMatrix& text_matrix, const Position& position, const std::string& text )
{
    text_matrix( position ) = text;
    std::cout << "Text \"" << text << "\" written at position ";
    display_position( position );
    std::cout << std::endl;
}

void read_from_text_matrix( const TextMatrix& text_matrix, const Position& position )
{
    const std::string& text = text_matrix( position );
    std::cout << "Text at ";
    display_position(position);
    std::cout << " : "<< std::endl;
    std::cout << "  \"" << text << "\"" << std::endl;
}

Note : I compiled this application in VC9 + SP1 - got just some forgettable warnings.

注意:我在VC9 + SP1中编译了这个应用程序,只是得到了一些被遗忘的警告。

#2


7  

There are two ways to represent a 2-dimension array in C++. One being more flexible than the other.

用c++表示二维数组有两种方法。一个比另一个更灵活。

Array of arrays

数组的数组

First make an array of pointers, then initialize each pointer with another array.

首先创建一个指针数组,然后用另一个数组初始化每个指针。

// First dimension
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
    // Second dimension
    array[i] = new int[4];
}

// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
    for( int j = 0; j < 4; ++j )
    {
        std::cout << array[i][j];
    }
}

THe problem with this method is that your second dimension is allocated as many arrays, so does not ease the work of the memory allocator. Your memory is likely to be fragmented resulting in poorer performance. It provides more flexibility though since each array in the second dimension could have a different size.

这种方法的问题是,您的第二个维度被分配了相同数量的数组,因此不能简化内存分配器的工作。你的记忆可能会支离破碎,导致性能下降。它提供了更大的灵活性,因为第二个维度中的每个数组可能有不同的大小。

Big array to hold all values

包含所有值的大数组

The trick here is to create a massive array to hold every data you need. The hard part is that you still need the first array of pointers if you want to be able to access the data using the array[i][j] syntax.

这里的诀窍是创建一个大型数组来保存所需的所有数据。难点在于,如果您希望能够使用数组[i][j]语法访问数据,仍然需要第一个指针数组。

int* buffer = new int[3*4];   
int** array = new int*[3];

for( int i = 0; i < 3; ++i )
{
    array[i] = array + i * 4;
}

The int* array is not mandatory as you could access your data directly in buffer by computing the index in the buffer from the 2-dimension coordinates of the value.

int*数组不是必需的,因为您可以通过从值的二维坐标计算缓冲区中的索引来直接访问缓冲区中的数据。

// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
    for( int j = 0; j < 4; ++j )
    {
        const int index = i * 4 + j;
        std::cout << buffer[index];
    }
}

The RULE to keep in mind

记住这条规则

Computer memory is linear and will still be for a long time. Keep in mind that 2-dimension arrays are not natively supported on a computer so the only way is to "linearize" the array into a 1-dimension array.

计算机内存是线性的,而且还会持续很长一段时间。请记住,在计算机上没有本机支持二维数组,因此唯一的方法是将数组“线性化”为一维数组。

#3


5  

You can alloc rowscolssizeof(int) and access it by table[row*cols+col].

您可以alloc rowscolssizeof(int)并通过table[row*cols+col]访问它。

#4


4  

The standard way without using boost is to use std::vector :

不使用boost的标准方法是使用std::vector:

std::vector< std::vector<int> > v;
v.resize(rows, std::vector<int>(cols, 42)); // init value is 42
v[row][col] = ...;

That will take care of new / delete the memory you need automatically. But it's rather slow, since std::vector is not primarily designed for using it like that (nesting std::vector into each other). For example, all the memory is not allocated in one block, but separate for each column. Also the rows don't have to be all of the same width. Faster is using a normal vector, and then doing index calculation like col_count * row + col to get at a certain row and col:

这将自动处理新的/删除您需要的内存。但是它的速度很慢,因为std::vector并不是为这样使用它而设计的(将std:::vector嵌套在一起)。例如,不是将所有内存分配到一个块中,而是为每个列分配单独的内存。而且行不必都是相同的宽度。Faster使用法向量,然后进行col_count * row + col等索引计算,得到某一行和col:

std::vector<int> v(col_count * row_count, 42);
v[col_count * row + col) = ...;

But this will loose the capability to index the vector using [x][y]. You also have to store the amount of rows and cols somewhere, while using the nested solution you can get the amount of rows using v.size() and the amount of cols using v[0].size().

但这将削弱使用[x][y]索引向量的能力。您还必须在某处存储行和cols的数量,在使用嵌套解决方案时,您可以使用v.size()获得行数量,使用v[0].size()获得cols数量。

Using boost, you can use boost::multi_array, which does exactly what you want (see the other answer).

使用boost,您可以使用boost::multi_array,它可以实现您想要的效果(请参见另一个答案)。


There is also the raw way using native C++ arrays. This envolves quite some work and is in no way better than the nested vector solution:

还有使用本机c++数组的原始方法。这需要做很多工作,而且并不比嵌套向量解决方案更好:

int ** rows = new int*[row_count];
for(std::size_t i = 0; i < row_count; i++) {
    rows[i] = new int[cols_count];
    std::fill(rows[i], rows[i] + cols_count, 42);
}

// use it... rows[row][col] then free it...

for(std::size_t i = 0; i < row_count; i++) {
    delete[] rows[i];
}

delete[] rows;

You have to store the amount of columns and rows you created somewhere since you can't receive them from the pointer.

您必须存储在某处创建的列和行数量,因为您无法从指针接收它们。

#5


4  

Here is the easy way to do this in C:

这里有一个简单的方法,在C:

void manipulate(int rows, int cols, int (*data)[cols]) {
    for(int i=0; i < rows; i++) {
        for(int j=0; j < cols; j++) {
            printf("%d ", data[i][j]);       
        }
        printf("\n");
    }
}

int main() {
    int rows = ...;
    int cols = ...;
    int (*data)[cols] = malloc(rows*sizeof(*data));
    manipulate(rows, cols, data);
    free(data);
}

This is perfectly valid since C99, however it is not C++ of any standard: C++ requires the sizes of array types to be compile times constants. In that respect, C++ is now fifteen years behind C. And this situation is not going to change any time soon (the variable length array proposal for C++17 does not come close to the functionality of C99 variable length arrays).

这是完全有效的,因为C99,但是它不是任何标准的c++: c++需要数组类型的大小来编译时间常量。在这方面,c++现在比C晚了15年,而且这种情况不会很快改变(c++ 17的可变长度数组建议没有接近C99可变长度数组的功能)。

#6


3  

2D C-style arrays in C and C++ are a block of memory of size rows * columns * sizeof(datatype) bytes.

C和c++中的2D C样式数组是一个大小为行*列* sizeof(数据类型)字节的内存块。

The actual [row][column] dimensions exist only statically at compile time. There's nothing there dynamically at runtime!

实际的[row][列]维度仅在编译时静态存在。在运行时没有动态的东西!

So, as others have mentioned, you can implement

因此,正如其他人提到的,您可以实现

  int array [ rows ] [ columns ];

As:

为:

 int  array [ rows * columns ]

Or as:

或者为:

 int * array = malloc ( rows * columns * sizeof(int) );

Next: Declaring a variably sized array. In C this is possible:

接下来:声明一个可变大小的数组。在C中,这是可能的:

int main( int argc, char ** argv )
{
  assert( argc > 2 );

  int rows    = atoi( argv[1] );
  int columns = atoi( argv[2] );

  assert(rows > 0 && columns > 0);
  int data [ rows ] [ columns ];  // Yes, legal!

  memset( &data, 0, sizeof(data) );

  print( rows, columns, data );
  manipulate( rows, columns, data );
  print( rows, columns, data );
}

In C you can just pass the variably-sized array around the same as a non-variably-sized array:

在C中,你可以将不同大小的数组与非不同大小的数组一样传递给它:

void manipulate( int theRows, int theColumns, int theData[theRows][theColumns] )
{
  for (   int r = 0; r < theRows;    r ++ )
    for ( int c = 0; c < theColumns; c ++  )
      theData[r][c] = r*10 + c;
}

However, in C++ that is not possible. You need to allocate the array using dynamic allocation, e.g.:

但是,在c++中,这是不可能的。您需要使用动态分配来分配数组,例如:

int *array = new int[rows * cols]();

or preferably (with automated memory management)

或者更好(使用自动内存管理)

std::vector<int> array(rows * cols);

Then the functions must be modified to accept 1-dimensional data:

然后对函数进行修改,接受一维数据:

void manipulate( int theRows, int theColumns, int *theData )
{
  for (   int r = 0; r < theRows;    r ++ )
    for ( int c = 0; c < theColumns; c ++  )
      theData[r * theColumns + c] = r*10 + c;
}

#7


2  

If you're using C instead of C++ you might want to look at the Array_T abstraction in Dave Hanson's library C Interfaces and Implementations. It's exceptionally clean and well designed. I have my students do a two-dimensional version as an exercise. You could do that or simply write an additional function that does an index mapping, e.g.,

如果您使用的是C而不是c++,您可能想看看Dave Hanson的库C接口和实现中的Array_T抽象。它特别干净,设计得很好。我让我的学生做一个二维的版本作为练习。你可以这样做,或者简单地写一个做索引映射的函数,例如,

void *Array_get_2d(Array_T a, int width, int height, int i, int j) {
    return Array_get(a, j * width, i, j);
}

It is a bit cleaner to have a separate structure where you store the width, the height, and a pointer to the elements.

有一个单独的结构来存储宽度、高度和指向元素的指针会更简洁一些。

#8


1  

I recently came across a similar problem. I did not have Boost available. Vectors of vectors turned out to be pretty slow in comparison to plain arrays. Having an array of pointers makes the initialization a lot more laborious, because you have to iterate through every dimension and initialize the pointers, possibly having some pretty unwieldy, cascaded types in the process, possibly with lots of typedefs.

我最近遇到了一个类似的问题。我没有Boost。向量的向量与普通数组相比是非常慢的。拥有一个指针数组会使初始化变得更加困难,因为您必须遍历每个维度并初始化指针,可能在过程中有一些非常笨拙的级联类型,可能有大量的typedef。

DISCLAIMER: I was not sure if I should post this as an answer, because it only answers part of your question. My apologies for the following:

免责声明:我不确定是否应该把这个作为答案,因为它只回答了你问题的一部分。以下是我的歉意:

  • I did not cover how to read the dimensions from standard input, as other commentators had remarked.
  • 正如其他评论员所说,我没有涉及如何从标准输入中读取维度。
  • This is primarily for C++.
  • 这主要是为了c++。
  • I have only coded this solution for two dimensions.
  • 我只把这个解写成了二维的形式。

I decided to post this anyway, because I see vectors of vectors brought up frequently in reply to questions about multi-dimensional arrays in C++, without anyone mentioning the performance aspects of it (if you care about it).

无论如何,我决定发布这篇文章,因为我看到了在c++中频繁地回答关于多维数组的问题的向量,没有人提到它的性能方面(如果您关心它的话)。

I also interpreted the core issue of this question to be about how to get dynamic multi-dimensional arrays that can be used with the same ease as the Java example from the question, i.e. without the hassle of having to calculate the indices with a pseudo-multi-dimensional one-dimensional array.

我还将这个问题的核心问题解释为:如何获得动态多维数组,以便与问题中的Java示例一样轻松地使用它们,即不需要使用伪多维一维数组来计算索引。

I didn't see compiler extensions mentioned in the other answers, like the ones provided by GCC/G++ to declare multi-dimensional arrays with dynamic bounds the same way you do with static bounds. From what I understand, the question does not restrict the answers to standard C/C++. ISO C99 apparently does support them, but in C++ and prior versions of C they appear to be compiler-specific extensions. See this question: Dynamic arrays in C without malloc?

我没有看到在其他答案中提到的编译器扩展,比如GCC/G++提供的用于声明具有动态边界的多维数组的扩展,就像使用静态边界一样。根据我的理解,这个问题并不局限于标准的C/ c++。ISO C99显然支持它们,但是在c++和以前的C版本中,它们似乎是特定于编译器的扩展。看到这个问题了吗:没有malloc的C中的动态数组?

I came up with a way that people might like for C++, because it's little code, has the ease of use of the built-in static multi-dimensional arrays, and is just as fast.

我想到了一种人们可能喜欢使用c++的方式,因为它的代码很少,具有内置静态多维数组的易用性,而且速度也很快。

template <typename T> 
class Array2D {
private:
    std::unique_ptr<T> managed_array_;
    T* array_;
    size_t x_, y_;

public:
    Array2D(size_t x, size_t y) {
        managed_array_.reset(new T[x * y]);
        array_ = managed_array_.get();
        y_ = y;
    }
    T* operator[](size_t x) const {
        return &array_[x * y_];
    }
};

You can use it like this. The dimensions do not

你可以这样使用它。尺寸不

auto a = Array2D<int>(x, y);
a[xi][yi] = 42;

You can add an assertion, at least to all but the last dimension and extend the idea to to more than two dimensions. I have made a post on my blog about alternative ways to get multi-dimensional arrays. I am also much more specific on the relative performance and coding effort there.

您可以添加一个断言,至少可以添加到最后一个维度,并将其扩展到两个以上的维度。我在博客上发表了一篇关于获取多维数组的替代方法的文章。我还更具体地介绍了相关性能和编码工作。

Performance of Dynamic Multi-Dimensional Arrays in C++

c++中动态多维数组的性能

#9


0  

There is no way to determine the length of a given array in C++. The best way would probably be to pass in the length of each dimension of the array, and use that instead of the .length property of the array itself.

在c++中,无法确定给定数组的长度。最好的方法可能是传入数组的每个维度的长度,而不是使用数组本身的.length属性。

#10


0  

You could use malloc to accomplish this and still have it accessible through normal array[][] mean, verses the array[rows * cols + cols] method.

您可以使用malloc来实现这一点,并且仍然可以通过普通数组[][][]来访问它,而不是通过数组[row * cols + cols]方法。

main()
{
   int i;
   int rows;
   int cols;
   int **array = NULL;

   array = malloc(sizeof(int*) * rows);
   if (array == NULL)
       return 0;  // check for malloc fail

   for (i = 0; i < rows; i++)
   {
       array[i] = malloc(sizeof(int) * cols)
       if (array[i] == NULL)
           return 0;  // check for malloc fail
   }

   // and now you have a dynamically sized array
}