• C语言面试必看-指针笔试题详解


    指针你真的学会了吗!来试试下面这八道面试的笔试题吧!

    笔试题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,得到的是整个数组的地址,向后加一之后跳到了数组的末尾,如下图:
    在这里插入图片描述
    将(&a+1)强制类型转换为(int*),(因为(&a+1)的类型是一个数组指针)。
    *(a+1)是首元素+1,指针指向了2,再解引用,打印的就是2
    *(ptr - 1),原本ptr指向的是上图位置,现在减一,指向5的位置,所以打印出来的就是5

    笔试题2

    题目:

    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+0x1,因为题目给出了结构体的大小是20个字节,所以这里指针p加一的时候是向后跳过了20字节的大小,那么0x100000加20就是0x100014(20转换为16进制就是14)。
    (unsigned long)p + 0x1这里把p强制类型转换为unsigned long类型之后,p就是一个无符号长整形的一个数据,加1就是0x100001。
    (unsigned int*)p + 0x1这里将p强制类型转换为unsigned int*的决定了指针p加一向后跳过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;
    }

    解析:
    第一个ptr1和第一题是一样的道理,只不过这里是用ptr1[-1]打印的,ptr1[-1]和*(ptr1 - 1)是一样的道理。
    a是首元素的地址,强制类型转换为一个int类型的数据之后再进行加1,就跳过了一个字节的空间,那么数组首元素1,(int类型的数据是4个字节,在VS中数据采用小端存储)在内存中的存放实际上是01 00 00 00 接着是02 00 00 00…如下图
    在这里插入图片描述
    这里我只画出了1和2在内存中的存储情况,回到题目中的(int)a + 1,将a强制类型转换为int的类型的数据,然后加1跳过一个字节,指向01 后面的第一个00字节,再强制类型转换为(int*)的指针,后面在解引用ptr2的时候就会向后访问4个字节的空间也就是00 00 00 02,那么打印出来的时候就是2000000(打印地址的时候前面的0会省略),所以第一个打印4,第二个打印2000000

    笔试题4

    题目:

    #include
    int main()
    {
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( “%d”, p[0]);
    return 0;
    }

    这道题目的坑是注意二维数组a的初始化,逗号表达式的值是最后一个表达式的值,所以a的初始化是

    int a[3][2] = { 1, 3, 5};

    笔试题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的访问大小是4个字节,而我们a的初始化是5行5列的。
    &p[4][2] 找第5行第3个元素,&a[4][2]找第5行第3个元素
    在这里插入图片描述
    那么指针相减得到的是指针之间的个数,而&p[4][2] 和 &a[4][2]之间差了四元素的大小,所以&p[4][2] - &a[4][2]的值是-4,那么-4要以%p地址的形式打印的话就是fffffffc,因为:
    -4的补码是11111111111111111111111111111100,转换位16进制就是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得到整个二维数组的地址,+1向后跳过整个二维数组的大小,再减一,指向的就是10,所以第一个打印的就是10
    aa是二维数组的数组名,代表的就是第一个数组的地址,+1跳到第二个数组(假设第二个数组名位arr),再解引用得到第二个数组的第一个元素的地址(*&arr就是arr,数组名代表首元素(6)地址),所以ptr2-1之后指向的就是5的位置,打印出来就是5

    笔试题7

    题目:

    #include
    int main()
    {
    char *a[] = {“work”,“at”,“alibaba”};
    char**pa = a;
    pa++;
    printf(“%s\n”, *pa);
    return 0;
    }

    这题还是很简单的,a是一个字符串指针数组,pa是一个二级指针,指向a数组的第一个指针(第一个指针指向第一个字符串的首字符地址),pa++之后指向指向第二个指针(第二个指针指向第二个字符串的首字符地址),所以打印的结果就是第二个字符串" 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;
    }

    要理解这道题目我们要首先知道c cp cpp分别是什么?
    c是一个指针数组,存放了四个字符串
    cp是一个二级指针数组,存放的是四个一级指针
    cpp是一个三级指针,存放的是cp数组的首元素地址

    那么我们来看一下第一个 * *++cpp
    1.前置++cpp指向c+2解引用之后cp数组的第二个元素即c+2(三级指针解引用一次得到的是二级指针的内容), 而c+2是只指向的“POINT”的首字符P的地址,那么再解引用就能找到P,%s就会打印出 POINT

    2.* - - *++cpp+3在这个表达式中,加法的优先级是最低的,所以先进行++cpp,由于上一次cpp已经++过一次了,所以这次再++的时候指向的就是c+1的地址了,解引用之后就得到了c+1,那么c+1再进行- -之后再解引用之后指向的就是 "ENTER"字符串的首字符E的地址(二级指针解引用得到的是一级指针的地址),再加3指向的就是’E‘,所以打印出来就是ER注意这里的(c+1)已经进行了一次- -,所以c+1指向的地址不再是“NEW”而是“ENTER”

    3.*cpp[-2]+3,通过前面cpp的两次++,我们知道cpp已经是指向c+1的了,那么cpp[-2]就是得到了c+3,那么再解引用 得到的就是“FIRST”字符串的首字符地址,再加3指向的就是S,所以打印出来就是ST

    4.cpp[-1][-1]+1,cpp[-1]找到的是c+2,c+2[-1]找到的是"NEW"字符串的首字符地址,再加1的话就是指向E,那么打印出来之后就是EW

    运行结果如下:
    在这里插入图片描述
    希望能帮助你对指针有更深入的了解!

  • 相关阅读:
    Vue2 Vue3对比
    文件的逻辑结构与物理结构的对比与区别
    ubuntu环境下openssl库的简单使用
    能带你起飞的【数据结构】成王第十篇:二叉树3
    【微信小程序】获取/设置屏幕亮度
    day071:网络编程(IP、端口、协议)、InetAddress类、UDP协议、TCP协议
    数据集收集列表(opencv,机器学习,深度学习)持续更新
    记一次排查:接口返回值写入excel后,从单元格copy出来的数据会带有多重引号的问题
    React 编写网页聊天界面(仿钉钉)
    数组19—unshift() :将一个或多个元素添加到数组的开头
  • 原文地址:https://blog.csdn.net/Javaxaiobai/article/details/126782817