椋鸟C语言笔记#19:数组名、指针访问数组、一维数组传参的本质

萌新的学习笔记,写错了恳请斧正。


目录

数组名的理解

例外情况

使用指针访问数组

数组访问的特殊写法

一维数组传参的本质


数组名的理解

数组名其实就是数组首元素的地址,只有两个例外(马上讲)

我们不妨写一个程序验证一下:

#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个字节呢?

其实,这就是两个例外中的一个。

例外情况
  1. sizeof(数组名):sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小
  2. &数组名:这里的数组名表示整个数组,取出的是整个数组的地址 (整个数组的地址和数组首元素的地址值一样但是类型不同 ,解引用得到的不是首元素而是整个数组)

为了更深入的理解取地址数组名与数组首元素地址的区别,我们看看这段代码:

#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[]的方括号内不需要数字,而有数字也会被忽略


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

椋鸟Starling

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

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

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

打赏作者

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

抵扣说明:

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

余额充值