Bo2SS

Bo2SS

6 复杂结构与指针

课程内容#

结构体#

  • 关键字:struct
    • 声明结构体变量时,需要加上 struct,而不能只用结构体名字
      • struct person Yu;
  • 赋值、访问:
    1. '.' 直接引用 —— '.' 前面是结构体变量
    2. '->' 间接引用 ——'->' 前面是指向结构体变量的指针
    • 举例:a. 自己回家、b. 告诉朋友自己家地址,来我家
  • 声明结构体变量时的占用空间
    • 定义结构体不占用空间
    • 各变量的累加之和
    • 但要考虑对齐原则
      • ① 成员所占字节数的最大值的整数倍
      • ② 成员相对于结构体起始地址的偏移能够被其自身大小整除
        • 如果不能,则在前一个成员后面补充字节
        • 见下面示例:
        • image-20210201001235880
        • img
        • 变量 a、b、c 并不能在一起,b 的偏移需要是 4 的倍数,所以 b 的偏移为 4,c 的偏移为 8 了
      • 参考结构体对齐详解——cnblogs
      • 省空间做法:将同一类型的变量放在一起定义
    • 可以使用预定义的宏强行更改对齐的字节数
  • 匿名结构体:struct {...;} var;
    • 只在初始化的时候使用一次
    • var 就是声明的结构体变量了。定义结构体同时声明变量

共用体(联合体)#

  • 关键字:union

    • 共用一片空间
    • 空间大小按共用体内占用内存最大的字段来划分
  • unsigned char 的意义

    • 图片
    • 首先我们通常意义上理解,byte 没有什么符号位之说,更重要的是如果将 byte 的值赋给 int,long 等(而不是)数据类型时,系统会做一些额外的工作

    • 如果是char,那么系统认为最高位是符号位,而 int 可能是 16 或者 32 位,那么会对最高位进行扩展,赋给 unsigned int 也一样

    • 而如果是 unsigned char,那么不会扩展

  • 内存占用结构图

  • 图片

⭐指针与地址#

  • 学会对数据的本源去操作

  • 取地址符:&

    • 取的是首地址:第 0 个字节的地址
  • 每一个字节都会对应一个地址标号

  • 64 位 / 32 位:地址的寻址范围

    • 32 位最多匹配 4GB 的内存条
      • 2^30 Byte = 1 GB 👉 32 位最多支持 4 GB
  • 指针变量

    • 用来存储地址,地址一般表现为 16 进制
    • 不管指针什么类型(int、char),它们的地位一样,都是存储地址
      • 占用空间大小:64 位 - 8 字节;32 位 - 4 字节(64 位代表地址的位数是 64)
      • int *p 可以传给 char *q 吗?完全可以,都是占用 8 个字节(64 位)
      • 区分类型的意义见下:等价形式转换
    • int *p;
      • 定义的时候 * 用来表示 p 是指针变量
      • 定义完后,p 代表指针,*p 的 * 代表取值操作
    • 指针变量也是变量!
      • 可以用指针 Q 存储指针 p 的地址
  • scanf 函数说明

    • 要修改变量的值,所以必须用地址传值
      • 传地址的参数,可以叫传出参数,因为操作也会在函数外体现
    • 函数的值传递,其操作只在作用域里生效
  • 等价形式转换

    • 图片
  1. 取值操作
  2. +1 的 1 的偏移量取决于p 表示的类型的字节数(区分类型的意义)
  3. 前提:指针 p 指向结构体变量 a

函数指针#

  • 变量:为了避免歧义,函数变量声明应该是这样

    • 图片
    • 将 * add(add 为函数名)括起来
  • 类型:typedef 可以将变量提升为类型

    • 图片
    • 可以用类型定义变量
  • typedef 的两种用法

    • 内建类型、结构体类型的重命名
      • typedef long long lint;
      • typedef char * pcahr; // char * → pchar
      • 有点像 #define,但还是有微妙的区别,详见代码演示
      • typedef struct __node { int x,y;} Node, *PNode;
        • 同时定义了两个别名
        • PNode p; // 可以定义 Node 结构体类型的指针变量
    • 提升为类型
      • typedef int (*func)(int);
        • 可以定义无数多个函数指针变量
  • main 函数参数

    • 图片
    • 带参数的话,传参数的是谁呢?操作系统

    • return 0; // 返回给系统

    • "echo $?" 可以用来判断系统上次命令运行是否成功

      • 0:成功
      • 非 0:不成功
    • 参数解读

      • argc:参数个数
      • argv:对应二维数组,接收的是 argc 个字符串,一维数组接收的是一行字符串
        • *arr [] 对应 arr [][]
      • env:环境变量
        • env 是指向 char * 的指针
          • env 是一个地址,指向一个字符数组的地址
          • env 这个地址还能往后走,所以实际对应一个二维字符数组
        • ❓**env 与 * env [] 的定义方式有什么不同?在这里是没区别的!
      • ❓❗不能用 int ** 表示二维数组

问:泽哥,我定义一个 char str [10][10] 的二维数组,不能用 char** 接收。而 main 函数的 **env 可以接收字符串数组,我该怎么理解,字符串数组不算二维数组?
答:后者是通过 malloc 出来的,是动态数组

随堂练习#

一:结构体字节对齐#

  • 图片
  • 定义顺序不一样

  • 左:8 字节;右:12 字节

二:共用体内存图#

  • 图片

👇

  • 图片

三:ip 转整数#

  • 图片
  • 192.168.1.2

    • 每一段,最高 255,即可以用 1 字节来表示,对应 unsigned char
    • 总共就是 4 字节,对应 int 类型
  • 代码

  • 图片 * union中struct必须声明变量 * 可以不用sscanf?如果不用,则不方便读取xxx.xxx.xxx.xxx中每一段的值 * 大端、小端机 * 小→数字低位→低地址 * 大→数字低位→高地址
ip(192.168.0.1)按每段顺序存储在小端机
int 数字字节地址编号0123
ip 存储10168192
      • 一般的电脑都是小端机
      • 判断是否是小端机:定义 int 类型 num = 1,判断其最高位的值
        • int 类型地址强转为 char 类型地址,则可以取第 0 号字节地址上的值
        • 直接读数字会按照本机字节序从高 / 低位开始读是吗?是的
      • 本端、对端字节序不匹配怎么办
        • 过程:本机字节序→网络字节序(统一标准)→对端字节序
        • 只有读取的时候,才必须区分字节序,其他情况都不用考虑
          • 如果没有细化到字节,应该是体会不到字节序的
        • 参考理解字节序- 阮一峰
    • 输出
  • 图片

附加:用尽可能多的形式表示 a [1].x#

  • 图片

【至少有 30 种,利用前面提到的等价形式、套娃!】

  • 图片
  • 代码

  • 图片

亮点笔记#

代码演示#

代码#

演示结构偏移量计算、宏定义类型和 typedef 区别、主函数参数详解#

  • 图片
  • 图片
  • 字符串要以 '\0' 结尾,才方便结束读取的判断(num 的低位为 0 即可)

  • 地址对应的是 long int 类型(64 位 - 8 字节,32 位 - 4 字节)

  • 被注释掉的 offset () 宏定义有什么不足?

    • 还需要定义变量,会占用空间
    • 所以可以借用空地址(0 或 NULL)强转
  • 定义类型别名时,宏定义只是简单替换,没有 tpydef 省心

  • main 函数输入参数

    • 根据空格划分,可以用双引号整合多个字符串
  • 程序输出

  • 图片

附加知识点#

  • 在 C++ 的面向对象中,结构体是一个 class
  • 引用效率比指针高,指针多了一个传递
  • 如何根据一个已知的内存地址,读取值
    • 将地址传给一个指针,再用取值符 *
  • 语法糖
    • 指计算机语言中添加的某种语法,对语言的功能没有影响,但是更方便程序员使用
    • 让程序更加简洁,有更高的可读性

思考点#

Tips#

  • 重点在于指针与地址的应用关系

  • 记笔记,很重要

    • typora 记录
  • 简历

    • 可以用ShareLaTeX
    • 计算机方向的简历:黑白,注意缩进,感觉踏实
  • 参考工具书第 9、10 章


课程速记#

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。