这道题你们可能会让你们有点晕,至少我是的,由于咱们平时都是buf+1这种写法,若是你是第一次接触这种写法的话,其实你们只要把数组考虑成普通变量就好了,给你们举个例子 java
int a = 0; linux
int *p = &a+1; windows
这里的&a你们是否是感受很正常,就是这样,那么如今咱们反过来,&buf就是取数组的地址, 数组
你们都知道&a+1 是表明a的地址加上四个字节,那是由于a是int型的,占四个字节,因此加上4个字节,那么&buf地址再加1就是加上buf变量的大小,buf是10个char元素数组,因此&buf + 1就至关于buf的地址加上10*1(char型的大小) 数据结构
上面 只是帮助你理解,若是纯粹从代码的角度来讲, 函数
&buf的地址类型为 char (*p)[10] 至关于行指针的类型 ,那么p+1就至关于p的地址加上10*1个字节。 3d
int a=3,b;
b=++a+(++a)+(++a);
printf("%d",b); 指针
这道题在windows下与linux下的结果不一样,可是我我的支持linux下gcc编译的结果16,windows下为18,编译器的不一样,解释就不一样, blog
下面解析一下linux下为何为16?get
不知道你们数据结构课的时候有没有写过表达式计算,其中有一种实现就是用两个栈来表示,一个栈用来表示运算符,另外一个表示操做数。b = ++a + (++a) + (++a)
首先++入栈 以下图(编译器是从左往右一个个字符读取的 因此a先入栈)
而后a入栈
这时候会继续日后面读取 发现是一个+号,由于加号优先级比++小,因此先执行++a
这时候会把++弹出栈,a弹出栈,再把++a的结果压栈,+号压栈,
这里必定要注意是把++a的结果虽然是4可是因为++a返回的是引用,因此压栈放的是a这个变量,而不是4
而后继续执行后面的(++a),这里是同样的,我就不详解释,当把第一个(这里的第一个值得是第一个带括号的++a)(++a)运算完毕以后,会继续读取后面的+号,这时候发现栈里面已经有了一个加号,优先级同样,按照c语言运算符+号的运算方向,从左往右,因此先运算栈里面的加号此时栈里面的状况以下图:
这时候执行了两次++a,a的值已经变为5了,因此这时候两个a相加等于10,这时候运算结束以后,将10压入栈,(注意这里压栈的就是10不像以前压栈的是a这个变量)
结束以后栈以下
后面再次执行++a 一样先计算++a,再将a的值压入栈中,在执行加法:
a的值变为6了 因此最后结果为16.
下面这幅图是windows下的结果,编译器的不一样。
上面这个题目须要咱们用到汇编语言栈帧的问题,在汇编中若是咱们调用另外一个函数,会使用call命令,call所作的事情第一个将下一条命令的地址压栈,而后jmp到调用函数的地址,这里还会设置,esp与ebp的知识,我在这知识提一下,由于栈帧的知识不是一两句能说清楚的,函数的第一句都会
push ebp;这句是为了保护调用函数的栈帧,
ebp地址上面是局部变量,
因此(int*)(*(&p+1));获得就是保护的上一个函数的ebp栈帧。
p-=1;获得就是a的地址
*p = 520;这样就能够改变a的内容了。
可是这个能不能运行成功跟gcc版本有关系。gcc4.8能运行而且能修改。
java中实例代码初始化块{}与直接在声明的时候初始化的优先级?
答案是同样,那个在前面那个就先执行
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
下面的能编译吗?gcc的版本不同形成不一样结果,gcc5.几版本 编译不经过
这里涉及前加加与后加加哪一个返回引用的问题,以及贪心词法(C语言缺陷与陷阱)
我记录一下个人见解,a++返回临时变量 这时候不能再对这个临时变量进行后加加,由于它不是左值
int a = 1;
int b = 2;
int c = a+++++b;