[1] 数组和指针的前世今生 - 数组篇

让人混淆的代码

char my_array[10];
char *my_ptr;
...
i = strlen(my_array);
j = strlen(my_ptr);
printf("%s,%s",my_ptr,my_array);
printf("array at location %x holds string %s",my_array,my_array);

声明,定义和函数参数声明

这里写图片描述
* 对编译器而言,数组是一个地址,指针是一个地址的地址

什么时候数组和指针时相同的?

C语言标准有3条规则:
1、表达式中的数组名被编译器当作一个指向该数组第一个元素的指针
2、下标总是和指针的偏移量相同
3、在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针

规则1

表达式中的数组名就是指针

int a[10],*p,i=2
// 1
p=a;
p[i];
// 2
p=a;
*(p+i);
// 3
p=a+i;
*p;
  • 对数组的引用a[i]在编译时被编译器改写为*(a+i)的形式
  • 所以a[6]和6[a]都是正确的
  • 编译器会自动把下标的步长调整到数组存储的类型的大小,这也是为什么每个指针只能指向一种类型,因为编译器需要知道每次+1的偏移量,应该解引用时取多少个字节

规则2

C语言把数组下标作为指针的偏移量
* 从BCPL(C语言的祖先继承而来),因为总可以通过指针访问,所以对下标的范围检查也被认为是没必要的
* 根本原因是指针和偏移量是底层硬件所使用的基本类型
这里写图片描述
这里写图片描述

规则3

作为函数参数的数组名等同于指针

形参:在函数定义和声明中定义
实参:在实际调用的时候传递给函数的值
C语言标准要求“类型的数组”形参的声明应该调整为“类型的指针”,因此在函数形参定义的时候,编译器必须把数组形式改写为指向数组第一个元素的指针形式,编译器只向函数传递数组的地址,而不是整个数组的拷贝,隐式转换的存在意味着下述三个声明是完全等同的

void my_function(int *np);
void my_function(int np[]);
void my_function(int np[200]);

数组和指针可交换性的总结

1、用a[i]这种形式对数组进行访问总是被编译器“改写”或者解释成像“*(a+i)”这种指针访问;
2、指针始终是指针。它绝不可以改写成数组。你可以用下表形式访问指针,一般都是指针作为函数参数的时候,而且你知道实际传递给函数的是一个数组;
3、只有在把它作为函数的参数,数组的声明可以看作一个指针。作为函数参数的数组始终会被编译器修改成指向数组第1个元素的指针;
4、因此,当把一个数组定义为一个函数的参数时,可以选择把它定义为数组,也可以定义为指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针;
5、在其他所有情况下,定义和声明必须匹配。如果定义了一个数组,在其他文件中进行声明时也必须是数组,指针也是如此。

Reference

C专家编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值