[Avanzado C] Función de devolución de llamada (puntero avanzado 2, explicación detallada, visita obligada para principiantes)

Tabla de contenido

6. Matriz de punteros de función

6.1 Calculadora sencilla

6.2 Matriz de puntero de función para realizar la calculadora

7. Un puntero a una matriz de punteros de función (solo para entender)

8. Función de devolución de llamada

8.1 Comprensión de las funciones de devolución de llamadaEditar

8.1.1 Mejorar una calculadora simple con devoluciones de llamada

8.2 Uso de la función de biblioteca qsort

8.2.1 Clasificación de burbuja

8.2.2 El concepto de qsort

8.3 Idea de clasificación de burbujas para realizar qsort


         Este artículo incluye, entre otros, un resumen de puntos de conocimiento, como matrices de punteros de función , punteros a matrices de punteros de función y funciones de devolución de llamada. Heredando el puntero anterior avanzado (1) resumen de puntos de conocimiento, portal -->  http://t.csdn.cn/mgVGJ

Puntero avanzado (3): análisis y resumen de puntero y matriz de preguntas de prueba escritas, Portal -->  http://t.csdn.cn/aKVsj 

        Si hay algún error, por favor señale y corrija, ¡gracias por su visita!

6. Matriz de punteros de función

Una matriz es un espacio de almacenamiento que almacena el mismo tipo de datos, por lo que ya hemos aprendido acerca de las matrices de punteros,
Por ejemplo:
int * matriz [ 10 ];
//Cada elemento del arreglo es un int*

Luego almacene la dirección de la función en una matriz, luego esta matriz se denomina matriz de punteros de función, ¿ cómo definir la matriz de punteros de función ?

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

 La respuesta es: parr1 //1

Parr1 primero se combina con [] , lo que indica que parr1 es una matriz, ¿cuál es el contenido de la matriz?
Es un puntero de función de tipo int (*)() . --> Para que una variable quite su nombre, es su tipo.
int my_strlen(const char* str)
{
	return 0;
}
int main()
{
  //指针数组
	char* arr[10];
  //数组指针
	int arr2[5] = { 0 };
	int(*p)[5] = &arr2;//p是一个指向数组的指针变量

	//函数指针
    int (*pf)(const char*) = my_strlen;//pf是一个指向函数的函数指针变量
	
	//函数指针数组-存放函数指针的数组
	int (*pfArr[10])(const char*);
    //1.pf先与[10]结合,代表这是一个数组,数组有10个元素;
    //2.去掉pf[10],剩余int (*)(int,int)为数组每个元素的类型--函数指针类型

	return 0;
}

Los siguientes tres métodos de escritura son todos equivalentes
1. *(*pf)("abcdef");
2. pf ("abcdef");
3. my_strlen("abcdef");

Ilustremos implementando una función de calculadora, donde se usa la matriz de puntero de función:

6.1 Calculadora sencilla

De acuerdo con nuestro pensamiento normal, escribir una calculadora simple para realizar la función de suma, resta, multiplicación y división de números enteros debe escribirse aproximadamente como este código:

Luego ejecútelo y vea cómo va:

El problema anterior es que después de ingresar 0, no imprime inmediatamente "Salir de la calculadora" y luego finaliza el programa, sino que continúa ingresando dos operandos antes de imprimir la información, y también imprime un 6 por cierto, debe haber un problema con este código Vamos a mejorarlo un poco.

//写一个计算器能完成整数的+ - * /
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("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数:>");
			scanf("%d %d",&x,&y);
			ret = Mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default :
			printf("选择错误\n");
			break;
		}
	}while(input);
	return 0;
}

Ejecute el código y continúe probando:

 El problema está resuelto, pero se encuentra un nuevo problema:

 Hay demasiadas declaraciones de cambio de caso en el código anterior. Cuando quiero agregar funciones como: << >> & | ^ && || en este contador, habrá más y más declaraciones de caso. ¿Cómo debo corregirlo? ?

En este momento, se utilizará una matriz de punteros de función .

ejemplo:

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()
{
	//存放函数指针的数组 - 函数指针数组
	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;
}

Este código utiliza una matriz de punteros de función, almacena las direcciones de las cuatro funciones de operación en la matriz y luego atraviesa la matriz a través de un bucle, llama a las cuatro funciones de operación a su vez para realizar cálculos y generar los resultados. Este enfoque puede reducir la duplicación de código y mejorar la capacidad de mantenimiento del código.

 6.2 Matriz de puntero de función para realizar la calculadora

//函数指针数组实现计算器
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;//用于接收值
   
    //转移表 - 函数指针的数组
	int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
							 //   0    1   2   3    4
	//NULL的作用是为了占用0下标,然后让函数指针数组的元素下标对应上菜单的功能
	do {
		//菜单
		menu();
		//进行选择
		printf("请选择:>");
		scanf("%d", &input);
		//用函数指针数组代替switch
		if (input == 0)
		{
			printf("退出计算器\n");
			return 0;
		}
		else if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:>");
			scanf("%d %d",&x,&y);
			ret = (***pfArr[input])(x, y);//其实比函数指针的用法就多了一个[input]
			 //跟函数指针一样,调用函数的时候 * 是没有任何意义的
			printf("%d\n",ret);
		}
		else
		{
			printf("选择错误\n");
		}
	} while (input);
	return 0;
}

Una matriz de punteros de función es una matriz cuyos elementos son punteros de función. Cada puntero de función apunta a una función específica, y la función correspondiente se puede llamar a través del puntero de función. La matriz de punteros de función se puede utilizar para resolver el problema de la redundancia del código y puede atravesar y llamar fácilmente a diferentes funciones, lo que simplifica la estructura y la lógica del código y mejora la capacidad de mantenimiento y la escalabilidad del código.

Propósito de la matriz de punteros de función: tabla de transferencia

7. Un puntero a una matriz de punteros de función (solo para entender)

//指向函数指针数组的指针
int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a - b;
}
int main()
{   //函数指针
	int(*pf)(int, int) = Add;
	//函数指针数组
	int (*pfArr[4])(int, int) = { Add,Sub };
	//指向函数指针数组的指针
	 int (*(*ppfArr)[4])(int,int) = &pfArr;

	 return 0;
}

Cómo entender un puntero a una matriz de punteros de función:

8. Función de devolución de llamada

concepto

Una función de devolución de llamada es una función que se llama a través de un puntero de función. Si pasa un puntero de función (dirección) como parámetro a otra función, cuando este puntero se usa para llamar a la función a la que apunta, decimos que se trata de una función de devolución de llamada.
El implementador de la función no llama directamente a la función de devolución de llamada, sino que la llama otra parte cuando ocurre un evento o condición específicos, y se usa para responder al evento o condición.
El problema de la redundancia de código: problemas con la primera versión de Simple Calculator

Hay muchas partes con la misma lógica y código redundante.

 En este momento, debe usar la función de devolución de llamada para resolver el problema:

8.1 Comprensión de las funciones de devolución de llamada

8.1.1 Mejorar una calculadora simple con devoluciones de llamada

#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;
}
//将冗余重复部分用Calc函数封装(只用了一个函数),通过这个函数里面传入的函数指针调用计算器函数
void Calc(int(*pf)(int, int))//pf函数指针,传过来哪个函数地址就用哪种类型计算
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:>");
	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("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
			break;
			}
		} while (input);
	return 0;
}

Resumir:

Función de devolución de llamada: la función pasada como parámetro, las cuatro funciones de Add, Sub, Mul y Div son funciones de devolución de llamada,

La función Calc es una herramienta

8.2 Uso de la función de biblioteca qsort

8.2.1 Clasificación de burbuja

Revise el proceso de clasificación de burbujas:

La idea de la clasificación de burbujas: comparar dos elementos adyacentes, suponiendo que se van a organizar en orden ascendente

Cómo escribir el código para la clasificación de burbujas:
①El número de veces está determinado por el número de elementos

②Logaritmo comparativo determinado por el número de viajes         

③Dos elementos se intercambian en pares y se organizan en orden ascendente

//冒泡排序 
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//趟数
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//比较对数
		{
			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;
}

insuficiente:

Pero la desventaja de este tipo de burbuja también es obvia, es decir, solo se puede ordenar un número entero.

Si encuentra datos de punto flotante, estructura y otros tipos de datos, no puede organizarlos, entonces, ¿cómo puede resolverlos?

En este momento, se usará qsort.

8.2.2 El concepto de qsort

qsort-- ordenación rápida

Es una función de biblioteca, que se usa para ordenar la función de biblioteca usando el método de clasificación rápida

La ventaja de qsort es

1. Confeccionado

2. Puede ordenar cualquier tipo de datos

 

qsort puede ordenar cualquier tipo de datos

1. Compara el tamaño de 2 enteros, > < ==

//qsort函数的使用者提供这个函数
//qsort 默认是升序
int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
    //排成倒序的话,什么都不用动,只需要return *(int*)p2 - *(int*)p1;//调换顺序即可
}
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来排序整型数组,这里就要提供一个比较函数,这个比较函数能够比较2个整数的大小
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
   test1();
}

 

2. Compare 2 cadenas, strcmp --> revise el conocimiento de cadenas: http://t.csdn.cn/V7E9a

3. Compare 2 datos de estructura (estudiantes: Zhang San, Li Si) especifique el estándar de comparación

Revise el conocimiento de los miembros de acceso a objetos de estructura: http://t.csdn.cn/DVEVj

//测试qsort 排序结构体数据
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);*/
}

edad de impresión:

imprimir género:

8.3 Idea de clasificación de burbujas para realizar qsort

Use la idea de la clasificación de burbujas para implementar una función de clasificación de burbujas bubble_sort() similar a la función de qsort

Cada parámetro se compone de:
base, num, ancho, función cmp, elem1 y elem2

A continuación, explique las ideas de diseño de cada parámetro de qsort:

①¿Por qué la base se define como tipo vacío*?

void* es un tipo de puntero general en lenguaje C , que puede apuntar a cualquier tipo de datos . En la función qsort, dado que se deben ordenar diferentes tipos de datos, se deben usar punteros de tipo void* para aceptar varios tipos de datos.El parámetro base es un puntero al primer elemento de la matriz que se ordenará . Dado que apunta a datos de cualquier tipo, el uso de void* es el más general.

Ejemplo:

int a = 10;

void* p = &a;

ventaja:

No hay un tipo específico de puntero, por lo que puede recibir cualquier tipo de dirección

defecto:

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

p++  //-->  因为不知道是什么数据类型,不能直接++

Uso Correcto:

*(int*)p;//也可以转化成其它类型

②¿Por qué num debe diseñarse como size_t?

  • size_t es un tipo entero sin signo en lenguaje C, que se utiliza para representar el tamaño, la longitud y el valor del índice, y es adecuado para representar el número de elementos de la matriz.
  • El número de elementos de la matriz es un valor no negativo y es más razonable usar el tipo sin signo size_t para evitar números negativos.

  • El uso del tipo especializado size_t es más indicativo de la semántica de este parámetro que un simple int sin signo: representa un tamaño o longitud, no un número entero.

③Por qué el ancho debe diseñarse como size_t

En la función qsort, el parámetro ancho indica el tamaño de cada elemento de la matriz (en bytes)

  1. El ancho representa un concepto de "tamaño", utilizando el tipo size_t se puede expresar la semántica de este parámetro con mayor claridad.

  2. La unidad de ancho es byte, y size_t suele ser un tipo entero sin signo, y no habrá números negativos, por lo que es más adecuado para representar valores positivos.

  3. ancho requiere un rango lo suficientemente grande como para representar el tamaño de cualquier tipo de datos. El tipo size_t depende de la plataforma, pero generalmente tiene el tamaño de una palabra de máquina, lo que satisface los requisitos de tamaño de la mayoría de los elementos de datos.

  4. Al acceder a los elementos de la matriz, la posición del índice debe multiplicarse por el tamaño del elemento para obtener el desplazamiento de la dirección. Dado que el índice es de tipo size_t, el resultado de multiplicar los dos también debería ser de tipo size_t para evitar problemas de desbordamiento.

④ ¿Por qué diseñar un puntero de función cmp?

  1. qsort en sí es una función de clasificación general, que no puede saber el tipo de elementos que se van a clasificar, por lo que no puede comparar directamente dos elementos. El uso de punteros de función puede dejar la implementación de las operaciones de comparación al usuario.

  2. A través de punteros de función , los usuarios pueden implementar funciones de comparación para sus propios tipos de datos y encapsular una lógica de comparación específica. Esto aumenta la versatilidad y flexibilidad de qsort.

  3. Para diferentes tipos de datos, la lógica de la operación de comparación puede ser diferente. El uso de punteros de función puede evitar escribir mucha lógica de bifurcación condicional en qsort.

  4. Los punteros de función proporcionan un mecanismo de extensión. Si el usuario necesita cambiar la lógica de la operación de comparación, solo necesita pasar un nuevo puntero de función, sin cambiar la función qsort en sí.

⑤¿Por qué los tipos elem1 y elem2 son const void*?

  1. qsort ordena datos de cualquier tipo, por lo que la función de comparación debe poder manejar elementos de cualquier tipo. El uso de void* puede apuntar a cualquier tipo de datos, y const se usa para indicar que el contenido al que apunta el puntero no debe modificarse.

  2. qsort ordena datos de cualquier tipo, por lo que la función de comparación debe poder manejar elementos de cualquier tipo. El uso de void* puede apuntar a cualquier tipo de datos, y const se usa para indicar que el contenido al que apunta el puntero no debe modificarse.

  3. Al llamar a qsort, puede convertir directamente la dirección del elemento de matriz en un tipo const void* y pasarlo a la función de comparación para simplificar la llamada.

  4. La función qsort en sí misma no necesita comprender el tipo específico del elemento, simplemente pase el puntero void* a la función de comparación, y la función de comparación convierte e interpreta el contenido del puntero.

Inicie la implementación de la simulación: no es necesario cambiar la idea de clasificación de burbujas de preguntas grandes, solo se debe modificar el método de clasificación

int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
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++;
	}
}

//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
    //冒泡排序大题思路不需要改变,只需要对排序方式进行即可
	//要确定趟数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假设已经有序了
		//一趟冒泡排序的过程
		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);
}

análisis de qsort del código:

Cómo intercambiar datos:

¿Por qué este lugar está escrito como char*?

En la función bubble_sort, dado que el tipo de datos al que apunta la base no se conoce, debe convertirse al tipo char*, de modo que el tamaño de paso del puntero sea 1. De esta forma, al sumar y restar punteros, el tamaño de paso de los punteros se puede controlar de acuerdo con el parámetro de ancho, para realizar la clasificación de cualquier tipo de datos.

Nota: ancho significa 1 byte para char, pero no para otros tipos Ancho establece diferentes tipos de datos de acuerdo con diferentes parámetros y controla el tamaño del paso del puntero.

Proceso de intercambio: 1, 2, 3, 4 representan el pedido 

 El flujo general del código:

Ordenar por:

Ordenar edad y nombre por tipo de burbuja recién definido

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++;
	}
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
	//要确定趟数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假设已经有序了
		//一趟冒泡排序的过程
		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);

}

Ordenar por nombre:

 ordenar por edad

Este artículo está aquí, corríjame si hay algún error, y luego baje a este resumen detallado sobre sizeof y strlen:, resumen de análisis de preguntas de prueba de puntero y matriz, portal -->  http://t.csdn. cn/aKVsj

Bienvenidos todos a visitar.

Supongo que te gusta

Origin blog.csdn.net/weixin_65186652/article/details/131976796
Recomendado
Clasificación