• 25 数组参数和指针参数分析


    1 问题

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

    • 退化的意义

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

      • 当向函数传递数组时:

        • 将整个数组拷贝一份传入函数:×
        • 将数组名看作常量指针传数组首元素地址:√
      • C 语言以高效作为最初设计目标:

        • 低效:参数传递的时候如果拷贝整个数组,执行效率将大大下降
        • 不安全:参数位于栈上,太大的数组拷贝将导致栈溢出

    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])
      
    • 等价关系:数组退化后,所退化的指针必须能指向原数组中的每个元素

    数组参数 等效的指针参数
    一维数组:float a[5] 指针:float* a(指针指向 float
    指针数组:int* a[5] 指针的指针:int** a(指针指向 int*
    二维数组:char a[3][4] 数组的指针:char (*a)[4] (指针指向 char[4]
    • 被忽略的知识点

      • C 语言无法向一个函数传递任意的多维数组
      • 必须提供出第一维之外的所有维长度
        • 第一维之外的维度信息用于完成指针运算
        • N 维数组的本质是一维数组,元素是 N - 1 维的数组
        • 对于多维数组的函数参数,只有第一维是可变的
    • 示例:传递与访问二维数组

      • Demo

        #include <stdio.h>
        
        //3:完成指针运算,row:提供数组第一维的大小
        void access(int a[][3], int row)
        {
            int col = sizeof(*a) / sizeof(int);  //计算列数 = 二维数组第一个元素总大小/元素类型 = 3
            int i = 0;
            int j = 0;
            
            printf("sizeof(a) = %d
        ", sizeof(a));  //a退化为指针
            printf("sizeof(*a) = %d
        ", sizeof(*a));  //a指向一个数组,数组类型为int[3]
            
            for(i = 0; i < row; i++)
            {
                for(j = 0; j < col; j++)
                {
                    printf("%d
        ", a[i][j]);
                }
            }
            
            printf("
        ");
        }
        
        void access_ex(int b[][2][3], int n)
        {
            int i = 0;
            int j = 0;
            int k = 0;
            
            printf("sizeof(b) = %d
        ", sizeof(b));
            printf("sizeof(*b) = %d
        ", sizeof(*b));  //指向二维数组:int[2][3] = 24
            
            for(i = 0; i < n; i++)
            {
                for(j = 0; j < 2; j++)
                {
                    for(k = 0; k < 3; k++)
                    {
                        printf("%d
        ", b[i][j][k]);
                    }
                }
            }
            
            printf("
        ");
        }
        
        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);//数组指针类型不一样,调用错误:函数内部计算的列数依旧为3,会打印2×3的矩阵,前4个数字为aa中的数字,后两个为随机值
            access_ex(b, 1);
            access_ex(aa, 2);//数组指针类型不一样,调用错误:同理
            
            return 0;
        }
        
      • 编译

        test.c: In function ‘main’:
        test.c:53: warning: passing argument 1 of ‘access’ from incompatible pointer type
        test.c:3: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[2]’
        test.c:55: warning: passing argument 1 of ‘access_ex’ from incompatible pointer type
        test.c:23: note: expected ‘int (*)[2][3]’ but argument is of type ‘int (*)[2]’
        
      • 运行

        sizeof(a) = 4
        sizeof(*a) = 12
        0
        1
        2
        3
        4
        5
        6
        7
        8
        
        sizeof(a) = 4
        sizeof(*a) = 12
        0
        0
        0
        0
        2304389
        10582912
        
        sizeof(b) = 4
        sizeof(*b) = 24
        0
        0
        0
        0
        0
        0
        
        sizeof(b) = 4
        sizeof(*b) = 24
        0
        0
        0
        0
        2304389
        10582912
        134514315
        3522548
        134514304
        0
        -1074776072
        2202855
        
  • 相关阅读:
    使用XMLReader读XML
    C#命名空间大全详细教程
    C# using 三种使用方式
    SVN服务器搭建
    简单的自定义Session
    python学习第十八天 --错误&异常处理
    锁的等级:方法锁、实例锁、类锁
    java线程池如何合理的设置大小
    挖掘两个Integer对象的swap的内幕
    实现线程同步的方式
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13773677.html
Copyright © 2020-2023  润新知