🌀 数组指针

数组是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。那么以下列代码为例子,我们来分布图如下可进行观察 🧐

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

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针

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

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_02

数组指针是一种指向数组的指针,这句话在我看来是很重要的你能理解透彻的话,我觉得你的数组指针能上一个台阶多看多读几遍🥰

那么指针数组是怎么样的呢,如下代码所示 👇

int (*p)[10];

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组名_03

从这里我们不难去发现,原来指针数组和数组指针形成根本问题就在于操作符大小的优先级关系所在,所以当你定义变量的时候一定要去注意这个问题,不然的话就会有根本性质的不同。 

int arr[10] = {0};
int (*p)[10] = &arr;

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_04

上述代码当中取出的是数组的地址,注意取地址是取出数组所有的地址。arr 才是数组名首元素的地址相当于是 arr[0],而上述代码中取地址是不一样的,这个要区分开来。

💥重点核心在上面的代码中 p 就是一个数组指针,它是可以存放数组的地址的!

再举出一个例子,如下代码所示 👇

double* d[10];
double* (*pa)[10] = &d;

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组名_05

首先  pa 是个指针*,然后先把 (*pa) 先结合。pa 指向的是数组,指向的是d的数组有10个元素,所以这里一定是要写10个元素。切记!

💥注意:这个地方只能是10个元素,因为指向的数组它就是10个元素。

这样的话 pa 是一个指针指向的数组是10个元素,那么它所指向的类型是double*类型的。所以要在前面+上double*,所以,数组指针 p 指向的类型也必须要是 double* 类型的才可以。以上 pa 就 是 数组指针,和上面 p 都是属于是数组指针类型的。

不知道,你看完之后明白了 数组指针 和 指针数组 了没有,总之我刚学的时候真的是一脸懵逼。这两个总是能够搞混淆😅还放弃了不想学指针的念头哈哈,但是这是绝对不可以的 🤐 


💥 &数组名 和 数组名

&数组名取地址是取出它数组的地址

数组名 数组名仅仅是表示它首元素的地址

如下代码所示 👇

int arr[10] = {0};
int* p1 = arr;
int (*p2)[10] = &arr;

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_06

在上述代码所示👆

p1 只需要是 指针数组 就可以了

p2  它却需要的是 数组指针 就可以了

虽然,它们最后打印出来的值是一模一样的,但是他们的类型终究是不一样的。

如下代码所示 👇

#icnlude<stdio.h>
int main(void)
{
int arr[10] = {0};
int* p1 = arr;
int (*p2)[10] = &arr;
printf("p1 = %p\n",p1);
printf("p1+1 = %p\n",p1+1);
printf("%p2 = %p\n",p2);
printf("%p2+1= %p\n",p2+1);

return 0;
}

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组名_07

指针类型决定指针+1到底多少

p1 是一个整形指针+1,它会跳过个字节。

p2 是一个数组指针,p2指向的是一个数组。于是,p2+1就应该是跳过一个数组,指向对象的数组。

运行结果如下所示 👇 

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_08


第一行的编译结果与第二行的编译结果相差了个字节,个整形类型。

第三行的编译结果与第四行的编译结果相差了40个字节,个整形类型。

💥重点核心以后取地址数组名的话,一定要是数组指针!

注意⇢数组指针的第二个下标不能被省略,如果省略了第二个下标的话。那么指针类型就不明确了。

🔥 数组是首元素地址但有②个例外 

①. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组大小,单位是字节。

🔥注意:sizoof(数组名)这个是必须要单独存放的才算是表示数组的整个大小!

②. &数组名 - 数组名表示整个数组,取出的是整个数组的地址。

除了上述这两个,sizeof(数组名) 和 &数组名 其它的表示都是数组名(arr)首元素的地址。 

🔥 拓展数组指针访问二维数组

示例代码如下👇

#include<stdio.h>int main(void)
{
int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 10, 9 } };
int (*p)[3] = arr; //arr首元素(而是一个数组具有三个元素char arr[3])地址
printf("%d", *(p[2]+1));
return 0;
}


运行结果🖍

10

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_09

当然还有一种形式可以用指针变量来访问,如下代码所示👇

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


运行结果🖍

5

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_10

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组_11

💥 数组指针的使用 

💥注意: 使用数组指针的时候一般都不会在一维数组当中去使用!通常都是在二维数组中使用

大家可以思考下这是为什么,你可以试着去看看数组指针的形式在去思考🤔

那就假设我们先在一维数组当中去使用下,如下代码所示 👇

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

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组_12

上述代码👆,就是配合数组指针去使用的,可能小伙伴们看了会觉得很不自在我也觉得是,明明就可以用指针变量解决的一道题目,却还要用数组指针去解决。 

指针变量解决,如下代码所示 👇

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

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组指针_13

这样岂不是更方便吗?😜

接下来,我们来正确的使用数组指针。 如下代码所示 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define row 3
#define col 3
void print(int(*p)[col], int r, int c) //p是数组指针
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("\t%d ", *(p[i] + j));
}
printf("\n");
}
}
int main(void)
{
int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
print(arr, row, col);
return 0;
}

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组_14

编译运行结果 👇 

【C语言】进阶指针Ⅱ 数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二维数组、数组指针的使用。_数组_15

💥注意:二维数组的数组名表示首元素的地址,第一行是二维数组首元素地址!因为是一维数组的地址,所以在形参当中使用了指向一维数组指针来去进行使用。而这样的一维数组+i的话相当于找到了第i行当中的地址,解引用相当于拿到了第 i 行的数组名。这又相当于这①行首元素的地址,然后再+上 j 的话就相当于 j 的地址。最后,再括起来解引用,就找到了第 i行下标为 j 的地址进行引用 🥳