指针-->笔试题(必备)

前言:

目录

前言:

        本章介绍的指针笔试题是有点难度的,得花费一点时间来理解,并且我们在做题目的时候需要画图来理解。

文章目录

        笔试题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'的地址。

        本章完,感谢观看希望对你有所收获!

猜你喜欢

转载自blog.csdn.net/2201_75964502/article/details/131619130