每個?`sds.h/sdshdr`?結構表示一個 SDS 值:
~~~
struct sdshdr {
// 記錄 buf 數組中已使用字節的數量
// 等于 SDS 所保存字符串的長度
int len;
// 記錄 buf 數組中未使用字節的數量
int free;
// 字節數組,用于保存字符串
char buf[];
};
~~~
圖 2-1 展示了一個 SDS 示例:
* `free`?屬性的值為?`0`?, 表示這個 SDS 沒有分配任何未使用空間。
* `len`?屬性的值為?`5`?, 表示這個 SDS 保存了一個五字節長的字符串。
* `buf`?屬性是一個?`char`?類型的數組, 數組的前五個字節分別保存了?`'R'`?、?`'e'`?、?`'d'`?、?`'i'`?、?`'s'`?五個字符, 而最后一個字節則保存了空字符?`'\0'`?。

SDS 遵循 C 字符串以空字符結尾的慣例, 保存空字符的?`1`?字節空間不計算在 SDS 的?`len`?屬性里面, 并且為空字符分配額外的?`1`?字節空間, 以及添加空字符到字符串末尾等操作都是由 SDS 函數自動完成的, 所以這個空字符對于 SDS 的使用者來說是完全透明的。
遵循空字符結尾這一慣例的好處是, SDS 可以直接重用一部分 C 字符串函數庫里面的函數。
舉個例子, 如果我們有一個指向圖 2-1 所示 SDS 的指針?`s`?, 那么我們可以直接使用?`stdio.h/printf`?函數, 通過執行以下語句:
~~~
printf("%s", s->buf);
~~~
來打印出 SDS 保存的字符串值?`"Redis"`?, 而無須為 SDS 編寫專門的打印函數。
圖 2-2 展示了另一個 SDS 示例:
* 這個 SDS 和之前展示的 SDS 一樣, 都保存了字符串值?`"Redis"`?。
* 這個 SDS 和之前展示的 SDS 的區別在于, 這個 SDS 為?`buf`?數組分配了五字節未使用空間, 所以它的?`free`?屬性的值為?`5`?(圖中使用五個空格來表示五字節的未使用空間)。

接下來的一節將詳細地說明未使用空間在 SDS 中的作用。
- 介紹
- 前言
- 致謝
- 簡介
- 第一部分:數據結構與對象
- 簡單動態字符串
- SDS 的定義
- SDS 與 C 字符串的區別
- SDS API
- 重點回顧
- 參考資料
- 鏈表
- 鏈表和鏈表節點的實現
- 鏈表和鏈表節點的 API
- 重點回顧
- 字典
- 字典的實現
- 哈希算法
- 解決鍵沖突
- rehash
- 漸進式 rehash
- 字典 API
- 重點回顧
- 跳躍表
- 跳躍表的實現
- 跳躍表 API
- 重點回顧
- 整數集合
- 整數集合的實現
- 升級
- 升級的好處
- 降級
- 整數集合 API
- 重點回顧
- 壓縮列表
- 壓縮列表的構成
- 壓縮列表節點的構成
- 連鎖更新
- 壓縮列表 API
- 重點回顧
- 對象
- 對象的類型與編碼
- 字符串對象
- 列表對象
- 哈希對象
- 集合對象
- 有序集合對象
- 類型檢查與命令多態
- 內存回收
- 對象共享
- 對象的空轉時長
- 重點回顧
- 第二部分:單機數據庫的實現
- 數據庫
- 數據庫鍵空間
- 重點回顧
- RDB 持久化
- RDB 文件結構
- 重點回顧
- AOF 持久化
- AOF 持久化的實現
- 重點回顧
- 事件
- 文件事件
- 重點回顧
- 參考資料
- 客戶端
- 客戶端屬性
- 重點回顧
- 服務器
- 命令請求的執行過程
- 重點回顧
- 第三部分:多機數據庫的實現
- 復制
- 舊版復制功能的實現
- 重點回顧
- Sentinel
- 啟動并初始化 Sentinel
- 重點回顧
- 參考資料
- 集群
- 節點
- 重點回顧
- 第四部分:獨立功能的實現
- 發布與訂閱
- 頻道的訂閱與退訂
- 重點回顧
- 參考資料
- 事務
- 事務的實現
- 重點回顧
- Lua 腳本
- 創建并修改 Lua 環境
- 重點回顧
- 排序
- SORT <key> 命令的實現
- 重點回顧
- 二進制位數組
- GETBIT 命令的實現
- 重點回顧
- 慢查詢日志
- 慢查詢記錄的保存
- 慢查詢日志的閱覽和刪除
- 添加新日志
- 重點回顧
- 監視器
- 成為監視器
- 向監視器發送命令信息
- 重點回顧
- 源碼、相關資源和勘誤