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 章


課程速記#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。