Day 12 指针与数组

指针与数组:

数组指针

一、利用数组名遍历数组元素

     数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以int arr[] = { 99, 15, 100, 888, 252 };为例,该数组在内存中的分布如下图所示:

定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。以上面的数组为例,下图是 arr 的指向:

      1_1  使用数组名作为指针遍历数组元素

 

 二、利用指针遍历数组元素

1、指向数组开头的指针

我们也可以定义一个指向数组的指针,例如:

                          int arr[] = { 99, 15, 100, 888, 252 };

                          int *p = arr;

      arr 本身就是一个指针,可以直接赋值给指针变量 parr 是数组第 0 个元素的地址,所以int *p = arr;也可以写作int *p = &arr[0];。也就是说,arrp&arr[0] 这三种写法都是等价的。但是特别注意的是,arr 本身就是一个指针这种表述并不准确,严格来说应该是arr 被转换成了一个指针。区别在于:sizeof(arr)sizeof(p)

定义:如果一个指针指向了数组,我们就称它为数组指针(Array Pointer)。

数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关,上面的例子中,p 指向的数组元素是 int 类型,所以 p 的类型必须也是int *。反过来想,p 并不知道它指向的是一个数组,p 只知道它指向的是一个整数,究竟如何使用 p 取决于程序员的编码。

1_2使用数组指针来遍历数组元素

注意在求数组的长度时不能使用sizeof(p) / sizeof(int),因为 p 只是一个指向 int 类型的指针编译器只知道它指向的是一个整数但不知道是一个整数(数组),所以 sizeof(p) 求得的是 p 这个指针变量本身所占用的字节数,而不是整个数组占用的字节数。

 

2、指向数组某个位置的指针

     上节我们讲到,对指针变量进行加法和减法运算时,是根据数据类型的长度来计算的。p+1 指向下一个元素,p-1 指向上一个元素。那么p+i 指向下 i 个元素,p -i 指向上 i 个元素。1_3 p 指向数组的第 i 个元素

 

三、访问数组元素的两种方案

引入数组指针后,我们就有两种方案来访问数组元素了,一种是使用下标,另外一种是使用指针

1) 使用下标

也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素,它等价于 arr[i]

2) 使用指针

也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价于 *(p+i)

     不管是数组名还是数组指针,都可以使用上面的两种方式来访问数组元素。不同的是,数组名是常量,它的值不能改变,而数组指针是变量,它的值可以任意改变。也就是说,数组名只能指向数组的开头而数组指针可以指向数组开头,也可以指向其他元素。(例1_4   使用指针自增访问数组元素)(不能使用数组名自增访问)

数组指针

定义:如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组。指针数组的定义形式一般为:

          dataType *arrayName[length];

[ ]的优先级高于*该定义形式应该理解为

          dataType *(arrayName[length]);

括号里面说明arrayName是一个数组包含了length个元素括号外面说明每个元素的类型为dataType *即一个存放dataType类型数据的地址

 2_1 指针数组存放变量的地址

 2_22_3 指针数组与字符串结合

指针与二维数组

一、指向二维数组指针的定义

     二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有缝隙。以下面的二维数组 a 为例:int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; 假设数组 a 中第 0 个元素的地址为 1000,那么每个一维数组的首地址如下图所示:

  

为了更好的理解指针和二维数组的关系,我们先来定义一个指向 a 的指针变量 p

int  (*p)[4] = a;      //int (*p)[4]; p = a;

// int arr[] = {1,2,3};      int *p = arr; 

// int arr[][4] = {{1,2},{3,4},{5,6}};     int (*p)[4] = arr;

注意:1、括号中的*表明 p 是一个指针,它指向一个数组,数组的类型为int [4]这正是 a 所包含的每个一维数组的类型。

2[ ]的优先级高于*( )是必须要加的,如果赤裸裸地写作int *p[4],那么应该理解为int *(p[4])p 就成了一个指针数组,而不是二维数组指针。

 

二、用指向二维数组的指针访问二维数组

1) p指向数组 a 的开头,也即第 0 行;p+1前进一行,指向第 1 行。

2) *(p+1) = a[1]表示取地址上的数据也就是整个第 1 行数据。3_1

3) *(p+1)+1表示第 1 行第 1 个元素的地址。如何理解呢?

*(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址,因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针就像一维数组的名字,在定义时或者和 sizeof& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。

4) *(*(p+1) +1) = a[1][1]  表示第 1 行第 1 个元素的值。很明显增加一个 * 表示取地址上的数据。

根据上面的结论,可以很容易推出以下的等价关系:

a+i == p+i

a[i] == p[i] == *(a+i) == *(p+i)

a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

(3_2)


 

猜你喜欢

转载自blog.csdn.net/j_xianyu/article/details/81272477