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
每行中元素的数量.因此,执行数组索引操作需要数组的行大小,并且将数组变量强制转换为指针会丢失该信息.
我想将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)
为什么你不能只投中一个二维数组T
来T**
?好吧,因为他们彼此无关!
您可以将a转换T[a]
为a,T*
因为您获得了指向数组的第一个元素的指针.
您也可以使用2D数组执行此操作,但如果您有,T[a][b]
那么它会衰减为a,(T[b])*
因为2D数组不是指针数组,它是一个数组数组.
这是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'
+------------+-------+
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)
。这对于char
s 是正确的,但对于占用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]
。这是因为在执行指针算术时,c ++考虑了要操作的地址的类型,因此增加a 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'
+------------+-------+
Run Code Online (Sandbox Code Playgroud)
因为我们知道一维数组的值实际上只是一个指针,所以我们可以从此内存布局中看到name[0]
不是指针,它只是第一个数组的第一个字符。因此name
不包含2个1维数组指针,但包含2个数组的内容。(顺便说一句,在不存储指针的32位计算机上,可以节省8字节的内存,这对于8字节的2维数组来说是相当大的。)因此,尝试将name
a视为char**
将尝试使用字符作为指针。
了解了这一点之后,我们真的只需要避免使用c ++的指针算法来找到对该值的取消引用。为此,我们需要使用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)
请注意,在此示例中,即使我参考si2DArray
以为psi2DPointer
我仍在使用来自的信息si2DArray
来进行索引,即:
size(si2DArray)
size(*si2DArray)
sizeof(*si2DArray)
sizeof(**si2DArray)
因此,您可以看到从数组转换为指针会造成大量信息丢失。您可能会想保留元素类型,从而简化指针算法。值得注意的char*
是,httpreinterpret_cast
://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing仅将转换为定义的行为。