数组与函数(C/C++)

数组与函数(C/C++)
一维数组

首先要明确一维数组的数组名并不是一个指针:

int a[] = {1,2,3,4};
int *p;

cout<<"数组名a的类型为\t"<<typeid(a).name()<<endl;
cout<<"指针p的类型为\t"<<typeid(p).name()<<endl;

p = a;
cout<<"赋值后指针p的类型为\t"<<typeid(p).name()<<endl;

输出结果:

数组名a的类型为 A4_i
指针p的类型为   Pi
赋值后指针p的类型为     Pi

由此可知:数组名不是指针,但是可以赋值给指针,赋值时数组名将隐式转换为指向数组首元素的指针。

所以这时sizeof(a) = 16,而sizeof§ = 4。只有在数组被定义的函数体内,数组名才具备这个作用,一旦数组名作为参数传入函数,它的类型就会变为指针,无论形参是如何定义的(int arr[]或者int *arr):

void type(int arr[])
{
    cout<<"arr的类型为\t"<<typeid(arr).name()<<endl;
}
int main()
{
    int a[] = {1,2,3,4};
    cout<<"数组名a的类型为\t"<<typeid(a).name()<<endl;
    type(a);
}

输出结果为:

数组名a的类型为 A4_i
arr的类型为    Pi

因此这时sizeof(arr)不再等于16而等于4,这也是为什么希望传入数组名的同时传入数组长度,因为在数组被定义的函数体内求数组长度是最方便的。

再有就是一个指针p可以用p[1]去表达*(p+1),这两种表述是等价的,另外对a取址将得到数组所对应的地址,这个地址等于数组首元素的地址,虽然数值相等,但含义是不一样的。

int a[] = {1,2,3,4};

cout<<&a<<endl; //数组地址
cout<<a<<endl; //这里实际上存在类型的隐式转换,数组首元素地址

输出结果:

0x61fe80
0x61fe80

总结:只有在被定义的函数体内数组名可保持原有类型,具备sizeof的作用,且取址操作等于数组地址。将数组传入函数时传入的是数组名与数组长度,此时的数组名就是指向数组首元素的指针。

二维数组

二维数组的数组名也不是指针!

int a[2][3] = {
        {1,2,3},
        {4,5,6}
    };  
cout<<"数组名a的类型为\t"<<typeid(a).name()<<endl;
cout<<"a[0]的类型为\t"<<typeid(a[0]).name()<<endl;

输出结果:

数组名a的类型为 A2_A3_i
a[0]的类型为    A3_i

由此可知:a是一个二维数组名,a[0]是一个一维数组名,所以对a[0]的操作与一维数组名一致。

sizeof(a) = 24, sizeof(a[0]) = 12, sizeof(a[0][0]) = 4。

对a取址得到的是二维数组的地址,对a[0]取址得到的是第一行一维数组对应的地址,对a[0][0]取址得到的是第一行第一列元素对应的地址,与直接输出a所得结果相等,但代表的含义是不同的。

int a[2][3] = {
        {1,2,3},
        {4,5,6}
    };
cout<<"二维数组的地址为\t"<<&a<<endl;
cout<<"第一行的一维数组的地址为\t"<<&(a[0])<<endl;
cout<<"第一行第一列元素的地址为\t"<<&(a[0][0])<<endl;
cout<<"a = \t"<<a<<endl;
二维数组的地址为        0x61fe74
第一行的一维数组的地址为        0x61fe74
第一行第一列元素的地址为        0x61fe74
a =     0x61fe74

那么问题来了,a是否也被隐式转换成了指向数组首元素的指针?运行下面的代码:

int a[2][3] = {
        {1,2,3},
        {4,5,6}
    };
int *p = a;

得到报错信息:error: cannot convert ‘int (*)[3]’ to ‘int*’ in initialization

int * p[3]; //p是一个数组,数组中有三个int型指针
int (*p) [3]; //p是一个指针,指向一个int[3]数组

意思很明显,不能将一个指向int[3]数组的指针值赋给一个指向int型的指针,也就是说a被隐式转换成了一个指向int[3]数组的指针,即指向二维数组第一行一维数组的指针,这等价于&(a[0]),所以正确的写法应该是:

int (*p)[3] = a; //将p也定义为一个指向int[3]数组的指针,这里的a会被隐式转换为指向a[0]的指针,
//a[0][0]=**p,第一次解引用得到a[0]数组的地址(也是a[0][0]的地址),第二次解引用才拿到a[0][0]的
//值,所以p类似于一个二级指针,a的隐式转换也类似于一个二级指针
// 或者
int *p = a[0]; //这里利用了a[0]会被隐式转换为指向a[0][0]的指针
// 或者
int p[][3] = a; //将p定义为数组名,无隐式转换

所以,同样的,在将二维数组传入函数时,最后同时传入其行数与列数,因为在被定义的函数体内求这两个值最方便。

二维数组传入函数的方法:

void f(int (*p)[列数],行数,列数); //f(a,行数,列数)
void f(int *p,行数,列数); //f(a[0],行数,列数)
void f(int p[][列数],行数,列数); //f(a,行数,列数)

其中第二种方法最常用也最简单,因为在定义函数时无需事先知道数组的列数,相当于将二维数组当一维数组处理。

总结:a会被隐式转换为指向a[0]的指针,a[0]会被隐式转换为指向a[0][0]的指针,降一维,a = &(a[0])

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值