int**arr 为什么不能用于二维数组传参(但可以用于指针数组传参)

文章目录

前言:这个问题倒没什么难的,就是绕,想的多了思路一不小心就拧一块去了(

1.引子

对于下面这一串代码(无法正常运行),可能部分同学曾经写过,并奇怪为何无法运行,即如标题所说——int**arr 不能用于二维数组传参(但可以用于指针数组传参)

void test(int** arr) {
	for (int i = 0; i < 2; i++) 
		for (int j = 0; j < 2; j++) 
			printf("%d ", arr[i][j]);
	return;
}
int main() {
	int arr1[2][2] = { 1,2,3,4 };//二维数组
	test(arr1);
	return 0;
}

正常写法如下

//指针数组传参
void test(int** arr) {
	for (int i = 0; i < 2; i++) 
		for (int j = 0; j < 2; j++) 
			printf("%d ", *(*(arr + i) + j)/*等效于arr[i][j]*/);
	return;
}
int main() {
	int arr1[] = { 1,2 }; int arr2[] = { 2,3 };
	int* arr[] = { arr1,arr2 };//指针数组
	test(arr);
	return 0;
}

2.原因

  1. 解引用 * 对于 二维数组 和 指针 的规则不太一样
int main() {
	int a = 0; int* pa = &a; int** ppa = &pa;
	int arr[3][3] = {0};
	//ppa为二级指针,*ppa 为一级指针,**ppa为数据	——指针指向什么解出来就是什么
	//arr为二维数组首元素地址(指向其中的第一个一维数组),*arr 即对第一个一维数组的地址解引用,得到其中(这个一维数组)的首元素地址 	——数组……自己看吧,就挺难概括表达的
	//*(*arr)为元素
	return 0;
}
  1. 关于传参的问题

函数内的形参类型取决于你定义的形参类型,与传入的实参类型无关

也就是说:你传入函数的实参代表整个数组也好,只是一个普通的指针也罢,在进入形参为 int** arr 的函数后都会被识别为二级指针,进入形参为 int arr[][4] 的函数后都会被识别为一个指向这样的二维数组的指针

于是就有下面这样的代码:

#include<stdio.h>
void test(int arr[][2]) {//定义形参arr为这样一个二维数组的数组名——所以 arr 指向二维数组首元素(其中的首个一维数组)的地址
	printf("%d ", *arr); /*如上 1 所述,解引用后仍应是地址*/ printf("<=> %p\n", *arr);
	printf("%d\n", *(*arr));//如上 1 所述,得到数据
}
int main() {
	int a = 1;
	int* pa = &a;
	test(pa);//传入的实参只是个普通的指针
	return 0;
}

2023.11.14 补充(就是想补充一下而已):
int (*arr)[][2] 和 int arr[][2] 做参数时,arr 的含义是不一样的
前者 arr 指向整个二维数组;后者 arr 就是个二维数组名,指向二维数组首元素(即其中首个(整个)一维数组)

也就是前者解引用才能得到后者
我们以前者为例:

#include<stdio.h>
void test(int (*arr)[][2]) {			//★ 参数含义为:arr 指向整个二维数组
	printf("%d <=> %p\n", *arr, *arr);	//解引用,得到首元素地址,*arr 为指向其中首个(整个)一维数组的指针
	printf("%d <=> %p\n", **arr, **arr);//解引用,得到一维数组首元素地址
	printf("%d\n", ***arr);				//得到数据
}
int main() {
	int arr[2][2] = { 1,2,3,4 };
	test(arr);
	return 0;
}

因而对于开头的问题我们可以得到如下逻辑:

在这里插入图片描述

验证:根据错误实例的推断,我们可以知道,对形参只用一次解引用即得数据

void test(int** arr) {
	for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) printf("%d ", *arr);//
	return;
}
int main() {
	int arr1[2][2] = { 1,2,3,4 };
	test(arr1);
	return 0;
}

2024.1.10 补:VS 的 .c 文件允许以上的写法,但 .cpp 文件会说 “int (*)[2]” 类型的实参与 “int **” 类型的形参不兼容,报错 —— 编译器真是奇妙 ……

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值