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;
}
創作不容易,如果對您有幫助,請多打賞!!!!