第一题
cpp
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
先自己思考一下,然后再看解析哦
【解析】
&a表示整个数组的地址,+1表示跳过整个数组
它属于数组指针 ,需要强转成int*类型的指针才能赋给ptr
而ptr属于整型指针 ,-1跳过四个字节,也就是说(ptr-1)指向对应数字5的位置,解引用之后得到数字5
第二题
cpp
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;
}
先自己思考一下,然后再看解析哦
【解析】
p是结构体指针,+1跳过20个字节
注意用16进制表示****,0x100000+0x000014=0x100014
p转换成unsigned long类型时正常计算0x100000+0x000001=0x100001
int*类型指针+1跳过4个字节,所以计算方式为0x100000+0x000004=0x100004
第三题
cpp
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr = (int *)((int)a + 1);
printf( "%x", *ptr);
return 0;
}
先自己思考一下,然后再看解析哦
【解析】
a表示首元素地址,转换成int类型再+1,相当于只是跳过一个字节
我们看该数组再内存中的存储方式(小端存储)
低地址 高地址
++01 00 00 00++ 02 00 00 00 03 00 00 00 04 00 00 00
原先首地址读取的内容 0x1
低地址 高地址
01 ++00 00 00 02++ 00 00 00 03 00 00 00 04 00 00 00 移动一个字节后
变成0x2000000
所以输出的内容就是0x2000000
第四题
cpp
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf("%d", p[0]);
return 0;
}
先自己思考一下,然后再看解析哦(此题很坑!)
【解析】
括号仅仅表示的是优先运算,而不是表示数组每行的分隔(花括号才表示二维数组中的分行),所以此数组可以简化为a[3][2]={1,3,5}
p表示的是首元素的地址,即第一行的地址 ,而p[0]表示的是第一行的第一个元素,即1
第五题
cpp
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;
}
先自己思考一下,然后再看解析哦
【解析】
a是二维数组,也可以理解为一个数组指针int(*)[5]
p是一个数组指针int(*)[4]
p = a; //表示将a的首元素地址赋给p
a+1跳过5个整型,而p+1跳过4个整型
为了方便理解,我画了个方便理解的图(此类题目非常建议画图)
注:二维数组在内存中也是连续存放的
先看%d打印的,两个地址相减表示的是两者之间的元素个数,而小地址---大地址为负数,据图可得结果为-4
%p是打印地址,而内存中的存储的补码就是地址
即打印结果为-4的补码0xFFFFFFFC
第六题
cpp
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
先自己思考一下,然后再看解析哦
【解析】
a[]是一个字符指针数组,存放的是三个字符串的首地址信息
而pa是二级指针,指向的是a[]数组的首元素地址,a[0]的地址
pa++表示的是pa指向a[]数组的下一个地址,即a[1]的地址
所以打印*pa即表示打印a[]数组中的第二个元素,即"at"
第七题
cpp
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;
}
**提示:**优先级:加号<解引用(间接访问)操作符<自增自减操作符
先自己思考一下,然后再看解析哦
【解析】
根据题目的描述,可以得出初始状态的表示方式:
第一问:
先算自增操作符,所以cpp移到下一位,然后按照连线就可以推出两次解引用后得到的是POINTER
第二问:
先算自增 ,(注意此处cpp是在第一问的基础上变化的),得在cp+2的位置上,然后自减 得c,最后算+3,得ENTER的后两位:ER
第三问(思路与前面类似)
cpp[-2]等价于*(cpp-2),也就是指向cp的位置 ,存的是c+3的地址 ,解引用后得FIRST的首地址,最后+3得ST
第四问:
注意此时cpp指向的是cp+2,因为上一问并没有改变cpp的内容,cpp[-1]就是指cp+1的位置,而再算后面的[-1]就是指c+2-1=c+1 ,最后算+1,所以得NEW的后两位EW