
前言:一個普通的插入排序.
//// 插入排序默認從大到小//externvoidsort_insert_int(inta[],int len) {
int i, j;
for(i =1; i < len; ++i) {
intkey = a[j = i];
// 從小到大while(j >0&& a[j -1] < key) {
a[j] = a[j -1];
--j;
}
a[j] = key;
}
}
這時候有人就想了, 那陣列是 double 的, 那怎么弄了. 也有一種解決方案
#definesort_insert(a, len) \ _Generic(a
, int* : sort_insert_int
, double* : sort_insert_double
, default: sort_insert_default) (a, len)
是不是有所啟發. 當然了. 對于上面是使用從大到小封裝. 那如果需要從小到大呢. 可以這么做
staticinlineint_compare_2(constintleft,constint key) {
returnleft - key;
} externvoidsort_insert_2(inta[],int len,
intcompare(constintleft,constint key)) {
int i, j;
for(i =1; i < len; ++i) {
intkey = a[j = i];
while(j >0&& compare(a[j -1], key) <0) {
a[j] = a[j -1];
--j;
}
a[j] = key;
}
}
單獨把比較的行為抽象出來, 注冊進去. 是不是很開心.
細致一點封裝
也許到這里會更開心. 既然能通過高科技泛型模擬出來. 那我們不也可以使用舊科技弄弄.
typedefint(* compare_f)(constvoid* left,constvoid* key);staticinlineint_compare_3(constvoid* left,constvoid* key) {
return*(int*)left - *(int*)key;
}externvoidsort_insert_3_(void* data, size_t ez,int len, compare_f compare) {
char* a = data;
void* key;
int i, j;
if((key =malloc(ez)) == NULL)
return;
for(i =1; i < len; ++i) {
memcpy(key, &a[i * ez], ez);
for(j = i; j >0&& compare(&a[(j -1) * ez], key) <0; --j)
memcpy(&a[j * ez], &a[(j -1) * ez], ez);
if(j != i)
memcpy(&a[j * ez], key, ez);
}
free(key);
}#definesort_insert_3(a, len, compare) \ sort_insert_3_(a, sizeof(*(a)), len, (compare_f)compare)
是不是很巧妙, 一切都編程 void * 了. 當然了如果使用 C99 版本以上, 或者說用高版本的 GCC.
可以寫的更好.
externvoidsort_insert_4_(void* data, size_t ez,int len, compare_f compare) {
char* a = data;
char key[ez];
int i, j;
for(i =1; i < len; ++i) {
memcpy(key, &a[i * ez], ez);
for(j = i; j >0&& compare(&a[(j -1) * ez], key) <0; --j)
memcpy(&a[j * ez], &a[(j -1) * ez], ez);
if(j != i)
memcpy(&a[j * ez], key, ez);
}
}
這里用了 C99 的 VLA 特性. 不知道細心的同學是否和思考. GCC 是怎么實作 VLA 可變長陣列呢.
撥開云霧見青天, 我們不妨來個實驗驗證一哈. 看下面測驗代碼
#include #include /* * file : vla.c
* make : gcc -g -Wall -O2 -o vla.exe vla.c
*
*/intmain(intargc,char* argv[]) {
chara[10];
intb =7;
char c[b];
int* d =malloc(sizeof(int));
if(d == NULL)
exit(EXIT_FAILURE);
*d =1000;
chare[*d];
printf("%p : char a[10]\n", a);
printf("%p : int b\n", &b);
printf("%p : char c[b]\n", c);
printf("%p : int * d\n", d);
printf("%p : char e[*d]\n", e);
free(d);
return EXIT_SUCCESS;
}
最終輸出結果是
通過地址匹配對于 vla 可變陣列, GCC是放在堆疊上的. 所有可以預測, 當可變陣列大小太大. 函式堆疊會直接崩潰.
如果你有想法, 那么就去實作它, 多數簡單我們還是能獨立捉出來滴~~
通用套路
還有一種套路, 采用宏模板去實作, 簡單提一下這個思路. 看下面代碼
#ifdefined(__T)#define__f(type) sort_insert_##type#define__F(type) __f(type)staticvoid__F(__T) (__T a[],intlen,intcompare(const__T left,const __T key)) {
int i, j;
for(i =1; i < (int)len; ++i) {
__T key = a[j = i];
while(j >0&& compare(a[j -1], key) <0) {
a[j] = a[j -1];
--j;
}
a[j] = key;
}
}#endif
一般而言上面模板函式都會封裝在一個區域檔案中使用的時候也很方便, 例如下面這樣
// 定義部分, 宣告和定義分離可以自己搞#undef__T#define__T int#include "sort_insert.c"// 使用部分和普通函式無異sort_insert_int(a, LEN(a), _compare_2);
當然除了上面一種基于檔案的函式模板. 還用一種純基于函式宏的函式模板實作.
#definesort_insert_definition(T) \staticvoidsort_insert_##T (T a[],intlen,intcompare(constT left,const T key)) { \
int i, j; \
for(i =1; i < len; ++i) { \
T key = a[j = i]; \
while(j >0&& compare(a[j -1], key) <0) { \
a[j] = a[j -1]; \
--j; \
} \
a[j] = key; \
} \
}
sort_insert_definition(int)
使用還是一樣 sort_insert_int(a, LEN(a), _compare_2); 跑起來. 第一種函式模板, 在嵌入式用的多
第二種在實戰中用的多, 對于處理各種演算法相關的代碼很普遍. 到這里應該可以理解上面那些
C 封裝中一個小函式存在的套路

另外如果你想更好的提升你的編程能力,學好C語言C++編程!彎道超車,快人一步!筆者這里或許可以幫到你~
分享(原始碼、專案實戰視頻、專案筆記,基礎入門教程)
歡迎轉行和學習編程的伙伴,利用更多的資料學習成長比自己琢磨更快哦!
編程學習:

編程學習:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/270574.html
標籤:C
