函数中的二维数组和二级指针

本文探讨了二维数组和二级指针在C++中的区别,通过函数参数传递和地址运算揭示它们的本质差异。尽管二者在某些方面表现相似,但传递后二维数组的指针性质发生改变,无法直接通过a[][]访问元素。要访问数组元素,需要正确类型转换。通过示例解释了指针加法在不同类型的指针中如何影响地址偏移,从而帮助理解如何正确操作指针以访问二维数组的元素。
摘要由CSDN通过智能技术生成

二维数组和二级指针

被指针逼疯了才想出如此歪门邪道去理解它,文章错误之处还请大家私聊或者在评论区告诉我

下面函数调用时,二维数组a必须用类型强转才能实现对int** a的参数传递
说明二维数组和二级指针依然有明显的区别,我们用打印地址的方法来探究它们的区别(注:二维数组名是个指针)

#include <iostream>
using namespace std;
void func(int **a)
{
	cout <<"传递之后a:  "<< a<<endl;
	cout <<"传递之后a+1:"<< a + 1 << endl;
}
int main()
{
	int a[3][3] = { 0,1,2,3,4,5,6,7,8 };
	func((int **)a);//强制类型转换
	cout <<"传递之前a:  "<< a<<endl;
	cout <<"传递之前a+1:"<< a + 1<<endl;
}

c++对函数形参实参之间匹配要求很严格,必须做到一一对应,如果不强制类型转换(int **)a,编译器就会报错,这也证明二维数组和二级指针存在着很明显的区别
输出结果为

结果
在16进制运算下传递之后的a之间相差8,而传递之前的a之间相差了12

笔者的机器中,指针占8个字节,这就说明传递之后的a是个普通指针
而int类型占4个字节,12除以4为3,正好是二维数组a[3][3]中列的个数,说明a依旧和数组有关系(也是个指针,因为数组名就是个指针)

这里说个自己总结的指针和数字相加的理解方式
c和c++中不同数据之间要想进行运算(加减乘除)必须先进行类型转换,而在上面每一个的加法运算中,都有一次“隐式”类型转换,把字面常量1转换成了表达式中a的类型,传递之前的a是数组类型的指针,所以1换成对应的类型(占12个字节),同理传递之后的a为普通指针,1就换成对应的类型(占8个字节),这样子就好理解为什么同样是指针+1,为何差值就不相同呢

那么问题来了,函数参数传递成功之后,我能在函数中用a[][]访问数组中的元素吗

肯定不能,因为传递之后a的本质已经变了,从上面来看,常量1都被换成不同的类型了,a肯定也变了,他已经和数组没直接关系了
那要想访问a中的元素也不是不可以,只要搞明白指针就行了,反正数据都存在内存里,也跑不了

#include <iostream>
using namespace std;

void func(int **a)
{
	cout << a<<endl;
	cout << (int*)a << endl;
	cout << *((int*)a)<<endl;
	cout << *(int*)(a + 1) << endl;
	cout << *(int*)(a + 2) << endl;
}
int main()
{
	int a[3][3] = { 0,1,2,3,4,5,6,7,8 };
	func((int **)a);
}

结果为:

结果
在函数中又进行了一次强制类型转换把a转换成了int*类型,你可以这样理解,我们为了把数组传入函数中进行了强制类型转换转成了(int **),那我们要在函数中使用这个数组就要把它的类型再转回来,而二维数组可以用int (*a)[]来表示,所以我们把它强制转换为(int *)的类型,这样我们就可以把他当成二维指针使用了(类型转换不改变指针所指的地址)
但使用上还是要有所注意的,拿cout << *(int*)(a+1) << endl;举例子:括号中的a+1,因为a是普通指针(和数组无关了),所以加1时,指针加了8个字节,而不是12,所以不能完成一次跨行的行为,这就导致输出为2(int为4占字节,8个字节相当于2个int,从0跨越到2),而不是第二行开头的3
可以借助图片理解(图中每列的地址相同)0,1,2,3,4,5之间地址相差4个字节,函数中的int**a的地址和第一列相同

这样就好理解了,如果我们想一一访问数组里的元素的话只需让a先进行强制转注意转换成int*,(这个int*可以看成一个int(*)[1]所以它+1只会跳过4个字节,变成下一个int)然后再和常量相加,再执行解引用操作

#include <iostream>
using namespace std;
void func(int **a)
{
	cout << a<<endl;
	cout << (int*)a << endl;
	cout << *((int*)a + 1) << endl;
	cout << *((int*)a + 2) << endl;
	cout << *((int*)a + 3) << endl;
}
int main()
{
	int a[3][3] = { 0,1,2,3,4,5,6,7,8 };
	func((int **)a);
}

输出结果为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值