經典 K&R qsort 簽名
void qsort(void *v[], int left, int right,
int (*comp)(void *, void *));
核心設計:類型抹除與回調
void *v[]:任意指針陣列,元素大小固定為指針寬度(4/8 位元組)
comp:使用者提供具體類型比較邏輯,在回調內完成強制轉型
- 排序演算法本身完全不知曉元素真實類型,僅搬運指針
為何能這樣轉型?
- 任意指針隱式轉換為
void*
void* 可顯式轉換回目標指針類型
- 所有指針在同一平台佔用相同位元組數,指針運算(加減/比較/賦值)不需知道指向類型
- 關鍵限制:qsort 內部絕不解引用
void* 做算術/邏輯運算,僅做指針搬移
實戰:字串指針陣列排序
int str_cmp(void *a, void *b) {
return strcmp(*(char**)a, *(char**)b); // 解引用兩次拿到 char*
}
char *fruits[] = {"banana", "apple", "pear", "orange"};
qsort((void**)fruits, 0, 3, str_cmp);
// 結果:apple, banana, orange, pear
泛型交換輔助函數
void swap(void *v[], int i, int j) {
void *tmp = v[i];
v[i] = v[j];
v[j] = tmp;
}
避坑指南
- 比較函數必須正確處理
const 與多級指針轉型
- 傳遞陣列時需強轉
(void**),否則編譯器警告
- 結構體排序時,比較函數接收
struct T*,轉型為 const struct T*
- 嚴禁在 qsort 內對
void* 做 sizeof、算術運算
現代替代:C11 qsort_s / C++ std::sort
qsort_s 增加上下文指針,避免全域變量傳遞比較參數
- C++ 模板實現零開銷泛型,型別安全,內聯優化更快
- 嵌入式 C 專案仍以經典
qsort 為主流