《指针的编程艺术(第二版)》一3.2 指针与二维数组

简介:

本节书摘来自异步社区《指针的编程艺术(第二版)》一书中的第3章,第3.2节,作者 蔡明志,更多章节内容可以访问云栖社区“异步社区”公众号查看

3.2 指针与二维数组

指针的编程艺术(第二版)
一维数组与指针的关系前面已经介绍过。一维数组的元素值,可使用[]或一个*得到,假设有一个数组如下:

int i[7] = {0, 1, 2, 3, 4, 5, 6};
int *ptr=i;

(i+2) 或i[2] 或(ptr+2) 或ptr[2],都表示数组某一个元素的值。而二维数组(two dimension array){XE "二維陣列(two dimension)"},则需要两个,或一个与一个[ ],或两个[ ],才能得到数组的元素值。其余的表示法,只能得到数组元素的地址。

假设一个二维数组的定义如下,

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


4aadb98ba785537858a62c109382695a0a88af75

其中j是此数组的名称,表示这个数组第1行第1列元素的地址,而j+1是第2行第1列元素的地址,除此之外


dad72fa135ff3c677e1d9c63e737894e2ee1c207

j[0]和j[1]等同于j和j+1,表示第1行第1个元素和第2行第1个元素的地址。j和j[0] 虽然表示同一元素的地址,但两者对于加1个单位的意思不同。

j+1表示第2行第1个元素的地址,也即是j+1==&j1。而j[0]+1是第1行第2个元素的地址,也就是j[0]+1==&j0,如下图所示。


91d9c3154664ff1c008359e5c3667da132481342

关于二维数组的每个元素所在内存的概念已在第1章讨论过,请参阅范例address2Array-5和address2Array-10。

接下来,请问j和(j+1)是某个元素的地址,还是某个元素的值呢?答案是某个元素的地址。j与j都表示第1行第1列元素的地址(&j0)。而j+1与(j+1) 都表示第2行第1列元素的地址(&j1),如下图所示。


6a77a0b068b164ff77b0a51bb6c8a4ef5792f52c

虽然j与j表示相同的意思,但两者都加1,表示的意义是不相同的。j+1表示第2行第1列的地址,而 j+1表示第1行第2列元素的地址(&j0)。同理,*(j+1)+1是第2行第1列的元素地址(&j1)。请参阅范例pointerArr2-5。

范例pointerArr2-5

/* pointerArr2-5.c */
#include <stdio.h>
#include <conio.h>
int main()
{
  int j[3][2] = {10, 20, 30, 40, 50, 60}; 
  int k; 
  for(k=0; k<3; k++)
    printf("j[%d] = %p\n", k, j[k]);
  printf("\n");
  for(k=0; k<3; k++)
    printf("j+%d = %p\n", k, j+k );
  printf("\n");
  for(k=0; k<3; k++)
    printf("*(j+%d) = %p\n", k, *(j+k));
  getch();
  return 0;
}

输出结果


83b709f2eec190930715befc9cbc2fe3bc4d5e31

从输出结果可知,每列之间相距8个字节,因为每列有两个int的元素。

综上所述,如果有一个二维数组k,如下所示:

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

数组的示意图如下图所示。


783f076f4a5bc166c5983564129189d9683479c2

如何得到元素值6(位于第2行第3个元素)的地址呢?答案如下:

&k[1][2],k[1]+2,*(k+1)+2

从&k1可以很清楚地看出,它表示k1元素的地址。*(k+1)和k[1]都表示第2行第1个元素的地址,所以再加2,都可得到第2行第3个元素的地址。

当我们得到元素的地址后,再加上一个*就可以得到该元素的值,所以

 

k[1][2],*(k[1]+2),*(*(k+1)+2)

都可以得到数组第2行第3列的值。由以上的语句,可以推导出以下的公式。

k[x][y] == *(k[x]+y) == *(*(k+x)+y)

这一公式很容易理解,因为*和[]是互通的。请参阅范例pointerArr2-10。

范例pointerArr2-10

/* pointerArr2-10.c */
#include <stdio.h>
#include <conio.h>
int main()
{
  int k[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
  printf("&k[1][2] = %p\n", &k[1][2]);
  printf("k[1][2] = %d\n", k[1][2]);
  printf("*(k + 1) + 2 = %p\n", *(k + 1) + 2);
  printf("*(*(k + 1) + 2) = %d\n", *(*(k + 1) + 2));
  printf("k[1] + 2 = %p\n", k[1] + 2);
  printf("*(k[1] + 2) = %d\n", *(k[1] + 2));
  getch();
  return 0;
}

输出结果


5f1bea08569ac0f053bfb9eaab986c10efbb4952

范例程序使用3种方法,得到k1 的地址与数值。要得到k1 的值6,可以使用(k[1]+2)及((k+1)+2)。如果要得到k1 的地址,则可使用&k1、k[1]+2及(k+1)+2,此处以%p输出数组第2行第3个元素的地址是0022FF58。如果使用%x取代%p,则会省略前面的0。两者都可以用于输出内存地址。

相关文章
|
6月前
|
C语言
C语言---二维数组&&指针
C语言---二维数组&&指针
27 0
|
5月前
指针\动态二维数组空间
指针\动态二维数组空间
29 4
|
20天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
20天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
5月前
|
C语言
C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)
C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)
|
5月前
|
C语言
C语言----指针模拟二维数组
C语言----指针模拟二维数组
|
6月前
|
存储 算法 C语言
C语言指针与二维数组在函数参数传递和动态内存管理中的应用
C语言指针与二维数组在函数参数传递和动态内存管理中的应用
56 0
|
6月前
指针的基础应用(数组的颠倒和排序,二维数组的表示)
指针的基础应用(数组的颠倒和排序,二维数组的表示)
33 0