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\n", sizeof(a)); //a退化为指针 printf("sizeof(*a) = %d\n", sizeof(*a)); //a指向一个数组,数组类型为int[3] for(i = 0; i < row; i++) { for(j = 0; j < col; j++) { printf("%d\n", a[i][j]); } } printf("\n"); } 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)); //指向二维数组:int[2][3] = 24 for(i = 0; i < n; i++) { for(j = 0; j < 2; j++) { for(k = 0; k < 3; k++) { printf("%d\n", 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);//数组指针类型不一样,调用错误:函数内部计算的列数依旧为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
-