2011-11-20 126 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