• 八道超经典指针面试题(三千字详解)


    目录

    第一题:

    第二题: 

    第三题:

    第四题:

    第五题:

    第六题:

     第七题:

    第八题:


    第一题:

    1. int main()
    2. {
    3. int a[5] = { 1, 2, 3, 4, 5 };
    4. int *ptr = (int *)(&a + 1);
    5. printf( "%d,%d", *(a + 1), *(ptr - 1));
    6. return 0;
    7. }

    预测其输出结果。

    题解思路:指针题是需要画图的,不画图思路是绕不出来的。下图就是a数组的内存布局。

    int * ptr =(int *)(&a + 1);ptr所指如图:

    很多同学可能不太明白:数组名为一个数组的首元素地址,但除两种情况:

    1.&+数组名——————————————这里就表示是整个数组的地址。

    2.sizeof(数组名)——————————   这里表示的是整个数组所占的字节数。

    回到题目,(&a+1)中的1的意思就是步距为一个数组,在首元素地址的基础上加上了一整个数组的字节。

    接下来看看printf()中的a+1、ptr-1:

    那么答案一目了然:分别是第二个元素——2,与覅五个元素——5. 

    第二题: 

    1. struct Test
    2. {
    3. int Num;
    4. char *pcName;
    5. short sDate;
    6. char cha[2];
    7. short sBa[4];
    8. }*p;
    9. //假设p 的值为0x100000。 如下表表达式的值分别为多少?
    10. //已知,结构体Test类型的变量大小是20个字节
    11. int main()
    12. {
    13. printf("%p\n", p + 0x1);
    14. printf("%p\n", (unsigned long)p + 0x1);
    15. printf("%p\n", (unsigned int*)p + 0x1);
    16. return 0;
    17. }

    思路与题解:

    0x开头的是十六进制数。

    在第一个printf()中p+0x1,一个Test结构体占20个字节,且p是struct Test *p类型,p每次加上一个1都要移动对应的20字节(详情请见初级指针的指针与指针类型).又因为是十六进制,20=0x14,所以p+0x1=0x100014.

    在第二个printf()中(unsigned long)p+0x1,在这里p先由指针变量被强制类型转换为无符号long类型,因此p+0x1就是普通的整数相加,得到0x100001。然后%p在将p的数据以地址的形式打印出来了。

    在第三个printf()中,p被再次转换成指针,但这次是以无符号整型的形式。unsigned int *就限定了每次指针访问的空间为四个字节。所以p+1的结果为0x100004

    第三题:

    1. int main()
    2. {
    3. int a[4] = { 1, 2, 3, 4 };
    4. int *ptr1 = (int *)(&a + 1);
    5. int *ptr2 = (int *)((int)a + 1);
    6. printf( "%x,%x", ptr1[-1], *ptr2);
    7. return 0;
    8. }

    与题一同理:

    ptr1:由int * ptr1=(int *)(&a+1);画出下图:

    ptr1[-1]其实就相当于*(ptr1-1)。因为其实‘[]’与’*‘的功能是一样的。(详情见七千字详解操作符

     ptr2:

    但是我们仔细看一下 int *ptr2 = (int *)((int)a + 1);中数组名a被强制转换为int类型的了。所以a+1只能向前移动一个字节。为了更好的观察我把这部分的图化成这个形式。(因为vs编译器是小端存储,左移这里的数据是01000000而不是00000001)

    (int)a+1往后移动了一个字节如下图 :

     这就是ptr2所指向的数据。

     综上所述,答案为:0x02 00 00 00,00 00 00 04.

    第四题:

    1. #include <stdio.h>
    2. int main()
    3. {
    4. int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    5. int *p;
    6. p = a[0];
    7. printf( "%d", p[0]);
    8. return 0;
    9. }

    思路与答案:

    这里其实用到了逗号表达式(详情见七千字详解操作符)与二级数组。

    其实在a[3][2]中的数据为:

    a指向

    p=a[0]指向

     所以答案是1.

    第五题:

    1. int main()
    2. {
    3. int a[5][5];
    4. int(*p)[4];
    5. p = a;
    6. printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    7. return 0;
    8. }

    思路与答案:

     这个就是a[5][5]的布局,其中的数字代表帝即位元素。

    a[5][5]:

    先分析a[4][2],a[4][2]也等效于*(*(a+4)+2),你看哪种便于理解。如下图:

     p[4][2]:

    由int (*p)[4]得出:p为int [4]类型的指针,那么p就指向一个有四个元素的数组。由此可得p+1一次会移动四个元素:

     &p[4][2] - &a[4][2]的值为相差的元素个数,因此&p[4][2] - &a[4][2]=-4

    但是这里还需要我们谈一下:

    &p[4][2] - &a[4][2]得出的整数结果是-4,-4在内存中存储的是一个二进制的补码,原理如下

    因此我们内存中的-16是这样的

    原码:1000 0000 0000 0100

    反码:1111 1111 1111 1011

    补码:1111 1111 1111 1100

    因为%p是无符号数,所以 %p直接提取内存中的补码:0xfffffffc

    因为%d是输出有符号整数,所以要将补码重新转成原码才输出:-4. 

    第六题:

    1. int main()
    2. {
    3. int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    4. int *ptr1 = (int *)(&aa + 1);
    5. int *ptr2 = (int *)(*(aa + 1));
    6. printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    7. return 0;
    8. }

    思路与题解:

    aa数组的内存步距如下: 

    aa指向第一行的地址: 

     

    &aa去除的是整个数组的地址,所以&aa+1如下图:

     aa+1则会指向第二行的数据:

     

     

    所以:

     答案呼之欲出:10,5

     第七题:

    这是一道阿里巴巴的笔试题:

    1. #include <stdio.h>
    2. int main()
    3. {
    4. char *a[] = {"work","at","alibaba"};
    5. char**pa = a;
    6. pa++;
    7. printf("%s\n", *pa);
    8. return 0;
    9. }

     思路与题解:

     

    pa++如下图:

     

    因此答案为:“at” 

    第八题:

    1. int main()
    2. {
    3. char *c[] = {"ENTER","NEW","POINT","FIRST"};
    4. char**cp[] = {c+3,c+2,c+1,c};
    5. char***cpp = cp;
    6. printf("%s\n", **++cpp);
    7. printf("%s\n", *--*++cpp+3);
    8. printf("%s\n", *cpp[-2]+3);
    9. printf("%s\n", cpp[-1][-1]+1);
    10. return 0;
    11. }

    思路与题解:

    指针间的关系图如下:

    **++cpp就等效于*(*(cpp+1)) 得到如图:

    顺着指针得出:POINT 

    *--*++cpp+3等效于*(*(cpp+1)+1)+3,我们从内到外分析,

    由cpp+1得到如图:

     又*(cpp+1)+1得到:

     

    *(*(cpp+1)+1)解出来是c[0]的地址,*(*(cpp+1)+1)+3就是这样的。

     

     因此*(*(cpp+1)+1)+3打印出来就是ER。

    *cpp[-2]+3: 

    *cpp[-2]+3相当于:**(cpp-2)+3得到下图:

     由此可见答案为:ST

     

     

  • 相关阅读:
    工作7年收集到的git命令
    万字详解JVM,让你一文吃透
    洛谷_P3388
    9. 吴恩达机器学习-推荐系统
    关于go和rust语言的对比
    无锁队列原理及实现(三)
    zabbix 配置 nginx 监控
    vscode中使用指定路径下的cmake
    Java(五):Java 基础语法
    代码随想录算法刷题训练营day24:LeetCode(77)组合
  • 原文地址:https://blog.csdn.net/qq_64484137/article/details/125605822