35-数组参数和指针参数分析

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:4.4.5

 

一、思考

         为什么C语言中的数组参数会退化为指针?

 

二、退化的意义

1) C语言中只会以值拷贝的方式传递参数

2) 当向函数传递数组时:

         - 将整个数组拷贝一份传入函数(X错,这样操作效率会大大降低)

         - 将数组名看做常量指针传数组首元素地址

 

         C语言以高效为最初设计目标(数组参数退化的目的):

         a) 参数传递的时候如果拷贝整个数组执行效率将大大下降

         b) 参数位于栈上,太大的数组拷贝将导致栈溢出

 

三、二维数组参数

1) 二维数组参数同样存在退化的问题

         - 二维数组可以看做是一维数组

         - 二维数组中的每个元素是一维数组

 

2) 二维数组参数中第一维的参数可以省略(函数形参使用注意

         - void f(int a[5]) <-->void f(int a[]) <-->void f(int* a)           指针

         - void g(int a[3][3]) <-->void g(int a[][3]) <-->void g(int (*a)[3])     数组指针

 

四、等价关系

五、被忽视的知识点

1) C语言中无法向一个函数传递任意的多维数组

2) 必须提供除第一维之外的所有维长度

       - 第一维之外的维度信息用于完成指针运算

       - N维数组的本质是一维数组,元素是N-1维的数组

       - 对于多维数组的函数参数只有第一维是可变的

实例分析
传递与访问二维数组
35-1.c
#include <stdio.h>
 
 /*
显示二维数组信息,数组类型int (*)[3]
功能:
用sizeof()计算指针类型大小,为了确认数组是否退化为指针
用sizeof()计算数组大小,一维数组是a,二维数组应该是*a
由于一维数组会退化,丢掉索引值,因此需要一个参数记录丢失的索引值
遍历数组,显示结果
*/ 
void access(int a[][3], int row)    //打印二维数组信息
{
    int col = sizeof(*a) / sizeof(int);        //计算有多少列:3列
    int i = 0;
    int j = 0;
    //知识点:a所占用的内存空间:3*4,因为a退化为指针类型
    printf("sizeof(a) = %d\n", sizeof(a));   
    //一维数组:a的数组元素所占用的内存空间:12,*a指向了一维数组
    printf("sizeof(*a) = %d\n", sizeof(*a));       
   
    for(i=0; i<row; i++)        //行
    {
        for(j=0; j<col; j++)    //列
        {
            printf("a[%d][%d] = %d\n", i, j, a[i][j]);  //遍历二维数组
        }
    }
   
    printf("\n");
}


void access_ex(int b[][2][3], int n)   //打印三维数组信息
{
    int i = 0;
    int j = 0;
    int k = 0;
   
    /*
    1、确认数组退化为指针
    2、打印数组大小
    */
    //打印4,b退化为指针类型,指针大小都为4
    printf("sizeof(b) = %d\n", sizeof(b));  
    //int (*b)[2][3] = 大小2*3*4=24,退化为指针,指向二维数组
    printf("sizeof(*b) = %d\n", sizeof(*b));     
    
    //打印数组大小,一维数组是a,二维数组应该*a(二维指针)
    //遍历数组
    for(i=0; i<n; i++)            //一维
    {
        for(j=0; j<2; j++)        //二维
        {
            for(k=0; k<3; k++)    //三维
            {
                printf("b[%d][%d][%d] = %d\n", i, j, k, b[i][j][k]);
            }
        }
    }
   
    printf("\n");
}
 
int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
   
    access(a, 3);
    access(aa, 2);         //传递参数不兼容,显示结果会出现随机值
    access_ex(b, 1);
    access_ex(aa, 2);
   
    return 0;
}

操作:

1) main函数:

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
   
    access(a, 3);
    //access(aa, 2);         //传递参数不兼容,显示结果会出现随机值
    //access_ex(b, 1);
    //access_ex(aa, 2);
   
    return 0;
}

gcc 35-1.c -o 35-1.out编译正确,打印结果:

sizeof(a) = 4
sizeof(*a) = 12
a[0][0] = 0
a[0][1] = 1
a[0][2] = 2
a[1][0] = 3
a[1][1] = 4
a[1][2] = 5
a[2][0] = 6
a[2][1] = 7
a[2][2] = 8

 

2) main函数:

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
   
    access(a, 3);
    access(aa, 2);         //传递参数不兼容,显示结果会出现随机值
    //access_ex(b, 1);
    //access_ex(aa, 2);
   
    return 0;
}

gcc 35-1.c -o 35-1.out编译有警告:

35-1.c:32:2: warning: passing argument 1 of ‘access’ from incompatible pointer type [enabled by default]
  access(aa, 3);
  ^
警告:编译函数access到参数1时,指针类型不兼容  
35-1.c:3:6: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[2]’
 void access(int a[][3], int row)
      ^
提示:期望的'int (*)[3]',但是参数是'int (*)[2]'

打印结果:

sizeof(a) = 4
sizeof(*a) = 12
a[0][0] = 0
a[0][1] = 1
a[0][2] = 2
a[1][0] = 3
a[1][1] = 4
a[1][2] = 5
a[2][0] = 6
a[2][1] = 7
a[2][2] = 8

sizeof(a) = 4    //因为函数参数为int a[][3]
sizeof(*a) = 12
a[0][0] = 0
a[0][1] = 0
a[0][2] = 0
a[1][0] = 0
a[1][1] = 0
a[1][2] = 0

3) main函数:

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
   
    access(a, 3);
    //access(aa, 2);         //传递参数不兼容,显示结果会出现随机值
    access_ex(b, 1);
    //access_ex(aa, 2);
   
    return 0;
}

打印结果:

sizeof(a) = 4
sizeof(*a) = 12
a[0][0] = 0
a[0][1] = 1
a[0][2] = 2
a[1][0] = 3
a[1][1] = 4
a[1][2] = 5
a[2][0] = 6
a[2][1] = 7
a[2][2] = 8

sizeof(b) = 4
sizeof(*b) = 24
b[0][0][0] = 0
b[0][0][1] = 0
b[0][0][2] = 0
b[0][1][0] = 0
b[0][1][1] = 0
b[0][1][2] = 0

4) main函数

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    int aa[2][2] = {0};
    int b[1][2][3] = {0};
   
    access(a, 3);
    //access(aa, 2);         //传递参数不兼容,显示结果会出现随机值
    access_ex(b, 1);
    access_ex(aa, 2);
   
    return 0;
}

编译有警告:

35-1.c:56:2: warning: passing argument 1 of ‘access_ex’ from incompatible pointer type [enabled by default]
  access_ex(aa, 2);
  ^
警告:编译到函数access_ex第一个参数时,指针类型不匹配  
35-1.c:24:6: note: expected ‘int (*)[2][3]’ but argument is of type ‘int (*)[2]’
 void access_ex(int b[][2][3], int n)
      ^
提示:期望'int (*)[2][3]'但是参数是'int (*)[2]'

打印结果:

sizeof(a) = 4
sizeof(*a) = 12
a[0][0] = 0
a[0][1] = 1
a[0][2] = 2
a[1][0] = 3
a[1][1] = 4
a[1][2] = 5
a[2][0] = 6
a[2][1] = 7
a[2][2] = 8

sizeof(b) = 4
sizeof(*b) = 24
b[0][0][0] = 0
b[0][0][1] = 0
b[0][0][2] = 0
b[0][1][0] = 0
b[0][1][1] = 0
b[0][1][2] = 0

sizeof(b) = 4
sizeof(*b) = 24
b[0][0][0] = 0
b[0][0][1] = 0
b[0][0][2] = 0
b[0][1][0] = 0
b[0][1][1] = 1309061
b[0][1][2] = 7498624
b[1][0][0] = 134514331
b[1][0][1] = 2527220
b[1][0][2] = 134514320
b[1][1][0] = 0
b[1][1][1] = -1075465608
b[1][1][2] = 1207527

分析:

         虽然能打印出数据,但是出现垃圾数据。

 

小结:

1) C语言中只会以值拷贝的方式传递参数

2) C语言中的数组参数必然退化为指针

3) 多维数组参数必须提供除第一维之外的所有维长度

4) 对于多维数组的函数参数只有一维是可变的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值