2014-06-23 137 views
1

我在用於從設備檢索數據的供應商API方面遇到問題。如在供應商的文檔建議的電話會議的工作版本看起來像下面這樣:cArray [] []指針陣列投射

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

的調用簽名被描述爲:

void getData(xSize, ySize, int*); 

我很感興趣,有這個功能將數據複製到INTS的連續數組與動態大小,像下面這樣:

int *flatDataArray = (int*) malloc(xSize * ySize * sizeof(int)); 

我有一個很難得到呼叫權限,以及內存設計缺陷是有些diffi崇拜調試:(

我想我的誤解是圍繞如何表示一個int數組,以及將它轉換爲(int *)時會發生什麼。在這個例子中是int **類型的「dataArray」,還是其他的?如果是這樣,你是否必須構造一個指向flatDataArray的指針數組才能使上述函數正常工作?

+0

指針可用於遍歷1維數組,但指向指針的指針不能用於迭代2維數組,這僅僅是數組的數組。建議閱讀:[comp.lang.c常見問題](http://www.c-faq.com/)的第6部分。 –

+0

@KeithThompson我相信,只要指針知道它指向一個*類型的n元素的數組,而不僅僅指向一個類型變量的指針。 – ThoAppelsin

+1

問題是什麼?函數將指針加倍而不是指向雙精度數組的指針。 – this

回答

2

由於演員陣容,第一行「有效」。

鑑於:

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

表達值類型dataArray獨立是int (*)[20]。一個指向數組的指針20 int。這是有道理的,因爲按照C標準,數組的表達式值是它的第一個元素的地址和所述相同的指針類型。那麼,陣列中的第一個「元素」(dataArray就是int[20]),指針類型爲int(*)[20]

也就是說,相同的規則適用於該數組數組中的第一個數組。總之,這將工作:

int dataArray[15][20]; 
getData(15, 20, dataArray[0]); 

就像dataArray是導致int (*)[20]類型的第一個元素(數組)的地址的表達式,即陣列中的第一陣列同樣具有表達值,它是地址第一個元素,int,並且與該地址關聯的類型爲int *碰巧,這是陣列數組的第一個數組的第一個元素。在底層系統的線性內存背景下,它正在運行,它最終會解析到相同的地址(其中dataArray放置在內存中)。這是與該地址相關聯的類型,取決於它如何設計,是不同的。不管類型如何,底層內存背景都是相同的:一個300 int的連續序列。下面的全部返回的地址將是相同的;只有不同的類型(並在註釋中註明)

&dataArray   // int (*)[15][20] 
dataArray    // int (*)[20] 
dataArray[0]   // int * 
&dataArray[0][0]  // int * 

並且不,這些不是唯一的組合。我至少離開了一個。看看你是否可以找出缺少的東西。

不管怎麼說,作爲分配你在這裏:

int *flatDataArray = malloc(xSize * ySize * sizeof(int)); 

的作品,因爲你只是建立一個xSize by ySize線性背景。因爲這是C,以下也將工作,利用VLA(可變長度數組)的語言的特徵:

int (*arr2D)[ySize] = malloc(xSize * sizeof(*arr2D)); 

假設xSize的數量,並且ySize的數量你尋求(我看起來錯了一半的時間,這就是爲什麼我更喜歡monikers「row」和「col」)。上面的配置說「分配給我空間xSizeint[ySize]件事」。在代碼的好處是,你可以解決這個問題,就像你陣列的二維數組(這是它到底是什麼):

arr2d[i][j] = value; 

0..(xsize-1)0..(ysize-1)任何ij,就像你/可以像你正常宣佈一樣。這個(VLA)是C做的一件事情,C++沒有做到這一點(但是再次說明,C++中有很多容器可以用一種不同的方式解決這個問題,所以它不是一個真正公平的比較)。

祝你好運。

+0

這個答案真棒謝謝! – meawoppl

1

對於一個2維數組聲明如下:

double dataArray[15][20]; 

平整出來的版本,簡直是以下幾點:

dataArray[0]; 

如果你是存儲第一的這個地址雙指針(地址變量)爲雙精度

double * flatDataArray = dataArray[0]; 

下面的循環,例如,由於訪問每一個元件以鄰接方式,這樣的事實,他們已在多維鄰接的並且從未:

for (int i = 0; i < 15 * 20; i++) { 
    dataArray[0][i]; // alternatively: flatDataArray[i]; 

作爲每編輯:更改所有doubleint,或任何你想要的類型。

說,這是的char S,這裏怎麼會變成什麼樣子,什麼dataArray*dataArray**dataArray將類似於:

char0 char1 ... char14 char15 char16 ... char29 ... char299 
// >        dataArray       < 
// >  *dataArray  < >       <    
// > < > < 
// ^the **dataArray 

dataArray可能得不到解除引用更多,兩次最大。通過使用**dataArray的地址,您的手上就會有*dataArray。類似於*dataArray。不適用於dataArray,在這種情況下,您寧可簡單地使用&dataArray

&dataArray每一個,dataArray*dataArray將具有相同的值,這是char0的地址,或跨越從char0char14陣列,或陣列的跨越從char0-char14char285-char299陣列。

**dataArray將具有char0的值。

其他三種有什麼區別?那麼,他們指向不同的類型,因此增加他們會有不同的解釋。怎麼樣,當你增加一個整數的指針,你提前4個字節,而不是1

如果你碰巧由1遞增&dataArray,像&dataArray + 1,你會提前300個字節(300 * sizeof(char))這是類似。如果您恰好將dataArray加1(這是*dataArray的地址),則會提前15個字節,依此類推。

如果您恰好將*dataArray增加1,即**dataArray,char0的地址,則會提前1個字節。現在,這裏是:

  • *dataArraydataArray[0]
  • 遞增1是dataArray[0] + 1
  • 那提領將*(dataArray[0] + 1)
  • 簡寫是dataArray[0][1]
  • 說我們是更增加它,總共15次
  • dataArray[0][15]

似乎是非法的,不是嗎?好吧,事實並非如此,因爲這部分內存仍在爲你分配的部分。事實上,你可以遠至dataArray[0][299]。它只意味着提前299個字節,並訪問該位置,並且該位置都是您的。

瘋了,不是嗎?我寫了這麼多關於它的更瘋狂。我甚至不確定這是否會回答你的問題......我想因爲getData(15, 20, dataArray[0]);getData(15, 20, *dataArray);這樣的電話會更合理,但我懷疑那裏的類型轉換會失敗。

我希望這至少對某人有意義。

+0

非常感謝徹底。在這個答案和評論之間,我想我有我需要將這一切全部整理在一起。重要的見解是,根據供應商如何實現該功能,傳遞的指針可以具有兩種語義之一。我相信,因爲在編譯時API的大小不爲人所知,所以在指針運算下必須有一些手冊。 – meawoppl

0

此代碼是罰款:

int dataArray[15][20]; 
getData(15, 20, (int*) dataArray); 

和它的作品,因爲你是個指針爲int觀看整個對象dataArray;並且由於dataArray確實包含整數,所以沒有任何別名違規。

這將是未定義的行爲,編寫getData(15, 20, dataArray[0]);,因爲在這種情況下,您使用的指針只是20個int的數組,這是dataArray的第一個元素,所以您不允許溢出這20個int。 (編號:C99 6.5。6#8)

我對具有這種功能將數據複製到雙打的鄰接陣列與動態大小

intdouble是不同的,所以可以不通過任何種類的陣列的double到這個函數(正如你已經描述過函數一樣;如果這個函數實際上需要void *然後根據一些以前的函數調用輸出數據,那將是不同的)。除非API還包含一個指向double的函數,否則您必須檢索int,然後將它們轉換爲double。例如,

int array1[xSize][ySize]; 
getData((int *)int_array); 

double array2[xSize][ySize]; 
for (size_t ii = 0; ii < xSize; ++ii) 
    for (size_t jj = 0; jj < ySize; ++jj) 
     array2[xSize][ySize] = array1[xSize][ySize]; 

最後一行執行值變換從intdouble

在C數組中可以有這樣的運行時間尺寸。 (實際上在2011年,這被改爲可選功能,以前它是標準的)。如果您使用的編譯器不再支持這種類型的數組,您可以使用malloc

如果兩個維度在編譯時都不知道,那麼你必須malloc一維數組,然後找出偏移量;例如

int *array1 = malloc(xSize * ySize * sizeof *array1); 
getData(array1); 

double *array2 = malloc(xSize * ySize * sizeof *array2); 
for (size_t ii = 0; ii < xSize * ySize; ++ii) 
    array2[ii] = array1[ii]; 

// what was previously array1[4][6] 
array2[4 * ySize + 6]; 

NB。 void getData(xSize, ySize, int*);不是有效的呼叫簽名。呼叫簽名將具有數據類型而不是變量名稱。您可以在包含的頭文件中找到函數聲明來訪問此API。