C语言进阶之泛型列表(Generic List)

news2024/12/28 4:11:07

1.前言

        数据结构是需要泛型的,而在C语言中实现泛型就只能去用指针魔法了,来跟我一起实现吧!所有代码经测试未发现明显bug,可放心食用.

2.代码截图展示

1.list.h

2.main.c

3.list.c

3.结语

        这次分享的列表采用动态数组的方式实现,下次我会去用链表实现,两种实现方式各有优劣,希望初学者能够自己去实现一下.本次分享到此结束,记得点赞加收藏,你的点赞是我更新的动力!!!

4.可复制代码展示

//list.h
#pragma once
#include <assert.h>
#include <crtdefs.h>
#include <stdbool.h>
#include <stdio.h>   // IWYU pragma: export
#include <stdlib.h>  // IWYU pragma: export
#include <string.h>  // IWYU pragma: export
#include <time.h>    // IWYU pragma: export

typedef struct {
  void *data;
  size_t dataSize;
  size_t size;
  size_t capacity;
} List;

#define DEFAULT_CAPACITY 4
#define DRFPTR(type, ptr) (*(type *)ptr)

List *ListCreate(size_t dataSize);
#define mListCreate(TYPE) ListCreate(sizeof(TYPE))
void ListDestory(List *pList);
bool CheckCapacity(List *pList, size_t insertSize);
void ListPushBack(List *pList, const void *data);
void ListPopBack(List *pList);
void ListPrint(const List *pList, void (*pfPrint)(const void *));
size_t ListSize(List *pList);
size_t ListCapacity(List *pList);
void ListPushFront(List *pList, const void *data);
void ListPopFront(List *pList);
void ListPosInsert(List *pList, size_t pos, const void *data);
void ListPosErase(List *pList, size_t pos);
void ListRandomInsertIntData(List *pList,
                             size_t count,
                             size_t maxNum);
void ListSort(List *pList, int (*pfCmp)(const void *, const void *));
void ListRandomInsertDoubleData(List *pList, size_t count);
void ListDataModify(List *pList,
                    size_t pos,
                    void (*pfModify)(void *));
bool ListIsEmpty(List *pList);
bool ListReserve(List *pList, size_t size);
size_t ListResize(List *pList, size_t size);
void *ListDataAt(List *pList, size_t index);
void *ListHeadData(List *pList);
void *ListTailData(List *pList);
void ListClear(List *pList);
size_t ListFindData(List *pList,
                    const void *findData,
                    int (*pfCmp)(const void *, const void *));
void ListIndexAccess(const List *pList,
                     const size_t index,
                     void (*pfPrint)(const void *));
//main.c
#include "list.h"

typedef struct {
  char name[20];
  int age;
} People;

int CmpPeopleAge(const void *e1, const void *e2) {
  return DRFPTR(People, e1).age - DRFPTR(People, e2).age;
}
int CmpPeopleName(const void *e1, const void *e2) {
  return strcmp(DRFPTR(People, e1).name, DRFPTR(People, e2).name);
}
void PrintPeople(const void *data) {
  printf("name:%-10s\tage:%2d\n", DRFPTR(People, data).name,
         DRFPTR(People, data).age);
}
void ModifyInt(void *data) {
  int *d = (int *)data;
  *d = 666666;
}
void ModifyDouble(void *data) {
  // printf("输入>>>");
  // scanf("%lf", (double *)data);
  *(double *)data = 0.123456;
}
void PrintInt(const void *data) {
  printf("%d ", *(int *)data);
}
void PrintDouble(const void *data) {
  printf("%.5lf ", *(double *)data);
}
int CmpInt(const void *e1, const void *e2) {
  return *(int *)e1 - *(int *)e2;
}
int CmpDouble(const void *e1, const void *e2) {
  return (*(double *)e1 > *(double *)e2
              ? 1
              : (*(double *)e1 < *(double *)e2 ? -1 : 0));
}
void test_int() {
  List *list = mListCreate(int);
  printf("list size: %zu\n", ListSize(list));
  printf("list capacity: %zu\n", ListCapacity(list));

  // for (int i = 0, data; i < 3; i++) {
  //   data = rand() % 10;
  //   ListPushBack(list, &data);
  // }
  // ListPrint(list, PrintInt);

  // for (int i = 0, data; i < 3; i++) {
  //   data = rand() % 10;
  //   ListPushFront(list, &data);
  // }
  // int a = 666;
  // ListPosInsert(list, 2, &a);

  // ListPrint(list, PrintInt);
  // for (int i = 0; i < 1; i++) {
  //   ListPopBack(list);
  //   ListPopFront(list);
  // }
  // ListPosErase(list, 1);
  // ListPosErase(list, 0);
  // ListPosErase(list, ListSize(list) - 1);

  ListRandomInsertIntData(list, 1234, 666);

  // ListPrint(list, PrintInt);
  ListSort(list, CmpInt);
  // ListPrint(list, PrintInt);

  printf("list size: %zu\n", ListSize(list));
  printf("list capacity: %zu\n", ListCapacity(list));
  size_t index;
  while (1) {
    int data;
    printf("输入>>>");
    scanf("%d", &data);
    index = ListFindData(list, &data, CmpInt);
    if (index == ListSize(list)) {
      printf("找不到该数据,请重新输入!\n");
    } else {
      break;
    }
  }
  printf("find data index is %zu\n", index);
  ListIndexAccess(list, index, PrintInt);
  ListDestory(list);
}
void test_double() {
  List *list = mListCreate(double);
  ListRandomInsertDoubleData(list, 13);
  ListPrint(list, PrintDouble);
  // ListSort(list, CmpDouble);
  ListDataModify(list, 0, ModifyDouble);
  ListDataModify(list, 4, ModifyDouble);
  printf("list new size:%zu:\n", ListResize(list, 5));
  ListPrint(list, PrintDouble);
  // printf("list[last] is %lf\n",
  //        *(double *)ListDataAt(list, ListSize(list) - 1));
  printf("list head data is %lf\n",
         DRFPTR(double, ListHeadData(list)));
  printf("list tail data is %lf\n",
         DRFPTR(double, ListTailData(list)));
  // ListClear(list);
  printf("list size: %zu\n", ListSize(list));
  printf("list capacity: %zu\n", ListCapacity(list));
  size_t index;
  while (1) {
    double data;
    printf("输入>>>");
    scanf("%lf", &data);
    index = ListFindData(list, &data, CmpInt);
    if (index == ListSize(list)) {
      printf("找不到该数据,请重新输入!\n");
    } else {
      break;
    }
  }
  printf("find data index is %zu\n", index);
  ListIndexAccess(list, index, PrintDouble);
  ListDestory(list);
}
void test_struct() {
  List *list = mListCreate(People);
  People p;
  for (int i = 0; i < 3; i++) {
    printf("输入姓名>>>");
    scanf("%s", p.name);
    printf("输入年龄>>>");
    scanf("%d", &p.age);
    ListPushBack(list, &p);
  }
  ListPrint(list, PrintPeople);
  // ListSort(list, CmpPeopleAge);
  ListSort(list, CmpPeopleName);
  ListPrint(list, PrintPeople);
  size_t index;
  while (1) {
    People p;
    printf("输入>>>");
    scanf("%s", p.name);
    // scanf("%d", &p.age);
    // index = ListFindData(list, &p, CmpPeopleAge);
    index = ListFindData(list, &p, CmpPeopleName);
    if (index == ListSize(list)) {
      printf("找不到该数据,请重新输入!\n");
    } else {
      break;
    }
  }
  printf("find data index is %zu\n", index);
  ListIndexAccess(list, index, PrintPeople);
  ListDestory(list);
}
int main(void) {
  srand((unsigned int)time(NULL));
  // test_int();
  // test_double();
  test_struct();

  return 0;
}
//list.c

#include "list.h"

List *ListCreate(size_t dataSize) {
  List *list = (List *)malloc(sizeof(List));
  if (NULL == list) {
    printf("malloc fail!\n");
    exit(-1);
  }
  void *ptr = malloc(DEFAULT_CAPACITY * dataSize);
  if (NULL == ptr) {
    printf("malloc fail!\n");
    exit(-1);
  }
  list->data = ptr;
  list->dataSize = dataSize;
  list->capacity = DEFAULT_CAPACITY;
  list->size = 0;

  return list;
}
void ListDestory(List *pList) {
  assert(pList);
  free(pList->data);
  pList->data = NULL;
  free(pList);
  pList = NULL;
}
bool CheckCapacity(List *pList, size_t insertSize) {
  assert(pList && insertSize);
  if (insertSize <= pList->capacity - pList->size) {
    return true;
  }
  if (insertSize > 1) {
    void *ptr = realloc(pList->data, (pList->capacity + insertSize) *
                                         pList->dataSize);
    if (NULL == ptr) {
      printf("realloc fail!\n");
      return false;
    }
    pList->data = ptr;
    pList->capacity = pList->capacity + insertSize;
    return true;
  } else {
    void *ptr =
        realloc(pList->data, 2 * pList->capacity * pList->dataSize);
    if (NULL == ptr) {
      printf("realloc fail!\n");
      return false;
    }
    pList->data = ptr;
    pList->capacity = 2 * pList->capacity;
    return true;
  }
}
void ListPushBack(List *pList, const void *data) {
  assert(pList && data);
  if (CheckCapacity(pList, 1)) {
    memcpy(pList->data + pList->dataSize * pList->size, data,
           pList->dataSize);
    pList->size++;
  }
}
void ListPopBack(List *pList) {
  assert(pList);
  if (pList->size) {
    pList->size--;
  }
}
void ListPrint(const List *pList, void (*pfPrint)(const void *)) {
  assert(pList);
  for (int i = 0; i < pList->size; i++) {
    pfPrint(pList->data + pList->dataSize * i);
  }
  printf("\n");
}
size_t ListSize(List *pList) {
  assert(pList);
  return pList->size;
}
size_t ListCapacity(List *pList) {
  assert(pList);
  return pList->capacity;
}
void ListPushFront(List *pList, const void *data) {
  assert(pList && data);
  if (CheckCapacity(pList, 1)) {
    for (int i = pList->size; i > 0; i--) {
      memcpy(pList->data + i * pList->dataSize,
             pList->data + (i - 1) * pList->dataSize,
             pList->dataSize);
    }
    memcpy(pList->data, data, pList->dataSize);
    pList->size++;
  }
}
void ListPopFront(List *pList) {
  assert(pList);
  if (pList->size) {
    for (int i = 0; i < pList->size; i++) {
      memcpy(pList->data + i * pList->dataSize,
             pList->data + (i + 1) * pList->dataSize,
             pList->dataSize);
    }
    pList->size--;
  }
}
void ListPosInsert(List *pList, size_t pos, const void *data) {
  assert(pList && data);
  assert(pos < pList->size);
  if (CheckCapacity(pList, 1)) {
    for (int i = pList->size; i > pos; i--) {
      memcpy(pList->data + i * pList->dataSize,
             pList->data + (i - 1) * pList->dataSize,
             pList->dataSize);
    }
    memcpy(pList->data + pos * pList->dataSize, data,
           pList->dataSize);
    pList->size++;
  }
}
void ListPosErase(List *pList, size_t pos) {
  assert(pList);
  assert(pos < pList->size);
  if (pList->size) {
    for (int i = pos; i < pList->size; i++) {
      memcpy(pList->data + i * pList->dataSize,
             pList->data + (i + 1) * pList->dataSize,
             pList->dataSize);
    }
    pList->size--;
  }
}
void ListRandomInsertIntData(List *pList,
                             size_t count,
                             size_t maxNum) {
  assert(pList);
  assert(maxNum + 1 < RAND_MAX);
  if (CheckCapacity(pList, count)) {
    int data = 0;
    for (int i = 0; i < count; i++) {
      data = rand() % (maxNum + 1);
      memcpy(pList->data + pList->dataSize * pList->size, &data,
             sizeof(int));
      pList->size++;
    }
  }
}
void ListSort(List *pList,
              int (*pfCmp)(const void *, const void *)) {
  assert(pList && pfCmp);
  if (pList->size > 1) {
    // qsort(void *Base, size_t NumOfElements, size_t SizeOfElements,
    // int (*PtFuncCompare)(const void *, const void *)
    // __attribute__((cdecl)))
    qsort(pList->data, pList->size, pList->dataSize, pfCmp);
  }
}
void ListRandomInsertDoubleData(List *pList, size_t count) {
  assert(pList);
  if (CheckCapacity(pList, count)) {
    double data = 0;
    for (int i = 0; i < count; i++) {
      data = (double)rand() / RAND_MAX;
      memcpy(pList->data + pList->dataSize * pList->size, &data,
             sizeof(double));
      pList->size++;
    }
  }
}
void ListDataModify(List *pList,
                    size_t pos,
                    void (*pfModify)(void *)) {
  assert(pList && pfModify);
  assert(pos < pList->size);
  pfModify(pList->data + pList->dataSize * pos);
}
bool ListIsEmpty(List *pList) {
  assert(pList);
  if (0 == pList->size) {
    return true;
  } else {
    return false;
  }
}
bool ListReserve(List *pList, size_t size) {
  assert(pList);
  return CheckCapacity(pList, size);
}
size_t ListResize(List *pList, size_t size) {
  assert(pList);
  if (size <= pList->size) {
    pList->size = size;
  } else {
    if (CheckCapacity(pList, size - pList->size)) {
      memset(pList->data + pList->dataSize * pList->size, 0,
             (size - pList->size) * pList->dataSize);
      pList->size = size;
    }
  }
  return pList->size;
}
void *ListDataAt(List *pList, size_t index) {
  assert(pList);
  assert(index < pList->size);
  return pList->data + pList->dataSize * index;
}
void *ListHeadData(List *pList) {
  assert(pList);
  if (pList->size) {
    return pList->data;
  } else {
    return NULL;
  }
}
void *ListTailData(List *pList) {
  assert(pList);
  if (pList->size) {
    return pList->data + pList->dataSize * (pList->size - 1);
  } else {
    return NULL;
  }
}
void ListClear(List *pList) {
  assert(pList);
  pList->size = 0;
}
size_t ListFindData(List *pList,
                    const void *findData,
                    int (*pfCmp)(const void *, const void *)) {
  assert(pList && findData && pfCmp);
  for (int i = 0; i < pList->size; i++) {
    if (0 == pfCmp(findData, pList->data + pList->dataSize * i)) {
      return i;
    }
  }
  return pList->size;
}
void ListIndexAccess(const List *pList,
                     const size_t index,
                     void (*pfPrint)(const void *)) {
  assert(pList && pfPrint);
  assert(index < pList->size);
  pfPrint(pList->data + pList->dataSize * index);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通信工程学习:什么是VIM虚拟化基础设施管理器

VIM:虚拟化基础设施管理器 VIM(Virtualized Infrastructure Manager)虚拟化基础设施管理器,是一种负责管理和控制虚拟化环境中所有虚拟资源的工具和系统。以下是关于VIM虚拟化基础设施管理器的详细解释: 一、定义与功能 VIM是网络功能虚拟化(NFV)架构中…

DVWA-File Inclusion(文件包含)渗透测试

概念&#xff1a; 漏洞产生原因&#xff1a; 主要是由于开发人员没有对用户输入的文件路径进行严格的过滤和验证。例如&#xff0c;如果一个 Web 应用程序接受用户输入的文件路径&#xff0c;然后使用这个路径进行文件包含&#xff0c;而没有对用户输入进行任何检查&#xff0c…

dll 研究 1

起因&#xff0c; 目的: 就是想看看 dll 里面有什么。 过程: 找到&#xff0c;打开 dumpbin 在开始菜单中搜索 “Developer Command Prompt for VS”打开&#xff0c; 然后输入 dumpbin 查看 a.dll 中 dumpbin /headers a.dll 查看头部信息dumpbin /EXPORTS a.dlldumpbin /a…

基于SSM+小程序的在线课堂微信管理系统(在线课堂1)(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 &emsp1、管理员实现了首页、个人中心、用户管理、课程分类管理、课程信息管理、课程订阅管理、课程视频管理、公告栏管理、留言板管理、系统管理。 2、用户实现了首页、课程信息、公…

Web3Auth 如何工作?

Web3Auth 用作钱包基础设施&#xff0c;为去中心化应用程序 (dApp) 和区块链钱包提供增强的灵活性和安全性。在本文档中&#xff0c;我们将探索 Web3Auth 的功能&#xff0c;展示它如何为每个用户和应用程序生成唯一的加密密钥提供程序。 高级架构 Web3Auth SDK 完全存在于用…

消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许

业务场景&#xff1a; 在做发票校验时&#xff0c;报错“消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许”而且计算税额失效&#xff0c;红灯报错。 初步怀疑是税码配置问题 FTXP J1是进项税&#xff0c;但是这里维护了销项税和均一税&#xff0c;在这里删除是需…

【Python开发环境搭建】在pycharm中使用虚拟环境进行开发

每个虚拟环境都是独立的&#xff0c;打包生成的exe文件更加小巧&#xff0c;不会因为兼容性问题出现干扰 1、打开项目后&#xff0c;在右下角点击Python解释器&#xff0c;选择添加新的解释器&#xff0c;添加本地解释器 2、选择新建&#xff0c;选择合适的路径&#xff0c;取…

商业终端数据打包-android-鸿蒙——国产系统-———未来之窗行业应用跨平台架构

一、未来之窗星辰传送阵炼化炉横空出世 以下是为您编写的引言&#xff1a; 在当今的网络世界中&#xff0c;网页隔段时间就提示登录的现象令人困扰&#xff0c;严重影响了终端交互的流畅性。传统的设备 ID 识别方式存在无法动态变更数据的局限&#xff0c;轮询模式更是会使服务…

C# 利用simd比较两个文件是否相等(高性能)

主要用到两个指令集&#xff0c;CompareEqual指令与MoveMask指令&#xff0c;因为电脑cpu原因&#xff0c;我们采用Avx2。 Avx2.CompareEqual&#xff0c;比较两个Vector256<byte>向量&#xff0c;如果元素相同返回255&#xff0c;否则返回0。 Avx2.MoveMask如果Vector…

滚珠丝杠在人形机器人及线控制动和转向中大放异彩

直线驱动器用于对旋转角度不大、高负载的场景,在人形机器人中多用于四肢。直线驱动器多采取“电机+丝杠”,将旋转运动转为关节末端的直线运动,能够起到较好的支撑和承重效果,能够较好的适配应用场景的负载需求。 特斯拉人形机器人Optimus 双足、双臂采用连杆结构,连杆末端…

GS-SLAM论文阅读笔记--GEVO

前言 这篇文章看着就让人好奇。众所周知&#xff0c;高斯是一个很不错的建图方法&#xff0c;但是本文的题目居然是只用高斯进行单目VO&#xff0c;咱也不知道这是怎么个流程&#xff0c;看了一下作者来自于MIT&#xff0c;说不定是个不错的工作&#xff0c;那就具体看看吧&am…

IDEA服务启动时无法输出日志

起服务时&#xff0c;控制台啥日志也没有 解决方案&#xff1a;选择【启用调试输出】 SQL的日志无法打印 原来安装了一个Mybatis Log Free&#xff0c;用的好好的。 后来换了个项目&#xff0c;SQL执行日志就打印不出来了。 解决方案&#xff1a;换个插件&#xff0c;我换了…

Python语言把二进制转成十六进制

0 Preface/Foreword 0.1 10进制转其他进制 bin()oct()hex() 0.2 其他进制转10进制 int(, 2)int(, 8)int(, 16) 1 转换方法 1.1 方法1 先将二进制转成10进制&#xff0c;再将10进制转成16进制 decim int(00000101, 2) hexadecim hex(decim) print hexadecim 1.2 方法…

Snap AR眼镜Spectacles的技术揭秘:通往真正AR体验的道路

Snap公司自2010年成立以来&#xff0c;一直致力于探索增强现实&#xff08;AR&#xff09;技术的边界。经过多年的研发与迭代&#xff0c;Snap终于在最新一代Spectacles中实现了重大突破&#xff0c;为用户带来了前所未有的沉浸式AR体验。本文将深入探讨Spectacles的发展历程、…

【vue3】登录功能怎么实现?

无论是手机端还是pc端&#xff0c;几乎都包含登录注册方面功能&#xff0c;今天总结登录注册功能。 实现功能 注册 密码加密 登录 校验 token处理 1.环境搭建运行&#xff08;nodeexpressmongodb&#xff09; 在目录里安装express和mongoose&#xff0c;并在根目录创建server.j…

C语言编译和链接详解(通俗易懂,深入本质)

我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。在 Windows 下,可执行程序的后缀有.exe和.com(其中.exe比较常见);在类 UNIX 系统(Linux、Mac OS 等)下,可执行程序没有特定的后缀,系统根据文件的头部信息来判…

YOLOv8改进 - 注意力篇 - 引入SK网络注意力机制

一、本文介绍 作为入门性篇章&#xff0c;这里介绍了SK网络注意力在YOLOv8中的使用。包含SK原理分析&#xff0c;SK的代码、SK的使用方法、以及添加以后的yaml文件及运行记录。 二、SK原理分析 SK官方论文地址&#xff1a;SK注意力文章 SK注意力机制:SK网络中的神经元可以捕…

音视频通话 SDK

腾讯云视立方音视频通话 SDK 是音视频终端 SDK&#xff08;腾讯云视立方&#xff09;的子产品 SDK 之一&#xff0c;基于音视频通话场景&#xff0c;提供专属含 UI 快速接入方案&#xff0c;仅需三步即可快速集成上线&#xff0c;轻松实现1对1视频聊天、多人视频通话和聊天应用…

内网基础知识

内网基础知识 寄了&#xff0c;最后net time /domain命令还是运行不了 内网也指局域网(Local Area Network&#xff0c;LAN)&#xff0c;是指在某一区域内由多台计算机互连而成的计算机组&#xff0c;组网范围通常在数千米以内。 工作组 work group 一种资源管理模式&#…

[SAP ABAP] PARAMETERS

PARAMETERS定义用户可以输入值的输入字段(单值Input) 基本语法 PARAMETERS PNAME. PNAME命名长度不能超过8位 PARAMETERS创建一个单一的输入域且最多只能输入一行&#xff0c;定义后的PNAME可作为变量在程序中运用 示例1 p_1的数据类型为CHAR1 输出结果&#xff1a; 补…