数组名的意义

数组名只有单独放在sizeof内部以及放在&后才代表整个数组的地址。其余情况数组名都表示数组首元素地址。

之前我们说过用sizeof(a)计算的是整个数组的大小,现在我们知道其中的原因了。由于sizeof里的数组名a表示整个数组的地址,故sizeof(a)求的是整个数组的大小。

以一维数组为例:

我们常利用这条性质来求数组中的元素个数

int a[] = {1,2,3,4,5,6,7,8};
sizeof(a);//sizeof给出整个数组所占据的内存的大小,单位是字节
sizeof(a[0]);//给出数组中单个元素的大小
sizeof(a)/sizeof(a[0])//得到数组一共有多少个元素

这样的代码一旦修改数组中初始的数据,不需要修改遍历的代码。

以二维数组为例:

int arr[3][4] = {0};
sizeof(arr)//这表示整个二维数组的大小

当然对于“数组名只有单独放在sizeof内部以及放在&后才代表整个数组的地址”这个结论有一个特殊情况。

当数组作为函数参数时,传参传过去的数组名是数组首元素的地址,这个时候在函数内部使用sizeof(arr),其中的arr表示的就是首元素的地址,而不是整个数组的地址,因此我们在函数内部不可使用sizeof来计算整个数组的大小,也就不能用上述方法来计算数组的元素个数。

int search(int a[],int key){
	......
}

int main()
{
	int a[] = {1,2,3,4);
	search(a,key);
)

如上述代码,在main函数中调用search函数把a,也就是数组首元素地址传给了search函数,也就是说search函数接收到的a是数组首元素的地址,因此search函数里面的数组名a表示数组首元素地址,因此在search函数内部不可以用sizeof(a)来计算整个数组的大小。

那如果我们在search函数内部用sizeof(a)来计算整个数组的大小会怎么样呢?

如图所示,在main函数中调用search函数,将arr,也就是数组的首元素地址传给search函数,因此在search函数内部,arr表示数组的首元素地址,故sizeof(arr)实际上就是sizeof(int *),为4字节,故最终输出结果为1。

因此数组作为函数参数时,我们不能用上述方法在函数内部求数组的大小,所以我们通常单独使用一个参数来接收数组的大小:

int search(int a[],int key,int len){
	......
}

int main()
{
	int a[] = {1,2,3,4};
	int len = sizeof(a)/sizeof(a[0]);
	search(a,key,len);
)

如上述代码,因为是在运算符sizeof里面使用,故这里的数组名a表示整个数组的地址,在调用search函数时,将其传给search函数时它又表示数组首元素的地址了。

搞懂这个特殊情况后,我们再思考一个问题,为什么数组作为函数参数时,我们传的是数组首元素的地址呢?

这是因为有些数组是一片很大的空间,比如存储了1000个int类型元素的数组,它的大小是4000字节,如果我们传参的时候把整个数组传过去,那么在函数内部就要重新开辟4000字节大小的空间来接收传过来的值,这无疑会造成空间的浪费,而数组元素在内存中是连续存储的,传大小很小的首元素的地址就能找到其他元素,相当于是传了整个数组,因此没有必要传整个数组,传首元素地址就可以了。

学到这,我们已经了解数组名的意义了,数组名既可以表示数组首元素的地址,也可以表示数组的地址。

数组首元素地址和数组地址有什么联系和区别吗?

联系:

两个在数值上是一样的

区别:

当数组名arr表示数组地址时,arr+1直接跳过一个数组的大小

如图所示,首先输出数组arr的地址,然后输出arr+1,二者之间刚好相差0x28,也就是相差十进制的40字节,即相差一个数组的大小,说明arr+1跳过一个数组的大小。

当数组名arr表示首元素的地址时,arr+1表示下一个元素的地址,即第二个元素的地址

如图所示输出arr+1的结果和输出&arr[1] (第二个元素的地址)是相同的,因此arr+1就表示第二个元素的地址。

故arr表示首元素(arr[0)])地址,那么arr+1就表示第2个元素(arr[1])的地址,以此类推,arr+2表示第3个元素(arr[2])的地址,arr+i表示arr[i]的地址。

我们刚刚提到过,除了那两种情况,数组名都表示数组首元素地址,对于一维数组而言,数组首元素就是第一个元素。

那么对于二维数组而言,数组首元素是什么呢?

二维数组的首元素就是第1行数组,所以二维数组的首元素地址就是第1行数组的地址。

 

我们可以用数组指针来保存二维数组首元素的地址:

arr[3][4] = {0);
int(*p)[4] = arr

此时arr保存的是二维数组首元素的地址,即第1行数组的地址,可以把arr看作是int[4]类型的数组指针,所以arr+1相当于跳过一个int[4],也就是arr+1直接跳过第1行数组,指向第2行数组,是第2行数组的地址。

那么arr+i就是指向第i+1行数组,相当于第i+1行的数组地址,*(arr+i) 相当于第i+1行的数组,第i+1行数组可以看作第i+1行的数组名,通常情况下数组名表示数组首元素的地址,所以 *(arr+i)也是第i+1行数组首元素的地址。

为了加深对上述概念的理解,我们可以看看下面这段代码:

int arr[3][4] = {0};
sizeof(arr[0]);

这里的sizeof(a[0])计算的是什么呢?

arr[0]表示数组首元素,对于二维数组而言,首元素就是第1行数组,故这里的arr[0]表示第1行数组,第1行数组又可以看作第1行数组的数组名,此时属于数组名单独放在sizeof里面的情况,故sizeof(arr[0])表示第1行数组的大小,那么最终的值就是16。

我们再看看下面这段代码:

int arr[3][4] = {0};
sizeof(arr[0]+1);

arr[0]表示第1行数组,也就是第1行的数组名,但是由于他不是单独放在sizeof内部,也不是放在&后面,故它表示的就是第1行数组首元素的地址,故arr[0]+1表示第1行数组第2个元素的地址,故sizeof(arr[0]+1)算出的结果是4/8。

我们最后再来看一段代码:

int arr[3][4] = {0};
sizeof(*(arr+1));

arr表示二维数组首元素的地址,即第1行数组的地址,那么arr+1就是第2行数组的地址,*(arr+1)表示第2行数组,第2行数组又可以看作第2行数组名,而此时它又是单独放在sizeof内部的,故sizeof( *(a+1))就表示第2行数组的大小,结果为16。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子非鱼Swx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值