泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。在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语言实现泛型编程的更多相关文章

  1. C语言的泛型编程

    1 问题引入 首先引入一个问题,实现一个泛型的swap函数,分别使用C++和C实现. 2 C++的泛型 C++有良好的泛型编程机制,所以我很快就写出了C++版的泛型swap函数. template&l ...

  2. 部分博文目录索引(C语言+算法)

    今天将本博客的部分文章建立一个索引,方便大家进行阅读,当然每一类别中的文章都会持续的添加和更新(PS:博文主要使用C语言) 博客地址:http://www.cnblogs.com/archimedes ...

  3. C语言中void*详解及应用

    void在英文中作为名词的解释为“空虚:空间:空隙”:而在C语言中,void被翻译为“无类型”,相应的void *为“无类型指针”.void似乎只有“注释”和限制程序的作用,当然,这里的“注释”不是为 ...

  4. 《类型编程晋级——shapeless类库使用指南》前言及第一章翻译

    从年初开始进行此项工作,我和合作伙伴包亮付出了大量而艰辛的劳动,现基本翻译完毕,有出版意向,如果有意向欢迎联系,不甚感激!也欢迎各位博友对此翻译提出意见建议以及指导如何出版,在此谢过! 前言 时间回到 ...

  5. c/c++面试准备笔记1

    在c++程序中调用被C编译器编译后的函数,为什么要加extern  "C"? C++语言支持函数重载,C语言不支持函数重载.函数被C++编译后在库中的名字与C语言的不同.C++提供 ...

  6. c/c++相关面试准备笔记1

    在c++程序中调用被C编译器编译后的函数,为什么要加extern  “C”? C++语言支持函数重载,C语言不支持函数重载.函数被C++编译后在库中的名字与C语言的不同.C++提供了C连接交换指定符号 ...

  7. C语言泛型编程--抽象数据类型

    一.数据类型: 在任何编程语言中,数据类型作为一个整体,ANSI-C包含的类型为:int.double.char……,程序员很少满意语言本身提供的数据类型,一个简单的办法就是构造类似:array.st ...

  8. C语言泛型编程——泛型冒泡排序

    在实际编程中,常常会需要一些方法(函数),比如排序,它们具体实现基本一致,仅仅只有参数类型不同, 那么可不可以有一种通用的函数,不管是什么类型的参数都可以通用呢? 泛型编程:泛型即是指具有在多种数据类 ...

  9. C++ STL泛型编程——在ACM中的运用

    学习过C++的朋友们应该对STL和泛型编程这两个名词不会陌生.两者之间的关系不言而喻,泛型编程的思想促使了STL的诞生,而STL则很好地体现了泛型编程这种思想.这次想简单说一下STL在ACM中的一些应 ...

随机推荐

  1. SQL Server代理(10/12):使用代理账号运行作业

    SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. 在这一系列的上一篇,你查看了msdb库下用 ...

  2. 【视频处理】YUV格式说明

    YUV,是一种颜色编码方法,Y表示明亮度(Luminance.Luma),U和V则是色度.浓度(Chrominance.Chroma). YUV,Y`UV,YCbCr,YPbPr等都可以称为YUV,彼 ...

  3. [锋利JQ]-图片提示效果

    新知识点: 在HTML-Dom中 "style" 属性,是所有HTML标签共有的一个对象属性,这个对象属性可以为元素设置内嵌样式. style是元素的属性,但是它自身则是一个对象, ...

  4. ligerUI布局时,Center中的Tab高度太小问题解决

    1.0 引用的js,css <link href="/Content/scripts/ligerUI/skins/Aqua/css/ligerui-all.css" rel= ...

  5. 在Winform开发中使用日程控件XtraScheduler

    在一些应用场景中,我们可能需要记录某一天,某个时段的日程安排,那么这个时候就需要引入了DevExpress的日程控件XtraScheduler了,这个控件功能非常强大,提供了很好的界面展现方式,以及很 ...

  6. VS2015如何创建单元测试并启动调试

    1: 添加单元测试 2:打开单元测试类 关键点: 类上加上标记:[TestClass],方法上添加标记:[TestMethod],方法输出使用:Assert.IsNotNull(s,"测试失 ...

  7. Java/Android引用类型及其使用分析

    Java/Android中有四种引用类型,分别是: Strong reference     - 强引用Soft Reference        - 软引用Weak Reference      - ...

  8. CodeSmith连接Oracle

    Win7上仅安装了Oracle32位客户端,此时CodeSmith无法连接Oracle数据库. 解决方法一:如果同一台电脑安装了Oracle64位数据库,这样CodeSmith可以连接数据库. 解决方 ...

  9. 根据商品名称、价格区间检索商品的SQL语句

    如果名称和价格为空会检索出所有的数据 select * from TblProduct where (@proName='' or chvProName like '%'+@proName+'%') ...

  10. 优化JavaScripe 提升首页加载速度的几种方案解析

    优化目的: 1. 减少load量. 2. 优化js,加快页面加载速度. 网站中最影响网站打开速度的是什么?我会告诉是网站中的javascript,简称JS.模板中引用的JS文件越多,打开速度越慢,细读 ...