二维数组调时候的传参问题 and 一维数组的中括号秘密( [ ] )——实参与形参的对应 —————— 开开开山怪

本文深入探讨了一维和二维数组的基础知识,详细讲解了数组与指针的关系,以及如何正确地在函数间传递数组参数。

1> 一维数组的基本知识储备

重要概念 1: 实参与形参: 在c中,实参可以是常量变量表达式。但是形参只能是 变量
重要概念 2: 数组结构: 任何数组的式是 type 数组名[ count ] ,数组名是一个指针常量,指类是数组元素的类型
重要概念 3: 指类:指类即指针所指向的空间的元素类型,对于指针变量来说,它的指类就是去掉和这个指针变量紧挨的 * 。任何申请的指针变量的结构都可以为 type * 变量名

int * pp的指类的 int , 此时的 type == int
double *** pp的指类是double** ,此时的 type == double**

像我们经常用的数组例如 int array[4] 相当于申请了4个int 空间,array 是数组名,但它的本质是指针常量,是一个地址,是这个数组的首元素首地址,而这个array 的指类是int ,指类的意思是指针所指向的空间的元素的类型。
当我们需要访问这个数组中的某个元素时,我们通常采用array[0], array[1]……,来访问数组中的第一个元素,第二个元素……。
上面说到array是一个指针常量,也代表数组首元素的首地址,对于星号运算符( * )大家应该不陌生,是一个指向运算符,后边可以跟指针常量,指针变量,指针表达式,那对 *array就有两种不同的状态 1:当处于等号的左边是表示array所指向的空间。 2:处于等号的右边,则表示array所指向的空间的值。
当我们采用 array[0] array[1] array[2] 进行访问数组中的元素的时候其实本质如下:

在这里插入图片描述

结论[ ] 运算符相当于 *( ) 运算符
array[0] = = * (array + 0) == *(0 + array)
array[1] == * (array + 1) == *(1 + array)
在这里插入图片描述

2 > 二维数组的基本知识储备

采用简单的例子说明问题

一维数组 的基本形式 int array[3] 表示申请了三个元素的数组,元素的类型为int类型
二维数组 的基本形式 int array[3][2] 表示这个数组是三行四列,数组中的每个元素的类型为int类型

重点:在上面说到 一维数组 int array [3] 中的array是指针常量,且指类为int类型
而此时的 int array [3] [2] 中的array该怎么解释呢?

由于int array[3][2] 中的 [ 2 ]array 较远可以将 [2] 进行左挪形成 int [2] array[3] 则形成
type array[3] , 此时的数据类型为 typeint [2]

此时的array同样也是一个指针常量但是一个二阶指针,但此时 array 的指类为 typeint [2] ,此时的 array + 1 则移动一个指类的长度即2 * 4 = 16个字节;array + 1 依旧是指针;此时的 array 代表的是 行指针array + 1 则挪动一行的长度;

在这里插入图片描述

3> 一维数组和二维数组的传参问题

int array[3]

1> 一维数组的实参与形参的传递

void  funOne(int *p);  //函数的声明
void funOne(int *p) { //函数的定义
	
} 

int main() {
  int array[3];
  
  funOne(array);	
  return 0; 
}




//实参与形参传递时要求参数个数一致,参数的顺序一致,参数的类型一致
//此时实参是array是一个一阶指针,指类是int类型,同时形参 p也是一阶指针,且指类为int类型。

2> 二维数组的形参与实参的传递

void funOne();
void funOne() {
}

int main() {
  int array[3][2];

  funOne(array);
  return;
}

对于这个简单二维数组 int array[3][2] 来说,进行形参与实参的传递时,形参应该怎么写?
在上面已经说到不管是几维数组,结构都遵循 type 数组名[count]
int array[3][2] == int[2] array[3]
type 为 int [2]
array是 指针常量
array所指向的空间的元素类型为int[2] ,这就对应到我一开始说到的指类,
array的指类是int [2];

对比一位数组来看
int array[3] 我们形参变量定义的时候为int *p
int array[3][2] 那对应是不是 int *p[2]呢?

错误写法: int * p[2]
分析: 因为形参实参传递的时候应遵循对应的规则,我们只需要做对应的判断 , 由于 [ ] 运算符的优先级高于 * 运算符,所以 [ ] 与变量 p 紧密结合,而 * 则与 int 进行结合,此时就形成的这样一个局面 int * p[2] ; 发现这个结果就相当于 type 变量名[count] ,那就相当于此时的 p 是一个数组首地址,是在一个指针常量,且指类是 type 即 int * , 这明显与上述的 array 的指类 type 不相同,所以 int * p[2] 是错误写法。

正确的写法: int ( * p)[2]
分析: 上边错误写法是因为 [ ] 运算符降低了 * 与变量 p 的结合性,那我们可以采用 ( ) 来提高 * 与变量 p 的高度结合性, int ( * p)[2] 由于 [ ] 此时并没有与变量 p 进行结合,则 [2] 可以进行左挪形成 int[2] ( * p) 其实这样就相当于 type * 变量名,根据指类的概念 p 的指类为 type 即 int[2] 与 array 对应。

<think>好的,我现在要解决用户关于Java中二维数组作为形参实参的影响机制的问题。首先,我需要回忆Java的参数传递机制。记得Java中参数传递都是值传递,基本类型传递的是值的副本,而引用类型传递的是引用的副本。那二维数组属于引用类型,所以当它作为参数传递时,际上传递的是数组引用的副本。 接下来,我需要确定二维数组的结构。二维数组在Java中际上是数组的数组,也就是说,每个外层数组的元素是一个内层数组的引用。因此,当传递二维数组给方法时,形参实参会指向同一个外层数组对象。但形参本身是一个副本,这个副本存储的是外层数组的引用。 然后,需要考虑修改形参实参的影响。如果方法内部修改了形参指向的外层数组的元素(比如修改某个内层数组的引用),由于形参实参引用的副本,这种修改会影响实参,因为它们指向同一个外层数组。例如,如果方法中执行了array[0] = new int[3],那么实参对应位置也会改变。但是,如果在方法内部将形参重新指向一个新的二维数组,比如array = new int[2][3],这不会影响实参,因为此时形参的引用副本指向了新对象,而实参仍然指向原来的对象。 另外,如果方法内部修改的是内层数组的元素,比如array[0][0] = 5,这同样会影响实参,因为内层数组的引用并未改变,只是元素值被修改了,而实参形参仍然共享这些内层数组的引用。 需要验证这些理解是否正确。查看用户提供的引用,比如引用[1]提到Java是值传递和引用传递共存,但本质是值传递。这说明传递的是引用的副本,而不是引用本身。引用[4]中的JNI例子也展示了二维数组作为参数传递时,如何获取数组元素,进一步支持了二维数组作为引用传递的机制。 可能用户混淆的地方在于,容易认为传递的是引用本身,导致方法内对形参的任何修改都会反映到实参,但际上只有修改引用指向的对象内容才会影响实参,而改变形参的引用指向不会影响实参。需要明确区分修改引用指向的对象和修改引用本身。 总结起来,回答的结构应该是先解释Java参数传递机制,再具体到二维数组的情况,举例说明不同操作对实参的影响,并引用相关资料中的观点支持结论。最后生成相关问题,帮助用户深入理解。</think>在Java中,二维数组作为形参传递时,遵循Java的**值传递机制**,但具体表现需结合二维数组的**引用类型特性**来分析。以下是分步解释: --- ### 一、Java参数传递的核心机制 1. **基本数据类型**:传递的是值的副本,形参实参内存地址独立 2. **引用类型**:传递的是对象引用的副本,形参实参指向同一个对象[^1] - 例如数组、对象等 - 对形参引用的**对象内容**修改会影响实参 - 对形参引用的**重新赋值**不会影响实参 --- ### 二、二维数组的特殊性 二维数组本质是「数组的数组」,其内存结构为: ``` int[][] arr = { {1,2}, // arr[0]指向第一个一维数组 {3,4} // arr[1]指向第二个一维数组 } ``` - 外层数组存储的是内层数组的引用 - 形参接收的是外层数组引用的副本 --- ### 三、具体场景分析 #### 场景1:修改内层数组元素 ```java void modifyElement(int[][] arr) { arr[0][0] = 99; // 修改际存储的值 } // 用时 int[][] myArr = {{1,2}, {3,4}}; modifyElement(myArr); System.out.println(myArr[0][0]); // 输出99 ``` **结果**:实参内容被修改,因为操作的是**共享的引用指向的对象** #### 场景2:重新分配外层数组引用 ```java void reassignOuter(int[][] arr) { arr = new int[][]{{5,6}}; // 改变形参的引用 } // 用后 System.out.println(myArr[0][0]); // 仍输出1 ``` **结果**:实参不受影响,因为修改的是**形参的副本引用** #### 场景3:修改内层数组引用 ```java void reassignInner(int[][] arr) { arr[0] = new int[]{7,8}; // 修改外层数组元素 } // 用后 System.out.println(myArr[0][0]); // 输出7 ``` **结果**:实参被修改,因为操作的是**共享的外层数组对象** --- ### 四、内存示意图 ``` 实参myArr → 外层数组对象 ├─ [0] → 内层数组对象A └─ [1] → 内层数组对象B 形参arr(副本)→ 外层数组对象 ``` - 对虚线框外的修改不影响实参 - 对虚线框内的修改影响实参 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值