1.
#include<stdio.h>
void main(void)
{
int a[5]={1,2,3,4,5};
int *p=(int *)(&a+1);
printf("%d,%d\n",*(a+1),*(p-1));
}
上述代码输出的结果是2,5。原因是在于&a是整个数组的地址,类型是int (*)[5],而a是代表的数组中第一个元素的地址&a[0],其类型是int *,因此,在(int*)(&a+1)代表的是将整个数组地址右移,此时假设a整个数组的地址是0x1000,那么(&a+1)代表的就是整个数组的地址再右移动一个同样的&a类型的字节大小,也就是a数组有5各元素,一个元素占用4各字节,所以a共占用20个字节,那么(&a+1)的地址就是0x0000+20=0x1014;但是它前边还有一个强制转换,转换成了int类型,然后再去p-1,这个时候p就减去4个字节,变成了0x1010,并且此时由于强制转换,对0x01000的解释有所不同,此时这个地址代表的是数组首元素的地址,如下图所示:
地址 值
0x1000 1
0x1004 2
0x1008 3
0x100C 4
0x1010 5
因此*(p-1)指向的就是a数组的最后一个元素5,因此会输出5。
2.
#include<stdio.h>
void func(int b[][3])
{
++b;
b[1][2]+=2;
}
void main(void)
{
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
func(a);
printf("%d\n",a[2][2]);
}上述代码输出的值是10,这是因为b是一个二维数组,二维数组就是一个一维数组里边的每个元素由多个元素组成,比如b[x][y],实际上是一个一维数组,里边的元素为b[0]...b[x-1],然后b[0]里边又有y个元素,相当于此时b[0]就是数组名,里边有b[0][0]...b[0][y]。然后先进行++b,这代表着先加一,后使用,因此就相当于b=b+1;而数组名又代表着地址,因此这里实际上相当于&b[0]=&b[0]+1=&b[1],因此,就相当于把b数组的行首地址赋值b[1]的行首地址,那么此时b[0][0]=4而不再是等于1,因此,b[1][2]=9+2=11;也就是a[2][2]=11;
3.
#include <stdio.h>
int main() {
int a = 10, b = 20, c,d;
d=a,b;//没有加括号,只将a的值赋给d
c = (a, b); // 使用逗号操作符连接a和b
printf("c = %d,d=%d\n", c,d); // 输出c的值
return 0;
}上述代码需要注意的是c=(a,b);这是一个逗号操作符,逗号操作符的用法是计算并返回其右侧表达式的值,而不管左侧表达式的值。因此输出c=20;但是d=a=10,要注意看有没有括号。
4.
#include<stdio.h>
void main(void)
{
int i,j;
i=sizeof(char);
j=++i + i++;
printf("%d %d\n",i,j);
}该代码输出i=3,j=4(可能还存在争议);解析如下:首先sizeof是输出一个类型所占的内存,以字节为单位,所以得到i的初始值为1,然后++操作符优先级高于算数运算符,那么先算自增运算符之后,再去进行加法运算,然后++i代表的是先加1后使用,i++代表的是先使用,后加一。
5.
#include <stdio.h>
void fun(int a, int *b, int **c)
{
int *p = &a; // p 指向 a 的地址(此处是局部变量 a)
*p = 5; // 改变局部变量 a 的值为 5
*c = b; // c(即主函数中 q 的地址)被赋值为 b 的地址
**c = 6; // 改变 b 所指向的值为 6
}
int main()
{
int x = 1, y = 2, z = 3; // 定义变量
int *q = &z; // q 指向 z 的地址
fun(x, &y, &q); // 调用 fun 函数
printf("%d,%d,%d,%d\n", x, y, z, *q); // 输出 x, y, z, *q
return 0;
}上述代码输出结果为1,6,3,6;对于为什么x输出值为1,即x的值未发生改变,这是因为c语言中函数参数的传递默认为按值传递,而不是按引用传递。实际上是将x的值复制了一份传递给函数参数a,但是现在a和x是两个独立的变量,不等价于a=x;因为并没有将x这个变量复制给a,只是将其值给了a。因此x并没有发生改变,如果想要改变x,应该调用fun(&x,…),改成引用传递。