• 刷爆指针笔试题


    第一题

    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. }
    8. //程序的结果是什么?

    先自己思考一下,然后再看解析哦


    【解析】

    &a表示整个数组的地址,+1表示跳过整个数组

    它属于数组指针,需要强转成int*类型的指针才能赋给ptr

    而ptr属于整型指针,-1跳过四个字节,也就是说(ptr-1)指向对应数字5的位置,解引用之后得到数字5

    第二题

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

    先自己思考一下,然后再看解析哦


    【解析】

    p是结构体指针,+1跳过20个字节

    注意用16进制表示,0x100000+0x000014=0x100014

    -------------------------

    p转换成unsigned long类型时正常计算0x100000+0x000001=0x100001

    -------------------------

    int*类型指针+1跳过4个字节,所以计算方式为0x100000+0x000004=0x100004

    第三题

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

    先自己思考一下,然后再看解析哦


    【解析】

    a表示首元素地址,转换成int类型再+1,相当于只是跳过一个字节

    我们看该数组再内存中的存储方式(小端存储)

    低地址                                                         高地址

    01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00

    原先首地址读取的内容 0x1

    低地址                                                         高地址

    01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 移动一个字节后

    变成0x2000000

    所以输出的内容就是0x2000000

    第四题

    1. #include
    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]={1,3,5}

    p表示的是首元素的地址,即第一行的地址,而p[0]表示的是第一行的第一个元素,即1

    第五题

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

    先自己思考一下,然后再看解析哦


    【解析】

    a是二维数组,也可以理解为一个数组指针int(*)[5] 

    p是一个数组指针int(*)[4]

    p = a; //表示将a的首元素地址赋给p

    a+1跳过5个整型,而p+1跳过4个整型

    为了方便理解,我画了个方便理解的图(此类题目非常建议画图)

    注:二维数组在内存中也是连续存放的

    先看%d打印的,两个地址相减表示的是两者之间的元素个数,而小地址—大地址为负数,据图可得结果为-4

    %p是打印地址,而内存中的存储的补码就是地址

    即打印结果为-4的补码0xFFFFFFFC

    第六题

    1. #include
    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. }

    先自己思考一下,然后再看解析哦


    【解析】

    a[]是一个字符指针数组,存放的是三个字符串的首地址信息

    而pa是二级指针,指向的是a[]数组的首元素地址,a[0]的地址

    pa++表示的是pa指向a[]数组的下一个地址,即a[1]的地址

    所以打印*pa即表示打印a[]数组中的第二个元素,即"at"

    第七题

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

    提示:优先级:加号<解引用(间接访问)操作符<自增自减操作符

    先自己思考一下,然后再看解析哦


    【解析】

    根据题目的描述,可以得出初始状态的表示方式:

    第一问:
    先算自增操作符,所以cpp移到下一位,然后按照连线就可以推出两次解引用后得到的是POINTER

    第二问:

    先算自增,(注意此处cpp是在第一问的基础上变化的),得在cp+2的位置上,然后自减得c,最后算+3,得ENTER的后两位:ER

    第三问(思路与前面类似)

    cpp[-2]等价于*(cpp-2),也就是指向cp的位置,存的是c+3的地址,解引用后得FIRST的首地址,最后+3得ST

    第四问:
    注意此时cpp指向的是cp+2,因为上一问并没有改变cpp的内容,cpp[-1]就是指cp+1的位置,而再算后面的[-1]就是指c+2-1=c+1最后算+1,所以得NEW的后两位EW

  • 相关阅读:
    离散数学 --- 谓词逻辑 --- 谓词与量词的引入
    vue项目查看vue版本-- 踩坑
    Infoblox DDI NIOS 8.5.2 -- DDI 核心网络服务管理
    TypeScript详解十三:内置工具类型
    启动新线程处理数据-比较耗时的任务最好要异步的处理,并且要设置合适的线程结束点---SpringCloud工作笔记191
    游戏设计模式专栏(十):在Cocos游戏开发中运用外观模式
    day37 XSS跨站&权限维持&钓鱼捆绑&浏览器漏洞
    刘德华被奥迪第三方策划公司给坑了
    09驾校科目一考试系统——提交分数
    Altium Designer内电层(Plan)GND和POWER出现的死铜如何去除-AD
  • 原文地址:https://blog.csdn.net/m0_73969414/article/details/134020368