【问题标题】:How to dynamically allocate a contiguous 2D array in C++?如何在 C++ 中动态分配连续的二维数组?
【发布时间】:2017-09-21 22:46:29
【问题描述】:

我需要一个用于垃圾 API 的二维字符数组,它绝对需要使用数组而不是向量(非常强调这一点,因为我所有的搜索都只有“使用向量”的答案。我希望我可以)。

我想办法是分配一个大小为行 * 字符长度的外部数组,而不是这样做:

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

但我不确定我需要使用什么方法来使其连续?我需要先分配一个海量的一维数组,然后将一维数组分块分配给二维数组吗?

【问题讨论】:

  • 每个维度在编译时是否已知?只有一个 ?没有?
  • > 是否需要先分配一个海量的一维数组,然后将一维数组分块分配给二维数组? |似乎是个不错的选择
  • @Jarod42 我最好知道“行”维度,但我希望两个维度都是动态的。如果有人知道,我会怎么做?
  • 你能展示一下函数的原型吗?
  • 显然,您不要那样做!相反,您使用适当大小的std::vector<char>,适当的std::vector<char*> 并在那里打包指针,最后在输出数组上使用vdata() 以满足某些API...

标签: c++ arrays


【解决方案1】:

正如其他答案所说:分配n * m 条目以创建连续数据,然后可以将其包装在指针中以创建二维数组。

...绝对需要使用数组而不是向量...

我不确定vector 是否是基于正在使用的API 或要求的约束——但值得注意的是vector 可以 用于内存实现的管理 -- 同时仍然使用原始数据(可以通过&vec[0]vec.data() 访问,它返回指向数组第一个元素的指针,并且可以与接受原始数据的函数一起使用指针)。

由于这个问题是关于 c++ 的,一个选择是将n * m 的数组包装在class 中,作用 就像一个二维数组,但实际上是连续的。

一个简单的例子可以是:

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;
};

(理想情况下,char* 应该是 std::unique_ptr<char[]>std::vector<char> 以避免出现内存泄漏的情况,但既然你说 vector 不可行,我会尽量少写这个)

这个例子重载了调用运算符(operator())——但这也可以是像at(...)这样的命名函数;选择将取决于您。那么这种类型的使用将是:

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

或者,如果[][] 语法对于表现得像一个二维数组很重要(而不是(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) );
  }
  ...
};

这将允许您拥有“正常”的二维数组语法,同时仍然是连续的:

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

【讨论】:

  • 这是一个非常干净的解决方案,并且似乎有效。然而,“列”是 1 列的列大小,所以从技术上讲,我需要一个 3-D 数组(但是,我将把它包装在另一个管理它的类中)。非常感谢,我会进行一些测试并报告。
【解决方案2】:

这是一个很好的方法:

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
}

【讨论】:

  • 有意思,我试试看。但是向量是连续的吗?
  • @user1324674:是的,自 C++11 以来它们保证是连续的,并且没有流行的 C++11 之前的非连续实现。
  • 据我所知read,C++03 保证了这一点。
  • @Jarod42:是的,你是对的。对于 C++98 不能保证,但对于 C++03 已经修复。好吧,这些版本有些融合在一起。我找到了 1998 年完成的proposal
  • 我认为即使在 C++98 中,各种要求也意味着在实践中它必须是连续的,即使直到 2003 年才真正阐明这一点
【解决方案3】:

“具有可变列长度的连续二维数组”在 C++ 中的主要问题是像 myArray[r][c] 这样的访问要求编译器在编译时知道 myArray 类型的列大小 >(与 C 不同,C++ 不支持可变长度数组 (VLA))。

为了克服这个问题,您可以分配一个连续的字符块,并另外创建一个指针数组,其中每个指针都指向一行的开头。有了这样的“视图”,您就可以使用myArray[r][c]-notation 间接寻址连续的内存块:

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;
    }
}

【讨论】:

  • 即使使用 VLA,我认为只有一个维度是可变的。不过,我可能错了。
猜你喜欢
  • 2021-12-02
  • 2012-11-12
  • 1970-01-01
  • 2013-11-14
  • 2021-02-03
  • 2017-09-28
  • 2015-09-17
  • 1970-01-01
相关资源
最近更新 更多