指针数组

存放指针的数组,本质为数组,只不过数组的每个元素是用来存放指针的

数组指针

数组的指针,本质为指针,只不过是数组的指针


一、指针数组

举例说明:

int *buf[5];

本质是数组,只是每一个元素是用来存放int *指针的

每个元素(变量)的类型为int *类型,所以每个元素其实就是一个int *的指针变量
&buf[0]、&buf[1]...为每个指针变量的地址,显然类型为int **


二、一维数组的“数组指针”

int buf[10]

1. buf

(1)数组第0个元素的指针,即第0个元素的第一个字节的地址,等价&buf[0]

(2)buf的指针类型为int *

2. &buf

(1)一维数组的“数组指针”
也就是整个一维数组的第一个字节的地址,其实就是第0个元素的第一个字节的地址,
但是此时含义不一样,此时是整个数组的指针


(2)&buf的指针类型:int (*)[10]

由于是数组的指针,所以指针类型与数组的样子必然非常相似,
这一点就好比“函数指针与函数的样子很相似”是一样的

int fun(void)
{

}

函数指针fun的类型为int (*)(void)


三、如何定义一个“一维数组指针变量”

*的后面加上变量名即可

int (*p)[10] = &buf;  //&buf的类型为int (*)[10]

&buf的类型为int (*)[10],所以p的类型也为int (*)[10],如果类型不同的话,就需要进行强制转换

疑问1:int (*)[10]中的10的作用?

答:10表示,通过“数组指针”访问所指向的空间时,所能访问的元素个数为10个。


一维数组的“数组指针”有什么意义 ?

在一维数组中,数组指针的意义并不大,
但是在多维数组中,一维数组的“数组指针”却非常重要,这是构建多维数组的基本组成


能不能省略数组指针类型中的()?

比如:

int (*p)[10]

()是不能省略的,不能省略的原因与函数指针类型中的()不能省略的原因是一样的,

如果将()省略后就变为了int *p[10][]的结合性高于*,所以p先和[]结合,
*则与int结合,p先和[]结合,那么p就是一个数组,而且是一个int *指针数组

四、buf与&buf异同

相同点:

二者值相等

不同点:

buf&buf的类型不同,因为类型不同,所以buf+1&buf+1的结果是不一样的


五、数组的“第一个元素指针”与“数组指针”之间的运算关系

int buf[10];

buf:数组第一个元素的指针
&buf:数组指针

在“第四章”我们讲过,*&是逆向运算,所以*&buf等于buf

所以:

*数组指针  ———————————————————————————————>  数组第0个元素的指针
 数组指针  <———————————————————————————————  &数组第0个元素的指针

数组指针 通过 *数组指针,强制转换为了数组第0个元素的指针
数组第0个元素的指针 通过 &数组第0个元素的指针,强制转换成了数组指针

在“数组指针”和“第一个元素指针”之间的&*的转换,其实起到的“强制转换”的作用,
这一点与普通变量的&*作用不同

int a = 10;

&a是变量的指针,*&a解引用,指的就是变量a
&a是真正的取地址,*&a是真正的解引用,所以他们不存在强制转换

数组元素也是一个普通变量,所以数组元素的&*,也是一样的含义

int buf[10];
  • &buf[0]:就是一个地址
  • *&buf[0]:相当于就是一个变量,或称一个变量空间

*buf 代表buf[0] 的变量空间,这是在解引用,
但是&buf&0个元素指针)确实是在强制转换,变为了“数组指针”

*数组指针”和“&第一个元素指针”所使用的*&,确是做强制转换

  • buf:类型为int *
  • &buf:类型为int (*)[10]

&buf:等价于(int (*)[10])buf
*&buf:等价于(int *)&buf

buf&buf都是地址,只是指针类型不同而已,所以对于&buf*(&buf)显然只是在做强制转换


六、数组指针的强制转换

1. 例子1

int buf[10];

int (*p)[8] = (int (*)[8])&buf;

&buf类型为int (*)[10],而左边变量p的类型为int (*)[8],所以需要进行强制转换

强转为int (*)[8]类型时表示,所指向的空间为8个元素,每个元素为int

p + n所得最终地址为p + n*8*sizeof(int)

验证:

printf("p = %d\n", p);
printf("p+1 = %d\n", p+1);

p+1,加的是1*8*sizeof(int)个字节

2. 例子2

int buf[10];

char (*p)[8] = (char (*)[8])&buf;

char (*)[8]类型表示,所指向的空间为8个元素,每个元素的char

p + n所得最终地址为p + n*8*sizeof(char),所加的为8char元素的数组空间

验证:

printf("p = %d\n", p);
printf("p+1 = %d\n", p+1);

指着相差1*8*sizeof(char)个字节。

疑问:char (*p)[8] = (char (*)[8])&buf;char (*p)[8] = (char (*)[8])buf;结果一样吗?

答:这两个结果是一样的,因为buf&buf值相等,都可以强制转换为char (*)[8]类型

3. 例子3

int buf[10];

int *p = (int *)&buf;

&bufint (*)[10]pint *类型,所以要做强制转换

前面说过,将“数组指针”强制转换为“数组第0个元素指针”时,完全可以通过*来强制转换,

所以等价于:

int *p = *&buf;

4. 例子4:

int buf[10];

int (*p)[10] = (int (*)[10])buf;

bufint *pint (*)[10],需要做强制转换

前面说过,将“数组第0个元素指针”强制转为“数组指针”,可以通过&来强制转换,

所以等价于:

int (*p)[10] = &buf;

大家需要注意:
如果没有强制转换需求的话,最好不要进行强制转换,因为这会导致访问数组空间时,
解释方式发生了变化,这会导致解释空间时多访问空间,或者少访问空间


七、能不能将int (*)[8]中的8省略?

不能,因为将8省略后,使用p去访问数组空间时,就不知道数组元素个数,
显然就更不知道不知道应该如何解释所指向的数组空间

int (*p)[8]

p+1:加的是一个数组空间的大小,这个数组9个元素,p+1*8*sizeof(int)

但是

int (*p)[]

p+1:加一个数组空间的大小时,这个数组多大?p+?

事实上由于int (*p)[]写法存在问题,编译器实际上不允许编译通过的

void fun(int (*p)[])
{
    printf("%p\n", p+1);  // 编译不通过的,因为定义形参p时,[]中没有数字
    printf("a = %d\n", a);
}

int main(void)
{
    int buf[10] =  {0,1,2,3,4,5};

    fun(&buf);


    return 0;
}

数组指针的作用

在一维数组中,其实还不能感受出“数组指针”的作用的,但是“数组指针”对于多维数组来说很重要,
后面讲多维数组时,我们就可以看出“数组指针”在多维数组中的作用


八、再说说一维数组的传参

正常情况下传递的是数组第一个元素的指针,那么可不可以传递“数组指针”呢?当然可以

传递数组指针后,访问数组的方式有两种:

1.以二维数组的方式来访问
这个后面再介绍。

2.将“数组指针”强制转换为“元素指针”,然后再访问每一个元素

例子

#include <stdio.h>

void fun(int n, int (*p)[n]) //n只有定义在前面,int (*p)[n]才能使用n
{
    int *buf = (int *)p; //等价于int *buf = *p;

    int i = 0;

    for(i=0; i<n; i++)
    {
        printf("%d\n", *(buf+i));
    }
}

int main(void)
{
    int buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    fun(10, &buf);

    return 0;
}