当前位置: 首页 > article >正文

C语言中的泛型尝试:void_ + 函数指针

文章目录C语言中的泛型尝试void* 函数指针 什么是泛型C语言中的工具void* 和函数指针 ️代码示例泛型排序函数 进阶示例泛型链表 优缺点分析 ⚖️优点缺点总结 C语言中的泛型尝试void* 函数指针 在编程世界中泛型Generic Programming是一种强大的技术它允许我们编写与数据类型无关的代码从而提高代码的复用性和灵活性。虽然C语言本身并不像C或Java那样直接支持泛型但通过巧妙地使用void*指针和函数指针我们可以在C中实现类似的泛型效果。这篇博客将深入探讨这一技术通过代码示例、图表和外部资源链接帮助你理解和应用这一概念。什么是泛型泛型编程的核心思想是编写可以处理多种数据类型的代码而无需为每种类型重写逻辑。例如一个排序算法应该能够排序整数数组、浮点数数组或字符串数组而不需要为每种类型编写单独的排序函数。在高级语言中这通常通过模板或泛型类型系统实现但在C语言中我们需要依赖一些底层机制来模拟这种行为。外部参考如果你想了解更多关于泛型编程的理论可以查看泛型编程 - Wikipedia页面它提供了全面的背景信息。C语言中的工具void* 和函数指针 ️在C语言中void*是一种通用指针类型它可以指向任何数据类型的数据。这为我们提供了类型无关的存储和传递数据的能力。然而void*本身并不包含类型信息因此我们需要额外的机制来处理数据。这就是函数指针的用武之地通过传递特定的处理函数如比较函数或打印函数我们可以实现对不同数据类型的操作。结合void*和函数指针我们可以创建泛型数据结构如链表、队列或排序函数这些结构可以处理任意类型的数据只要提供适当的操作函数。下面是一个简单的mermaid图表展示了这种泛型方法的基本工作流程定义泛型函数使用void*参数接收数据传递函数指针用于具体操作在函数内部调用函数指针处理数据实现类型无关的逻辑这种模式在C标准库中也很常见例如在qsort函数中它使用void*和比较函数指针来实现泛型排序。代码示例泛型排序函数 让我们通过一个示例来演示如何实现一个简单的泛型排序函数。这里我将展示一个使用冒泡排序算法的泛型版本它可以排序任何类型的数组只要提供一个比较函数。首先定义我们的泛型排序函数。它接受一个void*数组实际上是void**因为我们需要处理数组中的每个元素、数组大小、元素大小以及一个比较函数指针。#includestdio.h#includestring.h// 比较函数指针类型定义typedefint(*CompareFunc)(constvoid*,constvoid*);// 泛型冒泡排序函数voidgeneric_bubble_sort(void*array,size_tcount,size_tsize,CompareFunc comp){for(size_ti0;icount-1;i){for(size_tj0;jcount-i-1;j){// 计算当前元素和下一个元素的地址void*current(char*)arrayj*size;void*next(char*)array(j1)*size;// 使用提供的比较函数进行比较if(comp(current,next)0){// 交换元素使用临时存储进行字节级交换chartemp[size];memcpy(temp,current,size);memcpy(current,next,size);memcpy(next,temp,size);}}}}// 示例比较函数用于整数intcompare_int(constvoid*a,constvoid*b){return(*(int*)a-*(int*)b);}// 示例比较函数用于浮点数intcompare_float(constvoid*a,constvoid*b){floatfa*(float*)a,fb*(float*)b;return(fafb)-(fafb);// 安全比较避免精度问题}intmain(){// 测试整数数组intint_array[]{5,2,8,1,9};size_tint_countsizeof(int_array)/sizeof(int_array[0]);generic_bubble_sort(int_array,int_count,sizeof(int),compare_int);printf(Sorted integers: );for(size_ti0;iint_count;i){printf(%d ,int_array[i]);}printf(\n);// 测试浮点数数组floatfloat_array[]{3.14f,1.59f,2.65f,0.0f};size_tfloat_countsizeof(float_array)/sizeof(float_array[0]);generic_bubble_sort(float_array,float_count,sizeof(float),compare_float);printf(Sorted floats: );for(size_ti0;ifloat_count;i){printf(%.2f ,float_array[i]);}printf(\n);return0;}在这个示例中generic_bubble_sort函数通过void*接收数组并使用memcpy进行字节级的交换从而避免了对具体类型的依赖。比较函数由用户提供这使得排序逻辑完全泛型。外部参考如果你想深入了解C语言中的函数指针和void*GeeksforGeeks上的这篇教程提供了详细的解释和示例。进阶示例泛型链表 为了进一步展示泛型编程在C中的潜力让我们实现一个简单的泛型链表。这个链表可以存储任何类型的数据通过void*和函数指针来处理数据。首先定义链表节点和结构#includestdio.h#includestdlib.h#includestring.h// 链表节点结构typedefstructNode{void*data;// 泛型数据指针structNode*next;// 指向下一个节点}Node;// 链表结构typedefstruct{Node*head;size_tsize;}LinkedList;// 初始化链表voidlist_init(LinkedList*list){list-headNULL;list-size0;}// 向链表添加元素voidlist_append(LinkedList*list,void*data,size_tdata_size){Node*new_node(Node*)malloc(sizeof(Node));new_node-datamalloc(data_size);memcpy(new_node-data,data,data_size);// 复制数据new_node-nextNULL;if(list-headNULL){list-headnew_node;}else{Node*currentlist-head;while(current-next!NULL){currentcurrent-next;}current-nextnew_node;}list-size;}// 打印链表需要用户提供打印函数voidlist_print(LinkedList*list,void(*print_func)(constvoid*)){Node*currentlist-head;while(current!NULL){print_func(current-data);currentcurrent-next;}printf(\n);}// 释放链表内存需要用户提供免费函数如果数据是动态分配的voidlist_free(LinkedList*list,void(*free_func)(void*)){Node*currentlist-head;while(current!NULL){Node*nextcurrent-next;if(free_func!NULL){free_func(current-data);// 用户提供的免费函数}free(current);currentnext;}list-headNULL;list-size0;}// 示例打印函数用于整数voidprint_int(constvoid*data){printf(%d ,*(int*)data);}// 示例打印函数用于字符串voidprint_string(constvoid*data){printf(%s ,(char*)data);}intmain(){LinkedList int_list;list_init(int_list);// 添加整数inta10,b20,c5;list_append(int_list,a,sizeof(int));list_append(int_list,b,sizeof(int));list_append(int_list,c,sizeof(int));printf(Integer list: );list_print(int_list,print_int);// 不需要免费函数因为整数是栈分配的list_free(int_list,NULL);// 测试字符串链表LinkedList str_list;list_init(str_list);char*str1Hello;char*str2World;char*str3Generic;list_append(str_list,str1,sizeof(char*));list_append(str_list,str2,sizeof(char*));list_append(str_list,str3,sizeof(char*));printf(String list: );list_print(str_list,print_string);// 字符串是字面量不需要免费但如果是动态分配应提供免费函数list_free(str_list,NULL);return0;}这个泛型链表通过void*存储数据并通过用户提供的函数如print_func来处理数据。这展示了如何构建可重用的数据结构适应各种数据类型。注意在使用泛型数据结构时内存管理需要谨慎。如果数据是动态分配的用户必须提供适当的免费函数以避免内存泄漏。优缺点分析 ⚖️使用void*和函数指针实现泛型在C语言中既有优点也有缺点。优点灵活性可以编写与类型无关的代码提高复用性。标准库兼容许多C标准库函数如qsort和bsearch使用类似模式易于集成。低开销相对于高级语言的泛型实现这种方法通常更轻量级没有额外的运行时类型信息。缺点类型安全由于使用void*编译时类型检查较弱容易引入错误如错误转换类型。代码可读性代码可能变得复杂尤其是涉及多层函数指针时。性能函数指针调用可能比直接函数调用稍慢但通常可忽略。外部参考关于C语言泛型的最佳实践和陷阱Cprogramming.com的这篇文章提供了有用的建议。总结 通过void*和函数指针C语言程序员可以实现强大的泛型编程模式从而编写灵活、可复用的代码。虽然这种方法需要手动管理类型安全和内存但它提供了在低级语言中实现高级功能的途径。无论是排序函数、数据结构还是算法这种技术都能帮助你构建更加通用的解决方案。在实践中始终记得测试你的泛型代码 with 多种数据类型并提供清晰的文档说明如何使用函数指针。这样你就能充分利用C语言的潜力写出既高效又灵活的代码。如果你对C语言的泛型感兴趣可以继续探索更高级的主题如宏-based 泛型或使用_Generic关键字C11标准这些都能进一步扩展你的工具箱。Happy coding!

相关文章:

C语言中的泛型尝试:void_ + 函数指针

文章目录C语言中的泛型尝试:void* 函数指针 🧪什么是泛型?🤔C语言中的工具:void* 和函数指针 🛠️代码示例:泛型排序函数 📝进阶示例:泛型链表 📚优缺点分析…...

服务器Docker容器使用

0.基础指令 # 查看容器 docker ps docker images1.删除旧容器 docker rm -f novnc-test 2>/dev/null2.删除旧镜像 docker rmi ubuntu-novnc-vnc:22.04 2>/dev/null3.确认删除情况 docker ps -a | grep novnc-test docker images | grep ubuntu-novnc-vnc4.重新加载镜像 c…...

使用开源 Authentik 实现 AWS 单点登录

前言 懒得自己编了, Gemini 这样介绍 Authentik: 简单来说,Authentik 是一款功能极其强大的开源身份验证与访问管理 (IAM) 解决方案。 如果你觉得像 Okta 或 Auth0 这种商业服务太贵,或者觉得像 Keycloak 这种传统方案配置起来太头疼,那么…...

袁永福 电子病历,医疗信息化际

在AI辅助开发的语境下,Skill就是一个包含了领域知识、最佳实践、代码模板的知识包。 以"DAO层CRUD生成"为例,一个Skill包含: /mnt/skills/dao-crud/ ├── SKILL.md # 使用说明 │ ├── 何时使用这个Skill │ …...

算法优化中的多线程数据一致性问题的技术9

多线程数据一致性问题概述多线程环境下,数据一致性是算法优化中常见的技术挑战。多个线程同时访问和修改共享数据可能导致竞态条件、脏读或不可重复读等问题。确保数据一致性对算法正确性和性能至关重要。常见数据一致性问题类型竞态条件(Race Condition…...

BM25(Best Matching 25)信息检索

文章目录一、BM25本质在做什么二、核心思想(直观理解)1️⃣ 词出现次数(Term Frequency, TF)2️⃣ 词的稀有程度(IDF)3️⃣ 文档长度归一化三、BM25公式(核心)这是标准BM25打分函数&…...

AI 编程盛行的时代,为什么 “『DC- WFW』” 仍然具有必要性?沼

这&#xff0c;是一个采用C精灵库编写的程序&#xff0c;它画了一幅漂亮的图形&#xff1a; 复制代码 #include "sprites.h" //包含C精灵库 Sprite turtle; //建立角色叫turtle void draw(int d){for(int i0;i<5;i)turtle.fd(d).left(72); } int main(){ …...

算法的能耗模型与绿色计算优化方向的技术4

能耗模型基础理论算法复杂度与能耗关系时间复杂度与空间复杂度对硬件资源消耗的影响&#xff0c;建立数学模型描述指令执行次数、数据访问频率与能耗的关联。硬件层面的能耗因素CPU动态功耗&#xff08;CVf&#xff09;、静态功耗、内存访问能耗、缓存命中率等关键参数&#xf…...

3步解决浏览器Markdown阅读难题:从乱码到专业渲染的蜕变之路

3步解决浏览器Markdown阅读难题&#xff1a;从乱码到专业渲染的蜕变之路 【免费下载链接】markdown-viewer Markdown Viewer / Browser Extension 项目地址: https://gitcode.com/gh_mirrors/ma/markdown-viewer 你是否遇到过这样的窘境&#xff1a;在浏览器中打开本地M…...

Docker 容器中运行 AI CLI 工具:用户隔离与持久化卷实战指南暗

环境安装 pip install keystone-engine capstone unicorn 这3个工具用法极其简单&#xff0c;下面通过示例来演示其用法。 Keystone 示例 from keystone import * CODE b"INC ECX; ADD EDX, ECX" try:ks Ks(KS_ARCH_X86, KS_MODE_64)encoding, count ks.asm(CODE)…...

电子电路中的“心脏”:电源铝

前言 Kubernetes 本身并不复杂&#xff0c;是我们把它搞复杂的。无论是刻意为之还是那种虽然出于好意却将优雅的原语堆砌成 鲁布戈德堡机械 的狂热。平台最初提供的 ReplicaSets、Services、ConfigMaps&#xff0c;这些基础组件简单直接&#xff0c;甚至显得有些枯燥。但后来我…...

如何永久保存微信聊天记录:WeChatMsg本地数据备份完整指南

如何永久保存微信聊天记录&#xff1a;WeChatMsg本地数据备份完整指南 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/W…...

第十五节:启动序列——从 claude 命令到 REPL 就绪

知识图谱定位:前面两节我们分别拆解了终端 UI(第13节 React Ink)和命令系统(第14节 斜杠路由)——它们都假设一个前提:REPL 已经就绪。但从用户在终端敲下 claude 按回车,到他看到交互界面,这中间到底发生了什么?答案是一个精心设计的三阶段启动序列:cli.tsx::main()…...

贾子科学的历史意义与现实影响:挑战西方科学哲学霸权的新范式

贾子科学的历史意义与现实影响&#xff1a;挑战西方科学哲学霸权的新范式摘要&#xff1a; 贾子科学是贾龙栋于2025-2026年提出的原创科学哲学体系&#xff0c;其历史意义在于直接挑战以波普尔证伪主义为核心的西方科学划界标准&#xff0c;提出“公理驱动可结构化”新标尺&…...

Vitest单元测试教程

Vitest 是 Vite 生态的极速单元测试框架&#xff0c;API 兼容 Jest&#xff0c;上手快、配置简单、性能极高。下面从 安装 → 配置 → 编写测试 → 常用断言 → Mock → 组件测试 → 运行与覆盖率 完整流程带你上手。一、安装 1. 基础安装 npm i -D vitest # 或 yarn add -D vi…...

Jenkins 学习总结腋

先唠两句&#xff1a;参数就像餐厅点单 把API想象成一家餐厅的“后厨系统”。 ? 路径参数/dishes/{dish_id} -> 好比你要点“宫保鸡丁”这道具体的菜&#xff0c;它是菜单&#xff08;资源路径&#xff09;的一部分。查询参数/dishes?spicytrue&typeSichuan -> 好比…...

2025届学术党必备的十大AI科研平台横评

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 人工智能本领在学术写作范畴的运用越来越普遍&#xff0c;它的关键价值是协助科研者达成文献…...

ARM 架构 JuiceFS 性能优化:基于 MLPerf 的实践与调优死

Qt是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本笔记将重点介绍QSpinBox数值微调组件的常用方法及灵活应用。…...

OpenClaw 太难装了?试试 LangTARS:一行命令部署 + WebUI 管理面板,还能接入 Dify/Coze/nn??悠

1. 什么是 Apache SeaTunnel&#xff1f; Apache SeaTunnel 是一个非常易于使用、高性能、支持实时流式和离线批处理的海量数据集成平台。它的目标是解决常见的数据集成问题&#xff0c;如数据源多样性、同步场景复杂性以及资源消耗高的问题。 核心特性 丰富的数据源支持&#…...

PHP AI校验配置被低估的致命细节(内存泄漏触发点、AST解析偏差、Token限流阈值)——资深SRE连夜重写配置手册

第一章&#xff1a;PHP AI校验配置的全局认知与风险图谱PHP AI校验配置并非孤立的技术模块&#xff0c;而是横跨应用层、中间件、模型服务与基础设施的复合型安全控制面。其核心目标是在AI能力注入业务流程的同时&#xff0c;确保输入合法性、输出可控性、行为可审计及策略可收…...

嵌入式进阶——MCU启动与代码执行教程

MCU启动与代码执行教程 1. 简介 本教程旨在帮助理解&#xff0c;深入剖析ARM Cortex-M系列单片机上电后的完整启动流程&#xff0c;以及程序在Flash、RAM、寄存器三者的协同执行机制。基于STM32等典型MCU&#xff0c;从硬件复位瞬间开始&#xff0c;逐步讲解向量表加载、Reset_…...

学Simulink——基于Simulink的坡道起步防溜坡电机转矩控制

目录 手把手教你学Simulink ——基于Simulink的坡道起步防溜坡电机转矩控制 一、问题背景 二、系统架构与控制逻辑 1. 控制层级 2. 防溜坡转矩需求 三、无传感器坡度估计方法 方法:基于加速度计 + 车速微分 Simulink 实现 四、防溜坡转矩控制器设计 1. 基础转矩规划…...

基于yolov8和faster-rcnn的电动车戴头盔检测,界面可选择模型,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测、图像分类识别、目标追踪、图像分割、图像检索等项目可看我主页其他文章 功能演示&#xff08;看shi pin 下面的简介&#xff09;&#xff1a; https://www.bilibili.com/video/BV1DWXrBaE3Z/?spm_id_from333.1387.homepage.video_card.click&vd_source23c…...

打卡信奥刷题(3078)用C++实现信奥题 P7033 [NWRRC 2016] CodeCoder vs TopForces

P7033 [NWRRC 2016] CodeCoder vs TopForces 题目描述 在 Byteland&#xff0c;竞赛编程非常流行。事实上&#xff0c;每位 Byteland 的公民都在两个编程网站——CodeCoder 和 TopForces 上注册。每个网站都有自己专有的评分系统。每位公民在每个网站上都有一个唯一的整数评分&…...

打卡信奥刷题(3077)用C++实现信奥题 P7023 [NWRRC 2017] Equal Numbers

P7023 [NWRRC 2017] Equal Numbers 题目描述 给定一个包含 nnn 个整数 a1,…,ana_{1}, \ldots, a_{n}a1​,…,an​ 的列表。你可以执行以下操作&#xff1a;选择某个 aia_{i}ai​ 并将其乘以任意正整数。 你的任务是计算在进行 kkk 次操作后列表中可能出现的不同整数的最小数…...

法国Hornetsecurity联合里尔大学:如何让人工智能学会保护隐私

这项由法国Hornetsecurity公司与里尔大学、法国国家信息与自动化研究院(Inria)、法国国家科学研究中心(CNRS)以及里尔中央理工学院联合开展的研究&#xff0c;发表于2026年3月31日的计算机科学期刊&#xff0c;论文编号为arXiv:2603.29497v1。有兴趣深入了解的读者可以通过这个…...

SAP MM | 物料主数据:为什么修改了“特殊采购类型”但在 MM04 查不到修改历史?

在 SAP 物料主数据&#xff08;Material Master&#xff09;的操作中&#xff0c;用户有时会修改 “特殊采购类型”&#xff08;SOBSL&#xff09;&#xff0c;比如从“厂内生产”改为“从其他工厂调拨&#xff08;40&#xff09;”。但用户说&#xff0c;修改了主数据之后&…...

容器化网络与Kubernetes网络深度解析

一、Docker网络基础 Docker四大网络驱动 Driver 1: Bridge (默认) ┌────────────────────────────────┐ │ Docker主机 │ │ │ │ ┌─────────────┐ ┌──────────┐ │ │ │ Container A │ │ Bridge │ │ │…...

Shell流程控制(if-else、循环,实现复杂逻辑)

在Linux/Unix系统中&#xff0c;Shell脚本是自动化运维、批量处理任务的核心工具&#xff0c;而流程控制则是让脚本“摆脱线性执行”、实现灵活逻辑的关键。无论是简单的条件判断&#xff08;如“文件是否存在”&#xff09;&#xff0c;还是复杂的批量操作&#xff08;如“遍历…...

Shell通配符与正则表达式(批量匹配,精准筛选)

在Linux Shell运维、脚本开发中&#xff0c;“匹配”是高频操作——批量处理文件、筛选日志内容、定位目标数据&#xff0c;都离不开高效的匹配工具。而Shell通配符与正则表达式&#xff0c;正是支撑这些操作的核心技术。很多初学者容易混淆二者&#xff0c;误以为它们是“同一…...