萌新的学习笔记,写错了恳请斧正。
目录
数组名的理解
数组名其实就是数组首元素的地址,只有两个例外(马上讲)
我们不妨写一个程序验证一下:
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", &arr[0]);
printf("%p\n", arr);
return 0;
}
运行后发现两者结果相同,都是相同的地址。
但是在下面这一串代码中,好像情况有所不同:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr));
return 0;
}
这里输出的结果为数组的长度:40字节
但是arr难道不是数组首元素的地址吗,地址的长度怎么会是40个字节呢?
其实,这就是两个例外中的一个。
例外情况
- sizeof(数组名):sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小
- &数组名:这里的数组名表示整个数组,取出的是整个数组的地址 (整个数组的地址和数组首元素的地址值一样但是类型不同 ,解引用得到的不是首元素而是整个数组)
为了更深入的理解取地址数组名与数组首元素地址的区别,我们看看这段代码:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("&arr[0]+1 = %p\n", &arr[0]+1);
printf("arr = %p\n", arr);
printf("arr+1 = %p\n", arr+1);
printf("&arr = %p\n", &arr);
printf("&arr+1 = %p\n", &arr+1);
return 0;
}
其运行结果如下:
这里我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr 都是
首元素的地址,+1就是跳过一个元素;但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。
使用指针访问数组
知道数组名的含义后,我们其实就可以通过指针来访问数组了
#include <stdio.h>
int main()
{
int arr[10] = {0};
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
//输⼊
for(i = 0; i < len; i++)
scanf("%d", p + i); //@@1
//输出
for(i = 0; i < len; i++)
printf("%d ", *(p + i)); //@@2
return 0;
}
注:上方@@1和@@2两处的p均可替换为arr
所以说arr与p在这里是等价的
那我们能通过arr[i]来访问数组的元素,那是不是也可以通过p[i]来访问呢?
答案是肯定的,如下:
#include <stdio.h>
int main()
{
int arr[10] = {0};
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
//输⼊
for(i = 0; i < len; i++)
scanf("%d", p + i);
//输出
for(i = 0; i < len; i++)
printf("%d ", p[i]); //@@@
return 0;
}
所以p[i]实际上就等价于*(p+i)
那么arr[i]是不是也就等价于*(arr+i)呢?
是这样的。在编译器处理时,arr[i]实际上就是被转换成首元素指针加偏移量,然后解引用来访问的,而知道这些后,我们甚至可以玩一点新花样。
数组访问的特殊写法
我们知道加法操作符左右两边是可换的(两表达式不互相影响时)
所以*(arr+1)其实可以写成*(i+arr)
而*(arr+i)等价于arr[i],那么*(i+arr)是不是也就可以写成i[arr]呢?
答案是,可以!!!
所以arr[i]也可以写成i[arr]!!!
不过我们一般不这么写
一维数组传参的本质
如果我们把一维数组传递给一个函数,本质上传递的是首元素的地址
这也就是为什么数组传参后函数操作会实际的影响到数组本身
因为传递的是地址,解引用后实际操作的是原参数(实参)的内存空间
而只知道首元素地址是不能确定一个数组有多长的,所以我们一般把长度一起传过去
所以接受的类型应该是指针类型:
void Print(int* arr, int len)
{
for (int i = 0; i < len; i++)
printf("%d", arr[i]);
}
但我们之前讲过数组传参可以写成这样:
void Print(int arr[], int len)
{
for (int i = 0; i < len; i++)
printf("%d", arr[i]);
}
实际上这两种写法等价,本质上还是指针(其实是C语言专门设计为可以写成这样便于理解)
这也就解释了为什么参数中arr[]的方括号内不需要数字,而有数字也会被忽略