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中的一些应 ...
随机推荐
- 关于Entity Framework中的Attached报错的完美解决方案
我们在使用Entity Framework进行CRUD时,为了提升查询效率,一般均会启动NoTracking,即不追踪变化,设置代码如下: //这是DB First模式下设置方法: aTestEnti ...
- SQL--Having
Having--对分组信息进行过滤,因为分组之后的信息和原来的表信息没有关系了, Having可以用的之后,出现在Group子句中的列,还有聚合函数 SELECT s_Age ,COUNT(s_I ...
- IOS ID生成器
// // IdGenerator.m // Copyright (c) 2014年 青岛拓宇网络科技有限公司. All rights reserved. // #import "IdGen ...
- 使用.NET 4.0+ 操作64位系统中的注册表
一.64位系统中的注册表 以 LocalMachine 中的启动项为例: 64位应用的注册表位置还是在: SOFTWARE\Microsoft\Windows\CurrentVersion\Run 而 ...
- 国产达梦数据库的结合Enterprise Library的应用开发
在上篇<基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作>介绍了如何在Enterprise Library的数据访问层上支持这种神秘的国产数 ...
- 【要什么自行车】ASP.NET MVC4笔记03:调用编辑器 kindeditor
参考:http://www.cnblogs.com/guzhongx/p/kindeditor.html 1.下载kindeditor,存放于Content文件夹下 <script src=&q ...
- C#中的枚举类型enum用法
定义一个简单的枚举类型: enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; //这时候 Days.Sat = 0 ,后面依 ...
- ubuntu16.4下用jexus部署asp.net core rtm
上篇文章介绍了下用vs发布部署到iis环境,今天说下ubuntu 下部署asp.net core,不需要安装.net core sdk,自带运行时方式部署,利用jexus服务器转发请求到asp.net ...
- Scalaz(46)- scalaz-stream 基础介绍
scalaz-stream是一个泛函数据流配件库(functional stream combinator library),特别适用于函数式编程.scalar-stream是由一个以上各种状态的Pr ...
- Scalaz(30)- Free :Natural Tranformation ~> - map higher kinded types for free
当我们需要定义一些对应高阶类型进行相互类型转换的操作函数时,我们发现scala语言并不提供能定义这种函数的支持.举例来说:如果我们希望定义一个函数把对于任何T值的Option[T]转换成List[T] ...