Detailed explanation of the advanced part of C language (detailed explanation and simulation implementation of the classic callback function qsort())

Hello everyone! In the last article ( detailed explanation of the advanced part of C language (Pointer Advanced 2) - in short, it is a very humbling blog - CSDN blog ) I have already given a preliminary explanation of the callback function and a simple usage example, but due to the limited space, I did not proceed. A more detailed explanation will be added today.


Table of contents

1. The meaning of callback function

2.qsort() function 

1.Explain 

 2.Examples

3. Use bubble sort to simulate qsort()

1.main function

2.bubble_qsort()

3.cmp()

4.swap()

 Total code:


1. The meaning of callback function

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


2.qsort() function 

1.Explain 

According to the cplusplus website:

 Here comes the translation:

The qsort function is a function in the C language standard library and is used to quickly sort arrays. Its full statement is as follows:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

The qsort function accepts four parameters:

  1. base: Pointer to the first element of the array to be sorted.
  2. nmemb: Indicates the number of elements in the array.
  3. size: Indicates the size of each element in bytes.
  4. compar: Pointer to a callback function used to compare two elements

The callback function comparis used to compare the size relationship of two elements. It accepts two parameters, which are pointers to the elements to be compared. The callback function should return an integer value indicating the size relationship between the two elements. If a negative number is returned, it means that the first element is less than the second element; if a positive number is returned, it means that the first element is greater than the second element; if it returns zero, it means that the two elements are equal.

Generally, we need to write this callback function ourselves:

//升序排序  针对整型的排序:
int compare (const void * a, const void * b)
 {
     return ( *(int*)a - *(int*)b );
 }

//降序排列
 int compare (const void * a, const void * b)
 {
     return ( *(int*)b - *(int*)a );
 }

 2.Examples

Sort an array of integers

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {5, 3, 8, 2, 1, 4};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    qsort(arr, size, sizeof(int), compare);
    
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    
    return 0;
}

 

 At the same time, we can also sort other data types. The following is the sorting of structures.

 struct Student{
    char name[20];
    int score;
} ;

int compare(const void* a, const void* b) {
    return ((struct Student*)a)->score - ((struct Student*)b)->score;
}

int main() {
   struct Student students[] = {
        {"Alice", 85},
        {"Bob", 92},
        {"Charlie", 78},
        {"David", 80},
        {"Eva", 88}
    };
    int size = sizeof(students) / sizeof(students[0]);

    qsort(students, size, sizeof(struct Student), compare);

    printf("按照成绩排序后的学生列表:\n");
    for (int i = 0; i < size; i++) {
        printf("姓名:%s,成绩:%d\n", students[i].name, students[i].score);
    }

    return 0;
}


3. Use bubble sort to simulate qsort()

1.main function

Here main only performs the most basic processing, and then enters the bubble_qsort() function 

int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };     //定义整型数组并初始化
	int sz = sizeof(arr) / sizeof(arr[0]);    //计算数组长度
	int i = 0;
	bubble_sort(arr, sz, sizeof(arr[0]), cmp);    //模拟qsort函数实现冒泡排序
	for (i = 0; i < sz; i++)                   
	{
		printf("%d ", arr[i]);                     //排序完后对数组进行打印,验证排序是否成功
	}
}

2.bubble_qsort()

Bubble sort function bubble_sort, which accepts four parameters: the array to be sorted arr, the length of the array sz, the size of each element, widthand the comparison function cmp. The bubble sort function uses a two-level loop to implement the bubble sort process. The outer loop controls the number of bubble sort passes, and the inner loop traverses the pairs of elements that need to be compared in each pass. In each pass of bubble sort, if the result returned by the comparison function is greater than 0, the two adjacent elements are exchanged and the larger element is moved backward.

  • We can see that the type of the formal parameter is  void* arr, which can accept any type pointer
  • We will pass the parameters to be compared to the comparison function cmp():

The first one is: (char*)arr + (j * width) We first convert void* to char*, and then add j*width. Width is the size of each element, and j*width is what needs to be added. The number of bytes, so (char*)arr + (j * width) is the address of the first byte of the j-th element

void bubble_sort(void* arr, int sz, int width, int(*cmp)(void* e1, void* e2))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//冒泡排序趟数
		for (j = 0; j < sz - 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);
			}
		}
	}
}

3.cmp()

Although a pointer of type char* is passed, we still access four bytes after the cast. 

int cmp(void* e1, void* e2)   //所选择的比较方法
{
	return *((int*)e1) - *((int*)e2);
}

4.swap()

The parameters of the function include two pointers p1and p2, pointing to the two elements that need to be exchanged, and an integer widthindicating the size of each element.

Inside the function, we use a temporary variable tto hold the temporary value during the exchange. Then use a loop to iterate through each byte and swap the two elements byte by byte.

void swap(char* p1, char* p2, int width)   //实现数组元素的交换
{
	int t = 0;
	int i = 0;
	for (i = 0; i < width; i++)
	{
		t = *p1;
		*p1 = *p2;
		*p2 = t;
		p1++;
		p2++;
	}
}

 Original code:

#include<stdio.h>
 
//仿qsort函数重写冒泡排序
int cmp(void* e1, void* e2)   //所选择的比较方法
{
	return *((int*)e1) - *((int*)e2);
}
void swap(char* p1, char* p2, int width)   //实现数组元素的交换
{
	int t = 0;
	int i = 0;
	for (i = 0; i < width; i++)
	{
		t = *p1;
		*p1 = *p2;
		*p2 = t;
		p1++;
		p2++;
	}
}
void bubble_sort(void* arr, int sz, int width, int(*cmp)(void* e1, void* e2))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//冒泡排序趟数
		for (j = 0; j < sz - 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);
			}
		}
	}
}
int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };     //定义整型数组并初始化
	int sz = sizeof(arr) / sizeof(arr[0]);    //计算数组长度
	int i = 0;
	bubble_sort(arr, sz, sizeof(arr[0]), cmp);    //模拟qsort函数实现冒泡排序
	for (i = 0; i < sz; i++)                   
	{
		printf("%d ", arr[i]);                     //排序完后对数组进行打印,验证排序是否成功
	}
}

 Of course, this simulation method still has many shortcomings:

  1. Bubble sort is simple but inefficient
  2. Swapping positions byte by byte works for any type of element, regardless of element type or size. However, it has the disadvantage of being less efficient

I hope I can improve accordingly after learning new knowledge in the future. 

 

Guess you like

Origin blog.csdn.net/qq_74415153/article/details/133207122