数组名的理解
之前我们在使用指针访问数组内容时,有这样的代码:
int arr[10]={
1,2,3,4,5,6,7,8,9,10};
int* p=&arr[0];
这里我们使用&arr[0]
的方式拿到了数组第一个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址。
我们来做个测试,看数组名到底是不是首元素的地址:
从打印出来的值来看,它们确实是一样的,所以数组名确实是首元素的地址。
那么数组名是首元素地址的话,我们去求地址长度,在32位平台下应该为4个字节(地址的长度与多少位的平台有关)
我们用sizeof
计算下地址长度是多少:
这是为什么呢?
数组名就是数组首元素(第一个元素)的地址,但是有两个例外:
sizeof(数组名)
,sizeof中单独放数组名时,这里的数组名表示整个数组,不是首元素的地址,此时计算的是这整个数组的大小,单位是字节。&数组名
,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)
从值的角度来看的话,取整个数组的地址与取首元素的地址打印出来的值一模一样。
这是因为无论是取首元素地址,还是取整个数组的地址,它们的值都是从首元素的地址开始的。
但是我们平时写代码的时候要知道,数组名前+取地址符号是取整个数组的地址。
如果我们想看看它们的区别还是可以看到的,我们给首元素的地址、整个数组分别都+1:
我们发现,前两个地址+1都只跳过了一个整形的大小,而第三个地址+1却跳过了一个数组的大小(40个字节)
所以我们将三个地址打印出来只能看到打印出来的值是一样的,但是类型绝对是不同的,因为int*
类型+1跳过的应该是一个整形,而不是40个字节。
除此之外,任何地方使用数组名,数组名都表示首元素的地址。
使用指针访问数组
有了前面知识的支持,再结合数组的特点,我们就可以很方便的使用指针访问数组了。
为什么在访问数组的时候可以使用指针呢?
1.因为数组在内存中是连续存放的,只要是连续存放的,只要找到第一个,就可以顺藤摸瓜找到其他的了。
2.指针±整数的运算,方便我们获得每一个元素的地址
接下来我们写个代码,实现用指针访问数组,给数组的每个元素输入值,再输出值。
注意:
数组就是数组,是一块连续的空间(数组的大小与元素个数和元素类型都有关系)
而指针(变量)就是指针(变量),是一个变量(通常是4/8个字节)
那么它俩之间的联系是什么呢?
数组名是地址,是首元素的地址,可以使用指针来访问数组
拓展:
我们知道arr[i]
与*(arr+i)
这两种写法是完全等价的,并且*(arr+i)
里面的式子是加法,加法是支持交换律的。所以arr[i]==*(arr+i)==*(i+arr)
我们代入代码中看会不会错:
结果也是正确的。
既然这三个等价:arr[i]==*(arr+i)==*(i+arr)
*(arr+i)
可以写成arr[i]
,那么*(i+arr)
可不可以写成i[arr]
呢?
我们带入代码试试:
我们发现即使是这样程序也没有问题。那么这说明了什么呢?
我们知道[]
是个下标引用操作符,既然加号操作符+
可以实现:1+2
可以写成2+1
;那么,arr[i]
也就可以写成i[arr]
了
提示:这种方式虽然可行,但是不推荐。
因为这样写不利于阅读代码。
一维数组传参的本质
数组我们学过,数组是可以传递给函数的,现在我们讨论一下数组传参的本质。
首先从第一个问题开始:
写个函数实现数组元素的打印,我们之前都是在函数外部计算数组元素的个数:
那我们可以只把数组传给函数,少传一个参数。然后在函数内部求数组的元素个数再打印数组嘛?
此时我们这样写却出现错误,数组里的元素只打印了一个,这是为什么呢?我们进行调试:
- 按F11开始调试,创建数组执行完后打开监视,查看创建的数组有没有问题:
- 发现创建数组没有问题后按F11进入函数内,在监视里输入
arr,10
查看数组传参有没有问题:
此时数组的传参也没有问题ÿ