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
      
原文地址:https://www.cnblogs.com/bky-hbq/p/13773677.html