题一、
//结构体的大小是20个字节
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
这里第一个输出结果为0x100014因为程序认为其为一个结构体,结构体加1就是跳过这个结构体因此大小加20而16进制的20为14
第二个输出结果为0x100001,将其转化成整型变量加一得到的结果即为加1后的结果
第三个输出结果为0x100004,将其转化成整型指针加一,既编译器认为其指向一个整型变量,加一后就是加四个字节
题二、
#include <stdio.h>
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);
int* ptr2 = (int*)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2); //
return 0;
}
我们知道整型占的字节为4个,所以对于第一个&a+1等于跳过了这个数组,对于第二个相当于取整型(int)a+1相当于跳过了一个字节因此输出分别为
4 ; 02000000
题三、
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
题目三要注意的是,int(*p)[4]赋值给了a第一行前四个地址给了p,为一个数组,我们知道数组加1的时候为跳过当前数组有的元素个数,因此p[4]可以写成*(p+4)既跳过了16个元素,p[4][2]可以写成*(*(p+4)+2)取跳到的第四个数组的第三个元素具体可以看图
题四、
#include <stdio.h>
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *-- * ++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}
我们可以画图来解这道题目,首先我们看到指针指向的地点如下图所示
对于第一行打印的代码printf("%s\n", **++cpp);我们知道cpp地址加了1,所以指向变成了如下所示
对其进行解引用就可以得到"POINT"这个字符串
对于第二个打印的代码printf("%s\n", *--*++cpp+3);我们先对cpp进行加1,让其指向cp[2]然后进行解引用,在对其地址进行减1,所以cp[2]本来只想的是c[1]现在变成了c[0]如下所示
在对其解引用既"ENTER“的字符串,然后字符串+3得到了起始位置为E的地址,打印出来就是ER
现在指针指向位置就如上图所示了,对于第三个打印代码printf("%s\n", *cpp[-2]+3);我们先对CPP起始地址-2得到cp[0]的指针变量,在对其解引用指向C[3]再加三既FIRST中S的起始地址,打印即为ST
对于第四个打印的代码printf("%s\n", cpp[-1][-1]+1);此串代码相当于(*(cpp-1)-1)既cpp先减1对应cp[1]的位置,在对其解引用的到c[2]的位置然后对其地址+1就是E的起始地址打印出来EW。
让我们看看程序最终的运行结果如何
跟我们推理的一样