簡體   English   中英

cArray [] []指針數組轉換

[英]cArray[][] Pointer Array Casting

我在使用供應商API檢測設備數據時遇到問題。 供應商文檔中建議的調用的工作版本如下所示:

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

呼叫簽名描述為:

void getData(xSize, ySize, int*);

我有興趣使用此函數將數據復制到具有動態大小的連續數組中,具體如下:

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

我很難接到正確的電話,並且段錯誤有點難以調試:(

我認為我的誤解是關於如何表示int數組,以及當你將它轉換為(int *)時會發生什么。 在這個例子中是int **類型的“dataArray”,還是其他什么? 如果是這樣,你是否需要構造一個指向flatDataArray的指針數組,以使上述函數正常工作?

由於演員陣容,第一行“有效”。

鑒於:

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線性背景構建xSize by ySize 因為這是C,所以使用該語言的VLA(可變長度數組)功能也可以使用以下內容:

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

假設xSize數,而ySize是你尋找的數(我似乎錯過了一半的時間,這就是為什么我更喜歡monikers“row”和“col”)。 上面的分配說“為xSize int[ySize]事物的xSize數分配空間。”。 代碼中的好處就是你可以解決這個問題,就像二維數組陣列一樣(這正是它):

arr2d[i][j] = value;

對於任何i0..(xsize-1)j0..(ysize-1) ,就像你想/可能就像你正常宣布它一樣。 這個(VLA)是C做得很好的一點,C ++沒有(但是再一次,C ++中有容器 - 大量的東西,它們首先會以不同的方式解決這個問題,所以它不是真的公平比較)。

祝你好運。

對於聲明如下的二維數組:

double dataArray[15][20];

扁平化的版本將簡單如下:

dataArray[0];

如果你要將第一個double的地址存儲到指針(地址變量)中,則為double

double * flatDataArray = dataArray[0];

例如,以下循環以連續的方式訪問每個元素,這要歸功於它們已經是連續的而且從不在多維中:

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

根據編輯:將所有double更改為int或您希望的任何類型。

假設它是char ,這是它的樣子,以及dataArray*dataArray**dataArray會是什么樣的:

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

dataArray可能不會被解除引用 ,最多兩次。 通過獲取**dataArray的地址,您將擁有*dataArray 類似於*dataArray 不適用於dataArray ,在這種情況下,您只需簡單地使用&dataArray

&dataArraydataArray*dataArray每一個都將具有相同的 ,即char0的地址,或從char0char14的數組,或從char0-char14跨越到char285-char299的數組數組。

**dataArray將具有char0保存的值。

其他三個有什么區別? 嗯,他們指向不同的類型,因此增加它們將有不同的解釋。 這類似於當遞增整數指針時,前進4個字節而不是1個字節。

如果你碰巧將&dataArray遞增1,比如&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]就是dataArray[0][1]
  • 比如說,我們總共會增加15倍
  • dataArray[0][15]

看似非法,不是嗎? 嗯,事實並非如此,因為內存的那一部分仍然在為你分配的部分內。 實際上,你可以使用dataArray[0][299] 它只意味着提前299個字節,並訪問該位置 ,該位置全部屬於您。

瘋了,不是嗎? 更瘋狂的是我寫了很多關於它的文章。 我甚至不確定這是否會回答你的問題...我getData(15, 20, dataArray[0]);這樣的調用getData(15, 20, dataArray[0]); getData(15, 20, *dataArray); 因此會更加明智,盡管我懷疑那里的類型會失敗。

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

這段代碼很好:

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

並且它的工作原理是因為您通過指向int的指針查看整個對象dataArray ; 由於dataArray確實包含整數,因此沒有任何別名沖突。

編寫getData(15, 20, dataArray[0]);將是未定義的行為getData(15, 20, dataArray[0]); 因為在這種情況下,您使用的指針只是20個整數的數組,這是dataArray的第一個元素,因此不允許溢出這20個整數。 (參考: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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM