C语言实现泛型编程
泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。在C语言中,可以通过一些手段实现这样的泛型编程。这里介绍一种方法——通过无类型指针void*
看下面的一个实现交换两个元素内容的函数swap,以整型int为例:
void swap(int* i1,int* i2){
int temp;
temp = *i1;
*i1 = *i2;
*i2 = temp;
}
当你想交换两个char类型时,你还得重写一个参数类型为char的函数,是不是能用无类型的指针来作为参数呢?看如下改动:
void swap(void *vp1,void *vp2){
void temp = *vp1;
*vp1 = *vp2;
*vp2 = temp;
}
这段代码是错误的,是通不过编译的。首先,变量是不能声明为void无类型的。而你不知道调用此函数传进的参数是什么类型的,无法确定一种类型的声明。同时,不能将*用在无类型指针上,因为系统没有此地址指向对象大小的信息。在编译阶段,编译器无法得知传入此函数参数的类型的。这里要想实现泛型的函数,需要在调用的地方传入相关要交换的对象的地址空间大小size,同时利用在头文件string.h中定义的memcpy()函数来实现。改动如下:
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):
int x = ,y = ;
swap(&x,&y,sizeof(int));
下面看另一种功能的函数:
int lsearch(int key,int array[],int size){
for(int i = ;i < size; ++i)
if(array[i] == key)
return i;
return -;
}
此函数在数组array中查找key元素,找到后返回它的索引,找不到返回-1.如上,也可以实现泛型的函数:
void* lsearch(void* key, void *base, int n, int elemSize){
for(int i = ;i < n; ++i){
void *elemAddr = (char *)base+i*elemSize;
if(memcmp(key, elemAddr, elemSize) == )
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。
如果使用函数指针,则可以实现其行为的泛型:
void *lsearch(void *key,void *base,int n,int elemSize,int(*cmpfn)(void*,void*,int)){
for(int i = ;i < n; ++i){
void *elemAddr = (char *)base+i*elemSize;
if(cmpfn(key,elemAddr,elemSize) == )
return elemAddr;
}
return NULL;
}
再定义一个要调用的函数:
int intCmp(void* elem1,void* elem2){
int* ip1 = elem1;
int* ip2 = elem2;
return *ip1-*ip2;
}
看如下调用:
int array[] = {,,,,,};
int size = ;
int number = ;
int *found = lsearch(&number,array,size,sizeof(int),intCmp);
if(found == NULL)
printf("NO\n");
else
printf("YES\n");
C语言也可以实现一定的泛型编程,但这样是不安全的,系统对其只有有限的检查。在编程时一定要多加细心。
C语言实现泛型编程的更多相关文章
- C语言的泛型编程
1 问题引入 首先引入一个问题,实现一个泛型的swap函数,分别使用C++和C实现. 2 C++的泛型 C++有良好的泛型编程机制,所以我很快就写出了C++版的泛型swap函数. template&l ...
- 部分博文目录索引(C语言+算法)
今天将本博客的部分文章建立一个索引,方便大家进行阅读,当然每一类别中的文章都会持续的添加和更新(PS:博文主要使用C语言) 博客地址:http://www.cnblogs.com/archimedes ...
- C语言中void*详解及应用
void在英文中作为名词的解释为“空虚:空间:空隙”:而在C语言中,void被翻译为“无类型”,相应的void *为“无类型指针”.void似乎只有“注释”和限制程序的作用,当然,这里的“注释”不是为 ...
- 《类型编程晋级——shapeless类库使用指南》前言及第一章翻译
从年初开始进行此项工作,我和合作伙伴包亮付出了大量而艰辛的劳动,现基本翻译完毕,有出版意向,如果有意向欢迎联系,不甚感激!也欢迎各位博友对此翻译提出意见建议以及指导如何出版,在此谢过! 前言 时间回到 ...
- c/c++面试准备笔记1
在c++程序中调用被C编译器编译后的函数,为什么要加extern "C"? C++语言支持函数重载,C语言不支持函数重载.函数被C++编译后在库中的名字与C语言的不同.C++提供 ...
- c/c++相关面试准备笔记1
在c++程序中调用被C编译器编译后的函数,为什么要加extern “C”? C++语言支持函数重载,C语言不支持函数重载.函数被C++编译后在库中的名字与C语言的不同.C++提供了C连接交换指定符号 ...
- C语言泛型编程--抽象数据类型
一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...
- C语言泛型编程——泛型冒泡排序
在实际编程中,常常会需要一些方法(函数),比如排序,它们具体实现基本一致,仅仅只有参数类型不同, 那么可不可以有一种通用的函数,不管是什么类型的参数都可以通用呢? 泛型编程:泛型即是指具有在多种数据类 ...
- C++ STL泛型编程——在ACM中的运用
学习过C++的朋友们应该对STL和泛型编程这两个名词不会陌生.两者之间的关系不言而喻,泛型编程的思想促使了STL的诞生,而STL则很好地体现了泛型编程这种思想.这次想简单说一下STL在ACM中的一些应 ...
随机推荐
- PHP的反射机制
在面向对象中最经典的使用就是反射,之前在Java语言中,使用反射可以解耦,用于依赖注入. 在PHP中,同样也有如此强大的地方,我们利用反射来获取一个对象的实例. 首先我们先写一个类: class Te ...
- JAVA - IDEA快捷键(精简版)
快捷键 功能 Ctrl + Alt + V 对应eclipse ctrl + l + 2 自动补全 Ctrl + Alt + L 对应eclipse ctrl + shift + o 代码格式化 Ct ...
- Android 获取可靠的手机编码
项目中出现了将设备和用户信息进行绑定的需求.最先想到的是IMEI串码和IMSI串码.手机登陆的时候一直都没有问题.换了一个平板中之后IMEI和IMSI串码都获取不到了.后来查了一下原因,是因为平板上是 ...
- C#序列化s实体类成Xml,去除空格、换行符以及命名空间
序列化实体类成为一个干净的Xml,不带空格.换行符以及命名空间 /// <summary> /// 序列化成XML /// </summary> /// <typepar ...
- UWP游戏防内存修改器的方法
最近我一直在编写适用于Windows 10商店的游戏.这款游戏比较怕玩家用修改器改金钱,因为这种修改会导致某些内购失效并且损害公平性.于是我把自己见过的三种反修改器的方法给网友们介绍一下. 首先说明一 ...
- Java的HashSet类
如果要查找一个集合中是否包含了某个对象,那么就需要把这个对象和这个集合中的每个对象依次进行比较和判断,直到找到这个对象为止,或者把所有对象都比较一次为止(如果最后一个对象才是要查找的对象,或者集合中没 ...
- 【Java每日一题】20161102
package Nov2016; public class Ques1102 implements Parent{ @Override public void method() { } } inter ...
- MAC 卸载 openfire
顺序执行以下命令: sudo rm -rf /Library/PreferencePanes/Openfire.prefPane sudo rm -rf /usr/local/openfire
- 说说IT技术团队招聘那点事
因为近来由于新项目的需要,各种招聘比较多,几乎每周都要面试几个人,顺便对以前的面试和带开发经验进行简单的总结 1.首先负责招聘的人一定得是自己团队的人,而且在招聘的时候一定要想清楚目标候选人进来的职责 ...
- java多线程-同步块
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 ...