指针进阶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;

 

posted @ 2023-02-18 16:41  许木101  阅读(41)  评论(0)    收藏  举报