C语言使用void *类型作为函数传参

C语言使用void *怎么理解:

根据本人的理解,他就是指向操作数据区的首地址而已

凡是void指的数据区都要进行第二次初始化数据类型(即dtype p=(dtype)pdata)*。
举两个例子:

传入函数:

void tx_data(void *pdata)
{int* p=(int*)pdata;//第二次初始化//接下来对p操作}

传出函数:

static int data
void* rx_data(void )
{return &data;
}
//使用void *
int* p=(int*)rx_data();  //第二次初始化
//接下来对p操作

隐藏数据类型使用void*,就是这么简单,不要跟什么抽象挂钩,什么无类型就是任意类型,这种理解都是错的,完全是愚弄人
用void的好处:
1.隐藏数据类型,传参让别人不知传的啥,有保密的作用
2.隐藏数据类型,象元编程一样,等数据传过来再识别,再操作,可以简化代码,让代码输入量抽象起来,
3.隐藏数据类型,等数据传过来再识别,再操作,方便给用户堆代码,象linux操作系统的驱动程序都是用void
来给你堆
代码,这样可以让有限的代码转换无限的经济价值
4.隐藏数据类型,你在做各种通讯收发程序时,代码可以重用度高,修改方便,上面的int换成多个stuct的拼接嵌套就可以写出很复杂的程序

后面搞一简单的练兵,void*是随你写程序的功力对他的认识逐步提升的,菜鸟不用急,不积跬步无以至千里

典型的如内存操作函数memcpy和memset的函数原型分别为:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。如果memcpy和memset的参数类型不是void *,而是char *,那才叫真的奇怪了!这样的memcpy和memset明显不是一个“纯粹的,脱离低级趣味的”函数!

下面的代码执行正确

memset接受任意类型指针

int intarray[100];
memset ( intarray, 0, 100*sizeof(int) ); //隐藏数据类型byte的字节操作 第二次初始化

memcpy接受任意类型指针

int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof(int) ); //隐藏数据类型byte的字节操作 第二次初始化

使用枚举定义隐藏数据类型

enum datatype{//枚举出来的都是常量,首字母大写,且作用域为整个main函数_Char,_CharArr,_Int,_Float
};
//使用结构体定义一些数据
struct demo{char a;char stringArray[100];int number;float score;}DEMO;//使用枚举定义数据结构体数据类型长度
enum datalegth{//此处为了方便观察就不使用首字母大写_aLEN = sizeof(char),_stringArrayLEN = 20 * sizeof(char),_numberLEN = sizeof(int),_floatLEN = sizeof(float)
};

测试函数声明

int test(void *data,enum datatype type,int datalength);

测试函数实现

int test(void *data,enum datatype type,int datalength){switch(type){//第二次初始化case _Char:{//char *convertData = (char *)malloc(sizeof(char *));//_Char:后面接的是完整语句,不能出现声明,有两种解决办法,一种是在冒号后加分号,但这里是switch中,需要用大括号括起来(代码块,听说源于lisp)char *convertData = data;//将void *类型赋值给 char *类型char char1 = *convertData;printf("its a char: %c\n",char1);// free(convertData);break;}case _CharArr:{char *convertData = data;char charArr[datalength];strcpy(charArr,convertData);printf("its a string :%s\n",charArr);break;}case _Int:{int *number = data;printf("its a number:%d\n",*number);break;}case _Float:{float *convertData = data;printf("its a float:%f\n",*convertData);break;}}return 0;//为了便于添加功能,这里暂时留着
}

结构体变量赋值

DEMO.a = 'A';strcpy(DEMO.stringArray,"this is DEMO string variable");//strcpy有一个问题,只管复制进去的,但之前结构体中数组并未初始化可能导致后续//字符出现"粘连"如ble后面不是\0,而是之前堆栈弃用的内存空间的一些垃圾值// DEMO.array = "this is DEMO struct variable";//数组只有在初始化时才能这样赋值,之后通过遍历写入,或者strcpy进去DEMO.number = 88;DEMO.score = 100.0;
//使用结构体指针
struct demo *pDemo = NULL;//指针需要初始化,否则随机指向不可读写的内存区域,后续无法修改指针变量。
pDemo = &DEMO;
//函数调用
test(&(pDemo->a),_Char,_aLEN);  第二次初始化
test(&(pDemo->stringArray),_CharArr,_stringArrayLEN);
test(&(pDemo->number),_Int,_numberLEN);
test(&(pDemo->score),_Float,_floatLEN);
最终代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>enum datatype{//枚举出来的都是常量,首字母大写,且作用域为整个main函数_Char,_CharArr,_Int,_Float
};enum datalegth{//此处为了方便观察就不使用首字母大写_aLEN = sizeof(char),_stringArrayLEN = 100 * sizeof(char),_numberLEN = sizeof(int),_floatLEN = sizeof(float)
};int test(void *data,enum datatype type,int datalength);int main(int argc,char const argv[]){struct demo{char a;char stringArray[100];int number;float score;}DEMO;DEMO.a = 'A';strcpy(DEMO.stringArray,"this is DEMO string variable");//strcpy有一个问题,只管复制进去的,但之前结构体中数组并未初始化可能导致后续的字符出现"粘连"如ble后面不是\0,而是之前堆栈弃用的内存空间的一些垃圾值// DEMO.array = "this is DEMO struct variable";//数组只有在初始化时才能这样赋值,之后通过遍历写入,或者strcpy进去DEMO.number = 88;DEMO.score = 100.0;struct demo *pDemo = NULL;//指针需要初始化,否则随机指向不可读写的内存区域,后续无法修改指针变量。int length = sizeof(struct demo *);//结构体指针大小printf("length is %d\n",length);// pDemo = (struct demo *)malloc(sizeof(struct demo *));// if(pDemo == NULL) printf("分配内存失败!\n");//如果未分配内存     //malloc是分配内存块,C语言的变量名,函数名皆为符号,符号不占用空间,所以将通过malloc获取的内存空间,赋值给指针,实质上是赋值该内存块的首地址给指针,malloc有一个特性,不会将分配的内存块上的数据擦洗掉!!pDemo = &DEMO;printf("-------\n");test(&(pDemo->a),_Char,_aLEN);test(&(pDemo->stringArray),_CharArr,_stringArrayLEN);test(&(pDemo->number),_Int,_numberLEN);test(&(pDemo->score),_Float,_floatLEN);// free(pDemo);puts("finished prosess");return 0;
}int test(void *data,enum datatype type,int datalength){switch(type){//第二次初始化case _Char:{//char *convertData = (char *)malloc(sizeof(char *));//_Char:后面接的是完整语句,不能出现声明,有两种解决办法,一种是在冒号后加分号,但这里是switch中,需要用大括号括起来(代码块,听说源于lisp)char *convertData = data;//将void *类型赋值给 char *类型char char1 = *convertData;printf("its a char: %c\n",char1);// free(convertData);break;}case _CharArr:{char *convertData = data;char charArr[datalength];strcpy(charArr,convertData);printf("its a string :%s\n",charArr);break;}case _Int:{int *number = data;printf("its a number:%d\n",*number);break;}case _Float:{float *convertData = data;printf("its a float:%f\n",*convertData);break;}}return 0;//为了便于添加功能,这里暂时留着
}

简单的void* 返回int* 类型的函数和一个返回char* 类型的函数

#include <stdlib.h>
#include <stdio.h>
void reInt(int);
void* reIntp(int*);
void* reChar(char*);
int main()
{int num=10;int *nump;char str[10]="CSDN";char* strp;reInt(num);nump = (int*) reIntp(&num); //强制类型转化不能忘!隐藏数据类型  第二次初始化strp = (char*)reChar(str); //强制类型转化不能忘! 隐藏数据类型  第二次初始化printf("主函数输出:%d\n",*nump);printf("主函数输出:%s\n",strp);return 0;
}
//一般返回类型的函数
void reInt(int a)
{printf("void返回类型的函数的输出:%d\n",a);return; // 没有返回值
}
//void*返回类型的函数 返回int*
void* reIntp(int *a)
{printf("void*返回类型返回int*的函数的输出:%d\n", *a);return a; // 返回 int *隐藏数据类型
}
//void*返回类型的函数 返回char*
void* reChar(char* str)
{printf("void*返回类型返回char*的函数的输出:%s\n",str);return str;隐藏数据类型
}

void*函数的返回值类型struct

struct MyStruct {int a;char b;double c;
};void* get_struct() {struct MyStruct* s = malloc(sizeof(struct MyStruct));s->a = 1;s->b = 'b';s->c = 3.0;return s;
}int main() {struct MyStruct* s = (struct MyStruct*)get_struct();  第二次初始化printf("a: %d, b: %c, c: %f\n", s->a, s->b, s->c);free(s);return 0;
}

创作不容易,如果对您有帮助,请多打赏!!!!

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

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

相关文章

Sparse4D v3: Advancing End-to-End 3D Detection and Tracking

Sparse4D v3: Advancing End-to-End 3D Detection and Tracking 相关内容&#xff1a;总览&#xff0c;Sparse4D v1&#xff0c;Sparse4D v2&#xff0c; 单位&#xff1a;地平线(Sparse4D v1 v2 原班人马) GitHub&#xff1a;https://github.com/HorizonRobotics/Sparse4D …

昇思25天学习打卡营第5天 | 网络构建

目录 1.定义模型类 2.模型层 nn.Flatten nn.Dense nn.ReLU nn.SequentialCell nn.Softmax 3.模型参数 代码实现&#xff1a; 总结 神经网络模型是由神经网络层和Tensor操作构成的&#xff0c; mindspore.nn提供了常见神经网络层的实现&#xff0c; 在MindSpore中&a…

启动spring boot项目停止 提示80端口已经被占用

可能的情况: 检查并结束占用进程: 首先,你需要确定哪个进程正在使用80端口。在Windows上,可以通过命令行输入netstat -ano | findstr LISTENING | findstr :80来查看80端口的PID,然后在任务管理器中结束该进程。在

AI智能客服项目拆解(1) 产品大纲

本文作为拆解AI智能客服项目的首篇&#xff0c;以介绍产品大纲为主。后续以某AI智能客服产品为例&#xff0c;拆解相关技术细节。 AI智能客服是一种基于人工智能技术的客户服务解决方案&#xff0c;旨在提高客户满意度和优化企业运营。利用人工智能和自然语言处理技术&#xff…

MySQL之索引失效的情况

什么情况下索引会失效&#xff1f; 违反最左前缀原则范围查询右边的列不能使用索引不要在索引列上进行运算操作字符串不加单引号导致索引失效以%开头的like模糊查询 什么情况下索引会失效&#xff1f; 示例&#xff0c;有user表如下 CREATE TABLE user (id bigint(20) NOT NU…

实验1 多层感知器设计(MLP)

1.实验目的 掌握多层感知器的原理。掌握多层感知器的设计、训练和测试。2.实验要求 设计一个多层感知器,用于对给定的数据进行分类。要求代码格式规范,注释齐全,程序可正常运行。 3.模型设计 实验设计一个多层感知机,三层机构,只含一个隐藏层,输入层,隐藏层,输出层 1…

JAVA期末速成库(11)第十二章

一、习题介绍 第十二章 Check Point&#xff1a;P454 12.1&#xff0c;12.9&#xff0c;12.10&#xff0c;12,12 二、习题及答案 12.1 What is the advantage of using exception handling? 12.1使用异常处理的优势是什么? 答:使用异常处理有以下优势&#xff1a; 1. 提高…

C++ 模板类的示例-数组

类模板可以有非通用类型参数&#xff1a;1&#xff09;通常是整型&#xff08;C20标准可以用其它的类型&#xff09;&#xff1b;2&#xff09;实例化模板时必须用常量表达式&#xff1b;3&#xff09;模板中不能修改参数的值&#xff1b;4&#xff09;可以为非通用类型参数提供…

Android中使用performClick触发点击事件

Android中使用performClick触发点击事件 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨在Android开发中如何使用 performClick() 方法来触发点击…

数据库-python SQLite3

数据库-python SQLite3 一&#xff1a;sqlite3 简介二: sqlite3 流程1> demo2> sqlite3 流程 三&#xff1a;sqlite3 step1> create table2> insert into3> update4> select1. fetchall()2. fetchone()3. fetchmany() 5> delete6> other step 四&#…

Spark join数据倾斜调优

Spark中常见的两种数据倾斜现象如下 stage部分task执行特别慢 一般情况下是某个task处理的数据量远大于其他task处理的数据量&#xff0c;当然也不排除是程序代码没有冗余&#xff0c;异常数据导致程序运行异常。 作业重试多次某几个task总会失败 常见的退出码143、53、137…

【电路笔记】-放大器类型

放大器类型 文章目录 放大器类型1、概述2、关于偏置的注意事项3、A类(Class A)放大器4、B类(Class B)放大器5、AB类(Class AB)放大器6、C类(Class C)放大器7、总结1、概述 放大器通常根据输出级的结构进行分类。 事实上,功率放大确实发生在该阶段,因此输出信号的质量和…

Arduino (esp ) 下String的内存释放

在个人的开源项目 GitHub - StarCompute/tftziku: 这是一个通过单片机在各种屏幕上显示中文的解决方案 中为了方便快速检索使用了string&#xff0c;于是这个string在esp8266中占了40多k,原本以为当string设置为""的时候这个40k就可以回收&#xff0c;结果发觉不行…

【JS异步编程】async/await——用同步代码写异步

历史小剧场 懂得暴力的人&#xff0c;是强壮的&#xff1b;懂得克制暴力的人&#xff0c;才是强大的。----《明朝那些事儿》 什么是 async/await async: 声明一个异步函数 自动将常规函数转换成Promise&#xff0c;返回值也是一个Promise对象&#xff1b;只有async函数内部的异…

Java SE入门及基础(59) 线程的实现(上) 线程的创建方式 线程内存模型 线程安全

目录 线程&#xff08;上&#xff09; 1. 线程的创建方式 Thread类常用构造方法 Thread类常用成员方法 Thread类常用静态方法 示例 总结 2. 线程内存模型 3.线程安全 案例 代码实现 执行结果 线程&#xff08;上&#xff09; 1. 线程的创建方式 An application t…

利用 Docker 简化 Nacos 部署:快速搭建 Nacos 服务

利用 Docker 简化 Nacos 部署&#xff1a;快速搭建 Nacos 服务 引言 在微服务架构中&#xff0c;服务注册与发现是确保服务间通信顺畅的关键组件。Nacos&#xff08;Dynamic Naming and Configuration Service&#xff09;作为阿里巴巴开源的一个服务发现和配置管理平台&…

任务调度器——任务切换

一、开启任务调度器 函数原型&#xff1a; void vTaskStartScheduler( void ) 作用&#xff1a;用于启动任务调度器&#xff0c;任务调度器启动后&#xff0c; FreeRTOS 便会开始进行任务调度 内部实现机制&#xff08;以动态创建为例&#xff09;&#xff1a; &#xff0…

Linux 安装、配置Tomcat 的HTTPS

Linux 安装 、配置Tomcat的HTTPS 安装Tomcat 这里选择的是 tomcat 10.X ,需要Java 11及更高版本 下载页 ->Binary Distributions ->Core->选择 tar.gz包 下载、上传到内网服务器 /opt 目录tar -xzf 解压将解压的根目录改名为 tomat-10 并移动到 /opt 下, 形成个人…

测评推荐:企业管理u盘的软件有哪些?

U盘作为一种便携的存储设备&#xff0c;方便易用&#xff0c;被广泛应用于企业办公、个人学习及日常工作中。然而&#xff0c;U盘的使用也带来了数据泄露、病毒传播等安全隐患。为了解决这些问题&#xff0c;企业管理U盘的软件应运而生。 本文将对市面上流行的几款U盘管理软件…

Hadoop3:Yarn容量调度器配置多队列案例

一、情景描述 需求1&#xff1a; default队列占总内存的40%&#xff0c;最大资源容量占总资源60%&#xff0c;hive队列占总内存的60%&#xff0c;最大资源容量占总资源80%。 二、多队列优点 &#xff08;1&#xff09;因为担心员工不小心&#xff0c;写递归死循环代码&#…