c语言泛型模板与this指针

本文深入探讨C语言泛型模板的实现,包括泛型模板的封装、this指针构造及两种实现方法的对比。通过具体示例展示了泛型数组和顺序表的模板实现过程,适合对C语言泛型编程感兴趣的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

上次我简单讲了一下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*));排序,需自定义排序因子类qsort
  • traversal (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
};

三 总结

我们采用了两种方法实现了C语言泛型模板,并且也实现了this指针,但是两个差别还是挺大的.

方法一: 是拥有真正的类型,但是代码会疯狂的膨胀,它复制每一个蓝本并且单独实现了类型,而且它使用可能不符合常规(这个其实不重要).

方法二: 是没有真正类型的它是通过模拟实现的,但是它运行效率可能更快,也不会产生多余的代码,而且它使用符合常规(没有类型的缺点太致命了).

这两种方法各有优缺点,一般情况下可以用c++混编弥补C语言的缺陷,但是有些情况只能用c语言这个泛型模板就有优势了. 我希望有朋友 有更好的方案,请告诉我.
下面是顺序表动态实现的代码,可以自动管理内存,但是我没有封装this,有兴趣的朋友可以自己封装一下.

点击查看`SeqList.h`
/**
 * 作者: 徐南木
 * 说明: 动态顺序表模板
 * 编译器: 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上会陆续更新模板源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值