2011-04-05 76 views
7

我需要修改一些C++代碼,但由於我對語言比較陌生,因此無法理解某些表達式。數組:你能解釋這行代碼在做什麼嗎?

我有一個函數

void func(double m[2][12],double n[2][3]) 

是從調用的其他函數中這樣

double A[12]; 
double B[6]; 
(...) 
func((double (*)[12])A, (double (*)[3])B) 

的最後一行代碼是鑄造一維數組到2D的,但什麼是發生在那裏?我可以使用相同的技術,一維數組轉換成2D,這樣?:

double A[12]; 
double B[6]; 
(double (*)[12])A[0][5] = 5; 
+0

如果你正在使用C++並有權訪問C++ 0x我強烈建議使用std :: array。 – shuttle87 2011-04-05 18:41:46

回答

7

正在發生的事情是你所提到的正是 - 呼叫者鑄造1個維數組成,以便將它們傳遞給func(),它有兩個指向2D數組的參數。由於C中的二維數組只是'數組數組'(即沒有涉及指針),所以這種轉換當然是可能的。例如,該一維數組:

int oneDimensionalArray[] = { 0, 1, 2, 3 }; 

這2D陣列:

int twoDimensionalArray[] = { { 0, 1 }, 
           { 2, 3 } }; 

具有完全相同的存儲器佈局。你可以通過使用像你問題中那樣的瘋狂城鎮投射操作來強制類型匹配。

至於你的第二個問題,是的,你可以做到這一點,但你需要一個更多的括號:

((double (*)[12])A)[0][5] = 5; 

我不建議編寫代碼以這種瘋狂的事情怎麼回事,雖然。節目從哪裏來?

+1

+1爲「瘋狂鎮鑄造操作」 – Duck 2011-04-05 17:50:30

+1

在一個非常迂腐的層面上,不相關的指針類型之間的這種重新解釋鑄造不保證有什麼好處,但我認爲沒有實現這種方法無效的實現。 – Cubbi 2011-04-05 17:50:41

+0

該函數實際上有兩個指向1D數組的參數,而不是2D。另外,你的'twoDimensionalArray'聲明是無效的。此外,就第一個參數而言('A'),不存在對內存佈局的依賴。第二個參數('B')雖然有問題。 – AnT 2011-04-05 18:37:59

1

鑄造不是從一維到二維數組,而是一個指向靜態一維數組的指針!

double m1[12]; 

裝置類型的變量M1

double m2[2][12]; 

12個雙打靜態數組」是指隱含推斷類型'類型「的靜態陣列的2種元素的靜態陣列的可變平方米12雙打「' 當靜態數組用作函數參數時,它們退化爲數組元素類型的指針。 因此,對於陣列M1,上述我們可以使用任何以下功能

f11(double arg[12]) {} 
f12(double * arg) {} 

既可以與任何指針被調用以一倍或像雙元件的任何數組:

double a=0.0; 
double b[10]; 
f11(&a); f11(b); 
f12(&b); f12(b); 

類似地,對於陣列m2(上面),單個元素的類型是'double [12]'。因此,我們可以使用任何以下功能:

f21(double arg[2][12]) {} 
f22(double * arg[12]) {} 

其可與任何指針爲「陣列12的雙打」或類型「陣列12個雙打」等的元件的任何陣列可以稱爲:

double c[12]; 
double d[6][12]; 
f21((double (*)[12])c); f21(d); 
f22((double (*)[12])c); f22(d); 

現在爲您的代碼,功能void func(double m[2][12],double n[2][3])實際上需要一個指向和指向「的3個雙打靜態數組「的12個雙打靜態數組」 」。因此,你看到

double A[12]; 
double B[6]; 
func((double (*)[12])A, (double (*)[3])B) 

呼叫實際施放A(其被退化爲指向double)的指針的「12個雙打靜態數組」和投下B(其也退化爲指向double)指向'3雙打的靜態數組' 因爲所有給定的數組都使用雙精度,並且靜態數組在內存中按順序表示,所以這種強制轉換可能不會導致邏輯錯誤。

0

聲明

void func(double m[2][12],double n[2][3]) 

相當於

void func(double (*m)[12],double (*n)[3]) 

即第一陣列尺寸並不重要。頂層數組類型衰減爲指針類型,從而將2D數組參數聲明轉換爲指向1D數組的參數聲明。

此功能可與這些參數

double A[12]; 
double B[3]; /* note 3 instead of 6 */ 

正確的方式做被稱爲那就乾脆

func(&A, &B); 

注意,不投是必要的,只是&運營商的應用,給予AB已經有適當的類型(在本例中爲double[12]double[3])。在這種情況下,只能訪問m[0][i]n[0][i],但不能訪問m[1][i]n[1][i],因爲這些不存在。

在你的例子中,代碼的作者採取了一些真正奇怪的步驟。

首先,顯然作者並沒有意識到第一個參數可以表示爲&A,不需要強制轉換,因爲A是用適當的類型聲明的。

其次,完全不清楚爲什麼B被聲明爲大小爲6的數組,當函數需要大小爲3的數組時。爲了強制這個參數進入該函數,確實需要顯式強制轉換。

這兩個參數傳遞的方式只是一個錯誤代碼的例子。


作爲將一維數組成2D陣列......只要記住,在C和C++ T類型的任何對象可以被解釋爲與T類型的1個元素的一維數組。只需要將&運算符應用於該對象。例如

int i = 0; 
(&i)[0] = 5; /* access `&i` as `int[1]` array */ 
assert(i == 5); 

如果所討論的對象本身就是一個數組,那麼可以做同樣的事情。例如,一維數組可以作爲一個二維數組與第一大小等於被訪問1

int a[10] = { 0 }; 
(&a)[0][8] = 42; /* access `&a` as an `int[1][10]` array */ 
assert(a[8] == 42); 

這是在你的例子究竟發生了什麼,只是做了正確的方法是將&操作向原目的。代碼的作者使用演員達到相同的效果。演員不是正確的做法。它不能保證工作,它恰好在實踐中具有相同的效果。

相關問題