探究二级指针、二维数组

本文详细探讨了二级指针的概念,解释了二级指针如何存储一级指针的地址,并通过实例阐述了二级指针在二维数组中的应用。同时,文章分析了数组指针与指针数组的区别,数组地址与数组首元素地址的关系,以及一维数组和二维数组的差异。还介绍了如何在指针形式和数组下标形式之间进行转化,以加深对指针操作的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二级指针

简单来说,二级指针存储一级指针的地址,指向一级指针。

double a = 0, b = 0, c = 0, d = 0;
double* p0 = &a;
double* p1 = &b;
double* p2 = &c;
double* p3 = &d;
double** s = &p0;

如果a、b、c、d的地址是连续分配的,指针p0、p1、p2、p3的地址也是连续分配的,那么下面三种情况:

s + 1;		//&p1 移动4个字节 类型是double**
*s + 1;		//&b 移动8个字节 类型是double*
**s + 1;	//a + 1 = 1 类型是double

我们知道,指针加一的作用是加上其指向内容的数据类型的长度。
s开始指向的是一级指针p0,p0是指针,长度是4个字节,那么s+1就会移动4个字节,所以s指向了p1。
*s是s解引用的形式,也就是p0指针本身,而p0指针指向变量a,变量a的长度是8个字节,那么 *s+1就会移动8个字节,所以 *s(等同于p0)指向了b。
**s 是 *s解引用的形式,也就是变量a,那么 **s+1就是a变量本身加一,所以变量a由0变为1。

二级指针的应用:二维数组

数组指针和指针数组

int main() {
	int a = 0, b = 1, c = 3, d = 4;
	int* pr[4] = { &a,&b,&c,&d };	//指针数组
	int(*s)[4] = nullptr;			//数组指针
	int ar[4] = { 1,2,3,4 };
	s = &ar;

	return 0;
}

由程序可知,指针数组pr就是四个int*类型变量构成的一个数组,性质和其他类型的数组一样。
数组指针通俗来讲是指向数组的指针,将数组看成一个整体,这个指针指向的是整个数组。也就是说,定义成int(*s)[4],s就只能指向元素个数为4,类型为int的数组,不能指向其他类型的数组,或是元素数量不是4的数组。

数组地址和数组首元素地址

int main() {
	int ar[4] = { 1,2,3,4 };

	int* p0 = ar;
	int* p1 = &ar[0];

	int(*s)[4] = &ar;

	return 0;
}

我们知道,数组名就是数组首元素的地址,所以p0和p1是完全等价的,都存储数组首元素地址;通过指针数组定义方式的s指向的整个数组,存储数组的地址,虽然从结果上来看,数组首元素的地址和数组的地址相同,也就是说p0、p1、s中存储的地址都是相同的,但是区别在于它们加一的能力不同。p0、p1加一是相对于数组首元素地址的,加一是加数组中元素类型的长度;s是相对于数组地址的,加一是加数组的长度。
数组地址可以转化为数组首元素地址。s此时指向ar数组(s=&ar),那么*s就指向数组首元素(*s=ar)。

一维数组和二维数组

int main() {
	int ar[4] = { 1,2,3,4 };
	int size1 = sizeof(ar);	//16字节
	int* p1 = ar;			//数组首元素的地址
	int(*s1)[4] = &ar;		//数组的地址

	int br[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int size2 = sizeof(br);	//48字节
	int(*p2)[4] = br;		//数组首元素的地址
	int(*s2)[3][4] = &br;	//数组的地址

	return 0;
}

如果说一维数组是一个一个变量组成的集合的话,那么二维数组就是一个一个一维数组组成的集合。br[3][4]可以看成是由三个一维数组构成,每个一维数组有四个变量。这样我们把二维数组每一个元素都视为一维数组,那么二维数组的首元素地址就是第一个一维数组的地址。我们如何定义一个指向一维数组的指针呢?就是利用指针数组!所以代码int(*p2)[4] = br是指向二维数组首元素的地址就容易理解了。如果要指向整个二维数组,采用int(*s2)[3][4] = &br的形式,这说明s2指向这样一个数组,这个数组是三行四列的二维数组,且数组的类型是int型。

数组下标形式和指针形式的转化

int main() {
	int ar[4] = { 1,2,3,4 };
	printf("%d\n", ar[2]);			//3
	printf("%d\n", *(ar + 2));		//3

	int br[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	printf("%d\n", br[2][3]);			//12
	printf("%d\n", *(*(br + 2)+3));		//12

	return 0;
}

br作为二维数组首元素的地址,br+2首先移动指针指向第三个元素,也就是第三个一维数组的首元素地址处,解引用*(br+2)将其转换成指向这个一维数组首元素的指针,*(br+2)+3移动指针指向一维数组中第四个元素,解引用 *( *(br + 2)+3)就是这个元素的值。

二维数组的实例

int main() {
	int ar[5][2] = { 1,2,3,4,5,6,7,8,9,10 };
	int(*p)[2] = &ar[1];
	int* s = ar[1];

	printf("%d \n", p[1][3]);	//8
	printf("%d \n", s[3]);		//6

	return 0;
}

结合前面的知识,该程序的输出结果容易得出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值