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.mfbz.cn/a/778469.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

html+css+js图片手动轮播

源代码在界面图片后面 轮播演示用的几张图片是Bing上的&#xff0c;直接用的几张图片的URL&#xff0c;谁加载可能需要等一下&#xff0c;现实中替换成自己的图片即可 关注一下点个赞吧&#x1f604; 谢谢大佬 界面图片 源代码 <!DOCTYPE html> <html lang&quo…

C++继承初识

一。继承 1.继承本质是复用相同的代码&#xff08;属性&#xff09; 2.格式&#xff1a;class 类名&#xff1a;继承方式 父类 3.继承方式的规律&#xff1a; 父类的&#xff1a; 对于私有成员&#xff0c;不管哪种继承方式都不可见--->不想被子类继承的成员 对于保护…

代码随想录——划分字母区间(Leetcode763)

题目链接 贪心 class Solution {public List<Integer> partitionLabels(String s) {int[] count new int[27];Arrays.fill(count,0);// 统计元素最后一次出现的位置for(int i 0; i < s.length(); i){count[s.charAt(i) - a] i;}List<Integer> res new Ar…

非对称加密算法原理与应用2——RSA私钥加密文件

作者:私语茶馆 1.相关章节 (1)非对称加密算法原理与应用1——秘钥的生成-CSDN博客 第一章节讲述的是创建秘钥对,并将公钥和私钥导出为文件格式存储。 本章节继续讲如何利用私钥加密内容,包括从密钥库或文件中读取私钥,并用RSA算法加密文件和String。 2.私钥加密的概述…

JDK都出到20多了,你还不会使用JDK8的Stream流写代码吗?

目录 前言 Stream流 是什么&#xff1f; 为什么要用Steam流 常见stream流使用案例 映射 map() & 集合 collect() 单字段映射 多字段映射 映射为其他的对象 映射为 Map 去重 distinct() 过滤 filter() Stream流的其他方法 使用Stream流的弊端 前言 当你某天看…

深度学习模型加密python版本

支持加密的模型: # torch、torch script、onnx、tensorrt 、torch2trt、tensorflow、tensorflow2tensorrt、paddlepaddle、paddle2tensorrt 深度学习推理模型通常以文件的形式进行保存&#xff0c;相应的推理引擎通过读取模型文件并反序列化即可进行推理过程. 这样一来&#…

跨平台Ribbon UI组件QtitanRibbon全新发布v6.7.0——支持Qt 6.6.3

没有Microsoft在其办公解决方案中提供的界面&#xff0c;就无法想象现代应用程序&#xff0c;这个概念称为Ribbon UI&#xff0c;目前它是使应用程序与时俱进的主要属性。QtitanRibbon是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件&#xff0c;QtitanRibb…

vue3【实战】来回拖拽放置图片

效果预览 技术要点 img 标签默认就是可拖拽的&#xff08;a 标签也是&#xff09;事件 e 内的 dataTransfer 对象可用于临时存储事件过程中的数据拖拽事件的默认行为是用浏览器新开页签打开被拖拽对象&#xff0c;所以通常需要禁用默认的浏览器行为被拖拽元素必须设置 id&#…

拉曼光谱入门:2.拉曼光谱发展史、拉曼效应与试样温度的确定方法

1.拉曼光谱技术发展史 这里用简单的箭头与关键字来概括一下拉曼光谱技术的发展史 1928年&#xff1a;拉曼效应的发现 → 拉曼光谱术的初步应用20世纪40年代&#xff1a;红外光谱术的发展 → 拉曼光谱术的限制20世纪60年代&#xff1a;激光作为光源的引入 → 拉曼光谱术的性能提…

阿里云人工智能平台PAI部署开源大模型chatglm3之失败记录

想学习怎么部署大模型&#xff0c;跟着网上的帖子部署了一个星期&#xff0c;然而没有成功。失败的经历也是经历&#xff0c;记在这里。 我一共创建了3个实例来部署chatglm3&#xff0c;每个实例都是基于V100创建的&#xff08;当时没有A10可选了&#xff09;&#xff0c;其显…

数据库缓存管理

1. 简介 缓存管理器是数据库管理系统&#xff08;DBMS&#xff09;中负责管理内存中page并处理文件和索引管理器的page请求的组件。由于内存空间有限&#xff0c;我们不能将所有page存储在缓存池中。因此&#xff0c;缓存管理器需要制定替换策略&#xff0c;当空间填满时选择哪…

rider使用libman

问题 rider没有libman的相关功能&#xff0c;需要使用cli 安装Libman dotnet tool install -g Microsoft.Web.LibraryManager.Cli # 如果存在可以尝试更新 dotnet tool update -g Microsoft.Web.LibraryManager.Cli查看命令 libman --help初始化 cdnjs官网 libman init安…

【十三】图解 Spring 核心数据结构:BeanDefinition 其二

图解 Spring 核心数据结构&#xff1a;BeanDefinition 其二 概述 前面写过一篇相关文章作为开篇介绍了一下BeanDefinition&#xff0c;本篇将深入细节来向读者展示BeanDefinition的设计&#xff0c;让我们一起来揭开日常开发中使用的bean的神秘面纱&#xff0c;深入细节透彻理解…

CTFShow的RE题(三)

数学不及格 strtol 函数 long strtol(char str, char **endptr, int base); 将字符串转换为长整型 就是解这个方程组了 主要就是 v4, v9的关系&#xff0c; 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重点&…

刷代码随想录有感(127):动态规划——判断是否为子序列

题干&#xff1a; 代码&#xff1a; class Solution { public:bool isSubsequence(string s, string t) {vector<vector<int>>dp(s.size() 1, vector<int>(t.size() 1, 0));for(int i 1; i < s.size(); i){for(int j 1; j < t.size(); j){if(s[i …

方法引用详解

什么是方法引用&#xff1f;&#xff1a;针对于函数式接口中的抽象方法 为什么用方法引用&#xff1f;&#xff1a;避免代码的重复&#xff0c;简便书写&#xff0c;提高效率 在使用Lambda表达式的时候&#xff0c;我们实际上传递进去的代码就是一种解决方案&#xff1a;拿参数…

数据结构之“栈”(全方位认识)

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;数据结构 前言 栈是一种数据结构&#xff0c;具有" 后进先出 "的特点 或者也可见说是 ” 先进后出 “。大家一起加油吧冲冲冲&#xff01;&#xff01; …

u盘存了东西却显示没有文件怎么办?原因分析与解决方案

在数字化时代&#xff0c;U盘已成为我们日常生活中不可或缺的存储设备。然而&#xff0c;有时我们可能会遇到一种令人困惑的情况&#xff1a;明明在U盘中存储了重要文件&#xff0c;但插上电脑后却显示没有文件。这种突如其来的“消失”不仅让人感到焦虑&#xff0c;更可能对我…

web前端开发——开发环境和基本知识

今天我来针对web前端开发讲解一些开发环境和基本知识 什么是前端 前端通常指的是网站或者Web应用中用户可以直接与之交互的部分&#xff0c;包括网站的结构、设计、内容和功能。它是软件开发中的一个专业术语&#xff0c;特别是指Web开发领域。前端开发涉及的主要技术包括HTML…

Windows ipconfig命令详解,Windows查看IP地址信息

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 ipconfig 1、基…