• (C语言进阶)笔试题详解


    一.要点回顾

    1.一维整形数组 

    (1)sizeof()对一维整形数组的应用

    1. #include
    2. int main()
    3. {
    4.     int a[] = {1,2,3,4};
    5.     printf("%d\n", sizeof(a));//16
    6. //sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
    7.     printf("%d\n", sizeof(a+0));//  4/8
    8. //a不是单独放在sizeof内部,也没有取地址,所以a就是首元素的地址,故a+0也是首元素的地址
    9. //地址的大小为4/8个字节
    10.     printf("%d\n", sizeof(*a));//4
    11. //*a中的a是数组中首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素
    12. //首元素的大小为4个字节
    13.     printf("%d\n", sizeof(a+1));//  4/8
    14. //这里的a是数组首元素的地址,a+1为第二个元素的地址
    15. //sizeof(a+1)就是地址的大小
    16.     printf("%d\n", sizeof(a[1])); //4
    17. //                sizeof(*(a+1));
    18. //计算的是第二个元素的大小
    19.     printf("%d\n", sizeof(&a)); // 4/8
    20. //&a取出的是整个数组的地址,计算的也是地址
    21.     printf("%d\n", sizeof(*&a));//16
    22. //&a---->int(*)[4]
    23. //&a拿到的是整个数组的地址,解引用后获得整个数组的元素
    24. //故求的是整个数组所占内存的大小
    25.     printf("%d\n", sizeof(&a+1));//  4/8
    26. //&a拿到的是整个数组的地址,+1后跳过一整个数组的大小(16个字节)
    27. //&a+1也是地址,故为4/8个字节
    28.     printf("%d\n", sizeof(&a[0]));//   4/8
    29. //                   sizeof(&*(a+0))
    30. //a[0]是第一个数组元素,取地址后得到的是第一个元素的地址
    31.     printf("%d\n", sizeof(&a[0]+1)); //  4/8
    32. //&a[0]是数组首元素的地址,+1后得到第二个元素的地址
    33.     return 0;
    34. }

    2.一维字符型数组 

    (1) sizeof()对一维字符型数组的应用

    1. #include
    2. int main()
    3. {
    4.     char arr[] = { 'a','b','c','d','e','f'};
    5.     printf("%d\n", sizeof(arr));//6
    6. //sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
    7.     printf("%d\n", sizeof(arr+0));//  4/8
    8. //arr+0是数组首元素的地址
    9.     printf("%d\n", sizeof(*arr));//1
    10. //*arr是数组的首元素,大小为1字节
    11.     printf("%d\n", sizeof(arr[1]));//1
    12. //                  sizeof(*(arr+1))
    13. //为数组的第二个元素
    14.     printf("%d\n", sizeof(&arr));//  4/8
    15. //&arr取出的是整个数组的地址,是地址就是4/8个字节
    16.     printf("%d\n", sizeof(&arr+1)); //  4/8
    17. //&arr+1也是地址,故为4/8个字节
    18.     printf("%d\n", sizeof(&arr[0]+1));// 4/8
    19. //&arr[0]是数组首元素的地址,+1后得到第二个元素的地址
    20.     return 0;
    21. }

    (2)strlen()函数对一维字符型数组的应用 

    1. #include
    2. #include
    3. int main()
    4. {
    5. char arr[] = { 'a','b','c','d','e','f' };
    6. printf("%d\n", strlen(arr));//随机值
    7. //strlen函数从指定地址进入后,需要遇到\0才会停止计数
    8. //字符数组中没有\0,故其会一直向后读取,直到在内存中遇到\0
    9. printf("%d\n", strlen(arr + 0));//随机值
    10. //arr+0表示的是数组的首元素地址
    11. printf("%d\n", strlen(*arr));//错误
    12. //*arr表示的是数组的首元素'a'
    13. //strlen需要的参数为指针类型,报错
    14. printf("%d\n", strlen(arr[1]));//错误
    15. //arr[1]表示数组的首元素
    16. //strlen需要的参数为指针类型,报错
    17. printf("%d\n", strlen(&arr));//随机值
    18. //&arr取出的是整个数组的地址,而整个数组地址的起始点为首元素地址
    19. printf("%d\n", strlen(&arr + 1));//随机值-6
    20. //&arr拿到的是整个数组的地址,+1后跳过一整个数组的大小(6个字节)
    21. printf("%d\n", strlen(&arr[0] + 1));//随机值-1
    22. //&arr[0]是数组首元素的地址,+1后得到第二个元素的地址
    23. return 0;
    24. }

    3.字符串 

    (1)sizeof()对字符串的应用

    1. #include
    2. int main()
    3. {
    4. char arr[] = "abcdef";
    5. //[a b c d e f \0]
    6. printf("%d\n", sizeof(arr)); //7
    7. //arr在sizeof函数中表示全部元素,\0也会计数
    8. printf("%d\n", sizeof(arr+0)); // 4/8
    9. //第一个元素的地址
    10. printf("%d\n", sizeof(*arr)); //1
    11. //第一个元素
    12. printf("%d\n", sizeof(arr[1])); //1
    13. //第二个元素
    14. printf("%d\n", sizeof(&arr)); // 4/8
    15. //整个字符串的地址
    16. printf("%d\n", sizeof(&arr+1));// 4/8
    17. //从首元素地址跳过一整个字符串长度的地址
    18. printf("%d\n", sizeof(&arr[0]+1)); // 4/8
    19. //第二个元素的地址
    20. return 0;
    21. }

    (2)strlen()对字符串的应用

    1. #include
    2. #include
    3. int main()
    4. {
    5. char arr[] = "abcdef";
    6. //[a b c d e f \0]
    7. printf("%d\n", strlen(arr)); //6
    8. //首元素地址
    9. printf("%d\n", strlen(arr+0)); //6
    10. //首元素地址
    11. printf("%d\n", strlen(*arr)); //错误
    12. //strlen需要的参数为指针类型,报错
    13. printf("%d\n", strlen(arr[1])); //错误
    14. //strlen需要的参数为指针类型,报错
    15. printf("%d\n", strlen(&arr)); //6
    16. //首元素地址
    17. printf("%d\n", strlen(&arr+1)); //随机值
    18. //首元素地址跳过一整个字符串长度的地址
    19. printf("%d\n", strlen(&arr[0]+1)); //5
    20. //第二个元素的地址
    21. return 0;
    22. }

    4.字符型指针 

    (1)sizeof()对字符型指针的应用 

    1. #include
    2. int main()
    3. {
    4. char* p = "abcdef";
    5. printf("%d\n", sizeof(p));// 4/8
    6. //p是字符串的首元素地址
    7. printf("%d\n", sizeof(p+1));// 4/8
    8. //第二个元素的地址
    9. printf("%d\n", sizeof(*p));// 1
    10. //字符串首元素
    11. printf("%d\n", sizeof(p[0]));// 1
    12. //字符串首元素
    13. printf("%d\n", sizeof(&p));// 4/8
    14. //指向首元素地址的二级指针
    15. printf("%d\n", sizeof(&p+1));// 4/8
    16. //指向第二个元素地址的二级指针
    17. printf("%d\n", sizeof(&p[0]+1));// 4/8
    18. // sizeof(&(*(p+0))+1)
    19. //第二个元素的地址
    20. return 0;
    21. }

    (2)strlen()对字符型指针的应用

    1. #include
    2. #include
    3. int main()
    4. {
    5. char* p = "abcdef";
    6. printf("%d\n", strlen(p)); //6
    7. //第一个元素的地址
    8. printf("%d\n", strlen(p+1));//5
    9. //第二个元素的地址
    10. printf("%d\n", strlen(*p));//报错
    11. //第一个元素,与strlen所需的参数不同
    12. printf("%d\n", strlen(p[0]));//报错
    13. //第一个元素,与strlen所需的参数不同
    14. printf("%d\n", strlen(&p));//随机值1
    15. //整个字符串的地址
    16. printf("%d\n", strlen(&p+1));//随机值2
    17. //首个元素地址+整个字符串长度的地址
    18. printf("%d\n", strlen(&p[0]+1)); //5
    19. //第二个元素的地址
    20. return 0;
    21. }

    5.二维整形数组

    (1) sizeof()对二维整形数组的应用

    1. #include
    2. int main()
    3. {
    4. int a[3][4] = {0};
    5. printf("%d\n", sizeof(a));//48
    6. //a在sizeof中表示整个数组元素所占的内存大小
    7. printf("%d\n", sizeof(a[0][0]));//4
    8. //第一个元素
    9. printf("%d\n", sizeof(a[0]));//16
    10. //第一行元素
    11. printf("%d\n", sizeof(a[0]+1));// 4/8
    12. //第一行第二个元素的地址
    13. printf("%d\n", sizeof(*(a[0]+1)));//4
    14. //第一行第二个元素
    15. printf("%d\n", sizeof(a+1));// 4/8
    16. //第二行元素的地址
    17. printf("%d\n", sizeof(*(a+1)));//16
    18. //第一行元素
    19. printf("%d\n", sizeof(&a[0]+1));// 4/8
    20. //第二行元素的地址
    21. printf("%d\n", sizeof(*(&a[0]+1)));//16
    22. //第二行元素
    23. printf("%d\n", sizeof(*a));//16
    24. //第一行元素
    25. printf("%d\n", sizeof(a[3]));//16
    26. //第三行元素
    27. return 0;
    28. }

     二.笔试题

     1.第一题

    题目: 

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

    解析:

    答案:2,5

    #include<stdio.h>
    int main()
    {
        int a[5] = {1,2,3,4,5};
        int* ptr = (int*)(&a+1);
        //ptr为首元素地址跳过整个数组
        printf("%d,%d",*(a+1),*(ptr-1));//2,5
        return 0;
    }

    2.第二题 

    题目: 

    1. #include
    2. //已知结构体Test类型的变量大小为20个字节
    3. struct Test
    4. {
    5. int Num;
    6. char* pcName;
    7. short sDate;
    8. char cha[2];
    9. short sBa[4];
    10. }*p=(struct Test*)0x100000;
    11. int main()
    12. {
    13. printf("%p\n",p+0x1); //0x100014
    14. //struct Test类型加一增加20个字节
    15. printf("%p\n", (unsigned long)p + 0x1);//0x100001
    16. //unsigned long类型加一增加1个字节
    17. printf("%p\n", (unsigned int*)p + 0x1);//0x100004
    18. //unsigned int*类型加一增加4个字节
    19. return 0;
    20. }

    解析:

    答案: 0000000000100020 ,0000000000100001  , 0000000000100004

    #include
    //已知结构体Test类型的变量大小为20个字节
    struct Test
    {
        int Num;
        char* pcName;
        short sDate;
        char cha[2];
        short sBa[4];
    }*p=(struct Test*)0x100000;
    int main()
    {
        printf("%p\n",p+0x1);  //0x100014
        //struct Test类型加一增加20个字节
        printf("%p\n", (unsigned long)p + 0x1);//0x100001
        //unsigned long类型加一增加1个字节
        printf("%p\n", (unsigned int*)p + 0x1);//0x100004
        //unsigned int*类型加一增加4个字节
        return 0;
    }

    3.第三题 

    题目: 

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

    解析:

    答案:4,20000

     #include
    int main()
    {
        int a[4] = {1,2,3,4};
        int* ptr1 = (int*)(&a + 1);
        //ptr1为数组首元素地址跳过一整个数组的地址
        int* ptr2 = (int*)((int)a + 1);
        //(int)a+1增加一个字节,(int*)((int)a + 1)为首元素地址向后一个字节
    //00 00 00 01 | 00 00 00 02 | 00 00 00 03 | 00 00 00 04——数组中元素地址
    //01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00——在内存中存储(小端存储)
    //  |                                                  |
    // ptr2                                               ptr1
        printf("%x,%x",ptr1[-1],*ptr2);
    //以十六进制输出时,ptr1[-1]为后退四个字节,然后读取四个字节输出——00 00 00 04
    //*ptr2为读取四个字节然后输出——02 00 00 00
        return 0;
    }

    4.第四题 

    题目: 

    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. }

     解析:

    答案:1

    #include
    int main()
    {
        int a[3][2] = {(0,1),(2,3),(4,5)};//逗号表达式,读取的值为后面的数
        int* p;
        p = a[0];
        //p为第一行的元素 
        printf("%d",p[0]);
        //p[0]是第一行的第一个元素
        return 0;
    }

     

     5.第五题

    题目: 

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

     解析:

    答案: -4,FFFFFFFC

    #include
    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]);
    //&p[4][2]-&a[4][2]=(-4)
    //10000000 00000000 00000000 00000100——(-4)原码
    //11111111 11111111 11111111 11111011——反码
    //11111111 11111111 11111111 11111100——补码
    //FF FF FF FC——十六进制
    //按地址输出时把补码当做地址输出
        return 0;
    }

    6.第六题 

     题目:

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

    解析:

    答案: 10,5

    #include
    int main()
    {
        int aa[2][5] = {1,2,3,4,5,6,7,8,9,10};
        int* ptr1 = (int*)(&aa+1);
        //ptr1为首元素地址跳过整个数组后的地址
        int* ptr2 = (int*)(*(aa + 1));
        //          (int*)aa[1]
        printf("%d,%d",*(ptr1-1),*(ptr2-1)); //10,5
        //*(ptr1-1)—>*(a[2]-1)—>a[1][4]
        //*(ptr2-1))—>*(aa[1]-1)—>aa[0][4]
        return 0;
    }

    7.第七题 

    题目: 

    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. }

    解析:

    答案:at 

    #include
    int main()
    {
        char* a[] = {"work","at","alibaba"};
        char** pa = a;
        //pa为字符串首元素("work")的地址
        pa++;
        //++后pa指向"at"
        printf("%s\n",*pa);
        return 0;
    }

    8.第八题 

    题目: 

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

    解析:

    答案: POINT,ER,ST,EW

    #include
    int main()
    {
        char* c[] = {"ENTER","NEW","POINT","FIRST"};
        char** cp[] = {c+3,c+2,c+1,c};
        char*** cpp = cp;
        //cpp为c+3的地址


        printf("%s\n", **++cpp);//POINT
        //++cpp—>c+2的地址
        // **++cpp—>"POINT"的首元素地址

        printf("%s\n", *--*++cpp+3);//ER
        //cpp为c+2的地址
        //++cpp—>c+1的地址
        //--*++cpp—>c+1-1—>c
        //*--*++cpp—>"ENTER"的首元素地址
        //*--*++cpp+3—>"ENTER"第四个元素的地址

        printf("%s\n", *cpp[-2]+3);//ST
        //cpp为c+1的地址
        //cpp[-2]—>*(cpp-2)—>元素c+3—>"FIRST"的地址
        //*cpp[-2]+3—>*(cpp[-2]+3)—>"FIRST"的第四个元素的地址

        printf("%s\n", cpp[-1][-1]+1);//EW
        //cpp为c+1的地址
        //cpp[-1]—>*(cpp-1)—>元素c+2—>"POINT"的地址
        //cpp[-1][-1]—>*(cpp[-1]-1)—>"NEW"的地址
        //cpp[-1][-1]+1—>"NEW"第二个元素的地址
        return 0;
    }

  • 相关阅读:
    【数据结构与算法 | 基础篇】环形数组模拟队列
    Java List
    什么是Node.js的流(stream)?它们有什么作用?
    【20221206】【每日一题】01背包的基础
    UE4 局域网联机案例
    《算法导论》学习(十五)----二叉搜索树(C语言)
    C/C++知识总结
    抖音系|巨量算数接口signature分析及解密
    VBox启动失败、Genymotion启动失败、Vagrant迁移
    周末和技术大咖们聚餐,聊到了软件测试行业的“金九银十”高峰【内卷之势已然形成】
  • 原文地址:https://blog.csdn.net/2301_79580018/article/details/133823836