如果要写个函数支持多种数据类型,首先想到的就是C++的模板了,但是有时候只能用C语言,比如在linux内核开发中,为了减少代码量,或者是某面试官的要求…
屏山ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联公司的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18980820575(备注:SSL证书合作)期待与您的合作!
考虑了一阵子后,就想到了qsort上.qsort的函数原型:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
快排时,只要自己实现相应数据类型的比较函数cmpare就可以了.如果比较int型时,一个典型的compare函数如下:
那么,就是说可以利用void *. void *意指未指定类型,也可以理解为任意类型。其他类型的指针可以直接赋值给void *变量,但是void *变量需要强制类型转换为其它指针类型。这个相信大家都知道。那么下面以一个简单的题目为例,来探讨如何在C语言中实现模板函数。
方法1: 利用void *.
在看下面的源程序之前,需要了解几点。首先,在32位平台上,任何类型的指针所占的字节都是4个字节,因为32位机器虚拟内存一般为4G,即2的32次方,只要32位即4个字节就可以足够寻址,sizeof(void *)=4; 其次,虽然各种不同类型的指针所占的空间都为4个字节,但是不同类型的指针所指的空间的字节数却不同(这一点尤为重要,下面的程序我在开始没有调通就因为这点意识不强)。所以,如果你将一个指针强制转换为另一个类型的指针,指针本身所占的字节是不变的,但是,如果对这个指针进行运算,比如 *p,p++,p-=1等一般都是不同的。 再次,函数指针应该了解下,这里不多说。 最后,因为Sandy跟我说,C++开始的时候模板的实现其实就是利用宏替换,在编译的时候确定类型。所以,为了方便,类型也用了预编译指令#define。
span#include "stdio.h"/span
span#include "stdlib.h"/span
span//typedef int T; //或者下面的也可以./span
span#define T int/span
//这个FindMin是Sandy写的.felix021也写了个,差不多的就不贴出来的.
void FindMin(const void *arr,int arr_size,int arrmembersize,int *index,
int (*cmp)(const void *,const void *b)){
int i;
*index=0;
char *p=(char *)arr;
char *tmp=p;
for (i=1;iarr_size ;i++){
if (cmp(tmp,p)0){
tmp=p;
}
p+=arrmembersize;
}
(*index)=((int)(tmp-arr))/arrmembersize;
}
*//span
可以把指针看作是char *,如果转换为int *,那下面的位移就不正确了./span
indexspan=/spanispan;/span
span}/span
span}/span
spanreturn/span indexspan;/span
span}/span
spanint/span resultspan;/spanspan//result保存的是最小值索引./span
resultspan=/spanFindMinspan(/spanarr,span12/span,
#includestdio.h
struct student //结构体在函数外部定义
{
int num;
char Class[20];
char name[40];
float music;
float art;
float math;
};
void in(struct student stu[],int n); //函数声明在函数外部,主函数向子函数传递stu、n,才能在子函数中使用stu、n
void ave(struct student stu); //函数声明在函数外部,求平均数程序整体有些错误,我给改了
void main()
{
struct student stu[100]; //已经定义好的结构体全名是struct +你定义的名字,鉴于内存有限,100的长度已经够用了
int n,i;
printf("输入人数\t"); //增强互动性
while(scanf("%d",n)!=0)
{
in(stu,n);
for(i=0;in;i++)
{
printf("%s ",stu[i].name);
ave(stu[i]);
}
}
}
void in(struct student stu[],int n)
{
int i;
printf("输入信息(学号,班级,姓名,音乐成绩,艺术成绩,数学成绩)\n"); //增强互动性
for(i=0;in;i++)
{
scanf("%d %s %s %f %f %f",stu[i].num,stu[i].Class,stu[i].name,stu[i].math,stu[i].music,stu[i].art);
}
}
void ave(struct student stu)
{
float average;
average=(stu.music+stu.math+stu.art)/3.000;
printf("%5.lf\n",average);
}
1、结构体,函数声明都在主函数外;
2、被调函数使用主调函数需要传值;
3、结构体名为struct +定义名;
4、程序注意互动性。
STU f (STU a)
{ STU b={"Zhao", 'm', 85, 90};
int i;
strcpy( a.name, b.name );
a.sex = b.sex;
for ( i=0; i2; i++ ) a.score[i] = b.score[i];
以上是将b中的数据赋值给a,相当于a=b;这样的一个操作
return a;
}
main()
{ STU c= { "Qian", 'f', 95, 92 }, d;
d = f(c);//这里传的c是个复制品(传递的不是结构体指针),所以c不会变,d接收f()函数的返回值,因为返回值的内容是f()中的b的值,所以,d与c不同
printf ("%s,%c,%d,%d, ", d.name, d.sex, d.score[0], d.score[1]);
printf ("%s,%c,%d,%d\n", c.name, c.sex, c.score[0], c.score[1]);
}
输出结果为:A) Zhao,m,85,90, Qian,f,95,92
结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。在一般情况下,tag、member-list、variable-list这3部分至少要出现2个。
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明。
扩展资料:
一、结构体作用:
结构体和其他类型基础数据类型一样,例如int类型,char类型,只不过结构体可以做成你想要的数据类型,以方便日后的使用。
在实际项目中,结构体是大量存在的,研发人员常使用结构体来封装一些属性来组成新的类型。由于C语言内部程序比较简单,研发人员通常使用结构体创造新的“属性”,其目的是简化运算。
结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。让使用者不必关心这个是什么,只要根据定义使用就可以了。
二、结构体的大小与内存对齐:
结构体的大小不是结构体元素单纯相加就行的,因为我们主流的计算机使用的都是32bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。
所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。
程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
三、结构体的规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
参考资料来源:百度百科-结构体