简体   繁体   English

如何在C ++中动态分配连续的2D数组?

[英]How to dynamically allocate a contiguous 2D array in C++?

I need a 2d character array for use in a trash API that absolutely requires use of arrays and NOT vectors (much emphasis on this because all of my searching just had answers "use a vector". I wish I could). 我需要一个2d字符数组用于垃圾API,绝对需要使用数组和非向量(非常强调这一点,因为我所有的搜索只有答案“使用向量”。我希望我能)。

I figured the way to do it would be to allocate an external array of size rows * character length, instead of doing: 我认为这样做的方法是分配一个大小行*字符长度的外部数组,而不是:

char** arr;
arr = new char*[100];
// for loop that allocates the internal arrays

But I'm not sure what method I would need to use to make it contiguous? 但是我不确定我需要使用什么方法来使它连续? Do I need to allocate a massive 1D array first, then assign the 1D array to the 2D array in chunks? 我是否需要先分配一个海量的一维数组,然后将一维数组分配给二维数组?

As other answers have said: allocate n * m entries to create the contiguous data, and then it can be wrapped in pointers to create a 2d array. 正如其他答案所说:分配n * m个条目来创建连续数据,然后它可以用指针包装来创建一个二维数组。

... absolutely requires use of arrays and NOT vectors ... ...绝对需要使用数组而不是向量...

I'm not sure if vector is a constraint based on the API being used, or requirements -- but it's worth noting that vector can be used for the memory management of the implementation -- while still using the raw data (which can be accessed by &vec[0] or vec.data() , which returns a pointer to the first element of the array, and can be used with functions accepting raw pointers). 我不确定vector是否是基于所使用的API或要求的约束 - 但是值得注意的是, vector 可以用于实现的内存管理 - 同时仍然使用原始数据(可以访问) by &vec[0]vec.data() ,它返回指向数组第一个元素的指针,并且可以与接受原始指针的函数一起使用。

Since this question is about c++, one option is to wrap an array of n * m in a class that acts like a 2-d array while actually being contiguous. 由于该问题是关于C ++,一种选择是包裹的阵列n * mclass 行为像2-d阵列,而实际上是连续的。

A simple example could be: 一个简单的例子可能是:

class array_2d
{
public:

   array_2d( std::size_t rows, std::size_t columns )
     : m_rows(rows), m_cols(columns), m_array( new char[rows * columns] )
   {
   }

   ~array_2d()
   {
       delete [] m_array;
   }

   // row-major vs column-major is up to your implementation
   T& operator()( std::ptrdiff_t row, std::ptrdiff_t col )
   {
      // optional: do bounds checking, throw std::out_of_range first

      return m_array[row * m_cols + col];
      // alternatively:
      // return m_array[col * m_rows + row];
   }

   // get pointer to the array (for raw calls)
   char* data()
   {
     return m_array;
   }

private:

   char* m_array; 
   std::size_t m_rows;
   std::size_t m_cols;
};

(Ideally char* would be std::unique_ptr<char[]> or std::vector<char> to avoid memory-leak conditions, but since you said vector is not viable, I'm writing this minimally) (理想情况下, char*将是std::unique_ptr<char[]>std::vector<char>以避免内存泄漏情况,但是因为你说vector不可行,所以我写的最少)

This example overloads the call operator ( operator() ) -- but this could also be a named function like at(...) ; 这个例子重载了调用操作符( operator() ) - 但是这也可以是像at(...)那样的命名函数; the choice would be up to you. 选择取决于你。 The use of such type would then be: 那么这种类型的使用将是:

auto array = array_2d(5,5); // create 5x5 array
auto& i01 = array(0,1); // access row 0, column 1

Optionally, if the [][] syntax is important to behave like a 2d-array (rather than the (r,c) syntax), you can return a proxy type from a call to an overloaded operator [] (untested): (可选)如果[][]语法的行为类似于2d数组(而不是(r,c)语法),则可以从调用返回到重载operator [] (未经测试)的代理类型:

class array_2d_proxy
{
public:
   array_2d_proxy( char* p ) : m_entry(p){}

   char& operator[]( std::ptrdiff_t col ){ return m_entry[col]; }

private:

   char* m_entry;
};

class array_2d
{
  ...
  array_2d_proxy operator[]( std::ptrdiff_t row )
  {
    return array_2d_proxy( m_array + (row * m_cols) );
  }
  ...
};

This would allow you to have the 'normal' 2d-array syntax, while still being contiguous: 这将允许您使用“正常”的2d数组语法,同时仍然是连续的:

auto& i00 = array[0][0];

This is a good way to do it: 这是一个很好的方法:

void array2d(int m, int n) {
    std::vector<char>  bytes(m * n);
    std::vector<char*> arrays;
    for (int i = 0; i != m * n; i += n) {
        arrays.push_back(bytes.data() + i);
    }
    char** array2d = arrays.data();
    // whatever
}

The main problem in C++ with "continuous 2d arrays with variable column length" is that an access like myArray[r][c] requires the compiler to know the column size of the type of myArray at compile time (unlike C, C++ does not support variable length arrays (VLAs)). 在C ++中的主要问题“具有可变列长度连续的2D阵列”是像接入myArray[r][c]需要编译器知道的类型的列大小myArray 在编译时 (不同于C,C ++不支持可变长度数组(VLA))。

To overcome this, you could allocate a continuous block of characters, and additionally create an array of pointers, where each pointer points to the begin of a row. 为了克服这个问题,你可以分配一个连续的字符块,并另外创建一个指针数组,其中每个指针指向一行的开头。 With such a "view", you can then address the continuous block of memory indirectly with a myArray[r][c] -notation: 使用这样的“视图”,您可以使用myArray[r][c]注释间接地处理连续的内存块:

int main() {

    // variable nr of rows/columns:
    int rows = 2;
    int columns = 5;

    // allocate continuous block of memory
    char *contingousMemoryBlock = new char[rows*columns];

    // for demonstration purpose, fill in some content
    for (int i=0; i<rows*columns; i++) {
        contingousMemoryBlock[i] = '0' + i;
    }

    // make an array of pointers as a 2d-"view" of the memory block:
    char **arr2d= new char*[rows];
    for (int r=0; r<rows;r++) {
        arr2d[r] = contingousMemoryBlock + r*columns;
    }

    // access the continuous memory block as a 2d-array:
    for (int r=0; r<rows; r++) {
        for (int c=0; c<columns; c++) {
            cout << arr2d[r][c];
        }
        cout << endl;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM