向函数传递一维数组和已知大小的二维数组

来源:互联网 发布:js 按钮显示 隐藏 div 编辑:程序博客网 时间:2024/05/13 17:56

一维数组

在C语言中,向函数传递参数只有一种形式——值传递。不管是传递一个整型变量,还是传递一个指针,函数得到的都只是实参的拷贝值

先定义一个一维整型数组:

    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

首先明确一点:数组名和指针是两个不同的概念,尽管数组名在绝大部分情况下被隐式转换成指针使用。
我们没办法真正地把数组传递给函数,我们只能传递一份指向数组起始位置的指针的拷贝

函数原型:

void func(int *a);void func(int a[]);

在当前这个上下文环境中,二者等价。你可以使用任何一种声明,如果要说哪一种最准确,应该是第一种。因为实参实际上是个指针,而不是数组。

这样我们就把指向数组首元素的指针的拷贝传递给了函数。在实际应用中,我们通常还会传递另一个参数,用来表示数组的长度:

void func(int *a, int len);

通过第二个参数,我们可以很方便地在函数内遍历这个数组:

void func(int *a, int len) {    int i = 0;    while (i < len) {        printf("%d ", a[i]);        i++;    }}func(a, 10); // 打印数组a的所有元素

二维数组

接下来是二维数组,传递二维数组参数有更多需要注意的点。
先定义一个二维整型数组:

int b[2][3] = {     {0, 1, 2},     {3, 4, 5}};

我们实际上要向数组传递一个指向数组首元素的指针的拷贝,首先必须搞清楚数组名b的类型应该是:

int (*)[3]

数组名的类型取决于数组元素,数组b长度是2,每个元素是长度为3的整型数组,所以b的类型是上面那坨(如果这里有疑问可以看我的另一篇文章《彻底弄懂C语言数组名》)。
如果上面的内容没有疑问,那么就来看函数原型:

void func2(int (*p)[3]); // 两种都可以,第一种更准确void func2(int p[][3]);

同样地,我们可以传递另外两个参数,分别表示行数和列数:

void func2(int (*p)[3], int len_i, int len_j);

但是请千万注意:写成二级指针是错误的!

void func2(int **p); // 不可以这样~>_<~

为什么不行呢?因为指向指针的指针和指向数组的指针是不同的。如果这样写,有可能你的程序能正确运行,但也有可能因为寻址错误导致程序崩溃哦!

下面给出完整的例子:

#include <stdio.h>void func2(int (*p)[3], int len_i, int len_j);int main() {    int a[2][3] = {         {0, 1, 2},         {3, 4, 5}    };    func2(a, 2, 3);    return 0;}void func2(int (*p)[3], int len_i, int len_j) {    int i, j;    for (i = 0; i < len_i; i++) {        for (j = 0; j < len_j; j++) {            printf("%d ", p[i][j]);        }        printf("\n");    }}

这里写图片描述


但是,不知道你有没有发现一个问题,我们必须在函数原型中指定第二维的大小,这意味着函数不能复用。为了向函数传递一个大小未知的数组,我将介绍两种技巧。

第一种是通过void *指针接收一个数组,同时传递两个参数标记行和列,然后在函数内部将void *指针强制转换成二维数组。

还有一种技巧叫做压扁数组(flattening the array),是通过一级指针遍历二维数组的方法。只要数组在内存中连续,这个技巧就可以用。我将在下一篇文章中详细介绍这个技巧。

原创粉丝点击