前言
上次我简单讲了一下c语言泛型的模板,这次详解
C语言泛型模板的封装
和this指针构造
.
操作内容如下:
#include <stdio.h>
#include "template.h"
#include "Array.h"
int main() {
/***************C语言泛型示例**********************/
var a=Array(int);
a.pushLast(1);
a.pushLast(2);
a.pushFirst(3);
printf("len=%d\n",a.len());
while (a.len()!=0)
printf("%d,",a.popLast());
var b=Array(int);
b.pushLast(99);
while (b.len()!=0)
printf("%d,\n",b.popLast());
/***************C语言模板示例*********************/
#define T char
#include "StaticSeqList.h"
void print(char c)
{
printf("%c ",c);
}
StaticSeqList(char) stt = new(StaticSeqList(char));
stt.pushLast('a');
stt.pushLast('e');
stt.pushLast('c');
stt.traversal(print);
return 0;
}
一 第一种 模板思路
这是拥有真正完整类型的模板,我们用
静态顺序表
来实现这个模板.
template.h详解
我们首先创建
template.h
这个泛型模板基础头文件.
/**
* 作者: 徐南木
* 说明: 模板头文件
* 编译器: mingw-w64
* 时间: 2020/2/12 14:25
*/
#ifndef TEMPLATE_TEMPLATE_H
#define TEMPLATE_TEMPLATE_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
/*类型模板宏定义*/
#define var __auto_type
#define ___(type,T) T##_##type
#define __(type,T) ___(type,T)
#define _(type) __(type,T)
/* 作者: 徐南木
* 说明: 函数模板宏,funcname是函数名
* functype是一个接口宏,用来确定函数类型
* 时间: 2020/2/12 14:29
*/
#define $(funcname) __(funcname,functype)
/*函数宏定义*/
#define init(x) __(init,x)()
/* 作者: 徐南木
* 说明: 用指针new出来的对象必须使用delete释放
* 时间: 2020/2/12 14:44
*/
#define new(x) new##x
#define delete(x) __(delete,x)
#define _tostring(x) #x
#define tostring(x) _tostring(x)
#define size_init 100//初始块
/* 作者: 徐南木
* 说明: 交换变量
* @return: void
* 时间: 2020/2/12 15:07
*/
#define swap(a,b) do{\
typeof(a) t = (a);\
(a)= (b);\
(b)= (t);\
}while(0)
/* 作者: 徐南木
* 说明: 接收地址交换指定块变量
* 能交换所有元素
* @return: void
* 时间: 2020/2/12 15:29
*/
#define SWAP(a,b,size)({\
char buffer[(size)];\
memmove(buffer,(a),(size));\
memmove((a),(b),(size));\
memmove((b),buffer,(size));\
})
/* 作者: 徐南木
* 说明: 申请内存
* @return: void
* 时间: 2020/2/12 15:41
*/
#define MALLOC(ptr,type,n)({\
ptr=(type*)malloc(sizeof(type)*(n));\
if(!ptr){\
printf("error:%s文件%s函数内,%s申请失败!\n",__FILE__,__func__,tostring(ptr));\
exit(0);}\
})
/* 作者: 徐南木
* 说明: 改变内存大小
* 如果失败返回false
* @return: bool
* 时间: 2020/2/12 15:44
*/
#define REALLOC(ptr,type,n)({\
void* new_ptr=realloc(ptr,sizeof(type)*(n));\
bool flag=true;\
if(!new_ptr){\
printf("error:%s文件%s函数内,%s内存改变失败!\n",__FILE__,__func__,tostring(ptr));\
flag=false;}\
else \
ptr=(type*)new_ptr;\
flag;\
})
#endif //TEMPLATE_TEMPLATE_H
这个template.h
是基于gcc编译器实现的,下面所有文件都是基于gcc实现
StaticSeqList.h
我们来实现一个顺序表的基本功能,其实顺序表本质就是数组的一种封装.
1.StaticSeqList基本函数功能
length ();
返回顺序表长度being ();
返回第一个元素的地址end ();
返回最后一个元素的下一个地址getFirst ();
返回首元素getLast ();
返回尾元素popFirst ();
弹出首元素,并返回其值popLats ();
弹出尾元素,并返回其值getAt (int );
返回指定序号元素popAt (int );
弹出指定序号元素 ,并返回其值pushFirst (T);
向首部插入一个元素pushLast (T);
向尾部插入一个元素pushAt (T, int);
指定序号插入一个元素isAt (int );
判断索引是否正确full ();
判断是否为满empty ();
判断是否为空erase (T*);
删除迭代器元素clear ();
清空元素reverse ();
反转元素序列sort (int (*)(const void*,const void*));
排序,需自定义排序因子类qsorttraversal (void (*)(T));
遍历输出所有元素,需自定义输出函数index (T* );
返回迭代器的索引indexOf) (T);
返回该元素第一次出现的索引lastIndexOf(T);
返回该元素最后出现的索引id();
变量类型名
2.StaticSeqList模板实现
这个是无this指针的实现,先弄这个简单的.
注释我都详细的写在函数前,这个可能和你们学的数据结构实现操作可能有不同.
/**
* 作者: 徐南木
* 说明: 静态顺序表模板
* 编译器: mingw-w64
* 时间: 2020/2/12 19:39
*/
#ifndef T
#error No define "T"
#else
#include "template.h"
/*补充接口*/
#define StaticSeqList(T) T##_StaticSeqList
#define type _(StaticSeqList__)
#define functype type
typedef struct type type;
struct type{
int length;
T data[size_init];
T* (*being) (type*); //返回第一个元素的地址
T* (*end) (type*); //返回最后一个元素的下一个地址
T (*getFirst) (type*); //返回首元素
T (*getLast) (type*); //返回尾元素
T (*popFirst) (type*); //弹出首元素,并返回其值
T (*popLats) (type*); //弹出尾元素,并返回其值
T (*getAt) (type*,int ); //返回指定序号元素
T (*popAt) (type*,int ); //弹出指定序号元素 ,并返回其值
bool (*pushFirst) (type*,T); //向首部插入一个元素
bool (*pushLast) (type*,T); //向尾部插入一个元素
bool (*pushAt) (type*,T, int); //指定序号插入一个元素
bool (*isAt) (type*,int ); //判断索引是否正确
bool (*full) (type*); //判断是否为满
bool (*empty) (type*); //判断是否为空
void (*erase) (type*,T*); //删除迭代器元素
bool (*clear) (type*); //清空元素
bool (*reverse) (type*); //反转元素序列
bool (*sort) (type*,int (*)(const void*,const void*));//排序,需自定义排序因子类qsort
bool (*traversal) (type*,void (*)(T)); //遍历输出所有元素,需自定义输出函数
int (*index) (type*,T* ); 返回迭代器的索引
int (*indexOf) (type*,T); //返回该元素第一次出现的索引
int (*lastIndexOf)(type*,T); //返回该元素最后出现的索引
char* (*id)(); //变量类型名
};
char* $(id)()
{
return tostring(functype);
}
bool $(isAt)(type *this,int index)
{
if (this->length>index&&index>=0)
return true;
return false;
}
void $(erase)(type* this,T* it)
{
if (this->empty(this))
return;
int size=--this->length-(it-this->data);
memmove(it,it+1,size);
}
/* 作者: 徐南木
* 说明: 满返回真,否则返回假
* @return:
* 时间: 2020/2/13 11:25
*/
bool $(full)(type* this)
{
return this->length==size_init;
}
/* 作者: 徐南木
* 说明: 空返回真,否则返回假
* @return:
* 时间: 2020/2/13 11:27
*/
bool $(empty)(type* this)
{
return this->length==0;
}
/* 作者: 徐南木
* 说明: 返回容器第一个元素的地址
* 时间: 2020/2/13 11:14
* */
T* $(being)(type* this)
{
return &this->data[0];
}
/* 作者: 徐南木
* 说明: 返回容器最后元素的下一个地址
* 时间: 2020/2/13 11:16
*/
T* $(end)(type* this)
{
return &this->data[this->length];
}
/* 作者: 徐南木
* 说明: 返回第一个元素
* 时间: 2020/2/13 11:17
*/
T $(getFirst)(type* this)
{
return this->data[0];
}
/* 作者: 徐南木
* 说明: 返回最后一个元素
* 时间: 2020/2/13 11:17
*/
T $(getLast)(type* this)
{
return this->data[this->length-1];
}
/**
* 1.函数可以返回局部变量(无论自动变量还是静态变量)的值,不能返回非静态局部变量的指针
* 2.函数可以返回“static 局部变量”的指针,可以返回本函数调用malloc( )函数得到的局部指针
*/
T $(temp);
/* 作者: 徐南木
* 说明: 弹出头元素,若为空
则error:下溢操作,停止程序
* 时间: 2020/2/13 11:17
*/
T $(popFirst)(type* this)
{
if($(empty)(this))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
$(temp)=this->data[0];
memmove(this->data,this->data+1,--this->length);
return $(temp);
}
/* 作者: 徐南木
* 说明: 弹出尾元素,若为空
则error:下溢操作,停止程序
* 时间: 2020/2/13 11:21
*/
T $(popLast)(type* this)
{
if($(empty)(this))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
return this->data[--this->length];
}
/* 作者: 徐南木
* 说明: 获取指定索引的元素
* 时间: 2020/2/13 11:21
*/
T $(getAt)(type* this, int index)
{
if (index<0||index>=this->length)
{
//不在范围内,返回一个字节全为0的元素
memset(&$(temp),0, sizeof(T));
return $(temp);
}
return this->data[index];
}
/* 作者: 徐南木
* 说明: 指定索引的元素,弹出
* 时间: 2020/2/13 11:22
*/
T $(popAt)(type* this, int index)
{
if($(empty)(this)||!this->isAt(this,index))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
$(temp)=this->data[index];
memmove(this->data+index,this->data+1,--this->length-index);
return $(temp);
}
/* 作者: 徐南木
* 说明: 在首添加元素
* @return: bool
* 时间: 2020/2/13 11:24
*/
bool $(pushFirst)(type* this, T data)
{
if (this->full(this))
return false;
memmove(this->data+1,this->data,this->length++);
this->data[0]=data;
return true;
}
/* 作者: 徐南木
* 说明: 在尾添加元素
* @return: bool
* 时间: 2020/2/13 11:24
*/
bool $(pushLast)(type* this, T data)
{
if (this->full(this))
return false;
this->data[this->length++]=data;
return true;
}
/* 作者: 徐南木
* 说明: 指定索引添加元素
* @return: bool
* 时间: 2020/2/13 11:25
*/
bool $(pushAt)(type* this, T data, int index)
{
if(this->full(this)||index>this->length||index<0)
return false;
memmove(this->data+index+1,this->data+index,this->length-index);
this->data[index]=data;
++this->length;
return true;
}
/* 作者: 徐南木
* 说明: 清空元素
* @return: bool
* 时间: 2020/2/13 11:27
*/
bool $(clear)(type* this)
{
//顺序表比较简单直接置0;
this->length=0;
return true;
}
/* 作者: 徐南木
* 说明: 直接调用qsort封装
* @return: bool
* 时间: 2020/2/13 11:29
*/
bool $(sort)(type* this, int cmp(const void* ,const void *) )
{
if (this->empty(this))
return false;
qsort(this->data, this->length, sizeof(T), cmp);
return true;
}
/* 作者: 徐南木
* 说明: 反转
* @return: bool
* 时间: 2020/2/13 11:29
*/
bool $(reverse)(type* this)
{
int l=-1;
int r=this->length;
while (++l<--r)
{
swap(this->data[l],this->data[r]);
}
}
/* 作者: 徐南木
* 说明: 遍历
* @return:
* 时间: 2020/2/13 11:33
*/
bool $(traversal)(type* this, void pint(T))
{
// typeof(this->being(this)) it=this->being(this);
// for (; it != this->end(this) ; ++it)
// pint(*it);
for (int i = 0; i < this->length; ++i)
pint(this->data[i]);
puts("");
}
int $(index)(type* this, T* it)
{
return it - this->data;
}
/* 作者: 徐南木
* 说明: 返回第一个相同元素的索引
* 时间: 2020/2/13 11:35
* */
int $(indexOf)(type* this, T data)
{
for (int i = 0; i < this->length; ++i)
{
if (!memcmp(&data,&this->data[i], sizeof(T)))
return i;
}
return -1;
}
/* 作者: 徐南木
* 说明: 返回相同元素的最后一个索引
* 时间: 2020/2/13 11:36
*/
int $(lastIndexOf)(type* this,T data)
{
int index = -1;
for (int i = 0; i < this->length; ++i)
{
if (!memcmp(&data,&this->data[i], sizeof(T)))
index=i;
}
return index;
}
type $(init)() {
type seqList = {
.length=0,
.being=$(being),
.end=$(end),
.getFirst=$(getFirst),
.getLast=$(getLast),
.popFirst=$(popFirst),
.popLats=$(popLast),
.getAt=$(getAt),
.popAt=$(popAt),
.pushFirst=$(pushFirst),
.pushLast=$(pushLast),
.pushAt=$(pushAt),
.isAt=$(isAt),
.full=$(full),
.empty=$(empty),
.erase=$(erase),
.clear=$(clear),
.reverse=$(reverse),
.sort=$(sort),
.traversal=$(traversal),
.index=$(index),
.indexOf=$(indexOf),
.lastIndexOf=$(lastIndexOf),
.id=$(id)
};
return seqList;
}
type* $(new)()
{
type* seqList_prt;
MALLOC(seqList_prt,type,1);
*seqList_prt=$(init)();
return seqList_prt;
}
void $(delete)(type* ptr)
{
free(ptr);
}
到此一个模板封装已经完成了,这个除了没有this指针,可以完全独立操作了.
3.StaticSeqList的this指针构造
C语言可以用
{}
模拟一个独立的空间向外提供一个接口.
this指针就是基于这个实现,我们需要对模板用宏实现二次封装.
#undef type
#define type _(StaticSeqList)
typedef struct type type;
struct type{
int (*length) ();
T* (*being) (); //返回第一个元素的地址
T* (*end) (); //返回最后一个元素的下一个地址
T (*getFirst) (); //返回首元素
T (*getLast) (); //返回尾元素
T (*popFirst) (); //弹出首元素,并返回其值
T (*popLats) (); //弹出尾元素,并返回其值
T (*getAt) (int ); //返回指定序号元素
T (*popAt) (int ); //弹出指定序号元素 ,并返回其值
bool (*pushFirst) (T); //向首部插入一个元素
bool (*pushLast) (T); //向尾部插入一个元素
bool (*pushAt) (T, int); //指定序号插入一个元素
bool (*isAt) (int ); //判断索引是否正确
bool (*full) (); //判断是否为满
bool (*empty) (); //判断是否为空
void (*erase) (T*); //删除迭代器元素
bool (*clear) (); //清空元素
bool (*reverse) (); //反转元素序列
bool (*sort) (int (*)(const void*,const void*));//排序,需自定义排序因子类qsort
bool (*traversal) (void (*)(T)); //遍历输出所有元素,需自定义输出函数
int (*index) (T* ); 返回迭代器的索引
int (*indexOf) (T); //返回该元素第一次出现的索引
int (*lastIndexOf)(T); //返回该元素最后出现的索引
char* (*id)(); //变量类型名
};
#define newStaticSeqList(T) \
({\
\
__(_,StaticSeqList(T)) *this = T##_StaticSeqList___new();\
int length() { return this->length;} \
T* being() { return this->being(this);}\
T* end() { return this->end(this);}\
T getFirst() { return this->getFirst(this);}\
T getLast() { return this->getLast(this);}\
T popFirst() { return this->popFirst(this);}\
T popLats() { return this->popLats(this);}\
T getAt(int index) { return this->getAt(this,index);}\
T popAt(int index) { return this->popAt(this,index);}\
bool pushFirst(T data) { return this->pushFirst(this,data);}\
bool pushLast(T data) { return this->pushLast(this,data);}\
bool pushAt(T data,int index){ return this->pushAt(this,data,index);}\
bool isAt(int index) { return this->isAt(this,index);}\
bool full() { return this->full(this);}\
bool empty() { return this->empty(this);}\
void erase(T* it) { return this->erase(this,it);}\
bool clear() { return this->clear(this);}\
bool reverse() { return this->reverse(this);}\
bool sort(int cmp(const void*,const void*)){ return this->sort(this,cmp);}\
bool traversal(void print(T data)) { return this->traversal(this,print);}\
int index(T* it) { return this->index(this,it);}\
int indexOf(T data) { return this->indexOf(this,data);}\
int lastIndexOf(T data) { return this->lastIndexOf(this,data);}\
char* id() { return this->id();}\
StaticSeqList(char) staticSeqList={\
.length = length ,\
.being = being ,\
.end = end ,\
.getFirst = getFirst ,\
.getLast = getLast ,\
.popFirst = popFirst ,\
.popLats = popLats ,\
.getAt = getAt ,\
.popAt = popAt ,\
.pushFirst = pushFirst,\
.pushLast = pushLast ,\
.pushAt = pushAt ,\
.isAt = isAt ,\
.full = full ,\
.empty = empty ,\
.erase = erase ,\
.clear = clear ,\
.reverse = reverse ,\
.sort = sort ,\
.traversal = traversal,\
.index = index ,\
.indexOf = indexOf ,\
.lastIndexOf= lastIndexOf,\
.id = id \
}; \
staticSeqList;\
} )
#undef T
#undef type
#undef functype
#endif
注意: 此代码是和上面代码一起的,两个代码段合二为一就能完美运行
二 第二种 泛型思路
我们都知道C语言有个
void*
泛型指针 又称万能指针.
第二种方法就是基于此实现
下面用简单数组封装演示:Array.h
1.Array.h实现
我们实现一个能自动管理内存的数组,你完成不用担心他的内存空间,它可以自动释放和自动申请.维持一定的大小.
/*
* @作者: 徐南木
* @编译器: mingw-w64
* @编译环境: vscode win10-64位
* @Date: 2020-02-19 07:44:36
* @LastEditors: 徐南木
* @LastEditTime: 2020-02-21 01:46:19
* @Description:
*/
//
// Created by xunanmu on 2020/2/19.
//
#ifndef TEMPLATE_ARRAY_H
#define TEMPLATE_ARRAY_H
#include "template.h"
extern struct Array array;
struct Array{
bool (*autoMem) (void* this,const int* length,int* max,size_t size);
void*(*popFirst)(void* this, int* length,int* max,size_t size);
void*(*popLast)(void* this, int* length,int* max,size_t size);
bool (*pushFirst)(void *data,void* this,int* length,int* max, size_t size);
bool (*pushLast)(void *data,void* this,int* length,int* max, size_t size);
void (*delete_x)(void* ptr, int* length,int *max);
};
#define Array(T)\
({\
int length=0;\
int max=0;\
T* this=NULL;\
int len(){\
return length;\
}\
int size(){\
return max;\
}\
T getFirst(){\
return *this;\
}\
T getLast(){\
return this[length-1];\
}\
T popFirst(){\
return *((T*)array.popFirst(&this,&length,&max, sizeof(T)));\
}\
T popLast(){\
return *((T*)array.popLast(&this,&length,&max, sizeof(T)));\
}\
bool pushFirst(T data){\
return array.pushFirst(&data,&this,&length,&max, sizeof(T));\
}\
bool pushLast(T data){\
return array.pushLast(&data,&this,&length,&max, sizeof(T));\
}\
void delete_x(){\
array.delete_x(this,&length,&max);\
}\
struct {\
int (*len)();\
int (*size)();\
T (*getFirst)();\
T (*getLast)();\
T (*popFirst)();\
T (*popLast)();\
bool(*pushFirst)(T);\
bool(*pushLast)(T);\
void (*delete_x)();\
}arrays_temp={\
len,\
size,\
getFirst,\
getLast,\
popFirst,\
popLast,\
pushFirst,\
pushLast,\
delete_x,\
};\
arrays_temp;\
})
#endif //TEMPLATE_ARRAY_H
一样的用宏封装
2.Array.c 函数实现
我们采用静态内联,让工程只产生唯一变量提升效率.
//
// Created by xunanmu on 2020/2/19.
//
#include "Array.h"
static inline bool autoMem(void* this,const int* length,int* max,size_t size)
{
//若空间不足,申请100个内存单元
if (*max-*length==0)
{
if(! REALLOC(*(char**)this,char ,size* *max))
return false;
*max += size_init;
}
//如果空间超过200单元内存自动释放一半
else if (*max - *length>200)
{
if(! REALLOC(*(char**)this,char ,size* *max))
return false;
*max -= size_init;
}
return true;
}
static char temp[36];
static inline void* popFirst(void* this, int* length,int* max,size_t size)
{
autoMem(this,length,max,size);
if (*length<1)
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
*length-=1;
memmove(temp,this,size);
memmove((*(char**)this)+size,*(char**)this,*length*size);
return temp;
}
static inline void* popLast(void* this, int* length,int* max,size_t size)
{
autoMem(this,length,max,size);
if (*length<1)
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
*length-=1;
return *(char**)this+*length*size;
}
static inline bool pushFirst(void *data,void* this,int* length,int* max, size_t size)
{
if(!autoMem(this,length,max,size))
return false;
memmove(*(char**)this+size,*(char**)this,*length*size);
memmove(*(char**)this,data,size);
*length+=1;
return true;
}
static inline bool pushLast(void *data,void* this,int* length,int* max, size_t size)
{
if(!autoMem(this,length,max,size))
return false;
memmove(*(char**)this+*length*size,data,size);
*length+=1;
return true;
}
static inline void delete_x(void* ptr, int* length,int *max)
{
free(ptr);
*length=0;
*max=0;
}
//这是一个函数结构体接口
struct Array array={
autoMem,
popFirst,
popLast,
pushFirst,
pushLast,
delete_x
};
三 总结
点击查看`SeqList.h`我们采用了两种方法实现了C语言泛型模板,并且也实现了this指针,但是两个差别还是挺大的.
方法一: 是
拥有真正的类型
,但是代码会疯狂的膨胀,它复制每一个蓝本并且单独实现了类型,而且它使用可能不符合常规(这个其实不重要).方法二: 是
没有真正类型
的它是通过模拟实现的,但是它运行效率可能更快,也不会产生多余的代码,而且它使用符合常规(没有类型的缺点太致命了).这两种方法各有优缺点,一般情况下可以用
c++
混编弥补C语言的缺陷,但是有些情况只能用c语言这个泛型模板就有优势了. 我希望有朋友 有更好的方案,请告诉我.
下面是顺序表动态实现的代码,可以自动管理内存,但是我没有封装this,有兴趣的朋友可以自己封装一下.
/**
* 作者: 徐南木
* 说明: 动态顺序表模板
* 编译器: mingw-w64
* 时间: 2020/2/14 16:39
*/
#ifndef T
#error No define "T"
#else
#include "template.h"
/*补充接口*/
#define SeqList(T) T##_SeqList
#define type _(SeqList)
#define functype type
typedef struct type type;
/**
* type高度抽象类型,原因无他 就是好CTRL CV*/
struct type{
int length;
int max;
T* data;
T* (*being) (type*); //返回第一个元素的地址
T* (*end) (type*); //返回最后一个元素的下一个地址
T (*getFirst) (type*); //返回首元素
T (*getLast) (type*); //返回尾元素
T (*popFirst) (type*); //弹出首元素,并返回其值
T (*popLats) (type*); //弹出尾元素,并返回其值
T (*getAt) (type*,int ); //返回指定序号元素
T (*popAt) (type*,int ); //弹出指定序号元素 ,并返回其值
bool (*pushFirst) (type*,T); //向首部插入一个元素
bool (*pushLast) (type*,T); //向尾部插入一个元素
bool (*pushAt) (type*,T, int); //指定序号插入一个元素
bool (*isAt) (type*,int ); //判断索引是否正确
bool (*empty) (type*); //判断是否为空
void (*erase) (type*,T*); //删除迭代器元素
void (*clear) (type*); //清空元素
void (*reverse) (type*); //反转元素序列
void (*sort) (type*,int (*)(const void*,const void*));//排序,需自定义排序因子类qsort
void (*traversal) (type*,void (*)(T)); //遍历输出所有元素,需自定义输出函数
int (*index) (type*,T* ); //返回迭代器的索引
int (*indexOf) (type*,T); //返回该元素第一次出现的索引
int (*lastIndexOf)(type*,T); //返回该元素最后出现的索引
char* (*id)(); //变量类型名
};
char* $(id)()
{
return tostring(functype);
}
/* 作者: 徐南木
* 说明: 自动分配内存
* 如果内存不足返回false
* @return: bool
* 时间: 2020/2/16 17:03
*/
bool $(autoMem)(type* this)
{
//若空间不足,申请100个内存单元
if (this->max-this->length==0)
{
this->max += size_init;
return REALLOC(this->data,T,this->max);
}
//如果空间超过200单元内存自动释放一半
else if (this->max-this->length>200)
{
this->max -= size_init;
return REALLOC(this->data,T,this->max);
}
else
return true;
}
T* $(being)(type* this)
{
return &this->data[0];
}
T* $(end)(type* this)
{
return &this->data[this->length];
}
/*******************************
* 关于get()获取元素说明
* 他就是单纯的返回元素的值
* 你可以调用isAt()查看索引是否正确
* 不在范围内,返回一个字节全为0的元素
* return T(0);
* 如果不规范,程序错误自己负责
******************************/
T $(getFirst)(type* this)
{
if (this->empty(this))
{
T temp;
memset(&temp,0, sizeof(T));
return temp;
}
return this->data[0];
}
T $(getLast)(type* this)
{
if (this->empty(this))
{
T temp;
memset(&temp,0, sizeof(T));
return temp;
}
return this->data[this->length-1];
}
T $(getAt)(type* this, int index)
{
if (this->isAt(this,index))
{
T temp;
memset(&temp,0, sizeof(T));
return temp;
}
return this->data[index];
}
/***************************
* pop()删除并返回元素说明
* 如果删除不存在的元素导致下溢操作
* 那么对不起直接停止程序
***************************/
T $(popFirst)(type* this)
{
if(this->empty(this))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
$(autoMem)(this);
T temp=this->data[0];
//data[0]后面元素向前移
memmove(this->data,this->data+1,--this->length);
return temp;
}
T $(popLast)(type* this)
{
if(this->empty(this))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
$(autoMem)(this);
return this->data[--this->length];
}
T $(popAt)(type* this, int index)
{
if(this->empty(this)||!this->isAt(this,index))
{
printf("error:%s文件内%s函数产生下溢操作!",__FILE__,__func__);
exit(0);
}
$(autoMem)(this);
T temp=this->data[index];
//data[index]后面元素向前移
memmove(this->data+index,this->data+1,--this->length-index);
return temp;
}
/***********************
* push()函数
* 添加成功返回true
* 不成功返回false
***********************/
bool $(pushFirst)(type* this, T data)
{
if (!$(autoMem)(this))
return false;
//向后移动
memmove(this->data+1,this->data,this->length++);
this->data[0]=data;
return true;
}
bool $(pushLast)(type* this, T data)
{
if (!$(autoMem)(this))
return false;
this->data[this->length++]=data;
return true;
}
bool $(pushAt)(type* this, T data, int index)
{
if (!$(autoMem)(this))
return false;
if(index>this->length||index<0)
return false;
//data[index]向后移动
memmove(this->data+index+1,this->data+index,this->length-index);
this->data[index]=data;
++this->length;
return true;
}
/**************************/
bool $(isAt)(type *this,int index)
{
if (this->length>index&&index>=0)
return true;
return false;
}
bool $(empty)(type* this)
{
return this->length==0;
}
void $(erase)(type* this,T* it)
{
if (this->empty(this))
return;
int size=--this->length-(it-this->data);
memmove(it,it+1,size);
}
void $(clear)(type* this)
{
//顺序表比较简单直接置0;
this->length = 0;
this->max = 0;
free(this->data);
this->data=NULL;
}
void $(sort)(type* this, int cmp(const void* ,const void *) )
{
qsort(this->data, this->length, sizeof(T), cmp);
}
void $(reverse)(type* this)
{
int l=-1;
int r=this->length;
while (++l<--r)
{
swap(this->data[l],this->data[r]);
}
}
void $(traversal)(type* this, void pint(T))
{
for (int i = 0; i < this->length; ++i)
pint(this->data[i]);
puts("");
}
int $(index)(type* this, T* it)
{
return it - this->data;
}
int $(indexOf)(type* this, T data)
{
for (int i = 0; i < this->length; ++i)
{
if (!memcmp(&data,&this->data[i], sizeof(T)))
return i;
}
return -1;
}
int $(lastIndexOf)(type* this,T data)
{
int index = -1;
for (int i = 0; i < this->length; ++i)
{
if (!memcmp(&data,&this->data[i], sizeof(T)))
index=i;
}
return index;
}
type $(init)() {
type seqList = {
.length=0,
.max=0,
.data=NULL,
$(being),
$(end),
$(getFirst),
$(getLast),
$(popFirst),
$(popLast),
$(getAt),
$(popAt),
$(pushFirst),
$(pushLast),
$(pushAt),
$(isAt),
$(empty),
$(erase),
$(clear),
$(reverse),
$(sort),
$(traversal),
$(index),
$(indexOf),
$(lastIndexOf),
$(id)
};
return seqList;
}
type* $(new)()
{
type* seqList_ptr;
MALLOC(seqList_ptr,type,1);
*seqList_ptr = init(type);
return seqList_ptr;
}
void $(delete)(type* ptr)
{
free(ptr->data);
free(ptr);
}
#undef T
#undef type
#undef functype
#endif
- 我GitHub上会陆续更新模板源码