簡體   English   中英

訪問2D陣列時到底發生了什么

[英]What exactly happens when accessing a 2D array

我已經編碼了一段時間了,但是才意識到我對一個非常基本的操作的困惑可能會引起混淆。

int array[10][10];

array[1][1] = 0;

這足夠樣本-數組+(10 * 1 + 1)* sizeof(int)的地址分配為0。

但是,當進行動態數組時呢?

int **array;

// malloc/new the base array of pointers - say 10 as above.
array = malloc(10 * sizeof(int *));

// through pointers and alloc each with ints - again 10 per row as above.
for(int i=0; i<10; i++) 
    array[i] = malloc(10 * sizeof(int);

array[1][1] = 0;

在此示例中,編譯器必須引用數組第一層上的數組才能到達第二個指針才能到達內存。 同樣,此過程很簡單。

我的問題是:編譯器如何知道內存是連續的,因此它只能執行簡單的數學運算,而不是第一個示例中的引用,而不能在第二個示例中進行引用?

如果答案是:因為編譯器事先知道了數組的大小,那么就可以了,但是有一種方法可以告訴編譯器動態數組是單個分配,因此它可以執行更簡單的數學運算而不是額外的deref和額外的內存碎片分配? 或者,這是否需要VLA支持,以得到正確的按照這個職位它是這樣:

double (*A)[n] = malloc(sizeof(double[n][n]));

另一個網站也列出了這種可能性:

int r=3, c=4;
int **arr;

arr  = (int **)malloc(sizeof(int *) * r);
arr[0] = (int *)malloc(sizeof(int) * c * r);

真正讓我想知道編譯器如何解決問題,或者這是否只是使用VLA支持的另一種方式。

對於C ++,有boost和nested向量,但是它們甚至比上面的還要重,因此,如果可能的話,我會避免使用它們。


更新

老實說,我在這里應該做的只是編譯上面的示例,並在匯編輸出中輕描淡寫。 那將立即回答我所有的問題。 我的誤解是,我假設所有n維數組訪問都是通過與在編譯時已知的數組中進行數學運算類似的方式完成的。 我沒有意識到[] []作為**array ,在對動態分配的每個取消引用之間都進行了適當的索引編制,而對[i * dim + j]進行了雙重處理,而對編譯時已知的類型卻做了相應的索引。 動態2維數組不是我必須要做的事情。

int **int[10][10]的類型不同。

int **類型不包含有關有多少個元素的任何信息,因為它不是數組類型,而是指針類型(特別是指向int *的指針)。 int[10][10]包含編譯器需要知道所有元素的所有信息。

如果您嘗試在指針vs數組上使用sizeof ,則會注意到這一點。 下面的程序演示了這一點:

#include <stdio.h>                                                             

int main ( int argc, char * argv[] ) { 

    printf( "Size of int[10][10]: %lu\n", sizeof(int[10][10]) );
    printf( "Size of int**: %lu\n", sizeof(int**) );

    return 0;
}

動態內存不是在編譯時分配的,而是在運行時編譯的,因此,更改動態內存創建方式的編譯器最終可能會修改程序的行為(即,通過分配比一個連續的塊,並且malloc返回null)。

當然,您可以為100 ints分配足夠的內存,然后自己進行算術運算,從而獲得連續的內存塊:

int * mem = malloc( 10 * 10 * sizeof( int ) );

現在mem是100個整數的連續塊

int * array[10];
for ( int i = 0; i < 10; i++ )
    array[i] = &mem[10*i];

現在,您有一個10 int * s的數組,可以像以前一樣用於索引到mem(此數組是靜態分配的,但是如果要從此函數返回它,則需要動態分配它)。

因為類型完全不同。

在第一種情況下,具有二維的數組中的類型以及每個維度的長度是已知的,因此可以直接計算地址,並引用一次。

在第二種情況下,類型完全不同,類型是雙指針。 指向某種類型的指針的數組的指針,在您的情況下為int

編譯器只知道array是一個指向array的指針,該數組的大小未知,指向int的指針。 array是一個

int **array;

並且array[x]是一個指向int的指針。 注意,它只是一個指向int的指針。 它沒有指出它要指向多少個int

它可以只是一個int ,也可以不是。 每個指向int指針都可以指向不同數量的int

例如,array [0]可能指向十個整數。 array [1]可能指向20個int 沒有什么要求array [x]指向與array [y]相同數量的int

那個工作屬於你,程序員。 編譯器一無所知。 您需要為每個此類指針正確地將每個指針分配給一個int ,並為其分配正確數量的int ,然后首先將正確數量的指針分配給int 編譯器不知道每個有多少個,您的工作就是以某種形式或方式跟蹤它,以便編寫無錯誤的代碼。

歡迎使用C ++。

暫無
暫無

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

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