指针进阶1- 指针和数组
1. 指针和数组
区分指针和数组
指针是存储地址的变量,而数组是一组相同类型元素的集合
指针和数组是两个完全不同的对象。那么,指针与数组有什么联系 ?
指针与数组的联系
在说明指针与数组的联系之前,首先确认数组名的概念
什么是数组名,数组名等于什么
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
printf("%p\n", arr);
}

arr = &arr[0],数组名 = 数组第一个元素的地址
既然是地址,那么就可以用指针进行存储
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* pa = arr;
printf("%p\n", arr);
}
指针pa 存储元素0的地址,元素类型是整形, 所以pa的类型是int*整形指针
现在知道了数组名=数组首元素地址,地址可以用指针进行存储,这个指针有什么用吗
可以通过指针来访问数组
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* pa = arr;
for (int i = 0; i < 10; i++)
{
printf("%d ", *(pa + i));
}
printf("\n");
}

总结
指针和数组是两个完全不同的对象,但是由于数组名=数组首元素地址,将数组首元素地址存入指针后,可以通过指针来访问数组
这就是数组和指针之间的联系
[]下标引用操作符的本质
除了使用指针来访问数组外,还可以使用[]操作符来访问数组, 这也是一般访问数组的方法
但是这种方法难以理解 -> 数组名[下标] 为什么使用数组名+对应[下标],就可以访问数组元素 ?
下面将用两个例子说明 []操作符的本质
实例1:
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* pa = arr;
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]); // 下标引用访问数组
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(pa + i)); // 指针访问数组
}
printf("\n");
}

由此可见,arr[i] = *(pa+i)
实例2:
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* pa = arr;
for (int i = 0; i < 10; i++)
{
printf("%d ", i[arr]); // 下标引用访问数组
}
printf("\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(i + pa)); // 指针访问数组
}
}

i[arr] = *(i+pa)
结论是,[]仅仅只是一个操作符,这个操作符只关注两个操作数,地址和整数。这与操作数相较于操作符的位置无关,所以i[arr]和arr[i]是一样的
从本质上说,[]与*操作符相同,都是通过地址访问内存空间,不同是[]需要两个操作数(地址和整数),而*只需要一个操作数(地址)
2. 指针数组
什么是指针数组
数组是一组相同类型元素的集合,而指针是地址,所以指针数组就是一组相同类型地址的集合
#include <stdio.h>
int main()
{
int a = 0;
int b = 1;
int c = 2;
int* arr[3] = {&a, &b, &c}; //指针数组
}
这里的arr就是一个指针数组,数组的每一个元素都是一个整形指针
指针数组的应用
接下来,说明一下指针数组可能的应用场景,使用指针数组模拟多维数组
#include <stdio.h>
int main()
{
int t1[5] = { 1,2,3,4,5 };
int t2[5] = { 2,3,4,5,6 };
int t3[5] = { 3,4,5,6,7 };
int* arr[3] = { t1,t2,t3 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(*(arr + i))+j);
}
printf("\n");
}
}

解析

3. 数组指针
什么是数组指针
首先,看一段代码
#include <stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9};
printf("%p\n", arr);
printf("%p\n\n", arr+1);
printf("%p\n", &arr);
printf("%p\n", &arr+1);
}

如图所示, arr+1跳过4个字节, 而&arr+1跳过了40个字节
这是因为,arr=数组首元素的地址,类型为int*,所以+1跳过4个字节,而&arr取出的是整个数组的地址, 类型为int(*)[10], 所以+1跳过40个字节
如何存储整个数组的地址?答案是数组指针,所以数组指针就是存储一个数组地址的变量
数组指针的声明
#include <stdio.h>
int main()
{
int arr[5] = { 0,1,2,3,4};
int(*pa)[5] = &arr;
}
()操作符优先级最高,所以pa首先与*结合, 表示pa是一个指针
[5]表示pa存储的是一个数组的地址, 数组有5个元素
最前面的int表示数组每一个元素是int整形
多维数组数组名 VS &多维数组数组名
在说明数组指针的使用之前,确定一下多维数组的概念
多维数组数组名等于什么,&多维数组名又是什么
#include <stdio.h>
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
}

如图所示, arr+1跳过20个字节,而&arr+1跳过60个字节

可得出结论: 多维数组数组名 = 首行地址, +1跳过一整行,而&多维数组名 = 整个多维数组的地址, +1跳过整个数组
数组指针的使用
数组指针通常用于访问多维数组
#include <stdio.h>
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
int(*pa)[5] = arr;
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *( *(pa + i) + j) );
}
printf("\n");
}
}

arr = 首行地址也就是整个第一行的地址,实际上多维数组把每一行当做一个一维数组,所以可以用一个数组指针进行存储 ---> int(*pa)[5] = arr;

浙公网安备 33010602011771号