C之数组参数和指针参数(三十一)

        我们在前面讲了在 C 语言中,数组参数会退化为指针。那么这是为什么呢?在 C 语言中只会以值拷贝的方式传递参数,当向函数传递数组时,不是将整个数组拷贝一份传入函数而是将数组名看做常量指针传数组首元素地址。

        那么当初在设立 C 语言时,主要是用于 Unix 操作系统,而 Unix 效率要求很高。所以 C 语言以高效作为最初设计目标:a> 参数传递的时候如果拷贝整个数组执行效率将会大大下降;b> 参数位于栈上,太大的数组拷贝将导致栈溢出。函数调用栈是用一片内存来存放的,如果栈溢出,那么函数调用将无法执行,程序将会崩了。

        二维数组参数同样也存在退化,它可以看做是一维数组,它中的每个元素是一维数组。二维数组参数中第一维的参数可以省略,如:void f(int a[5]) ==> void f(int a[]) ==> void f(int* a);  void g(int a[3][3]) ==> void g(int [][3]) ==> void g(int (*a)[3]);那么我们平时所说的一维数组作为参数时将会退化为一维指针,二维数组并不会退化为二维指针,而是退化为数组指针。那么什么样的参数将退化为二维指针呢?我们总结了下面这张表

数组参数
等效的指针参数
一维数组:float a[5]
指针:float* a
指针数组:int* a[5]
指针的指针:int** a
二维数组:char a[3][4]
数组的指针:char(*a)[4]

        我们可以看出指针数组作为参数时才退化为二维指针。那么在 C 语言中无法向一个函数传递任意多的多维数组,必须提供除第一维之外的所有维长度;其中第一维之外的维度信息用于完成指针运算,N维数组的本质是一维数组,元素是 N - 1 维的数组,对于多维数组的函数参数只有第一维是可变的。下来我么以代码为例进行分析,代码如下

#include <stdio.h>

void access(int a[][3], int row)
{
    int col = sizeof(*a) / sizeof(int);
    int i = 0;
    int j = 0;
    
    printf("sizeof(a) = %d\n", sizeof(a));
    printf("sizeof(*a) = %d\n", sizeof(*a));
    
    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
            printf("%d\n", a[i][j]);
        }
    }
    
    printf("\n");
}

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    
    access(a, 3);
    access(aa, 2);
    
    return 0;
}

        我们看到在程序中我们在第25和26行分别定义了3*3,2*2的二维数组,但是 access 函数里参数的数组参数第二维指定是3。所以我们在第29行调用这个函数会报错,因为类型不匹配。我们来看看编译结果

图片.png

        我们看到它报警告了,也就是说这个程序虽然通过编译了,但是它允许的结果是不确定的。我们看到我们定义的 aa 数组是 2*2 的,但是它打印出了6个数,也就是当成 2*3 的了。所以我们这样调用是不对的。

        下来我们看个三维数组的代码,代码如下

#include <stdio.h>

void access_ex(int b[][2][3], int n)
{
    int i = 0;
    int j = 0;
    int k = 0;
    
    printf("sizeof(b) = %d\n", sizeof(b));
    printf("sizeof(*b) = %d\n", sizeof(*b));
    
    for(i=0; i<n; i++)
    {
        for(j=0; j<2; j++)
        {
            for(k=0; k<3; k++)
            {
                printf("%d\n", a[i][j][k]);
            }
        }
    }
    
    printf("\n");
}

int main()
{
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
    
    access_ex(b, 1);
    access_ex(aa, 2);
    
    return 0;
}

        我们在 access_ex 函数里指定的是第二维是2,第三维是3。但是我们定义的数组 aa 不是这样的,我们看看编译结果图片.png

        我们看到第二个编译出的结果也是不确定的。通过本节对数组参数和指针参数的学习,总结如下:1、C 语言中只会以值拷贝的方式传递参数,并且数组参数必然退化为指针;2、多维数组参数必须提供除第一维之外的所有维长度;3、对于多维数组的函数参数值第一维是可变的。


         欢迎大家一起来学习 C 语言,可以加我QQ:243343083

猜你喜欢

转载自blog.51cto.com/12810168/2106644