本文系統梳理《C和指針》第五部分中關於標準函數庫(第14章)與經典抽象數據類型(第15章)的核心知識點,涵蓋算術、隨機數、字符串轉換、浮點運算、日期時間、非本地跳轉、信號處理、可變參數、執行環境、快速排序與二分查找、本地化設置等標準庫函數,並介紹堆疊、佇列、樹等經典 ADT 的實現思路。
<stdlib.h>、<math.h>、<time.h> 等<stdlib.h>abs(int)、labs(long):求絕對值。div(int, int)、ldiv(long, long):執行除法並返回商與餘數的結構體(div_t/ldiv_t)。注意分母為 0 或結果溢出時行為未定義。<stdlib.h>rand():返回 0 ~ RAND_MAX(至少 32767)間的偽隨機數。常配合取模與偏移縮小範圍。srand(unsigned int):設置種子,通常用 time(0)。同種子產生的序列固定;未調用 srand 時默認等同於 srand(1)。<stdlib.h>atoi、atol:按十進制轉換,忽略前導空白與非法尾部字符。strtol、strtoul:支持 2~36 進制(base=0 時自動識別 0/0x 前綴),char** 參數可獲取首個未轉換字符位置。溢出時設置 errno=ERANGE 並返回 LONG_MAX 等極值。<math.h>返回值多為 double。需關注兩類錯誤:
sqrt(-5)),返回編譯器定義錯誤值,errno=EDOM。HUGE_VAL)或過小(返回 0),errno=ERANGE(視編譯器而定)。常用函數:exp、log/log10、pow、sqrt、floor/ceil、fabs、fmod、atof/strtod。
<time.h>clock():返回處理器時鐘嘗次數,除以 CLOCKS_PER_SEC 換算秒數。time():返回自 1970-01-01 00:00:00 UTC 的秒數(time_t 通常為 32 位有符號整數,2038 年會溢出)。ctime/asctime:將 time_t 或 struct tm 轉為固定格式字符串(如 "Fri Apr 08 17:52:04 2011\n\0"),內部常用靜態緩衝區,後續調用會覆蓋。gmtime/localtime:轉換為 UTC / 本地時間的 struct tm(含年、月、日、時、分、秒、星期、儒略日、夏令時標誌)。strftime:按格式化字符串(%Y-%m-%d %H:%M:%S 等)生成自定義時間字符串,安全且可移植。mktime:將 struct tm 轉回 time_t。difftime:計算兩時間差(秒),返回 double。<setjmp.h>setjmp(jmp_buf) 保存堆疊指針與程序計數器,首次返回 0;longjmp(jmp_buf, val) 恢復狀態並使 setjmp 返回 val(非 0)。可實現跨函數的錯誤恢復,類似異常處理但不層層展開棧幀。示例展示了事務處理中遇到致命/輕微錯誤分別跳轉的模式。
<signal.h>標準定義 6 種信號(SIGABRT、SIGFPE、SIGILL、SIGSEGV、SIGINT、SIGTERM)。signal(sig, handler) 設置處理函數,返回舊處理器;SIG_DFL(默認)、SIG_IGN(忽略)、SIG_ERR(出錯)。raise(sig) 可主動觸發信號用於測試。
<stdarg.h>(原文誤標為 signal.h)vprintf/vfprintf/vsprintf 接受 va_list,配合 va_start 使用,無需 va_end。示例展示了封裝可變參數打印函數。
<stdlib.h>、<assert.h>abort():異常終止,引發 SIGABRT。atexit(func):註冊退出處理函數,正常結束時按逆序調用。exit(status):正常終止,調用 atexit 函數、刷新流、關閉文件、刪除臨時文件。assert(expr):斷言失敗時輸出表達式、文件、行號並終止;定義 NDEBUG 或編譯選項 -DNDEBUG 可移除所有斷言。<stdlib.h>getenv(name):獲取環境變量,無則返回 NULL。標準無 putenv,移植性慎用。system(cmd):調用 Shell 命令,system(NULL) 檢測命令處理器是否存在。<stdlib.h>qsort(base, n, size, cmp):通用快速排序,比較函數接受 const void*,需在內部強轉類型。bsearch(key, base, n, size, cmp):二分查找,前提是數組已按相同比較函數排序,否則行為未定義。附帶完整示例:結構體數組按 key 字段排序後查找。
<locale.h>setlocale(category, locale):修改/查詢當前區域設置。category 可為 LC_ALL、LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME。locale="" 依環境變量自動設置;"C" 為最小字符集默認區域。localeconv():返回 struct lconv*,包含小數點、千分位分隔符、貨幣符號、正負號位置等格式化信息,供自定義格式化函數使用。strcoll/strxfrm:按當前 LC_COLLATE 進行字符串比較/轉換,後者將字符串轉換為可直接用 strcmp 比較的形式。抽象數據類型即數據結構,與語言無關。本章重點討論堆疊、佇列、樹等,並對比三種內存分配方式:靜態數組、動態數組(malloc)、鏈式動態分配(靈活但隨機訪問較慢)。
定義宏 STACK_TYPE 便於類型替換。接口包括 push、pop、top、is_empty、is_full。內部實現將所有非接口符號聲明為 static,封裝數據,防止用戶繞過接口直接訪問。