C語言中的指標和多維陣列



在 C 語言中,陣列是儲存在連續記憶體位置中的一組相同型別的值的集合。陣列(一維或多維)中的每個元素都由一個或多個唯一的整數索引標識。

另一方面,指標儲存變數的地址。陣列中第 0 個元素的地址是陣列的指標。您可以使用“解引用運算子”訪問指標指向的值。

您可以在 C 中宣告一維、二維或多維陣列。“維度”一詞指的是識別集合中元素所需的索引數。

指標和一維陣列

在一維陣列中,每個元素都由一個整數標識

int a[5] = {1, 2, 3, 4, 5};

這裡,數字“1”位於索引 0 處,“2”位於索引 1 處,依此類推。

儲存第 0 個元素地址的變數是它的指標 -

int *x = &a[0];

簡單來說,陣列的名稱也指向第 0 個元素的地址。因此,您還可以使用此表示式 -

int *x = a;

示例

由於指標的值會根據資料型別的尺寸遞增,“x++”會將指標移動到陣列中的下一個元素。

#include <stdio.h>

int main(){

   int arr[] = {1, 2, 3, 4, 5};
   int length = sizeof(arr) / sizeof(arr[0]);
   int i = 0;

   int *ptr = arr;

   while (i < length){
      printf("arr[%d]: %d \n", i, *(ptr + i));
      i++;
   }
   
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出 -

arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4
arr[4]: 5

指標和二維陣列

如果一維陣列類似於元素列表,則二維陣列類似於表格或矩陣。

二維陣列中的元素可以被認為是在邏輯上以行和列排列的。因此,任何元素的位置都由兩個索引決定,即它的行號和列號。行索引和列索引都從“0”開始。

int arr[2][2];

這樣的陣列表示為 -

Col0 Col1 Col2
Row0 arr[0][0] arr[0][1] arr[0][2]
Row1 arr[1][0] arr[1][1] arr[1][2]
Row2 arr[2][0] arr[2][1] arr[2][2]

需要注意的是,表格排列僅是一種邏輯表示。編譯器分配一塊連續的位元組。在 C 中,陣列分配以行優先的方式進行,這意味著元素以行方式讀入陣列。

這裡,我們宣告一個具有三行四列的二維陣列(第一個方括號中的數字始終指代行數)如下 -

int arr[3][4] = {
   {1, 2,  3,  4},
   {5, 6,  7,  8},
   {9, 10, 11, 12}
};

編譯器將以行優先的順序為上述二維陣列分配記憶體。假設陣列的第一個元素位於地址 1000 處,並且型別“int”的大小為 4 位元組,則陣列的元素將獲得以下分配的記憶體位置 -

Row 0 Row 1 Row 2
1 2 3 4 5 6 7 8 9 10 11 12
地址 1000 1004 1008 1012 1016 1020 1024 1028 1032 1036 1040 1044

我們將使用地址 & 運算子將陣列 num 的第一個元素的地址分配給指標 ptr。

int *ptr = &arr[0][0];

示例 1

如果指標遞增 1,它將移動到下一個地址。“3×4”陣列中的所有 12 個元素都可以在迴圈中訪問,如下所示 -

#include <stdio.h>

int main(){

   int arr[3][4] = {
      {1, 2,  3,  4},
      {5, 6,  7,  8},
      {9, 10, 11, 12},
   };

   // pointer ptr pointing at array num
   int *ptr = &arr[0][0];

   int i, j, k = 0;

   // print the elements of the array num via pointer ptr
   for (i = 0; i < 3; i++){
      for (j = 0; j < 4; j++){
         printf("%d   ", *(ptr + k));
         k++;
      }
      printf("\n");
   }
   
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出 -

1   2   3   4   
5   6   7   8   
9   10   11   12

通常,可以使用以下公式獲得陣列中任何元素的地址 -

add of element at ith row and jth col = baseAddress + [(i * no_of_cols + j) * sizeof(array_type)]

在我們的 3×4 陣列中,

add of arr[2][4] = 1000 + (2*4 + 2)*4 = 1044

您可以參考上圖,它確認“arr[3][4]”的地址是 1044。

示例 2

使用解引用指標獲取地址處的值。讓我們使用此公式在指標的幫助下遍歷陣列 -

#include <stdio.h>

int main(){

   // 2d array
   int arr[3][4] = {
      {1, 2,  3,  4},
      {5, 6,  7,  8},
      {9, 10, 11, 12}
   };

   int ROWS = 3, COLS = 4;
   int i, j;

   // pointer
   int *ptr = &arr[0][0];

   // print the element of the array via pointer ptr
   for (i = 0; i < ROWS; i++){
      for (j = 0; j < COLS; j++) {
         printf("%4d ",*(ptr + (i * COLS + j)));
      }
      printf("\n");
   }
   
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出 -

   1    2    3    4
   5    6    7    8
   9   10   11   12

指標和三維陣列

三維陣列是二維陣列的陣列。此類陣列用三個下標宣告 -

int arr [x] [y] [j];

此陣列可以被視為“x”個層的表格,每個表格具有“x”行和“y”列。

三維陣列的一個示例是 -

int arr[3][3][3] ={
   { {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
   { {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
   { {31, 32, 33}, {34, 35, 36}, {37, 38, 39} },
};

指向三維陣列的指標可以宣告為 -

int * ptr = &arr[0][0][0];

知道陣列的名稱本身就是第 0 個元素的地址,我們可以將三維陣列的指標寫為 -

int * ptr = arr;

“x”行和“y”列的每一層佔用 -

x * y * sizeof(data_type) 

位元組數。假設分配給上面宣告的三維陣列“arr”的記憶體從地址 1000 開始,則第二層(i = 1)從 1000 + (3 × 3) × 4 = 1036 位元組位置開始。

ptr = Base address of 3D array arr 

如果 JMAX 是行數,KMAX 是列數,則第 1 個切片的第 0 行和第 0 列的元素的地址為 -

arr[1][0][0] = ptr + (1 * JMAX * KMAX)

獲取第 i 個切片的第 j 行和第 k 列的元素值的公式可以給出如下 -

arr[i][j][k] = *(ptr + (i * JMAX*KMAX) + (j*KMAX + k))

示例:使用指標解引用列印三維陣列

讓我們使用此公式在指標解引用的幫助下列印三維陣列 -

#include <stdio.h>

int main(){

   int i, j, k;
   int arr[3][3][3] = {
      { {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
      { {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
      { {31, 32, 33}, {34, 35, 36}, {37, 38, 39} },
   };

   int JMAX = 3, KMAX = 3;
   int *ptr = arr; 	// &arr[0][0][0];

   for(i = 0; i < 3; i++){
      for(j = 0; j < 3; j++){
         for(k = 0; k < 3; k++){
            printf("%d ",*(ptr+(i*JMAX*KMAX)+(j*KMAX+k)));
         }
         printf("\n");
      }
      printf("\n");
   }
   
   return 0;
}

輸出

執行此程式碼時,將產生以下輸出 -

11 12 13 
14 15 16 
17 18 19 

21 22 23 
24 25 26 
27 28 29 

31 32 33 
34 35 36 
37 38 39

通常,使用指標訪問陣列與使用下標表示訪問陣列非常相似。兩者之間的主要區別在於,陣列的下標宣告以靜態方式分配記憶體,而我們可以使用指標進行動態記憶體分配。

要將多維陣列傳遞給函式,您需要使用指標而不是下標。但是,使用下標陣列比使用指標更方便,對於初學者來說可能比較困難。

廣告