二维数组转换为指针指针
Activity solution[a][b]; ... Activity **mother = solution;
我想将二维数组的对象转换为指针指针。 我怎样才能做到这一点;
我在谷歌search它。 但是我发现只有一个维数组的例子。
单纯的转换不会帮助你。 二维数组types和指针指针types之间没有任何兼容性。 这样的转换是没有意义的。
如果你真的需要这样做,你必须引入一个额外的中间“行索引”数组,这将弥合二维数组语义和指针指针语义之间的差距
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]
。
你可以做一维数组而不是二维数组的原因与实际数组元素存储在内存中的方式有关。 对于一维数组,所有元素都是连续存储的,所以expression式array[i]
等价于expression式*(array + i)
。 如您所见,数组大小不需要执行数组索引操作。 但是,对于二维数组,元素以“主要行”顺序存储,这意味着第零行中的所有元素都先存储,然后是第一行中的元素,接着是第二行中的元素因此,expression式array[i][j]
相当于*(array + (i * ROW_SIZE) + j)
,其中ROW_SIZE
是每行中元素的数量。 因此,数组的行大小需要执行数组索引操作,而将数组variables转换为指针会丢失该信息。
我想将二维数组的对象转换为指针指针。 我该怎么做?
为什么? 是因为一个接口需要一个指向指针的指针吗?
如果是这样,你需要创build一个包含这些指针的新数组。
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*
因为您获得了指向数组的第一个元素的指针。
你也可以用二维数组来做这个,但是如果你有一个T[a][b]
那么它衰变到一个(T[b])*
因为二维数组不是指针数组,而是一个数组。
这是c ++ ! 一切皆有可能! 但是这是c ++,所以需要一定程度的理解。
为此,我们以2个一维数组的简单例子开始: 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
这些数组真的只是一个指向他们第一个元素的指针! 这说明了arrays指针衰减,你可以阅读更多关于这里: http : //en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay
在我们继续讨论之前,需要注意一些重要的事情, char
必须占用1个字节,因此数组中每个后续char
的地址将只是下一个地址。 下标运算符就是这样使用的: firstName[1]
相当于*(firstName + 1)
。 这对于char
是正确的,但对于占用超过1个字节的任何其他types也是如此。 举个例子: short siArray = { 1, 2, 3, 4 }
, 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])
会输出:
0x76543218 0x7654321A
*(siArray + 1)
仍将索引与siArray[1]
相同的siArray
元素。 这是因为当进行指针运算时, c ++会考虑正在运行的地址的types,因此增加一个short*
实际上会增加sizeof(short)
的地址。 你可以在这里阅读更多关于指针运算的知识: http : //en.cppreference.com/w/cpp/language/operator_arithmetic
最后让我们看看c ++如何存储二维数组。 鉴于: char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } }
一个可能的内存布局将是:
+------------+-------+ | 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
不包含2个1维数组指针,但包含2个数组的内容。 (顺便说一下,在没有存储指针的32位机器上,会节省8字节的内存,这对于一个8字节的二维数组非常重要。)因此,试图将name
当作char**
来尝试使用字符作为指针。
了解了这一点之后,我们确实需要避免使用c ++的指针运算来find这个值。 要做到这一点,我们需要使用char*
以便加1就是加1。
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; }
现场示例
请注意,在这个例子中,即使我引用si2DArray
认为psi2DPointer
我仍然使用来自si2DArray
信息做索引,即:
- 主要维度中有多less个数组:
size(si2DArray)
- 次要维度中有多less个元素:
size(*si2DArray)
- 小维度的内存大小是多less:
sizeof(*si2DArray)
- 什么是数组的元素types:
sizeof(**si2DArray)
您可以看到,从数组转换为指针所造成的信息丢失是相当大的。 您可能会试图保留元素types,从而也简化了指针运算。 值得注意的是,只有转换为char*
才能被reinterpret_cast
视为定义的行为: http : //en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
你不能。 他们是根本不同的types。
不知道你是否在寻找这样的东西。 你应该提供更多关于你想达到的细节。 他们是根本不同的types。 一个解决scheme是在下面。
为了logging,如果有人认为它有用:
// 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]); } }