2011-11-20 106 views
14
Activity solution[a][b]; 

... 

Activity **mother = solution; 

我想将二维数组对象转换为指针指针。我怎样才能做到这一点;将二维数组转换为指针指针

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

+0

[相关FAQ](http://stackoverflow.com/questions/4810664/) – fredoverflow

回答

13

一个单纯的转换不会帮助你在这里。二维数组类型和指针指针类型之间没有任何兼容性。这种转换将毫无意义。

如果你真的真的需要做到这一点,你必须引入一个额外的中间“行索引”阵列,这将弥补二维数组语义和指针到指针语义

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]

+0

谢谢。它解决了我的问题 –

0

你不行。它们是根本不同的类型。

+0

能详细解释一下吗? –

+0

如果你更详细地描述你想用'mother'做什么,那么我可以在我的答案中给你一个建议。 –

4

我想将二维数组对象转换为指针指针。我怎样才能做到这一点?

为什么?是否因为接口期望指向指针的指针?

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

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])*因为二维数组不是指针数组,它是一个数组数组。

+0

谢谢。它解决了我的问题 –

8

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

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]); 
    } 
} 
3

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

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

+------------+-------+ 
| Address | Value | 
+------------+-------+ 
| 0x| 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你倒是得到:

0x0x76543214

这些AR射线实际上只是它们第一个元素的指针!这说明数组的指针衰减,你可以在此处详细了解:http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay

在我们继续之前有一些重要的事情,这里要注意,char。就拿起来正好是1个字节,从而每个后续char的数组中的地址会只是成为下一个地址。 Subscript Operator就是这样利用的: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 
+------------+--------+ 

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

0x76543218 0x7654321A

*(siArray + 1)仍将指数相同siArray的元素为siArray[1]。这是因为在进行指针运算时,会考虑正在操作的地址的类型,因此增加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' 
+------------+-------+ 

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


参透这一点,我们真的只需要避免使用的指针运算找到取消引用值。要做到这一点,我们需要一个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; 
} 

Live Example

注意,在即使我引用这个例子si2DArray认为psi2DPointer我仍在使用信息,从si2DArray做索引,即:

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

你可以由此看出从数组转换为指针所造成的信息丢失是很大的。您可能会试图保留元素类型,从而也简化了指针算术。这是值得指出的reinterpret_cast,只有到char*转换被认为是定义的行为:http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing

+0

非常感谢Jonathan为您提供的解决方案。你知道这种转换引起的开销吗?你的意思是“转换是实质性的”? – khateeb