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

通常,使用指针访问数组与使用下标表示访问数组非常相似。两者之间的主要区别在于,数组的下标声明以静态方式分配内存,而我们可以使用指针进行动态内存分配。

要将多维数组传递给函数,您需要使用指针而不是下标。但是,使用下标数组比使用指针更方便,对于初学者来说可能比较困难。

广告

© . All rights reserved.