目录
笔试题1:
笔试题2:
笔试题3:
笔试题4:
笔试题5:
笔试题6:
笔试题7:
笔试题8:
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
运行结果:
解析:
1.a是数组首元素的地址,+1得到第二个元素的地址,对其解引用得到的就是2;
2.&a取出整个数组的地址,+1跳过整个数组,对跳过的整个数组-1,得到的就是数组最后一位元素的地址,对其解引用的结果就是5
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
运行结果:
解析:
1.已知结构体变量的大小是20个字节,因为p是结构体指针类型,所以+1就是跳过20个字节,又因为十进制的20 等价于16进制的14,所以打印出来的结果为00100014
2.这里将其强制类型转换成unsigned long,表示整数,整数+1就是+1,所以打印出来的结果为00100001
3.这里将其强制类型转换成unsigned int*,表示整型指针,+1就是向后跳过4个字节,所以打印出来的结果为00100004
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;
}
运行结果:
解析:
1.&a取出的是整个数组的地址,+1就跳过整个数组,ptr1[-1] == *(ptr1-1),得到的就是下标为3的元素4
2.这里的a为数组名,即数组首元素的地址,强制类型转换为整型,+1就是加上数值1,即1个字节,ptr2就指向了第一个元素第二个字节处,对其解引用操作,访问4个字节的位置,因为数组在内存中是连续存储的,且是小端存储,即02 00 00 00,所以将其以%x的形式打印就为2000000
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
运行结果:
解析:
做这道题的时候我们一定要擦亮眼睛,注意这个二维数组初始化的时候里边写的是逗号表达式,而不是{ }。逗号表达式的运算法则是从左向右计算,最后一个表达式的结果为整个逗号表达式的结果,所以数组初始化的元素为{1,3,5},其余的元素均为0。a[0] == a[0][0],a[0]是第一行的数组名,数组名是数组首元素的地址,即元素1的地址,把它存放在指针变量p当中去,p[0] == *(p+0) == *p,即对p进行解引用操作,打印出来就为1。
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;
}
运行结果:
解析:
1.a为数组首元素的地址,即第一行的地址,它的类型是int (*) [5],p的类型是int (*) [4],虽然它们的类型不同,但并不影响将a的地址放在p里边去。
2.观察上图,我们可以看见&p[4][2]和&a[4][2]在内存中所指向的位置,这两者都是指针,指针减去指针得到的是中间元素的个数,因为随着数组下标的增长地址是由低到高变化的,所以%d打印的结果就为-4。%p打印的是地址,认为内存中存储的补码就是地址,所以结果为FFFFFFFC
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
运行结果:
解析:
1. &aa取出的是整个二维数组的地址,&aa+1跳过一个二维数组的大小,强制类型转换成int*类型,ptr1此时也指向了这个位置,所以*(ptr-1)打印的结果就为10
2.aa是数组名,表示数组首元素的地址,即第一行的地址,+1跳过一个int [5]的大小,指向第二行,对其进行解引用操作,此时,ptr2指向了6,*(ptr2-1)打印的结果就为5
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
运行结果:
解析:
这里给出了一个名为a的指针数组,每个数组的类型是char*类型,实际存放的并不是"work","at","alibaba",而是字符串首元素的地址,第一个char*指向了'w'的地址,第二个char*指向了'a'的地址,第三个char*指向了'a'的地址;数组名a是数组首元素的地址,char*的地址为char**类型,存放到pa这个二级指针中,pa++就跳过了一个char*的类型,*pa就拿到了数组第二个元素,即'a'的地址,%s打印就为at
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;
}
运行结果:
解析:
1.**++cpp,程序首先会执行++cpp操作,cpp会跳过一个char**的类型,此时就指向了c+2,对其解引用操作,我们拿到了c+2的这块空间里面的数据,即c+2,而c+2又是c数组下标为2的元素空间的地址,对其进行解引用操作,就拿到了c数组下标为2的空间,这块空间存放了‘P’的地址,%s就会根据P的地址向后打印字符串,打印的结果就是POINT
2. *-- * ++cpp + 3,按优先级来算,先从++cpp开始计算,此时的cpp不再指向c+2,而是指向了c+1,然后进行解引用操作,就拿到了c+1这块空间里面的数据,在进行--操作,相当于c+1减去1,那么这块空间的数据就是c了,在对其进行解引用操作,它就指向了c数组的第一个元素,即'E'的地址,最后+3,此时指针指向第二个'E',%s就会根据此时的地址向后打印字符串,结果就是ER
3. *cpp[-2] + 3 ,cpp[-2]可以看作是*(cpp - 2),即 **(cpp - 2)+ 3 ,cpp - 2指向了cp数组的第一个元素的空间,解引用操作,拿到了c+3这块空间,这块空间指向了c数组的下标为3的元素空间,解引用操作,拿到了这块空间,即'F'的地址,最后+3,指针指向了'S',%s就会根据此时的地址向后打印字符串,结果打印就是ST
4. cpp[-1][-1] + 1,cpp[-1][-1] 可以看作是*(*(cpp - 1) - 1) ,即 *(*(cpp - 1) - 1)+1,cpp - 1指向了cp数组的第二个元素的空间,解引用操作,拿到了c+2这块空间, - 1即c+2减去1,那么这块空间的数据就是c+1了,此时指向了c数组的第二个元素,解引用操作,拿到了这块空间的元素, 即'N'的地址,最后+1,指针指向了'E',%s就会根据此时的地址向后打印字符串,结果就是EW