国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看)

這篇具有很好參考價(jià)值的文章主要介紹了【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

6. 函數(shù)指針數(shù)組

6.1簡單計(jì)算器

6.2函數(shù)指針數(shù)組實(shí)現(xiàn)計(jì)算器

7. 指向函數(shù)指針數(shù)組的指針(僅作了解即可)

8.回調(diào)函數(shù)

8.1關(guān)于回調(diào)函數(shù)的理解?編輯

8.1.1用回調(diào)函數(shù)改良簡單計(jì)算器

8.2qsort庫函數(shù)的使用

8.2.1冒泡排序

8.2.2qsort的概念

8.3冒泡排序思想實(shí)現(xiàn)qsort


?????????這篇文章包括但不限于函數(shù)指針數(shù)組,指向函數(shù)指針數(shù)組的指針,回調(diào)函數(shù)等知識點(diǎn)的總結(jié)。承接著上文指針進(jìn)階(1)知識點(diǎn)總結(jié),傳送門-- >?http://t.csdn.cn/mgVGJ

指針進(jìn)階(3):指針和數(shù)組筆試題解析總結(jié),傳送門-->?http://t.csdn.cn/aKVsj?

????????如有錯誤,歡迎大家指點(diǎn)與糾正,感謝你的來訪!

6. 函數(shù)指針數(shù)組

數(shù)組是一個存放相同類型數(shù)據(jù)的存儲空間,那我們已經(jīng)學(xué)習(xí)了指針數(shù)組,
比如:
int * arr [ 10 ];
//數(shù)組的每個元素是int*

那要把函數(shù)的地址存到一個數(shù)組中,那這個數(shù)組就叫函數(shù)指針數(shù)組,那函數(shù)指針的數(shù)組如何定義呢?

int ( * parr1 [ 10 ])();//1
int * parr2 [ 10 ]();//2
int ( * )() parr3 [ 10 ];//3

?答案是:parr1 //1

parr1 先和 [] 結(jié)合,說明 parr1 是數(shù)組,數(shù)組的內(nèi)容是什么呢?
int (*)() 類型的函數(shù)指針。-->對于一個變量來說去掉它的名字,就是它的類型。
int my_strlen(const char* str)
{
	return 0;
}
int main()
{
  //指針數(shù)組
	char* arr[10];
  //數(shù)組指針
	int arr2[5] = { 0 };
	int(*p)[5] = &arr2;//p是一個指向數(shù)組的指針變量

	//函數(shù)指針
    int (*pf)(const char*) = my_strlen;//pf是一個指向函數(shù)的函數(shù)指針變量
	
	//函數(shù)指針數(shù)組-存放函數(shù)指針的數(shù)組
	int (*pfArr[10])(const char*);
    //1.pf先與[10]結(jié)合,代表這是一個數(shù)組,數(shù)組有10個元素;
    //2.去掉pf[10],剩余int (*)(int,int)為數(shù)組每個元素的類型--函數(shù)指針類型

	return 0;
}

以下三種寫法均等價(jià)
1.? ?*(*pf)("abcdef");
2.? ?pf ("abcdef");
3.? ?my_strlen("abcdef");

我們通過實(shí)現(xiàn)一個計(jì)算器的函數(shù)來說明,函數(shù)指針數(shù)組的用途用在哪里:

6.1簡單計(jì)算器

按照咱們正常的思路,寫一個簡單的計(jì)算器實(shí)現(xiàn)整數(shù)的加減乘除的功能,應(yīng)該大致寫成這種代碼:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

那么執(zhí)行一下,看一下狀況如何:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

以上出現(xiàn)的問題是,輸入0之后,沒有立即打印"退出計(jì)算器"然后結(jié)束程序,而是要繼續(xù)輸入兩個操作數(shù)之后才打印信息,還順便打印了個6,這樣的代碼肯定存在問題,咱們稍微改進(jìn)一下。

//寫一個計(jì)算器能完成整數(shù)的+ - * /
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
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("%d\n", ret);
			break;
		case 2:
			printf("請輸入兩個操作數(shù):>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("請輸入兩個操作數(shù):>");
			scanf("%d %d",&x,&y);
			ret = Mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("請輸入兩個操作數(shù):>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出計(jì)算器\n");
			break;
		default :
			printf("選擇錯誤\n");
			break;
		}
	}while(input);
	return 0;
}

執(zhí)行代碼,繼續(xù)測試:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

?問題是解決了,可是又發(fā)現(xiàn)新的問題:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

?以上的代碼的switch case語句太多了,當(dāng)我想要在這個計(jì)數(shù)器里面增加: << >> & | ^ && ||等功能,case語句的就會越來越多,那應(yīng)該怎么去糾正呢?

這時(shí)候就要用到函數(shù)指針數(shù)組了。

例子:

int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	//存放函數(shù)指針的數(shù)組 - 函數(shù)指針數(shù)組
	int (*pf[4])(int, int) = {Add,Sub,Mul,Div };
	                        // 0    1   2   3
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int ret = pf[i](8, 4);
		printf("%d\n", ret);
	}

	return 0;
}

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

這段代碼使用了函數(shù)指針數(shù)組,將四個運(yùn)算函數(shù)的地址存儲在數(shù)組中,然后通過循環(huán)遍歷數(shù)組,依次調(diào)用四個運(yùn)算函數(shù)進(jìn)行計(jì)算并輸出結(jié)果。這種方式可以減少代碼的重復(fù)量,提高代碼的可維護(hù)性。

?6.2函數(shù)指針數(shù)組實(shí)現(xiàn)計(jì)算器

//函數(shù)指針數(shù)組實(shí)現(xiàn)計(jì)算器
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
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;//用于接收值
   
    //轉(zhuǎn)移表 - 函數(shù)指針的數(shù)組
	int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
							 //   0    1   2   3    4
	//NULL的作用是為了占用0下標(biāo),然后讓函數(shù)指針數(shù)組的元素下標(biāo)對應(yīng)上菜單的功能
	do {
		//菜單
		menu();
		//進(jìn)行選擇
		printf("請選擇:>");
		scanf("%d", &input);
		//用函數(shù)指針數(shù)組代替switch
		if (input == 0)
		{
			printf("退出計(jì)算器\n");
			return 0;
		}
		else if (input >= 1 && input <= 4)
		{
			printf("請輸入兩個操作數(shù):>");
			scanf("%d %d",&x,&y);
			ret = (***pfArr[input])(x, y);//其實(shí)比函數(shù)指針的用法就多了一個[input]
			 //跟函數(shù)指針一樣,調(diào)用函數(shù)的時(shí)候 * 是沒有任何意義的
			printf("%d\n",ret);
		}
		else
		{
			printf("選擇錯誤\n");
		}
	} while (input);
	return 0;
}

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

函數(shù)指針數(shù)組是一個數(shù)組,其中的元素是函數(shù)指針。每個函數(shù)指針指向一個特定的函數(shù),可以通過函數(shù)指針調(diào)用相應(yīng)的函數(shù)。?函數(shù)指針數(shù)組可以用來解決代碼冗余的問題,可以方便地遍歷、調(diào)用不同的函數(shù),從而簡化代碼的結(jié)構(gòu)和邏輯,提高代碼的可維護(hù)性和可擴(kuò)展性。

函數(shù)指針數(shù)組的用途:轉(zhuǎn)移表

7. 指向函數(shù)指針數(shù)組的指針(僅作了解即可)

//指向函數(shù)指針數(shù)組的指針
int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a - b;
}
int main()
{   //函數(shù)指針
	int(*pf)(int, int) = Add;
	//函數(shù)指針數(shù)組
	int (*pfArr[4])(int, int) = { Add,Sub };
	//指向函數(shù)指針數(shù)組的指針
	 int (*(*ppfArr)[4])(int,int) = &pfArr;

	 return 0;
}

如何理解指向函數(shù)指針數(shù)組的指針:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

8.回調(diào)函數(shù)

概念

回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時(shí),我們就說這是回調(diào)函數(shù)。
回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。
代碼冗余問題:第一版簡單的計(jì)算器存在的問題
【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

存在著較多邏輯相同,代碼冗余的部分。

?這時(shí)候就需要用到回調(diào)函數(shù)解決問題了:

8.1關(guān)于回調(diào)函數(shù)的理解

8.1.1用回調(diào)函數(shù)改良簡單計(jì)算器

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
//將冗余重復(fù)部分用Calc函數(shù)封裝(只用了一個函數(shù)),通過這個函數(shù)里面?zhèn)魅氲暮瘮?shù)指針調(diào)用計(jì)算器函數(shù)
void Calc(int(*pf)(int, int))//pf函數(shù)指針,傳過來哪個函數(shù)地址就用哪種類型計(jì)算
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("請輸入兩個操作數(shù):>");
	scanf("%d %d", &x, &y);
    ret = pf(x, y);
	printf("%d\n", ret);
}
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 ret = 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("退出計(jì)算器\n");
			break;
		default:
			printf("選擇錯誤\n");
			break;
			}
		} while (input);
	return 0;
}

總結(jié):

回調(diào)函數(shù):被作為參數(shù)傳遞的函數(shù),Add、Sub、Mul、Div四個函數(shù)就是回調(diào)函數(shù),

而Calc函數(shù)則是工具人

8.2qsort庫函數(shù)的使用

8.2.1冒泡排序

回顧一下冒泡排序的過程:

冒泡排序的思想:兩兩相鄰的元素進(jìn)行比較,假設(shè)要排成升序【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

怎么去寫冒泡排序的代碼:
①由元素個數(shù)確定趟數(shù)

②由趟數(shù)確定比較對數(shù)? ? ? ? ?

③兩個元素兩兩交換排成升序

//冒泡排序 
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//趟數(shù)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//比較對數(shù)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0};
	//排序
	//使用
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);

	print_arr(arr, sz);
	return 0;
}

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

不足:

但是這個冒泡排序的缺點(diǎn)也很明顯,就是只能排整型int

如果遇到浮點(diǎn)型、結(jié)構(gòu)體等類型的數(shù)據(jù),就排不了,那么怎么可以解決呢?

這時(shí)候就要用到qsort了。

8.2.2qsort的概念

qsort-- quicksort

是一個庫函數(shù),是用來排序的庫函數(shù)使用快速排序的方法

qsort的好處是

1.現(xiàn)成的

2.可以排序任意類型的數(shù)據(jù)

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

?【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

qsort是可以排序任意類型的數(shù)據(jù)

1.比較2個整數(shù)的大小,> < ==

//qsort函數(shù)的使用者提供這個函數(shù)
//qsort 默認(rèn)是升序
int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
    //排成倒序的話,什么都不用動,只需要return *(int*)p2 - *(int*)p1;//調(diào)換順序即可
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
test1()
{
	int arr[] = { 3,1,5,2,4,9,8,6,5,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//使用qsort來排序整型數(shù)組,這里就要提供一個比較函數(shù),這個比較函數(shù)能夠比較2個整數(shù)的大小
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
   test1();
}

?【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

2.比較2個字符串,strcmp -->回顧字符串知識:http://t.csdn.cn/V7E9a

3.比較2個結(jié)構(gòu)體數(shù)據(jù)(學(xué)生:張三、李四)指定比較的標(biāo)準(zhǔn)

回顧結(jié)構(gòu)體對象訪問成員的知識:http://t.csdn.cn/DVEVj

//測試qsort 排序結(jié)構(gòu)體數(shù)據(jù)
struct Stu {
	char name[20];
	int age;
};
void print_arr1(struct Stu* arr, int sz)//打印年齡
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//printf("%d ", (*(arr + i)).age);
		//printf("%d ", (arr+i)->age);
		printf("%d ", arr[i].age);

	}
	printf("\n");
}
void print_arr2(struct Stu*arr, int sz)//打印姓名
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", (arr+i)->name);
		//printf("%s ", (*(arr+i)).name);
		//printf("%s ", arr[i].name);

	}
	printf("\n");
}
//按照年齡來比較
int cmp_stu_by_age(const void*p1,const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;

}
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void test2()
{
	struct Stu s[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };
	int sz = sizeof(s) / sizeof(s[0]);
	//測試按照年齡來排序
	print_arr1(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	print_arr1(s, sz);
	//測試按照名字來排序
	/*print_arr2(s,  sz);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	print_arr2(s, sz);*/
}

打印年齡:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

打印性別:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

8.3冒泡排序思想實(shí)現(xiàn)qsort

使用冒泡排序的思想來實(shí)現(xiàn)一個類似于qsort這個功能的冒泡排序函數(shù)bubble_sort()

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

各參數(shù)組成:
base,num,width,cmp函數(shù),elem1和elem2

接下來說明一下qsort各參數(shù)的設(shè)計(jì)思路:

①為什么base定義為void*類型?

void*是 C 語言中的一種通用指針類型,可以指向任意類型的數(shù)據(jù)。在 qsort 函數(shù)中,由于需要對不同類型的數(shù)據(jù)進(jìn)行排序,因此需要使用void*類型的指針,以便能夠接受各種類型的數(shù)據(jù),base參數(shù)是一個指向要排序數(shù)組第一個元素的指針。由于它要指向任意類型的數(shù)據(jù),所以使用void*是最通用的。

舉例:

int a = 10;

void* p = &a;

優(yōu)點(diǎn):

無具體類型的指針,所以它可以接收任何類型的地址

缺點(diǎn):

*p? //-->? void*的指針不能解引用操作符

p++? //-->? 因?yàn)椴恢朗鞘裁磾?shù)據(jù)類型,不能直接++

正確用法:

*(int*)p;//也可以轉(zhuǎn)化成其它類型

②為什么num要設(shè)計(jì)成size_t?

  • size_t 在 C 語言中是一種無符號整數(shù)類型,用于表示大小、長度和索引值,使用它表示數(shù)組元素個數(shù)很合適。
  • 數(shù)組元素個數(shù)是一個非負(fù)的值,使用無符號類型size_t可以避免出現(xiàn)負(fù)數(shù),更加合理。

  • 使用專門的 size_t 類型比簡單的 unsigned int 更能表明這個參數(shù)的語義 - 它表示一個大小或長度,而不是一個整數(shù)。

③為什么width要設(shè)計(jì)成size_t

在qsort函數(shù)中,width參數(shù)表示每個數(shù)組元素的大小(以字節(jié)為單位)

  1. width表示一個"大小"的概念,使用size_t類型可以更清楚地表達(dá)這個參數(shù)的語義。

  2. width的單位是字節(jié),size_t通常是無符號整數(shù)類型,不會有負(fù)數(shù),所以更適合表示正的值。

  3. width需要足夠大的范圍來表示任意數(shù)據(jù)類型的大小。size_t類型依賴平臺,但通常是機(jī)器字大小,能滿足大多數(shù)數(shù)據(jù)元素的大小需求。

  4. 在訪問數(shù)組元素時(shí),索引位置需要乘以元素大小才能獲得地址偏移量。既然索引是size_t類型,那么兩者相乘的結(jié)果也應(yīng)該是size_t類型,以避免溢出問題。

④為什么要設(shè)計(jì)一個函數(shù)指針cmp?

  1. qsort 本身是一個通用的排序函數(shù),不能知道要排序的元素類型,也就無法直接比較兩個元素。采用函數(shù)指針可以將比較操作的實(shí)現(xiàn)留給用戶。

  2. 通過函數(shù)指針,用戶可以自行實(shí)現(xiàn)針對自己數(shù)據(jù)類型的比較函數(shù),將具體的比較邏輯封裝起來。這提高了qsort的通用性和靈活性。

  3. 對于不同的數(shù)據(jù)類型,比較操作的邏輯可能不同。使用函數(shù)指針實(shí)現(xiàn)可以避免在qsort中寫大量的條件分支邏輯。

  4. 函數(shù)指針提供了一種擴(kuò)展機(jī)制。如果用戶需要改變比較操作的邏輯,只需要傳入一個新的函數(shù)指針就可以,而不需要改動qsort函數(shù)本身。

⑤為什么elem1和elem2類型是const void*類型?

  1. qsort要對任意類型的數(shù)據(jù)進(jìn)行排序,所以比較函數(shù)需要能處理任意類型的元素。使用void*可以指向任意類型的數(shù)據(jù),const用于表示不應(yīng)修改指針指向的內(nèi)容。

  2. qsort要對任意類型的數(shù)據(jù)進(jìn)行排序,所以比較函數(shù)需要能處理任意類型的元素。使用void*可以指向任意類型的數(shù)據(jù),const用于表示不應(yīng)修改指針指向的內(nèi)容。

  3. 在調(diào)用qsort時(shí)可以直接將數(shù)組元素的地址強(qiáng)制轉(zhuǎn)換為const void* 類型傳給比較函數(shù),簡化調(diào)用。

  4. qsort函數(shù)本身不需要了解元素具體類型,只要把void*指針傳給比較函數(shù),由比較函數(shù)轉(zhuǎn)換并解釋指針內(nèi)容即可。

開始模擬實(shí)現(xiàn):冒泡排序大題思路不需要改變,只需要對排序方式進(jìn)行即可

int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
//假設(shè)排序?yàn)樯?//希望這個bubble_sort函數(shù)可以排序任意類型的數(shù)據(jù)
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

//假設(shè)排序?yàn)樯?//希望這個bubble_sort函數(shù)可以排序任意類型的數(shù)據(jù)
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
    //冒泡排序大題思路不需要改變,只需要對排序方式進(jìn)行即可
	//要確定趟數(shù)
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假設(shè)已經(jīng)有序了
		//一趟冒泡排序的過程
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//兩個相鄰的元素比較
			//arr[j] arr[j+1]
			if (cmp((char*)base + j * width, (char*)base+(j+1)*width)>0)
			{
				//交換
				flag = 0;
				Swap((char*)base+j*width,(char*)base+(j+1)*width,width);
			}
		}
	}


}

void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
void test3()
{
	int arr[] = { 3,1,5,2,4,9,8,6,5,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:");
	print_arr(arr, sz);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("排序后:");
	print_arr(arr, sz);
}

qsort對于代碼的解析:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

如何交換數(shù)據(jù):

為什么這個地方寫成char*?

在bubble_sort函數(shù)中,由于不知道base指向的數(shù)據(jù)類型,因此需要將其強(qiáng)制轉(zhuǎn)換為char*類型,從而讓指針的步長為1。這樣,在進(jìn)行指針的加減運(yùn)算時(shí),就可以根據(jù)width參數(shù)來控制指針的步長,從而實(shí)現(xiàn)對任意數(shù)據(jù)類型的排序。

注意:width對于char來說是1個字節(jié)的意思,但是對于其它類型來說就不是了,width是根據(jù)參數(shù)不同來設(shè)置不同的數(shù)據(jù)類型,控制指針步長的。

交換的流程:1,2,3,4表示順序?

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

?代碼的整體流程:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

排序:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

通過新定義的冒泡排序排序年齡以及姓名

struct Stu {
	char name[20];
	int age;
};
int cmp_stu_by_age(const void*p1,const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;

}
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
//假設(shè)排序?yàn)樯?//希望這個bubble_sort函數(shù)可以排序任意類型的數(shù)據(jù)
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
	//要確定趟數(shù)
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假設(shè)已經(jīng)有序了
		//一趟冒泡排序的過程
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//兩個相鄰的元素比較
			//arr[j] arr[j+1]
			if (cmp((char*)base + j * width, (char*)base+(j+1)*width)>0)
			{
				//交換
				flag = 0;
				Swap((char*)base+j*width,(char*)base+(j+1)*width,width);
			}
		}
	}


}
void print_arr3(struct Stu* s, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", (s + i)->age);
		//printf("%s ", (*(arr+i)).name);
		//printf("%s ", arr[i].name);

	}
	printf("\n");

}
void print_arr4(struct Stu* s, int sz)
{
	int i = 0;
		for (i = 0; i < sz; i++)
		{
			printf("%s ", (s+i)->name);
			//printf("%s ", (*(arr+i)).name);
			//printf("%s ", arr[i].name);
	
		}
		printf("\n");

}
void test4()
{
	struct Stu s[] = { {"zhangsan",30} ,{"lisi",25},{"wangwu",50}};
	int sz = sizeof(s) / sizeof(s[0]);
	//測試按年齡來排序
	/*print_arr3(s, sz);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	print_arr3(s, sz);*/
	//測試按照名字來排序
	print_arr4(s, sz);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	print_arr4(s, sz);

}

按姓名排序:

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

?按年齡排序

【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看),C進(jìn)階,c語言,開發(fā)語言,筆記,vscode

這篇文章到這里就結(jié)束了,如有錯誤歡迎大家指正,然后下來就是這篇關(guān)于sizeof和strlen的詳細(xì)總結(jié):,指針和數(shù)組筆試題解析總結(jié),傳送門-->?http://t.csdn.cn/aKVsj

歡迎大家來訪。文章來源地址http://www.zghlxwxcb.cn/news/detail-627914.html

到了這里,關(guān)于【C進(jìn)階】回調(diào)函數(shù)(指針進(jìn)階2,詳解,小白必看)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • C/C++面向?qū)ο螅∣OP)編程-回調(diào)函數(shù)詳解(回調(diào)函數(shù)、C/C++異步回調(diào)、函數(shù)指針)

    C/C++面向?qū)ο螅∣OP)編程-回調(diào)函數(shù)詳解(回調(diào)函數(shù)、C/C++異步回調(diào)、函數(shù)指針)

    本文主要介紹回調(diào)函數(shù)的使用,包括函數(shù)指針、異步回調(diào)編程、主要通過詳細(xì)的例子來指導(dǎo)在異步編程和事件編程中如何使用回調(diào)函數(shù)來實(shí)現(xiàn)。 ??個人簡介:一個全棧工程師的升級之路! ??個人專欄:C/C++精進(jìn)之路 ??CSDN主頁?發(fā)狂的小花 ??人生秘訣:學(xué)習(xí)的本質(zhì)就是極致

    2024年02月03日
    瀏覽(23)
  • 【C語言】——指針五:轉(zhuǎn)移表與回調(diào)函數(shù)

    【C語言】——指針五:轉(zhuǎn)移表與回調(diào)函數(shù)

    1.1、轉(zhuǎn)移表的定義 ?? ??在之前的學(xué)習(xí)中,我們學(xué)習(xí)了 函數(shù)指針數(shù)組 (詳情請看【C語言】——指針?biāo)模鹤址羔樑c函數(shù)指針變量),在最后。我曾問到:函數(shù)指針數(shù)組有什么用呢?別急,本文給大家細(xì)細(xì)道來。 ?? ??函數(shù)指針數(shù)組常常被用在 轉(zhuǎn)移表 中,那轉(zhuǎn)移表是

    2024年03月26日
    瀏覽(29)
  • C 語言高級3--函數(shù)指針回調(diào)函數(shù),預(yù)處理,動態(tài)庫的封裝

    C 語言高級3--函數(shù)指針回調(diào)函數(shù),預(yù)處理,動態(tài)庫的封裝

    目錄 1.函數(shù)指針和回調(diào)函數(shù) 1.1 函數(shù)指針 1.1.1 函數(shù)類型 1.1.2 函數(shù)指針(指向函數(shù)的指針) 1.1.3 函數(shù)指針數(shù)組 ? ? ? ?1.1.4 函數(shù)指針做函數(shù)參數(shù)(回調(diào)函數(shù)) ?2.預(yù)處理 2.1 預(yù)處理的基本概念 2.2?文件包含指令(#include) 2.2.1 文件包含處理 ?2.2.2 #incude和#include\\\"\\\"區(qū)別 2.3?宏定義 2.3.1 無參

    2024年02月14日
    瀏覽(18)
  • 【C語言】指針進(jìn)階:字符指針&&數(shù)組指針&&函數(shù)指針

    【C語言】指針進(jìn)階:字符指針&&數(shù)組指針&&函數(shù)指針

    ?作者:@平凡的人1 ?專欄:《C語言從0到1》 ?一句話:凡是過往,皆為序章 ?說明: 過去無可挽回, 未來可以改變 ?? 感謝您的點(diǎn)贊與關(guān)注,同時(shí)歡迎各位有空來訪我的 ??平凡舍 回想之前,我們學(xué)了 指針 的一些基礎(chǔ)?? 指針與結(jié)構(gòu)體 我們知道了指針的概念: 指針就是

    2023年04月08日
    瀏覽(24)
  • 計(jì)算字符串的長度幾種方法 | 遞歸 | 指針減指針 | 計(jì)數(shù)器 | C語言 | 詳解 | 期末考試必看?。?!

    計(jì)算字符串的長度幾種方法 | 遞歸 | 指針減指針 | 計(jì)數(shù)器 | C語言 | 詳解 | 期末考試必看!??!

    1,題目描述 2,分析題目 Ⅰ,題目中要求 除了函數(shù)的形參,函數(shù)中不能夠使用多余的變量 (這是比較 苛刻 的要求)。 Ⅱ,根據(jù)此,很自然的想到需要使用 遞歸 來解決問題。 Ⅲ, 字符串的結(jié)束標(biāo)志是\\\'\\0\\\',因此可以將 讀取到\\\'\\0\\\' 作為結(jié)束條件 3,關(guān)于遞歸的基本知識 Ⅰ,遞

    2024年02月03日
    瀏覽(20)
  • Go語言進(jìn)階:函數(shù)、指針、錯誤處理

    函數(shù)是基本的代碼塊,用于執(zhí)行一個任務(wù)。 Go 語言最少有個 main() 函數(shù)。 你可以通過函數(shù)來劃分不同功能,邏輯上每個函數(shù)執(zhí)行的是指定的任務(wù)。 函數(shù)聲明包括函數(shù)名﹑形式參數(shù)列表﹑返回值列表(可省略)以及函數(shù)體。 形式參數(shù)列表描逑了函數(shù)的參數(shù)名以及參數(shù)類型。這

    2024年02月12日
    瀏覽(42)
  • 【C語言進(jìn)階(五)】指針進(jìn)階詳解(上)

    【C語言進(jìn)階(五)】指針進(jìn)階詳解(上)

    ??博主CSDN主頁:杭電碼農(nóng)-NEO?? ? ?專欄分類:C語言學(xué)習(xí)分享? ? ??代碼倉庫:NEO的學(xué)習(xí)日記?? ? ??關(guān)注我??帶你學(xué)習(xí)更多C語言知識 ? ???? 本篇文章將講解以下幾個方面內(nèi)容: 字符指針 數(shù)組指針 指針數(shù)組 數(shù)組傳參和指針傳參 函數(shù)指針 在這之前先溫故一下指針的概念

    2024年02月12日
    瀏覽(33)
  • C語言——指針詳解(進(jìn)階)

    C語言——指針詳解(進(jìn)階)

    前言: 學(xué)完 C語言初階 后,應(yīng)該對指針有了初步的了解,下面學(xué)習(xí)進(jìn)階的內(nèi)容,讓我們更快的掌握C語言指針。 指針的概念: 指針就是一個變量,用來存放地址,地址與內(nèi)存空間一一對應(yīng) 指針的大小是固定的4/8個字節(jié)(32位平臺/64位平臺) 指針是有類型的,指針的類型決定

    2024年02月16日
    瀏覽(18)
  • C語言:指針詳解【進(jìn)階】后篇

    C語言:指針詳解【進(jìn)階】后篇

    前言: 在C語言:指針詳解【進(jìn)階】前篇中我們深入學(xué)習(xí)了 字符指針 , 數(shù)組指針 , 指針數(shù)組 以及 數(shù)組傳參和指針傳參 。我們對指針的應(yīng)用有了較為深刻的認(rèn)識,今天這里我們將更加深入的進(jìn)行對更復(fù)雜的指針的探究。 在前面我們知道一個指針變量可以指向一塊內(nèi)存的地

    2024年02月05日
    瀏覽(18)
  • 【C語言】回調(diào)函數(shù),qsort排序函數(shù)的使用和自己實(shí)現(xiàn),超詳解

    【C語言】回調(diào)函數(shù),qsort排序函數(shù)的使用和自己實(shí)現(xiàn),超詳解

    先記錄一下訪問量突破2000啦,謝謝大家支持!??! 這里是上期指針進(jìn)階鏈接,方便大家查看:添加鏈接描述 大家好呀,今天分享一下上期指針進(jìn)階中剩余的內(nèi)容——回調(diào)函數(shù),這個很重要滴,讓我們一起來學(xué)會學(xué)懂他吧?。?! 標(biāo)準(zhǔn)概念: 回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)

    2024年02月12日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包