C語言泛型編程實例教程
本文實例講述了C語言泛型編程的方法,分享給大家供大家參考之用。具體分析如下:
首先,泛型編程讓你編寫完全一般化并可重復(fù)使用的算法,其效率與針對某特定數(shù)據(jù)類型而設(shè)計的算法相同。在C語言中,可以通過一些手段實現(xiàn)這樣的泛型編程。這里介紹一種方法——通過無類型指針void*
看下面的一個實現(xiàn)交換兩個元素內(nèi)容的函數(shù)swap,以整型int為例:
void swap(int* i1,int* i2){
int temp;
temp = *i1;
*i1 = *i2;
*i2 = temp;
}
當(dāng)你想交換兩個char類型時,你還得重寫一個參數(shù)類型為char的函數(shù),是不是能用無類型的指針來作為參數(shù)呢?看如下改動:
void swap(void *vp1,void *vp2){
void temp = *vp1;
*vp1 = *vp2;
*vp2 = temp;
}
但是這段代碼是錯誤的,是通不過編譯的。首先,變量是不能聲明為void無類型的。而你不知道調(diào)用此函數(shù)傳進(jìn)的參數(shù)是什么類型的,無法確定一種類型的聲明。同時,不能將*用在無類型指針上,因為系統(tǒng)沒有此地址指向?qū)ο蟠笮〉男畔ⅰT诰幾g階段,編譯器無法得知傳入此函數(shù)參數(shù)的類型的。這里要想實現(xiàn)泛型的函數(shù),需要在調(diào)用的地方傳入相關(guān)要交換的對象的地址空間大小size,同時利用在頭文件string.h中定義的memcpy()函數(shù)來實現(xiàn)。改動如下:
void swap(void *vp1,void *vp2,int size){
char buffer[size];//注意此處gcc編譯器是允許這樣聲明的
memcpy(buffer,vp1,size);
memcpy(vp1,vp2,size);
memcpy(vp2,buffer,size);
}
在調(diào)用這個函數(shù)時,可以像如下這樣調(diào)用(同樣適用于其它類型的x、y):
int x = 27,y = 2; swap(&x,&y,sizeof(int));
下面看另一種功能的函數(shù):
int lsearch(int key,int array[],int size){
for(int i = 0;i < size; ++i)
if(array[i] == key)
return i;
return -1;
}
此函數(shù)在數(shù)組array中查找key元素,找到后返回它的索引,找不到返回-1.如上,也可以實現(xiàn)泛型的函數(shù):
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;
}
代碼第三行:將數(shù)組的首地址強(qiáng)制轉(zhuǎn)換為指向char類型的指針,是利用char類型大小為1字節(jié)的特性,使elemAddr指向此”泛型“數(shù)組的第i-1個元素的首地址。因為之前已經(jīng)說過,此時你并不知道你傳入的是什么類型的數(shù)據(jù),系統(tǒng)無法確定此數(shù)組一個元素有多長,跳向下個元素需要多少字節(jié),所以強(qiáng)制轉(zhuǎn)換為指向char的指針,再加上參數(shù)傳入的元素大小信息和累加數(shù)i的乘積,即偏移地址,即可得此數(shù)組第i-1個元素的首地址。這樣使無論傳入的參數(shù)是指向什么類型的指針,都可以得到指向正確元素的指針,實現(xiàn)泛型編程。
函數(shù)memcmp()原型:int memcmp(void *dest,const void *src,int n),比較兩段長度為n首地址分別為dest、src的地址空間中的內(nèi)容。
此函數(shù)在數(shù)組base中查找key元素,找到則返回它的地址信息,找不到則返回NULL。
如果使用函數(shù)指針,則可以實現(xiàn)其行為的泛型:
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;
}
再定義一個要調(diào)用的函數(shù):
int intCmp(void* elem1,void* elem2){
int* ip1 = elem1;
int* ip2 = elem2;
return *ip1-*ip2;
}
看如下調(diào)用:
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語言也可以實現(xiàn)一定的泛型編程,但這樣是不安全的,系統(tǒng)對其只有有限的檢查。在編程時一定要多加細(xì)心。
相信本文所述對大家C程序設(shè)計的學(xué)習(xí)有一定的借鑒價值。
相關(guān)文章
如何使用C語言實現(xiàn)細(xì)菌的繁殖與擴(kuò)散
這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)細(xì)菌的繁殖與擴(kuò)散,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
C/C++獲取當(dāng)前時間的方法總結(jié)(最全)
這篇文章主要為大家整理了C/C++中獲取當(dāng)前時間的最全方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)和借鑒價值,需要的可以了解一下2023-03-03
matlab模擬退火算法單約束車間流水線調(diào)度解決實現(xiàn)及示例
這篇文章主要為大家介紹了matlab模擬退火算法求解單約束車間流水線調(diào)度的實現(xiàn)及示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02

