本文實例講述了C語言泛型編程的方法,分享給大家供大家參考之用。具體分析如下:
首先,泛型編程讓你編寫完全一般化并可重復使用的算法,其效率與針對某特定數據類型而設計的算法相同。在C語言中,可以通過一些手段實現這樣的泛型編程。這里介紹一種方法——通過無類型指針void*
看下面的一個實現交換兩個元素內容的函數swap,以整型int為例:
1
2
3
4
5
6
|
void swap( int * i1, int * i2){ int temp; temp = *i1; *i1 = *i2; *i2 = temp; } |
當你想交換兩個char類型時,你還得重寫一個參數類型為char的函數,是不是能用無類型的指針來作為參數呢?看如下改動:
1
2
3
4
5
|
void swap( void *vp1, void *vp2){ void temp = *vp1; *vp1 = *vp2; *vp2 = temp; } |
但是這段代碼是錯誤的,是通不過編譯的。首先,變量是不能聲明為void無類型的。而你不知道調用此函數傳進的參數是什么類型的,無法確定一種類型的聲明。同時,不能將*用在無類型指針上,因為系統沒有此地址指向對象大小的信息。在編譯階段,編譯器無法得知傳入此函數參數的類型的。這里要想實現泛型的函數,需要在調用的地方傳入相關要交換的對象的地址空間大小size,同時利用在頭文件string.h中定義的memcpy()函數來實現。改動如下:
1
2
3
4
5
6
|
void swap( void *vp1, void *vp2, int size){ char buffer[size]; //注意此處gcc編譯器是允許這樣聲明的 memcpy (buffer,vp1,size); memcpy (vp1,vp2,size); memcpy (vp2,buffer,size); } |
在調用這個函數時,可以像如下這樣調用(同樣適用于其它類型的x、y):
1
2
|
int x = 27,y = 2; swap(&x,&y, sizeof ( int )); |
下面看另一種功能的函數:
1
2
3
4
5
6
|
int lsearch( int key, int array[], int size){ for ( int i = 0;i < size; ++i) if (array[i] == key) return i; return -1; } |
此函數在數組array中查找key元素,找到后返回它的索引,找不到返回-1.如上,也可以實現泛型的函數:
1
2
3
4
5
6
7
8
|
void * lsearch( void * key, void *base, int n, int elemSize){ for ( int i = 0;i < n; ++i){ void *elemAddr = ( char *)base+i*elemSize; if ( memcmp (key, elemAddr, elemSize) == 0) return elemAddr; } return NULL; } |
代碼第三行:將數組的首地址強制轉換為指向char類型的指針,是利用char類型大小為1字節的特性,使elemAddr指向此”泛型“數組的第i-1個元素的首地址。因為之前已經說過,此時你并不知道你傳入的是什么類型的數據,系統無法確定此數組一個元素有多長,跳向下個元素需要多少字節,所以強制轉換為指向char的指針,再加上參數傳入的元素大小信息和累加數i的乘積,即偏移地址,即可得此數組第i-1個元素的首地址。這樣使無論傳入的參數是指向什么類型的指針,都可以得到指向正確元素的指針,實現泛型編程。
函數memcmp()原型:int memcmp(void *dest,const void *src,int n),比較兩段長度為n首地址分別為dest、src的地址空間中的內容。
此函數在數組base中查找key元素,找到則返回它的地址信息,找不到則返回NULL。
如果使用函數指針,則可以實現其行為的泛型:
1
2
3
4
5
6
7
8
|
void *lsearch( void *key, void *base, int n, int elemSize, int (*cmpfn)( void *, void *, int )){ for ( int i = 0;i < n; ++i){ void *elemAddr = ( char *)base+i*elemSize; if (cmpfn(key,elemAddr,elemSize) == 0) return elemAddr; } return NULL; } |
再定義一個要調用的函數:
1
2
3
4
5
|
int intCmp( void * elem1, void * elem2){ int * ip1 = elem1; int * ip2 = elem2; return *ip1-*ip2; } |
看如下調用:
1
2
3
4
5
6
7
8
|
int array[] = {1,2,3,4,5,6}; int size = 6; int number = 3; int *found = lsearch(&number,array,size, sizeof ( int ),intCmp); if (found == NULL) printf ( "NO\n" ); else printf ( "YES\n" ); |
C語言也可以實現一定的泛型編程,但這樣是不安全的,系統對其只有有限的檢查。在編程時一定要多加細心。
相信本文所述對大家C程序設計的學習有一定的借鑒價值。