(C/C++学习)6.数组指针和指针数组

说明:int (*p)[4] 和 int *p[4](数组指针和指针数组),如果你是一个初学者,也许当你看到这两个名词的时候,已经懵了。其实,只要你理解了其中的含义.这两个名词对你来说会相当简单并且很有趣,下面,我们就来深入探讨一下究竟什么是数组指针,什么是指针数组。

一.指针数组

1.前面我们已经学过数组了,比如说要创建一个一维整型数组,该怎么创建呢?应该是这样的:int arr[N];其中,arr是数组名,即变量名,N是你所创建的这个数组中的元素个数,而前面的int则是这些元素的类型。所以其实可以将它读作整型变量数组。那万一你所创建的数组元素不是整型和浮点型这些基本类型,而是一个指针类型呢?这就是指针数组了。

2.指针数组,首先它也是一个数组,只不过这个数组中的元素的类型为指针类型,举个例子:double *arr[4],这是一个指针数组,包含四个元素,其中每个元素都是double*类型的,简单来说,它就是一个用来存储指针的数组。用一个图来说明这个指针数组的内存布局:

捕获

3.既然指针数组是一个数组,那么它就应该有数组所应具有的一些特点。举个例子,对于double* p[4],p+1加的是数组的步长,即一个double*的大小,四个字节(注意:在32位机中,所有指针的大小都为4个字节)。而如果对数组名p进行取地址后,则&p+1加的是sizeof(p),即4*4 = 16个字节,即&p+1就跨过了整个数组。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     double *p[4] = {NULL};
  5     printf("p  = %p	",p);
  6     printf("p+1  = %p
",p+1);
  7     printf("&p = %p	",&p);
  8     printf("&p+1 = %p
",&p+1);
  9     return 0;
 10 }

程序运行结果:

捕2获

二.数组指针

1.指针相信大家都比较熟悉了,比如:int *p定义了一个指针p,该指针指向一个整型数据单元,如果对该指针执行加1操作,则加的是4个字节;又如char *q定义了一个指针q,该指针指向一个字符型的数据单元,如果对该指针执行加1操作,则实际上加的是1(个字节)。那么问题来了,万一要定义一个指针,它所指向的数据单元为一个一维数组怎么办呢?对他执行加1操作又能得到什么呢?这就是数组指针了。

2.数组指针,首先得明白它是一个指针,只不过这个指针指向的数据单元为一个数组,举个例子,现在有一个一维数组int arr[4];现在要定义一个数组指针来指向它,按照一般指针的理解,应该是这样的,int[4]* p;表示定义一个指针p,而该指针的类型为int[4]*型的,但这在编译器中是会报错的,没什么理由,语法规定。实际上对这个数组指针的定义应该是这样的:int (*p)[4] = arr;说实话,这样看着,笔者觉得挺别扭的,不过没办法,编译器就只认这个写法,不过这完全不影响我们按照第一种写法去理解数组指针的本质。

3.上面已经说了,数组指针实质就是一个指针,只不过其指向的类型与基本类型不同罢了。对于基本类型的指针,执行加1加的是指针指向数据类型的字节数,那么对于数组指针呢?显然加1加的也是指针指向数据类型的字节数,那么数组指针指向数据类型的大小怎么判断呢?举个例子:int(*p)[4],下面将通过一张内存数据图对此进行阐述:

捕3获

如图:该指针里面存的是一个数组的首地址,只不过该指针的类型为int[4] *型,这就导致了该指针的步长为4*4 = 16个字节,所以对该指针执行加一操作,实际上加的是16个字节,即整个数组的大小。

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[4];
  5     int (*p)[4] = (int(*)[4])arr;
  6     printf("%p	",p);
  7     printf("%p
",p+1);
  8     return 0;
  9 }

程序运行结果:

捕4获

4.数组指针与二维数组的关系是什么呢?首先要知道,二维数组 int arr[m][n] 可以想象成是具有m行,n列的一个数组矩阵,也可以想象成是有m个一维数组,其中每个一维数组里面又有n个int型的元素.那么是否可以用一个类型为int[n] *型的指针指向该二维数组来实现行间跳转访问呢?答案是肯定的!就拿上面例子来说,假如有一个二维数组int arr[m][n],则可以定义一个数组指针为:int (*p)[n] = arr(这里最好强转一下),然后用p对数组进行访问,由以上可讲可知,这里的p+1加的是n*4个字节,即加的是二维数组每行的字节数。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[3][4];
  5     int (*p)[4] = (int(*)[4])arr;
  6     printf("%p	",p);
  7     printf("%p
",p+1);
  8     return 0;
  9 }
 10 

程序运行结果:

捕454获

注意:二维数组的存储在内存中实际上是线性存储的,可以说任何数据在内存上的存储都是线性存储的,但这并不影响我们用二维的思维去理解它。

三.下面是一个数组指针当做二维数组名访问数组的示例,只是为了巩固与拓展一下以上,对于二维数组名的具体使用方式,在下次更新(后天)会详细介绍。这里就简单介绍一下,当把二维数组名赋给一个指针数组后,例如如下示例,则该指针就拥有了二维数组名访问二维数组的方式,比如在这里,p代表数组的首地址,由于其拥有了二维数组名的特性,则**p就是二维数组里的第一个元素,而*(*(p+i)+j)是二维数组第i行第j列的元素。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[3][4];
  5     int count = 0;
  6     for(int i = 0;i<3;i++)
  7         for(int j = 0;j<4;j++)
  8             arr[i][j] = count++;
  9     for(int i = 0;i<3;i++)
 10     {
 11         for(int j = 0;j<4;j++)
 12             printf("%2d  ",arr[i][j]);
 13         putchar(10);
 14     }
 15     int (*p)[4] = (int(*)[4])arr;
 16     for(int i = 0;i<3;i++)
 17     {
 18         for(int j = 0;j<4;j++)
 19             printf("%2d  ",*(*(p+i)+j));
 20         putchar(10);
 21     }
 22     return 0;
 23 }

程序运行结果:

656获

 

原文地址:https://www.cnblogs.com/tuihou/p/9732425.html