第27课 - 数组参数和指针参数分析
- 思考:为什么C语言中的数组参数会退化为指针?
答:
l C语言中只会以拷贝的方式传递参数
l 当向函数传递数组时有两种传递方式
(1)将整个数组拷贝一份传入函数
(2)将数组名看做常量指针传数组首元素地址
上面的两种方式,显然第二种更合理。C语言以高效为最初的设计目标,在函数传递的时候,如果拷贝整个数组执行效率将大大下降。
我们看下面的例程:
#include<stdio.h>
void f(int *p)
{
*p = 5;
}
int main()
{
int i;
f(&i);
printf("i = %d ",i);
}
只是一个简单传址调用(传地址的值),但是C语言中实际上只有一种传值的方式,它实际也是一种传值调用的方式,和下面的程序是一样的:
#include<stdio.h>
void f(int *p)
{
*p = 5;
}
int main()
{
int i;
int *pi = &i;
f(pi);
printf("i = %d ",i);
}
- 二维数组参数
(1)二维数组参数同样存在退化的问题
l 二维数组可以看做是一维数组
l 二维数组中的每个元素都是一维数组
(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]);
等效关系:
注意事项:
l C语言中无法向一个函数传递任意的多维数组
l 为了提供正确的指针运算,必须提供除第一维之外的所有维长度。
l 限制:
一维数组参数,必须提供一个标示数组结束位置的长度信息
二维数组参数,不能直接传递给函数
三维或更多维数组参数,无法使用
例程:
#include<stdio.h>
void f(int p[3][3])
{
printf("sizeof(p) = %d ",sizeof(p));
}
int main()
{
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
f(a);
}
运行结果:4
若改为:void f(int p[][])就无法运行,改成:void f(int p[][3])就可以运行。
改成:void f(int (*p)[3])也就是数组指针的形式,一样可以运行。
以上说明数组类型需要限定大小。这就好比在函数中有:printf(“%d ”,(*(p+1)[1]));这样的语句,不限定大小,就是打印不出来的语句。
自我领悟:在C语言中除了本身给的一些数据类型外,还在默认下自我组成了好多不同类型的数据类型。我们分析数据类型,不就是分配了不同大小的一些连续的数据嘛。所以,即使是我们自定义的数据类型(包括不同长度的数组),只有同类型的可以相互转换。当然有时我们可以用到强制转换符。这是因为,数据的存储都是线性的,可以进行重新的数据整合。
实例分析--传递与访问二维数组的方式
#include <stdio.h>
void access(int a[][3], int row) //不用传递有多少列,因为我们能推出来
{
int col = sizeof(*a) / sizeof(int); //*这把钥匙打开a这扇门,得到的是一个一维数组。
//其中有多少个元素,就是整体的长度除以每个元素的长度。
int i = 0;
int j = 0;
printf("sizeof(a) = %d ", sizeof(a));
for(i=0; i<row; i++) //行
{
for(j=0; j<col; j++) //列
{
printf("%d ", a[i][j]);
}
}
}
int main()
{
int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
access(a, 3);
printf(" ");
}
运行结果:sizeof(a) = 4
0 1 2 3 4 5 6 7 8