C++ 使用运算符new初始化二维数组

C++ 使用运算符new初始化二维数组,c++,c++11,C++,C++11,我试图声明一个2D数组,其中内部数组中的每个元素都有类型uint64\u t*。我想在一行中使用new,这在C++11或更高版本中应该是可能的。我试过这个: uint64_t ***db = new uint64_t*[2][64]; 但是,这是不正确的: cannot initialize a variable of type 'uint64_t ***' (aka 'unsigned long long ***') with an rvalue of type 'uint64_t *(*)

我试图声明一个2D数组,其中内部数组中的每个元素都有类型
uint64\u t*
。我想在一行中使用
new
,这在C++11或更高版本中应该是可能的。我试过这个:

uint64_t ***db = new uint64_t*[2][64];
但是,这是不正确的:

cannot initialize a variable of type 'uint64_t ***' (aka 'unsigned long long ***') with an rvalue of type 'uint64_t *(*)[64]'
请注意,当我用
auto
替换类型时,代码工作正常


变量的正确类型是什么?

数组不是指针

void *ptr;
uint64_t test;
 
ptr = phys_to_virt(physAddr);
test = *(uint64_t*)ptr;
在左边有一个指向整数指针的指针

在右边,返回一个指向整数指针数组的指针

这些类型不匹配

现在,在C/C++中,指针和数组令人困惑。这是因为数组很快就会变成指针

您的三星变量可用于存储锯齿状指针数组

要生成一个二维交错数组,您需要为第一个维度分配指针数组,然后分配一个或多个缓冲区来存储元素。到目前为止,最简单的方法是向量向量

当然,无论出于何种原因,您坚持使用原始指针,它看起来像:

template<class T>
T*const* make_packed2d( std::size_t x, std::size_t y ){
  T* inner = new T[x*y];
  T**outer = new T*[x];
  for (std::size_t i=0; i!=x;++i){
    outer[i]=inner+(i*y);
  }
  return outer;
}
template<class T>
void free_packed2d(T*const* ptr){
  if(!ptr) return;
  delete[] ptr[0];
  delete[] ptr;
}
左边是可以存储所用新表达式的变量类型。我只是从错误消息中复制了它,并在适当的位置添加了变量名

您会注意到“64”大小是硬编码到变量类型中的。C/C++中的“锯齿”数组是指向数组的指针数组,而N维数组是数组数组数组,其中子数组的大小是固定的

“锯齿”的优点是,您不需要知道子尺寸作为类型的一部分。非锯齿的优点是内存是连续的,并且不需要指向子数组的子缓冲区


我的
make_packed2d
尝试分割差异;它有一个指向子数组的子缓冲区,但它使实际数据连续,并且子缓冲区指向子数组的子部分。

您可以使用typedef来简化语法。那么答案类似于:

#包括
类型定义uint64_t*uint64_p;
int main(){
uint64_p**db=新uint64_p*[2];
uint64_t num=5;
db[0]=新uint64_p[64];
db[1]=新uint64_p[64];
db[0][0]=&num;

std::cout如果需要指向堆上数组的指针,可以使用指向第一个元素的指针。这意味着它的类型与分配单个元素的类型相同:

uint64_t* p1 = new uint64_t;
uint64_t* p2 = new uint64_t[2];
在第二行中,您应该只使用
p
p+1
,因为
p+2
在本例中超出了范围。这也适用于下面带括号的所有示例

如果您创建一个指向多维数组的指针,那么您也会使用指向第一个元素的指针,但表示法会略有变化。您并不总是需要括号,但我将括号保留在其中以清楚地查看模式:

uint64_t (*p1) = new uint64_t; // Optional parentheses.
uint64_t (*p2) = new uint64_t[2]; // Optional parentheses.
uint64_t (*p3)[3] = new uint64_t[2][3]; // Required parentheses.
uint64_t (*p4)[3][4] = new uint64_t[2][3][4]; // Required parentheses.
正如你所看到的,当有括号时,我们需要括号

现在是指针:

uint64_t *(*p1) = new uint64_t*; // Optional parentheses.
uint64_t *(*p2) = new uint64_t*[2]; // Optional parentheses.
uint64_t *(*p3)[3] = new uint64_t*[2][3]; // Required parentheses.
uint64_t *(*p4)[3][4] = new uint64_t*[2][3][4]; // Required parentheses.
最后一轮奖金:

uint64_t **(*p1) = new uint64_t**; // You can leave out the parentheses.
uint64_t **(*p2) = new uint64_t**[2]; // You can leave out the parentheses.
uint64_t **(*p3)[3] = new uint64_t**[2][3];
uint64_t **(*p4)[3][4] = new uint64_t**[2][3][4];

这回答了你的问题吗?这是std::array存在的一种符号,有助于使文章更清晰。@RushikeshTalokar我不这么认为——他们在LHS上使用auto。虽然这个代码片段可以解决这个问题,但确实有助于提高文章的质量。请记住,你是在为将来的读者回答这个问题,并且人们可能不知道你的代码建议的原因。这是一个很好的答案,因为它揭示了类型中何时存在数组大小的模式。谢谢!@dylhunn:很高兴它有帮助!
uint64_t (*p1) = new uint64_t; // Optional parentheses.
uint64_t (*p2) = new uint64_t[2]; // Optional parentheses.
uint64_t (*p3)[3] = new uint64_t[2][3]; // Required parentheses.
uint64_t (*p4)[3][4] = new uint64_t[2][3][4]; // Required parentheses.
uint64_t *(*p1) = new uint64_t*; // Optional parentheses.
uint64_t *(*p2) = new uint64_t*[2]; // Optional parentheses.
uint64_t *(*p3)[3] = new uint64_t*[2][3]; // Required parentheses.
uint64_t *(*p4)[3][4] = new uint64_t*[2][3][4]; // Required parentheses.
uint64_t **(*p1) = new uint64_t**; // You can leave out the parentheses.
uint64_t **(*p2) = new uint64_t**[2]; // You can leave out the parentheses.
uint64_t **(*p3)[3] = new uint64_t**[2][3];
uint64_t **(*p4)[3][4] = new uint64_t**[2][3][4];