[C] Detailed explanation of callback function and qsort

Callback function concept

A callback function is a function that is called through a function pointer. If you pass a function pointer (address) as a parameter to another
function, when this pointer is used to call the function it points to, we say this is a callback function. The callback function is not
directly called by the implementer of the function, but is called by another party when a specific event or condition occurs, and is used to
respond to the event or condition.
Simply put, the callback function is the function called through the function pointer is the callback function. There is a function qsort in our library, which uses the callback function.

Library function qsort (in the header file stdlib.h)

This function is a sorting function. We have learned bubble sorting, but that sorting can sort integers. The qsort we are talking about today can sort any type, and it sorts in ascending order by default. Let's take a look at his parameter list:

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

The void* here is untyped, because any type of array can be sorted, so I don’t know what kind of array pointer you are receiving with void*, size_t is an unsigned integer, num represents the size of the array, and width is The size of each element in the array, the last parameter is a function pointer, pointing to a function like int xxxx(const void *elem1, const void *elem2). Look at the picture below again:
insert image description here
if the content pointed to by elem1 is greater than the content pointed to by elem2, it returns a number greater than 0, if it is equal to it, it returns 0, and if it is less than it, it returns a number smaller than 0.
Then let's get started with this function:

// qsort需要的函数
int sort_int(const void* p1, const void* p2)
{
    
    
	return *((int*)p1) - *((int*)p2);
}
// 打印函数
void print(int* arr, int size)
{
    
    
	for (int i = 0; i < size; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
    
    
	int arr[] = {
    
     5,6,4,8,1,3,2,7,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
	qsort(arr, sz, sizeof(arr[0]), sort_int);
	print(arr, sz);
	return 0;
}

operation result:

insert image description here
The main thing is that void* cannot be dereferenced directly, it needs to be converted first, and then operated.

qsort simulation implementation

Because we have learned bubble sorting so far, we will use bubble sorting to simulate qsort today.
We will take down the above code and change qsort to my_qsort.

int sort_int(const void* p1, const void* p2)
{
    
    
	return *((int*)p1) - *((int*)p2);
}
// 打印函数
void print(int* arr, int size)
{
    
    
	for (int i = 0; i < size; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
    
    
	int arr[] = {
    
     5,6,4,8,1,3,2,7,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
	my_qsort(arr, sz, sizeof(arr[0]), sort_int);
	print(arr, sz);
	return 0;
}

Now we only need to implement my_qsort. What we pass here is an integer array, so we can use an integer pointer to accept it, but our qsort can sort any type of data, so we need to use void* to accept it. So the parameter list of the function is:

void my_qsort(void* arr, size_t num, size_t width, int (cmp)(const void, const void*))

No matter what data we sort in bubble sort, the number of times we sort will definitely not change, and the logarithm of each comparison is also fixed, so we can realize the general framework of bubble sort, where the function pointer points to A function can be thought of as a function that compares the size of two elements. Our comparison function needs two pointers, that is, the addresses of two elements. At this time, the size of the elements we pass in will play a role. The address of our first element can be considered as arr, and the second is arr+1 width . And because only arr is of (char ) type, we can realize that the unit of each jump is 1, so we have to convert arr to (char*) type before that because the elements we shoot are changing, we will here The parameters are set to
(char*)arr+j*width, (char*)arr+(j+1)*width, so that we can implement my_sort.

void my_qsort(void* arr, size_t num, size_t width, int (*cmp)(const void*, const void*))
{
    
    
	for (unsigned int i = 0; i < num - 1; i++)
	{
    
    
		for (unsigned int j = 0; j < num - 1 - i; j++)
		{
    
    
			if (cmp((char*)(arr)+j*width,(char*)(arr)+(j+1)*width)>0)
			{
    
    
				Swap((char*)(arr) + j * width, (char*)(arr) + (j + 1) * width,width);
			}
		}
	}
}

There is only one Swap function left here. After this function is implemented, our my_qsort can work normally.
Because we still want to exchange two elements, we need to pass the address of the two elements to the past, which is of type (char*), so we can use char* to receive it, and because char* can only access one at a time Bytes, if we want to exchange integers, we only need to exchange the contents of 4 bytes, so we also need to talk about the size of the elements.

void Swap(char* p1, char* p2, int width)
{
    
    
	char tmp = 0;
	for (int i = 0; i < width; i++)
	{
    
    
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}

At this point, our qsort has been implemented. Let's take a look at the running results:
insert image description here
we can see that our sorting is no problem.

This is the end of today's sharing, thank you for your attention and support!

Guess you like

Origin blog.csdn.net/bushibrnxiaohaij/article/details/131640656