??博客主頁:小王又困了
??系列專欄:C語言
??人之為學(xué),不日近則日退?
??感謝大家點(diǎn)贊??收藏?評論??
目錄
一.函數(shù)指針?
1.1函數(shù)指針的認(rèn)識
1.2函數(shù)指針的使用
二、函數(shù)指針數(shù)組
1.1函數(shù)指針的認(rèn)識
1.2 函數(shù)指針數(shù)組實現(xiàn)計算器
?三、指向函數(shù)指針數(shù)組的指針?
四、回調(diào)函數(shù)
通過使用qsort函數(shù)加強(qiáng)對回調(diào)函數(shù)的理解
qsort排序整形
qosrt排序結(jié)構(gòu)體?
?用冒泡排序的思想,模擬實現(xiàn)功能類似qsort的函數(shù)
前言:前面的的學(xué)習(xí)中,我們了解了字符指針,數(shù)組指針和指針數(shù)組,接下來就讓我繼續(xù)帶大家了解函數(shù)指針,函數(shù)指針數(shù)組,以及回調(diào)函數(shù)等重要知識。
一.函數(shù)指針?
1.1函數(shù)指針的認(rèn)識
函數(shù)指針 -- 指向函數(shù)的指針
函數(shù)指針的一般形式:
????????函數(shù)返回類型? ?(*函數(shù)名)(函數(shù)參數(shù)類型)
?例如:
void test(char* p ,int arr[5])
{}
int main()
{
void (*pf)(char* ,int*)=&test;
//函數(shù)指針
return 0;
}
函數(shù)名的意義:?
?函數(shù)名是函數(shù)的地址
&函數(shù)名也是函數(shù)的地址
1.2函數(shù)指針的使用
?說明:pf前可以不加*,但加*是,要用括號括起來
代碼分析:
( * ( void (*)() ) 0) ();
1.( void (*)() ) 0將0強(qiáng)制類型轉(zhuǎn)化為void(*)()
2. * ( void (*)() ) 0調(diào)用0地址處的函數(shù)
二、函數(shù)指針數(shù)組
1.1函數(shù)指針的認(rèn)識
把函數(shù)的地址存到一個數(shù)組中,那這個數(shù)組就叫函數(shù)指針數(shù)組
?函數(shù)指針數(shù)組的一般形式,例如:
????????int? (*parr3[10]) ( );
1.2 函數(shù)指針數(shù)組實現(xiàn)計算器
函數(shù)的參數(shù)返回類型相同,我們就可以將函數(shù)指針改寫成函數(shù)指針數(shù)組。
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a * b;
}
int Div(int a, int b)
{
return a / b;
}
void menu()
{
printf("***************************\n");
printf("***1.Add 2.Sub***\n");
printf("***3.Mul 4.Div***\n");
printf("***0.exit ********\n");
printf("***************************\n");
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();
printf("請選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("輸入操作數(shù):");
scanf("%d %d", &x, &y);
ret = Add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("輸入操作數(shù):");
scanf("%d %d", &x, &y);
ret = Sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("輸入操作數(shù):");
scanf("%d %d", &x, &y);
ret = Mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("輸入操作數(shù):");
scanf("%d %d", &x, &y);
ret = Div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
return 0;
}
?在case語句中,輸入和輸出函數(shù)多次出現(xiàn),使得程序看起來雜亂,冗余。如果想要實現(xiàn)更多的功能,要增加case語句,解決起來十分的不變,而且繁瑣。這是我們就可以用到函數(shù)指針數(shù)組來解決問題。
優(yōu)化代碼:
int main()
{
int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
//下標(biāo) 0 1 2 3 4
do
{
menu();
printf("請選擇:");
scanf("%d", &input);
if (input > 0 && input < 5)
{
printf("輸入操作數(shù):");
scanf("%d %d", &x, &y);
ret = pfArr[input](x, y);
printf("%d\n", ret);
}
else if (input == 0)
{
printf("退出程序\n");
}
else
{
printf("輸入錯誤,請重新輸入\n");
}
} while (input);
return 0;
}
說明:在數(shù)組的第一個元素加NULL,使得Add函數(shù)的下標(biāo)為一,讓各個函數(shù)的下標(biāo)菜單輸入的數(shù)相對應(yīng),使得程序編寫更加簡便。
?三、指向函數(shù)指針數(shù)組的指針?
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函數(shù)指針pf
void (*pf)(const char*) = test;
//函數(shù)指針的數(shù)組pfArr
void (*pfArr[5])(const char* str);
//指向函數(shù)指針數(shù)組pfArr的指針ppfArr
void (*(*ppfArr)[5])(const char*) = &pfArr;
return 0;
}
代碼解析:?
&pfArr取出的是整個數(shù)組的地址,數(shù)組的地址應(yīng)該放在數(shù)組指針中。pfArr是函數(shù)指針數(shù)組,所以它的地址應(yīng)該放在指向函數(shù)指針數(shù)組的指針中。
*與ppfArr結(jié)合,說明ppfArr是指針,指向的是一個數(shù)組元素為5,類型為void(*)(const* char*)
四、回調(diào)函數(shù)
回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng) 這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào) 用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a * b;
}
int Div(int a, int b)
{
return a / b;
}
void menu()
{
printf("***************************\n");
printf("***1.Add 2.Sub***\n");
printf("***3.Mul 4.Div***\n");
printf("***0.exit ********\n");
printf("***************************\n");
}
void Calc(int (*p)(int ,int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("輸入兩個操作數(shù):>");
scanf("%d%d", &x, &y);
ret = p(x, y);
printf("%d\n", ret);
}
int main()
{
int input = 0;
do
{
menu();
printf("請選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
return 0;
}
通過使用qsort函數(shù)加強(qiáng)對回調(diào)函數(shù)的理解
qsort函數(shù)的特點(diǎn):
1.快速排序的方法
2.適用于任何類型的排序
void qsort(void* base,
size_t num,
size_t size,
int (*cmp)(const void*, const void*));
我們從函數(shù)的定義可以看到,qsort函數(shù)調(diào)用時要傳入四個參數(shù)
- void* base? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?base指向的是待排序數(shù)組的第一個元素,由于我們不知道要排序數(shù)組的類型,所以使用void*
- size_t num? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?待排序數(shù)組中元素的個數(shù)
- size_t size? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 待排序數(shù)組中,一個元素所占字節(jié)的大小
- int (*cmp)(const void*, const void*))? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?cmp是比較函數(shù),傳入的是要比較的兩個數(shù)的地址 用void*接收是因為不知道參數(shù)的類型。void* 是無具體類型類型的指針? ?可以接受任意類型的指針? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?判斷條件
?int (*cmp)(const void* p1, const void* p2))
- p1指向的值小于p2指向的值? --? 返回小于0的數(shù)
- p1指向的值等于p2指向的值? --? 返回0
- p1指向的值大于p2指向的值? --? 返回大于0的值?
?注意:使用qsort函數(shù)是要引用頭文件的
#include? <stdlib.h>
qsort排序整形
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
void test()
{
int arr[10] = { 4,7,1,3,0,8,2,5,6,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
int main()
{
test();
return 0;
}
?
說明:qsort函數(shù)默認(rèn)是升序的。我們只需將p1和p2的位置調(diào)換,就可以實現(xiàn)降序。
qosrt排序結(jié)構(gòu)體?
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
struct stu
{
char name[20];
int age;
};
int cmp_stu_by_name(const void* p1, const void* p2)
{
return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
}
void print(struct stu *p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s\n", (p + i)->name);
}
}
void test()
{
struct stu arr[] = { {"zhangsan",24},{"lisi",15},{"wangwu",30} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
print(arr, sz);
}
int main()
{
test();
return 0;
}
?用冒泡排序的思想,模擬實現(xiàn)功能類似qsort的函數(shù)
用冒泡排序?qū)崿F(xiàn)全類型的排序會有三個問題
解決一我們可以仿照qsort函數(shù)傳遞void*的指針,同時傳遞要排序的元素的個數(shù)和每個元素的字節(jié)
解決二可以將兩個元素的比較方法,以函數(shù)參數(shù)的形式傳遞。
文章來源:http://www.zghlxwxcb.cn/news/detail-610666.html
void Swap(char* buf1, char* buf2, int size)//交換arr[j],arr[j+1]這兩個元素
{
int i = 0;
char tmp = 0;
for (i = 0; i < size; i++)
{
tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void bubble_sort(void* base, int sz, int size, int (*cmp)(const void*, const void*))
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
//假設(shè)要排升序,cmp返回>0
if (cmp((char*)base + j * size, (char*)base + (j + i) * size) > 0)
{
//交換
Swap((char*)base + j * size, (char*)base + (j + i) * size, size);
}
}
}
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
void test()
{
int arr[10] = { 4,7,1,3,0,8,2,5,6,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
int main()
{
test();
return 0;
}
本次的內(nèi)容到這里就結(jié)束啦。希望大家閱讀完可以有所收獲,同時也感謝各位讀者的支持。文章有問題可以在評論區(qū)留言,博主一定認(rèn)真認(rèn)真修改,以后寫出更好的文章。??文章來源地址http://www.zghlxwxcb.cn/news/detail-610666.html
到了這里,關(guān)于【C語言進(jìn)階】 指針進(jìn)階(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!