将2D数组转换为指针指针

时间:2011-11-20 18:35:48

标签: c++ pointers static

Activity solution[a][b];

...

Activity **mother = solution;

我想将2D对象数组转换为指向指针的指针。我怎么能这样做;

我在谷歌搜索过它。但是我发现只有一个维度数组示例。

6 个答案:

答案 0 :(得分:16)

单纯的转换对您没有帮助。在2D数组类型和指针到指针类型之间没有任何类型的兼容性。这样的转换毫无意义。

如果你真的需要这样做,你必须引入一个额外的中间“行索引”数组,它将弥合2D数组语义和指针到指针语义之间的差距

Activity solution[a][b];

Activity *solution_rows[a] = { solution[0], solution[1] /* and so on */ };

Activity **mother = solution_rows;

现在,访问mother[i][j]可以访问solution[i][j]

答案 1 :(得分:11)

您可以为一维数组而不是二维数组执行此操作的原因与实际数组元素存储在内存中的方式有​​关。对于一维数组,所有元素都是连续存储的,因此表达式array[i]等同于表达式*(array + i)。如您所见,执行数组索引操作不需要数组大小。但是,对于二维数组,元素以“行主要”顺序存储,这意味着第一行中的所有元素都先存储,然后是第一行中的元素,后面是第二行中的元素因此,表达式array[i][j]等同于*(array + (i * ROW_SIZE) + j),其中ROW_SIZE是每行中元素的数量。因此,执行数组索引操作需要数组的行大小,并且将数组变量强制转换为指针会丢失该信息。

答案 2 :(得分:6)

  

我想将2D对象数组转换为指向指针的指针。我怎么能这样做?

为什么呢?是因为接口需要指向指针的指针吗?

如果是这样,您需要创建一个包含这些指针的新数组。

Activity solution[a][b];

Activity* solutionPtrs[a];
for (int i = 0; i < a; ++i)
    solutionPtrs[a] = solution[a];

Activity** mother = solutionPtrs;

为什么您只能将T的二维数组投射到T**?好吧,因为他们彼此没有任何关系!

您可以将T[a]强制转换为T*,因为您获得了指向数组第一个元素的指针。

您也可以使用2D数组执行此操作,但如果您有T[a][b],则它会衰减为(T[b])*,因为2D数组不是指针数组,它是一个数组数组。

答案 3 :(得分:4)

这是!一切皆有可能!但是这是所以它需要一定程度的理解。

为此,让我们从2个1维数组的简单示例开始:char firstName[4] = { 'J', 'o', 'n', '\0' }char lastName[4] = { 'M', 'e', 'e', '\0' }让我们看一下可能的内存布局:

+------------+-------+
|  Address   | Value |
+------------+-------+
| 0x76543210 | 0x4A  | <- firstName[0] - 'J'
| 0x76543211 | 0x6F  | <- firstName[1] - 'o'
| 0x76543212 | 0x6E  | <- firstName[2] - 'n'
| 0x76543213 | 0x00  | <- firstName[3] - '\0'
+------------+-------+
| 0x76543214 | 0x4D  | <- lastName[0] - 'M'
| 0x76543215 | 0x65  | <- lastName[1] - 'e'
| 0x76543216 | 0x65  | <- lastName[2] - 'e'
| 0x76543217 | 0x00  | <- lastName[3] - '\0'
+------------+-------+

如果您要cout << firstName << ' ' << lastName进行此内存布局,请获取:

  

0x76543210 0x76543214

这些数组实际上只是指向第一个元素的指针!这说明了数组到指针衰减,您可以在这里阅读更多信息:http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay

在我们继续前进之前,需要注意一些重要事项,char正好占用1个字节,因此数组中每个后续char的地址将只是下一个地址。由此Subscript OperatorfirstName[1]方式利用*(firstName + 1)等同于char。这适用于short siArray = { 1, 2, 3, 4 },但对于占用超过1个字节的任何其他类型也是如此。我们举个例子:siArray+------------+--------+ | Address | Value | +------------+--------+ | 0x76543218 | 0x0001 | <- siArray[0] - 1 | 0x7654321A | 0x0002 | <- siArray[1] - 2 | 0x7654321C | 0x0003 | <- siArray[2] - 3 | 0x7654321E | 0x0004 | <- siArray[3] - 4 +------------+--------+ 可能的内存布局如下:

cout << siArray << ' ' << &(siArray[1])

即使*(siArray + 1)将输出:

  

0x76543218 0x7654321A

siArray仍会将siArray[1]的相同元素编入索引short*。这是因为在进行指针算术时会考虑正在操作的地址的类型,因此递增sizeof(short)实际上会使地址增加char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } }。您可以在此处阅读有关指针算术的更多信息:http://en.cppreference.com/w/cpp/language/operator_arithmetic

最后,让我们看一下如何存储二维数组。给定:+------------+-------+ | Address | Value | +------------+-------+ | 0x76543220 | 0x4A | <- name[0][0] - 'J' | 0x76543221 | 0x6F | <- name[0][1] - 'o' | 0x76543222 | 0x6E | <- name[0][2] - 'n' | 0x76543223 | 0x00 | <- name[0][3] - '\0' | 0x76543224 | 0x4D | <- name[1][0] - 'M' | 0x76543225 | 0x65 | <- name[1][1] - 'e' | 0x76543226 | 0x65 | <- name[1][2] - 'e' | 0x76543227 | 0x00 | <- name[1][3] - '\0' +------------+-------+ 可能的内存布局为:

name[0]

由于我们知道一维数组值实际上只是一个指针,我们可以从这个内存布局中看到name 不是一个指针,它只是第一个数组的第一个字符。因此name 包含2个1维数组指针,但包含2个数组的内容。 (顺便提一下,在没有存储指针的32位机器上可以节省8个字节的内存,这对于8字节的二维数组非常重要。)因此,试图将char**视为char*会尝试将这些字符用作指针。

理解了这一点后,我们真的只需要避免使用的指针算法来找到取消引用值。为此,我们需要使用const short si2DArray[2][3] = { { 11, 12, 13 }, { 21, 22, 23 } }; const auto psi2DPointer = reinterpret_cast<const char*>(si2DArray); for(auto i = 0U; i < size(si2DArray); ++i) { for(auto j = 0U; j < size(*si2DArray); ++j) { cout << *reinterpret_cast<const short*>(psi2DPointer + i * sizeof(*si2DArray) + j * sizeof(**si2DArray)) << '\t'; } cout << endl; } ,以便添加1实际上只是添加1.例如:

si2DArray

Live Example

请注意,在此示例中,即使我引用psi2DPointer认为si2DArray我还在使用size(si2DArray)中的信息进行索引,即:

  1. 主要维度中有多少个数组:size(*si2DArray)
  2. 次要维度中有多少个元素:sizeof(*si2DArray)
  3. 次要维度的记忆大小:sizeof(**si2DArray)
  4. 数组的元素类型是什么:char*
  5. 因此,您可以看到从数组转换为指针的信息丢失很大。您可能想要保留元素类型,从而也简化了指针算法。值得注意的是,只有转化为reinterpret_cast// in Link.js import React from 'react'; import '../../styles/Link.css' const Link = ({children, href}) => ( <a className="link" href={href}>{children}</a> ); 视为已定义的行为:http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing

答案 4 :(得分:0)

你做不到。它们基本上是不同的类型。

答案 5 :(得分:0)

不确定您是否在寻找这样的东西。您应该提供有关您想要实现的目标的更多详细信息。它们基本上是不同的类型。一种解决方案是在下面。

对于记录,如果有人发现它有用:

// define matrix
double A[3][3] = {
    { 1, 2, 3},
    { 4, 5, 6},
    { 7, 8, 9}
};

// allocate memory
double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
for (int i = 0; i < 3; i++)
    A_ptr[i] = (double *) malloc(sizeof (double) * 3);

// copy matrix
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        A_ptr[i][j] = A[i][j];
        printf(" %f ", A_ptr[i][j]);
    }
}