고급 C: 고급 포인터(4)

 콜백

콜백 함수는 함수 포인터를 통해 호출되는 함수입니다. (함수 포인터의 매우 중요한 기능은 콜백 함수를 구현하는 것입니다.) 이 함수의 포인터(주소)를 다른 함수의 매개변수로 넘기면 이 포인터가 가리키는 함수를 호출할 때 이것을 콜백함수라고 합니다. 콜백함수는 함수의 구현자가 직접 호출하는 것이 아니라 특정 사건이나 조건이 발생할 때 상대방에 의해 호출되며, 그 사건이나 조건에 대응하기 위해 사용된다.

예: 예를 들어 함수 A의 주소인 함수 B에 매개 변수가 있고 함수 B가 사용될 때 함수 A가 호출되는 경우 함수 A를 콜백 함수라고 합니다.

중요한 퀵 정렬 기능인 qsort를 통한 콜백 함수에 대해 알아보겠습니다.


//头文件:#include <stdlib.h>

void qsort(void* base,//指向了被排序的第一个函数
	size_t sum,//排序的元素个数,size_t指无符号整数
	size_t size,//一个元素大小,单位是字节
	//函数指针类型——这个函数指针指向一个函数,能够比较base指向的两个函数
    //这个回调函数返回小于零的数表明p1<p2
    //返回大于零的数表明p1>p2
    //返回等于零的数表明p1=p2
	int (*cmp)(const void* p1, const void* p2)
);

//void*指针是无类型指针,可以接受任意类型的地址(这也是qsort函数的一个重要的特点)
//(因为这个函数不知道你要排序什么类型的指针,所以用void*)
//1.不能进行解引用操作,2.不能直接进行指针运算

qsort 함수의 사용을 살펴보겠습니다(여기서는 정수 및 구조 정렬을 예로 사용합니다).

정수 유형 정렬

#include <stdio.h>
#include <stdlib.h>

//注意:这个函数需要自己书写(注意升降序)
int int_cmp(const void* p1, const void* p2)
{
    //由于p1,p2都是void*类型的,不能直接进行解引用操作,
    //因此将它们转换为int*再解引用获得它们的值
//这个是升序,若想改为降序,只需要将p1,p2的位置互换即可
	return (*(int*)p1 - *(int*)p2);
}

print(int sz, int arr[])
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

void test()
{
	int arr[] = { 3,1,4,5,8,6,7,9,0,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(int), int_cmp);
	print(sz, arr);
}

int main()
{
	test();
	return 0;
}

구조 유형 정렬(정수 멤버 기준)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Peo {
	char name[20];
	int age;
};

int cmp_byage(const void* p1, const void* p2)
{
	return (((struct Peo*)p1)->age - ((struct Peo*)p2) -> age);
}

test1()
{
	struct Peo p[] = {
   
   {"zhangsan",20},{"lisi",50},{"wangwu",15}};
	int sz = sizeof(p) / sizeof(p[0]);
	qsort(p, sz, sizeof(struct Peo), cmp_byage);
}

int cmp_byname(const void* p1, const void* p2)
{
	return strcmp(((struct Peo*)p1)->name, ((struct Peo*)p2)->name);
}

int main()
{
	test1();
	return 0;
}

정수 멤버를 기준으로 결과를 오름차순으로 정렬

 구조 유형 순서 지정(문자열 멤버 기준)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Peo {
	char name[20];
	int age;
};

int cmp_byname(const void* p1, const void* p2)
{
	return strcmp(((struct Peo*)p1)->name, ((struct Peo*)p2)->name);
}

void test2()
{
	struct Peo p[]= { {"zhangsan",20},{"lisi",50},{"wangwu",15} };
	int sz = sizeof(p) / sizeof(p[0]);
	qsort(p, sz, sizeof(struct Peo), cmp_byname);
}

int main()
{
	test2();
	return 0;
}

문자열 유형의 구성원을 기준으로 결과를 오름차순으로 정렬

 시뮬레이션 구현

qsort 함수의 원리를 더 잘 이해할 수 있도록 아래에서 이 함수를 시뮬레이션하고 구현해 보겠습니다.

이름을 붙였습니다: bubble_sort( )

1. 이 기능을 사용하는 발상은 버블정렬의 발상입니다.

2. 다양한 종류의 Sorting에 적용할 수 있습니다.

이 기능의 구체적인 구현 방법을 알아보려면 먼저 다음 질문에 대해 생각해야 합니다.

1. 서로 다른 유형의 데이터에 대해 단순한 수학적 비교 기호를 사용하여 비교해서는 안 됩니다.

해결 방법: 두 요소의 비교 방법을 함수 매개변수 형식으로 전달하고 유형에 따라 다른 비교 방법을 전달할 수 있습니다.

2. 데이터 유형에 따라 교환이 약간 다릅니다.

해결 방법: bubble_sort() 함수 내부에 중첩된 swap 함수를 사용하여 비교할 두 요소를 전달합니다 요소의 유형을 모르기 때문에 char* 형식으로 전달합니다(char*의 단계 크기가 가장 작기 때문에 요소의 크기에 따라 1바이트씩 교환할 수 있습니다).

구체적인 코드를 살펴보겠습니다(정수 배열의 오름차순을 예로 들어 보겠습니다).

#include <stdio.h>
#include <string.h>

//非字符串类型的比较方法
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}

//字符串类型的比较方法
//int char_cmp(const void* p1, const void* p2)
//{
//	return strcmp(根据两个字符串相关类型传入有关参数);
//}

//交换函数swap的实现
void swap(char* buf1, char* buf2, int size)
{
	int i = 0;
	char tmp = 0;
	for (i = 0; i < size; i++)
	{
		//由于不知道交换数据的具体单位,所以我么逐字节进行数据交换
		tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

void bubble_sort(void* base, int count, int size, int(*cmp)(void*, void*))
{
	//确定交换的趟数
	int i = 0;
	for (i = 0; i < count - 1; i++)
	{
		//确定一趟交换类型的次数
		int j = 0;
		for (j = 0; j < count - 1 - i; j++)
		{
			//这里假设是升序交换(即>0)
			//跟据交换参数的类型不同,将位置定位到第j个和第j+1个元素的位置上
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * 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[] = { 3,1,6,4,7,8,2,5,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), int_cmp);
	print(arr, sz);
}

int main()
{
	test();
	return 0;
}

자, 콜백함수와 qsort함수의 내용은 여기까지 입니다. 미래의 다창 직원분들의 많은 지원 부탁드립니다! ! !

Guess you like

Origin blog.csdn.net/asdssadddd/article/details/131781359