zoukankan      html  css  js  c++  java
  • C语言补遗

    前些天公司摸底 C 语言考试,得分比较难看,回来发了考试答案,这篇博客把我做错的题目拿出来理一理,补补课。

    • 判断对错:在定义数据结构时,没有特殊理由的话,都定义成四字节对齐;这样做可能浪费几个字节,但是不会出问题。

      这道题答案是对的,需要仔细 Google。

    • 以下程序运行 (64 位系统) 后的输出结果是 6 5 8 5

      int main()
      {
        char str1[] = "Hello";
        char str2[] = {'H', 'e', 'l', 'l', 'o'};
        char *p = str1;
        printf("%d %d %d %d
      ", sizeof(str1), sizeof(str2), sizeof(p), strlen(p));
      }
      

      这道题我的答案是 6,5,4,5,原因在于 64 位的指针的长度大小是 8 个字节,而不是一般的 4 个字节。 考点为 字符串数组长度 (+1), 64 位指针长度 (8) 字符串数组 x 包含末尾的’’

    • 如下程序, 在 64bit 系统运行输出为 24 4 8 16

      struct s1
      {
          char a;
          int b;
          short c;
          double d;
      };
      int main(void)
      {
          printf("%d %d %d %d
      ",
          sizeof(struct s1), offsetof(struct s1, b), offsetof(struct
          s1, c), offsetof(struct s1, d) ) ;
          //注: offsetof 为计算偏移量的宏
          return 0;
      }
      

      我的答案是 48,8,16,32,错误成了 2 倍。主要为结构体对齐规则, 这部分需要强化 一般考生都可以看到 b 按 4 字节对齐,需要填充 忽视 double 也需要 8 字节对齐 double 在 32 位 linux 平台下可能按照 4 字节对齐

    • 如下指针计算, 结果为 4

      int *p1 = (int *)0x500;
      int *p2 = (int *)0x510;
      printf(“%d
      ”, (p2 - p1));
      

      我错成了 16,答案应该是 16/4,指针的减法,按照指针类型计算跨越的步长

    • 如下程序, 请问输出多少? -128,128

      void main(void)
      {
      char x = 127;
      char a = x + 1;
      int b = x + 1;
      printf("%d %d", a, b);
      }
      

      我的答案是 128,128,整型加法隐式提升到 int 然后运算,所以 x+1 就是 128 溢出出现在赋值运算,第一个溢出了,第二个没有。没有考虑到第一个溢出之后的数据显示问题

    • 如下程序片段, 输出为: 2 7

      int *p;
      int x[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
      p = x[0] + 1;
      printf("%d %d
      ", *p, x[2][0]);
      

      我的答案是 4 7 。x[0] 是对二级指针解引用,类型是指向整型的指针,指向 1,+1 后,指向 x[0][1] 没争议

    • 计算如下定义长度 (64 位系统)

      typedef union {
          int a;
          long b;
          char c[6];
      }un;
      sizeof(un) = 8
      

      我的答案是 48,联合体的内存大小不会算,共用体的占用空间的大小,按照其最大成员算 本题中 long 是 8 字节

    • 请问输出多少

      union packet
      {
          struct packet_bit
          {
              unsigned char a:2;
              unsigned char b:3;
              unsigned char c:4;
          } bit;
          int i;
      } data;
      
      int main()
      {
          data.i = 0;
          data.bit.a = 1;
          data.bit.b = 2;
          data.bit.c = 0xF;
          printf("0x%04x
      ", data.i);
      }
      

      我的答案是 0xf,这道题完全是蒙出来的,考察的是位域的概念,位域结构体,按地址从低到高依次存储 a、b、c 一个规则大家可能都不熟悉: 一个位域必须存储在同一个字节中,不能跨两个字节 所以 a 和 b 储存在一个字节,c 再进来存不下,所以 c 单独存放在一个字节 再就是注意输出格式

    • 如下程序, 请写出打印结果 A b

      void fun(char *a, char *b)
      {
          a = b;
          (*a)++;
      }
      void main()
      {
          char c1 = 'A', c2 = 'a';
          char *p1 = &c1;
          char *p2 = &c2;
          fun(p1, p2);
          printf("%c %c
      ", c1, c2);
      }
      

      我的结果是 a b, 函数入参是按值传递的,只有通过传递地址才能改变函数外部的值,这里有一个陷阱,使用的地址,实际是从参数 b 传进来的,所以改变的也是参数 b 指向的值 。这道题不该错,因为在 fun 函数里,a 的值已经是 b 了,所以 a 指向的就是 b 指向的地址,因此改变的就是 c2 指向的字母啊

    • 下面函数的输出是 token3 = 4

      #define paster( n ) printf( "token" #n " = %d", token##n )
      void fun()
      {
          int token3 = 4;
          int tokenn = 3;
          paster( 3 );
      }
      

      我的答案是 token3 = 3,这是个知识盲点,可以参考 C 语言宏定义 ## 连接符和 #符的使用,# 将本身的字符替换之后再在两边加上双引号,## 是机械单纯得将两个 token 连接在一起

    • 如下程序, 输出为 100008 100001 100004

      struct test
      {
          int a;
          int b;
      };
      int main ()
      {
          struct test *p = (struct test *)0x100000;
          printf("%x %x %x
      ", (p+1), (long)p+1, (int *)p +1);
      }
      

      我的答案是 0x100008,0x100001,0x11。这道题比较有意思,程序第 8 行已经说明了,p 的值就是 0x100000(也就是说 p 指向的地址是 0x100000),后面 (int *)p,说明了它指向的是 int 类型,那么 + 1 就是在原来的地址上一个 int 的字节数,也就是 0x100004。需要总结的是,指针前面的表明的是这个指针指向的数据类型。

  • 相关阅读:
    Laravel 初始化
    ant design pro 左上角 logo 修改
    请求到服务端后是怎么处理的
    Websocket 知识点
    王道数据结构 (7) KMP 算法
    王道数据结构 (6) 简单的模式匹配算法
    王道数据结构 (4) 单链表 删除节点
    王道数据结构 (3) 单链表 插入节点
    王道数据结构 (2) 单链表 尾插法
    王道数据结构 (1) 单链表 头插法
  • 原文地址:https://www.cnblogs.com/bugxch/p/13833559.html
Copyright © 2011-2022 走看看