1 不能動的“地址”之 void指針
1.1 void指針初探
void *表示一個“不知道類型”的指針,也就不知道從這個指針地址開始多少字節為一個數據。和用int表示指針異曲同工,只是更明確是“指針”。
因此void *只能表示一個地址,不能用來&取值,也不能++和--移動指針,因此不知道多少字節是一個數據單位。
intnums[]={3,5,6,7,9}; void*ptr1=nums; //inti=*ptr1;//對于void指針沒法直接取值 int*ptr2=(int*)nums; printf("%d,%d ",ptr1,ptr2); inti=*ptr2; printf("%d ",i);
從輸出結果可以看出,無論是無類型的void指針還是int類型指針,指向的地址都是一樣的:
PS:void *就是一個不能動的“地址”,在進行&、移動指針之前必須轉型為類型指針。
1.2 void指針的用途
這里我們看一下我們之前了解的memset函數,其第一個參數就是一個void指針,它可以幫我們屏蔽各種不同類型指針的差異。 如下面代碼所示,我們既可以傳入一個int類型數組的指針,也可以傳入一個char類型數組的指針:
intnums[20]; memset(nums,0,sizeof(nums)); charchs[2]; memset(chs,0,sizeof(chs));
那么,我們也可以試著自己動手模擬一下這個memset函數,暫且命名為mymemset吧:
voidmymemset(void*data,intnum,intbyteSize) { //char就是一個字節,而計算機中是以字節為單位存儲的 char*ptr=(char*)data; inti; for(i=0;i
在這個mymemset函數中,我們利用void指針接收不同類型的指針,利用char類型(一個字節)逐個字節讀取內存中的每一個字節,最后依次填充指定的數字。
由于char類型是一個具體類型,所以可以使用++或者--進行指針的移動。
對于結構體類型,也可以使用我們的mymemset函數:
typedefstruct_Person { char*name; intage; }Person; Personp1; mymemset(&p1,0,sizeof(Person)); printf("p1.Age:%d ",p1.age);
最終的運行結果如下圖所示:
void *的用途:在只知道內存,但是不知道是什么類型的時候。
2 函數指針
2.1 指向函數的指針
我們可以在C中輕松地定義一個函數指針:
typedefvoid(*intFunc)(inti);
這里我們定義了一個無返回值的,只有一個int類型參數的函數指針intFunc。
我們可以在main函數中使用這個函數指針來指向一個具體的函數(這個具體的函數定義需要和函數指針的定義一致):
voidtest1(intage){ printf("test1:%d ",age); } intmain(void){ //聲明一個intFunc類型的函數指針 intFuncf1=test1; //執行f1函數指針所指向的代碼區 f1(8); return0; }最終運行結果如下圖所示,執行函數指針f1即執行了其所指向的具體的函數:
2.2 函數指針的基本使用
這里我們通過一個小案例來對函數指針做一個基本的使用介紹。相信大部分的C#或Java程序員都很熟悉foreach,那么我們就來模擬foreach對int數組中的值進行不同的處理。具體體現為for循環的代碼是復用的,但是怎么處理這些數據不確定,因此把處理數據的邏輯由函數指針指定。
voidforeachNums(int*nums,intlen,intFuncfunc) { inti; for(i=0;i在foreachNums函數中,我們定義了一個intFunc函數指針,printNum函數是滿足intFunc定義的一個具體的函數。
下面我們在main函數中將printNum函數作為函數指針傳遞給foreachNums函數。
intnums[]={1,5,666,23423,223}; foreachNums(nums,sizeof(nums)/sizeof(int),printNum);最終運行的結果如下圖所示:
通過函數指針,我們可以屏蔽各種具體處理方法的不同,也就是將不確定的因素都依賴于抽象,這也是面向抽象或面向接口編程的精髓。
三、函數指針應用案例
3.1 計算任意類型的最大值
(1)定義函數指針及getMax主體:
typedefint(*compareFunc)(void*data1,void*data2); // getMax 函數參數說明: //data待比較數據數組的首地址,uniteSize單元字節個數 // length:數據的長度。{1,3,5,6}:length=4 //比較data1和data2指向的數據做比較, //如果data1>data2,則返回正數 void*getMax(void*data,intunitSize,intlength,compareFuncfunc) { inti; char*ptr=(char*)data; char*max=ptr; for(i=1;i這里可以看到,在getMax中到底取幾個字節去比較都是由compareFunc所指向的函數去做,getMax根本不用關心。0) { max=item; } } returnmax; }
(2)定義符合函數指針定義的不同類型的函數:
intintDataCompare(void*data1,void*data2) { int*ptr1=(int*)data1; int*ptr2=(int*)data2; inti1=*ptr1; inti2=*ptr2; returni1-i2; } typedefstruct_Dog { char*name; intage; }Dog; intdogDataCompare(void*data1,void*data2) { Dog*dog1=(Dog*)data1; Dog*dog2=(Dog*)data2; return(dog1->age)-(dog2->age); }
(3)在main函數中針對int類型和結構體類型進行調用:
intmain(intargc,char*argv[]) { //test1:int類型求最大值 intnums[]={3,5,8,7,6}; int*pMax=(int*)getMax(nums,sizeof(int),sizeof(nums)/sizeof(int), intDataCompare); intmax=*pMax; printf("%d ",max); //test2:結構體類型求最大值 Dogdogs[]={{"沙皮",3},{"臘腸",10},{"哈士奇",5}, {"京巴",8},{"大狗",2}}; Dog*pDog=(Dog*)getMax(dogs,sizeof(Dog), sizeof(dogs)/sizeof(Dog),dogDataCompare); printf("%s=%d",pDog->name,pDog->age); return0; }
最終運行結果如下圖所示:
3.2 C 中自帶的qsort函數—自定義排序
qsort包含在
頭文件中,此函數根據你給的比較條件進行快速排序,通過指針移動實現排序。排序之后的結果仍然放在原數組中。 使用qsort函數必須自己寫一個比較函數。我們可以看看qsort函數的原型:
voidqsort(void*base,size_tnum,size_tsize,int(*comparator)(constvoid*,constvoid*));intnums[]={3,5,8,7,6}; qsort(nums,sizeof(nums)/sizeof(int),sizeof(int),intDataCompare); inti; for(i=0;i那么,快速排序后是否有結果呢?答案是肯定的,我們可以傳入各種比較方法,可以升序排序也可以降序排序。
審核編輯:湯梓紅
-
C語言
+關注
關注
180文章
7604瀏覽量
136698 -
函數
+關注
關注
3文章
4327瀏覽量
62573 -
指針
+關注
關注
1文章
480瀏覽量
70551 -
void
+關注
關注
0文章
23瀏覽量
9866 -
函數指針
+關注
關注
2文章
56瀏覽量
3778
原文標題:揭秘 C 語言的 void 指針
文章出處:【微信號:工程師進階筆記,微信公眾號:工程師進階筆記】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論