如何将二维数组作为函数的参数传递

本文探讨了C语言中二维数组作为函数参数的复杂性,并提供了解决方案,包括使用指针和手动寻址的方法。

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

      今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不至于再在这上面浪费时间。

正文: 

      首先,我引用了谭浩强先生编著的《C程序设计》上面的一节原文,它简要介绍了如何将二维数组作为参数传递,原文如下(略有改变,请原谅): 

[原文开始] 
     可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如: 
     void Func(int array[3][10]); 
     void Func(int array[][10]); 
     二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的: 
     void Func(int array[][]); 
     因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的: 
     void Func(int array[3][]);实参数组维数可以大于形参数组,例如实参数组定义为: 
     void Func(int array[3][10]); 
     而形参数组定义为: 
     int array[5][10]; 
     这时形参数组只取实参数组的一部分,其余部分不起作用。 
[原文结束] 

      大家可以看到,将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。大家在学编译原理这么课程的时候知道编译器是这样处理数组的: 
      对于数组 int p[m][n]; 
      如果要取p[i][j]的值(i>=0 && i<m && 0<=j && j < n),编译器是这样寻址的,它的地址为: 
      p + i*n + j; 
      从以上可以看出,如果我们省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。但是我们在编写程序的时候却需要用到各个维数都不固定的二维数组作为参数,这就难办了,编译器不能识别阿,怎么办呢?不要着急,编译器虽然不能识别,但是我们完全可以不把它当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我们可以把维数固定的参数变为维数随即的参数,例如: 
     void Func(int array[3][10]); 
     void Func(int array[][10]); 
     变为: 
     void Func(int **array, int m, int n); 
     在转变后的函数中,array[i][j]这样的式子是不对的(不信,大家可以试一下),因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把array[i][j]这样的式子手工转变为: 
     *((int*)array + n*i + j); 
     在调用这样的函数的时候,需要注意一下,如下面的例子: 
     int a[3][3] = 
     { 
       {1, 1, 1}, 
       {2, 2, 2}, 
       {3, 3, 3} 
     }; 

      Func(a, 3, 3); 

      根据不同编译器不同的设置,可能出现warning 或者error,可以进行强制转换如下调用:   
      Func((int**)a, 3, 3); 
  

      其实多维数组和二维数组原理是一样的,大家可以自己扩充的多维数组,这里不再赘述。

参考资源链接:[C语言中二维数组传给函数的三种方式解析](https://wenku.csdn.net/doc/6461e98c5928463033b4acd0?utm_source=wenku_answer2doc_content) 在C语言中,将二维数组作为函数参数传递时,有几种不同的方法可以选择,每种方法都有其特定的场景优缺点。为了帮助你理解这些方法,推荐参考这份资料:《C语言中二维数组传给函数的三种方式解析》。在这份资料中,你将能够找到详细的解释示例代码。 第一种方法是通过形参指定第二维的长度。这种方式的优点是代码易于理解,且由于编译器知道了第二维的大小,可以检查数组索引是否越界。但在实际使用中,这种方法的灵活性较低,因为如果数组的第二维大小改变,函数就必须相应修改。 第二种方法是声明形参为指向数组的指针。这种方法更加灵活,因为它不依赖于数组的具体第二维大小。这允许函数处理不同大小的数组,但需要在函数内部进行额外的计算来正确访问数组元素。同时,这也可能导致编译器无法进行越界检查,增加了出错的风险。 第三种方法是声明形参为指针的指针。这种方法在处理动态分配的二维数组时非常有用,因为你可以传递一个指针数组,每个指针指向一行数据。然而,这种方法要求程序员手动管理内存分配,并且同样缺乏编译时的越界检查。这使得它在复杂度错误率上都高于前两种方法。 总结来说,选择哪种方法取决于你的具体需求。如果你的数组大小固定,并且需要编译器进行越界检查,第一种方法可能是最安全的选择。如果你需要处理不同大小的数组,第二种方法提供了灵活性,但需要更小心地管理数组索引。而对于动态分配的数组更高级的指针操作,第三种方法可能是必要的,但要求编写者具有更高级的编程技巧对内存管理的深刻理解。在实际应用中,应根据数组的使用场景性能需求,选择最适合的方法。 参考资源链接:[C语言中二维数组传给函数的三种方式解析](https://wenku.csdn.net/doc/6461e98c5928463033b4acd0?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值