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

Bah*_*can 18 c++ static pointers

Activity solution[a][b];

...

Activity **mother = solution;
Run Code Online (Sandbox Code Playgroud)

我想将2D对象数组转换为指向指针的指针.我怎样才能做到这一点;

我在谷歌搜索它.但是我发现只有一个维数组的例子.

AnT*_*AnT 16

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

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

Activity solution[a][b];

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

Activity **mother = solution_rows;
Run Code Online (Sandbox Code Playgroud)

现在访问mother[i][j]将为您提供访问权限solution[i][j].


che*_*007 11

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


Pet*_*der 6

我想将2D对象数组转换为指向指针的指针.我怎样才能做到这一点?

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

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

Activity solution[a][b];

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

Activity** mother = solutionPtrs;
Run Code Online (Sandbox Code Playgroud)

为什么你不能只投中一个二维数组TT**?好吧,因为他们彼此无关!

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

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

  • 这行不应该是`solutionPtrs[a] = solution[a];`是`solutionPtrs[i] = solution[i];` (2认同)

Jon*_*Mee 6

这是!一切皆有可能!但这是因此需要一定程度的理解。

为此,让我们用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'
+------------+-------+
Run Code Online (Sandbox Code Playgroud)

给定这种内存布局,cout << firstName << ' ' << lastName您将获得:

0x76543210 0x76543214

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

在继续进行之前,char需要注意一些重要的事情,s恰好占据了1个字节,因此char数组中每个后继的地址将只是下一个地址。下标运算符以这种方式利用了这一点:firstName[1]等效于*(firstName + 1)。这对于chars 是正确的,但对于占用1个字节以上的任何其他类型也是如此。让我们举个例子: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
+------------+--------+
Run Code Online (Sandbox Code Playgroud)

即使cout << siArray << ' ' << &(siArray[1])会输出:

0x76543218 0x7654321A

*(siArray + 1)仍将索引相同的元素siArray作为siArray[1]。这是因为在执行指针算术时,考虑了要操作的地址的类型,因此增加a short*实际上将使地址增加sizeof(short)。您可以在此处阅读有关指针算术的更多信息:http : //en.cppreference.com/w/cpp/language/operator_arithmetic

最后,让我们看一下如何存储二维数组。给定: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'
+------------+-------+
Run Code Online (Sandbox Code Playgroud)

因为我们知道一维数组的值实际上只是一个指针,所以我们可以从此内存布局中看到name[0] 不是指针,它只是第一个数组的第一个字符。因此name 包含2个1维数组指针,但包含2个数组的内容。(顺便说一句,在不存储指针的32位计算机上,可以节省8字节的内存,这对于8字节的2维数组来说是相当大的。)因此,尝试将namea视为char**将尝试使用字符作为指针。


了解了这一点之后,我们真的只需要避免使用的指针算法来找到对该值的取消引用。为此,我们需要使用a,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;
}
Run Code Online (Sandbox Code Playgroud)

Live Example

请注意,在此示例中,即使我参考si2DArray以为psi2DPointer我仍在使用来自的信息si2DArray来进行索引,即:

  1. 主要维度中有多少个数组: size(si2DArray)
  2. 次要维度中有多少个元素: size(*si2DArray)
  3. 次要维度在内存中的大小是多少: sizeof(*si2DArray)
  4. 数组的元素类型是什么: sizeof(**si2DArray)

因此,您可以看到从数组转换为指针会造成大量信息丢失。您可能会想保留元素类型,从而简化指针算法。值得注意的char*是,httpreinterpret_cast//en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing仅将转换为定义的行为。