今天在翻阅头条时,无意看到这样一篇微头条,说是作者的同事在工作中遇到一个BUG,两人一起研究了大半天,非但没有解决问题,反而一起陷入了郁闷,甚至三观尽毁!
他没有说具体过程,在简化了问题后,是这样一个代码(我增加了一条打印地址的代码):
#include <stdio.h>
int main (int argc,char*argv[])
{
int a[5]={0,1,2,3,4};
int b=3;
printf("%d,%d",a[b],b[a]};
printf("%d,%d\n",&a[b],&b[a]);
return 0;
}
这个程序看上去蛮简单的,我的第一反应是该程序应该会报错,因为按照实例内容,b[a]这种表述方式看上去是在实在离谱,然而当我手动测试了一遍后,也大吃一惊。
没有报错,甚至连一个warning也没有,程序正常运行:
于是我怀疑是不是因为编译器的原因,又在VS 2017上尝试了一遍,结果依旧正常。
不甘心的我觉得可能是系统内核有关,便再次从虚拟机上的ubantu上gcc编译,果不其然,还是可以运行的通。
我估计不少朋友此刻的内心都是和我一样:开什么玩笑!这语法正确?这程序居然没有报错?这程序居然能正常运行?
两者不仅结果一样,连物理地址也是相同的。
在凌乱一番后,我开始研究起了这个程序。终于在翻阅了《C陷阱与缺陷中》,找到了一段关于数组指针的描述。书中说在C语言中,数组和下标是可以互相转换的,即对任何两个表达式a和b,只要其中一个是指针表达式而另一个是整数时,则a[b]和*((a)+b))的结果一致。
看完之后我表示更不明白了,因为从我个人来讲,确实理解不了将b作为数组索引有什么意义,也是头一次听到这种说法。由于书中没有过多提及,我又跑到GNU C library寻找相关资料,果然找到一段官方的解释,原文如下:
A postfix expression followed by an expression in [ ] (brackets) specifies an element of an array. The expression within the brackets is referred to as a subscript. The first element of an array has the subscript zero. By definition, the expression a[b] is equivalent to the expression *((a) + (b)), and, because addition is associative, it is also equivalent to b[a]. Between expressions a and b, one must be a pointer to a type T, and the other must have integral or enumeration type. The result of an array subscript is an lvalue.
由于我英语也一般,翻译了一下大概是这个意思,前一段是数组的相关定义,不需要解释。关键在于后一段,根据官方表示:根据数组定义,表达式a[b]等价于表达式*((a)+(b)),并且,由于加法是关联的,所以它也等价于b[a]。不过需要满足一个大前提:a式和b式,两者必须满足一个是指向类型T的指针,另一个必须是整形或枚举型。同时还给了一个具体的例子:
#include <stdio.h>
int main(void) {
int a[3] = { 10, 20, 30 };
printf("a[0] = %d\n", a[0]);
printf("a[1] = %d\n", 1[a]);
printf("a[2] = %d\n", *(2 + a));
return 0;
}
输出结果如下:
a[0] = 10
a[1] = 20
a[2] = 30
简单来讲,就是a[b]=*(a+b)=*(b+a)=b[a]。但对于为何这么设定,下面并没有具体说明原因。
对此我只想表示,C语言真神奇!
来源:
https://www.toutiao.com/a6824703081989538312/
“IT大咖说”欢迎广大技术人员投稿,投稿邮箱:aliang@itdks.com
来都来了,走啥走,留个言呗~
IT大咖说 | 关于版权
由“IT大咖说(ID:itdakashuo)”原创的文章,转载时请注明作者、出处及微信公众号。投稿、约稿、转载请加微信:ITDKS10(备注:投稿),茉莉小姐姐会及时与您联系!
感谢您对IT大咖说的热心支持!