前言:
目录
前言:
本章介绍的指针笔试题是有点难度的,得花费一点时间来理解,并且我们在做题目的时候需要画图来理解。
文章目录
笔试题1
笔试题2
笔试题3
笔试题4
笔试题5
笔试题6
笔试题7
笔试题8
笔试题1
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),这里的a是数组名,代表的是数组首元素的地址,类型为int*,整形指针加1跳过一个整形,所以a+1代表的是数组中第二个元素的地址,*(a+1)则代表第二个元素,所以就是2.
对于*(ptr-1),首先我们需要知道ptr是一个int*类型的指针,&a代表的是整个数组的地址,类型为int(*)[5],所以&a+1则代表跳过一个数组的大小,但是ptr却是将它强制类型转换为int*类型的指针,所以ptr-1代表指针向后跳过一个整形。
笔试题2
//由于还没学习结构体的计算,这里告知结构体的大小是20个字节
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
公布答案->
那么为什么答案是这个呢,接下来我们先将我们需要的图画出来->
解释:
首先对于0x1的理解,我们将其理解为1就行
p是一个结构体的指针,p+1则代表跳过,一个结构体的大小又因为结构体的大小为20个字节,且地址是以16进制表示的,而20的16进制为14,所p+1的地址为0x100014
unsigned long是无符号整形,(unsigned long)则表示将p强制类型转换为一个无符号整形,又因为整形加1,所以结果为0x100001
unsigned int*是无符号整形指针,先将p强制类型转换为无符号整型指针,+1代表跳过一个无符号整形,所以地址加4,所以结果为0x100004
笔试题3
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;
}
公布答案->
图->
解释:
&a+1,代表的是跳过一个数组后的地址类型为,int(*)[4],但是前面将其强制类型转化为(int*),ptr[-1]--->*(ptr-1),也就是4。
*ptr2:在解释这个之前我们需要知道我的机器是按小段字节序存储的,且数组随着下标的增加,元素的地址也是增加的,小段字节序是低字节的内容在低地址存储,所以才有了上面的图像,先将a转化为整形然后加1,即地址加1,得到的是向后移动一位的数字,然后在转化为地址,即向后移动一个字节的地址,然后再解引用访问4个字节的内容,%x是以16进制打印,为0x02000000.打印时前面不打印0,所以未2000000
总结:这道题考了数组在内存中的地址分布,考了机器的大小端字节序存储,考了*访问的时候字节的个数
笔试题4
#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;
}
公布答案:
图:
解释:
首先我们要注意的是数组内容的初始化是0 1 2 3 4 5? 并不是,而是1,3,5,0,0,0,为啥呢?因为我们要注意,(0,1)这里面的逗号是一个逗号表达式,取右边的结果。
a[0]的理解:因为a是一个二维数组,在内存中我们可以将它看成由3个一维数组组成的,所以a[0]代表的是第一个一维数组的数组名即一维数组的地址,p为整形指针,所以p[0]--->*(p+0)--->&(a[0]+0)--->(a[0][0]),所以为1.
笔试题5
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;
}
答案:
图:
解释:
因为p是一个int(*)[4]类型的指针,p又是指向a的,所以p+4跳过4个数组int[4],随着下标的增加数组的地址也是增加的,且指针减指针为两个指针之间相差元素的个数。
所以差4,但是地址前面小所以答案为-4
%p打印数字的时候是直接将-4的补码看作地址所以为FFFFFFFC
笔试题6
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;
}
答案:
图:
解释:
aa为数组名,数组名就是首元素的地址,也就是第一个一维数组的地址类型为 int(*)[5],aa+1则代表跳过一个一维数组,指向a[1],然后在强制类型转化为,int*的指针,解引用则只访问一个字节的内容.
&aa代表的是取出整个二维数组的地址,类型为int(*)[2][5],+1则代表跳过一个二维数组,然后强制类型转化为整形指针,-1代表指针向前跳过一个整形.
笔试题7:
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
图:
解释:
这个数组a存储了3个常量字符串的地址,a代表首元素的地址,即常量字符串的地址,类型为char** ,+1则代表跳过一个常量字符串,所以指向at,所以答案就是at
笔试题8
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:首先cpp是c+3的地址,+1则代表c+2的地址,*(c+2)得到的是point地址的地址**(c+2)则代表得到的是point的地址,所以打印为point
* -- *++ cpp+3:此时的++cpp代表的是c+1的地址,*(cpp)得到的是c+1,--得到的是c,再解引用得到的是字符串enter首元素的地址,+3的道德是'E'的地址。
*cpp[-2]+3:首先cpp[-2]代表的是*(cpp-2),得到的是(c+3),*(c+3)又得到的是F的地址+3得到的是'S'的地址,所以打印结果为ST
cpp[-1][-1]+1:cpp[-1]代表的是*(cpp-1),也就是c+2,cpp[-1][-1]则代表*(c+2-1),所以得到的是'N'的地址+1,则代表得到的是'E'的地址。
本章完,感谢观看希望对你有所收获!