C语言中如何将二维数组作为函数的参数传递

本文介绍在C语言中如何正确地将二维数组作为函数参数传递,包括固定和动态维数的方法,并提供了一个完整的示例程序。

转自:http://hi.baidu.com/outsmile/blog/item/38db95ede27206d2b31cb11d.html

最近调用二维数组比较多,感觉是个很有用的小知识点,就查了一下,这篇博客写的蛮好的,转载,侵删。

正文: 


   首先,我引用了谭浩强先生编著的《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); 

   其实多维数组和二维数组原理是一样的,大家可以自己扩充的多维数组,这里不再赘述。写到这里,我先向看了这篇文章后悔的人道歉,浪费你的时间了。下面是一 个完整的例子程序,这个例子程序的主要功能是求一个图中某个顶点到其他顶点的最短路经,图是以邻接矩阵的形式存放的(也就是一个二维数组),其实这个函数 也是挺有用的,但是我们这篇文章的重点在于将二维数组作为函数的参数传递。

<think>首先,用户的问题是关于C语言中把二维数组作为函数参数传递的方法。我需要根据提供的引用内容来回答。 参考引用: - 引用[1]:展示了二维数组作为函数参数传递的代码示例,使用形式如`int in(int a[][j])`,其中`j`是数组的第二维大小。 - 引用[2]:详细解释了二维数组的传参,包括两种方法:一种是直接传递数组(形参是数组),另一种是使用指针(形参是数组指针)。还解释了二维数组在内存中是连续存储的。 - 引用[3]:说明二维数组可以作为函数参数传递,并提到可以传递二维数组中的一行(即一维数组)。 系统指令回顾: - 所有行内数学表达式用`$...$`格式。 - 独立公式用`$$...$$`。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题并在末尾添加。 - 引用末尾自然地添加引用标识。 - 回答结构清晰,逐步解决问题。 用户上一次的问题:用户询问二维数组作为函数参数传递的方法,我需要基于引用内容回答。 关键点从引用总结: 1. 方法一:形参指定数组的第二维大小,如`void func(int arr[][j])`,其中`j`是已知常量。 2. 方法二:使用指针,形参是指向数组的指针,如`void func(int (*arr)[j])`,这样可以传递二维数组的地址。 3. 二维数组在内存中是连续存储的,类似于一维数组,所以传递时实际上是传递首元素的地址。 4. 在函数内部,可以使用数组下标访问元素。 5. 还可以传递二维数组中的一行作为一维数组参数。 我的回答结构: - 先简要介绍二维数组作为函数参数的必要性。 - 然后分步骤解释方法。 - 使用代码示例。 - 确保引用正确。 生成相关问题: - 在末尾添加相关问题,如: - 1. 二维数组作为函数参数时,为什么需要指定列的大小? - 2. 如动态传递二维数组? - 3. 二维数组指针普通指针的区别? 回答步骤: 1. 解释二维数组在内存中的布局(连续存储)。 2. 介绍第一种方法:形参指定第二维大小。 3. 介绍第二种方法:使用数组指针。 4. 解释为什么需要指定列大小:因为编译器需要知道每行的大小来计算偏移量。 5. 提供简单代码示例。 6. 自然地添加引用标识。 7. 生成相关问题。 确保语言:使用中文。 最终输出格式: - 回答主体。 - 相关问题。 </think>在C语言中,将二维数组作为函数参数传递时,由于二维数组在内存中是连续存储的(类似一维数组),编译器需要知道列尺寸来计算元素偏移量,因此参数传递需指定列大小。以下是两种常用方法,基于提供的引用内容总结而成[^1][^2][^3]。 ### 方法一:形参声明为数组形式(指定列大小) 在函数原型中显式声明二维数组的列大小。适用于编译时列大小已知的场景(如使用宏定义)。 - **语法**:`void func(int arr[][COL_SIZE])` 或 `void func(int arr[ROWS][COL_SIZE])`。 - **原理**:数组名`arr`被视为指向第一行的指针(即`int (*)[COL_SIZE]`),传递的是二维数组首地址。 - **示例代码**: ```c #include <stdio.h> #define ROWS 3 #define COLS 3 // 必须定义列大小宏 // 函数参数声明指定列大小 void inputArray(int arr[][COLS]) { for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { scanf("%d", &arr[i][j]); } } } int main() { int arr[ROWS][COLS]; inputArray(arr); // 直接传递数组名 return 0; } ``` - **缺点**:列大小必须在编译期常量,灵活性较低[^1][^2]。 ### 方法二:形参声明为数组指针(使用指针形式) 将二维数组视为指向一维数组的指针,形参声明为数组指针类型。适用于需要动态处理或避免硬编码大小的场景。 - **语法**:`void func(int (*arr)[COL_SIZE])`。 - **原理**:二维数组名本质是第一行的地址(类型为`int (*)[COL_SIZE]`),可直接传递。 - **示例代码**: ```c #include <stdio.h> #define COLS 3 // 列大小宏 // 使用数组指针作为形参 void printArray(int (*arr)[COLS], int rows) { for (int i = 0; i < rows; i++) { for (int j = 0; j < COLS; j++) { printf("%d ", arr[i][j]); } printf("\n"); } } int main() { int arr[2][COLS] = {{1, 2, 3}, {4, 5, 6}}; printArray(arr, 2); // 传递数组行数 return 0; } ``` - **优点**:兼容性高,可直接操作内存偏移。 - **注意**:列大小仍需预先指定;可通过附加行数参数实现动态访问[^2][^3]。 ### 关键要点总结 1. **为什么必须指定列大小**:二维数组元素按行优先连续存储(如`int arr[2][3]`等价于`int[6]`),编译器需列大小计算步长(如`arr[i][j]`的地址为`base + i * COLS * sizeof(int) + j * sizeof(int)`)。未指定列大小会导致编译错误[^2][^3]。 2. **内存布局**:二维数组是连续块,传递参数时实际传递首元素地址(如`&arr[0][0]`),但类型须匹配。 3. **传递单行**:二维数组的行可视为一维数组传递(如`func(arr[i])`),其中`arr[i]`是第一维索引的地址[^3]。 ### 常见问题及解决方法 - **动态二维数组**:若列大小动态,需手动模拟二维数组(如用一维数组+行偏移),或使用指针数组(`int**`),但后者非原生二维数组。 - **错误示例**:`void func(int arr[][])`无效,因列大小未知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值