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;
}
创作不容易,如果对您有帮助,请多打赏!!!!
原文地址:https://blog.csdn.net/weixin_44245323/article/details/140083286
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!