深入理解c指针(七)

本文详细介绍了C语言中的回调函数概念及其在简化重复代码中的应用,展示了如何使用qsort进行数组排序,包括升序和字符串长度排序,以及如何使用qsort对结构数据进行排序。同时,文中还涉及到了size_t数据类型、ASCII码值、strcmp函数和冒泡排序的模拟实现。
摘要由CSDN通过智能技术生成

目录

十、回调函数和qsort函数

1、回调函数

2、简单介绍size_t 数据类型

3、qsort 排序函数 

3.1 qsort函数简单举例1(升序排序)

3.2 qsort函数简单举例2(字符串长度排序)

3.3 简单讲解 -> 操作符

3.4 常见符号的ASCII码值

3.5 简单介绍strcmp函数 

3.6 使用qsort排序结构数据

4、qsort函数的模拟实现(利用冒泡排序算法)


十、回调函数和qsort函数

ps:关于函数指针的内容在深入理解c指针(六)

1、回调函数

       还是以加、减、乘、除四个函数的应用为例,在如下代码中,红色框中的代码是重复出现的,其中虽然执行计算的函数是有区别的,但是输入输出操作是冗余的,有没有办法,简化一些呢?
       因为红色框中的代码,只有调用函数的逻辑是有差异的,我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。

如下是使用回调函数的代码:

//使⽤回到函数改造后
#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}
void calc(int(*pf)(int, int))
{
	int ret = 0;
	int x, y;
	printf("输⼊操作数:");
	scanf_s("%d %d", &x, &y);
	ret = pf(x, y);
	printf("ret = %d\n", ret);
}
int main()
{
	int input = 1;
	do
	{
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf(" 0:exit \n");
		printf("*************************\n");
		printf("请选择:");
		scanf_s("%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;
}

2、简单介绍size_t 数据类型

   size_t 与int 、double一样是C语言中的一种数据类型,通常用于表示对象的大小(以字节为单位)或数组的索引。它是无符号整数类型,在不同的系统上的大小可能会有所不同,但通常被定义为能够容纳系统中最大对象大小的无符号整数类型。字节大小如下:

同时 size_t 数据类型以%zd形式打印:

#include<stdio.h>
int main()
{
	size_t a = 20;
	printf("%zd",a);
	return 0;
}
3、qsort 排序函数 

        在C语言中,qsort函数是stdlib.h标准库中的一个函数,用于对任意数据类型进行快速排序。qsort函数的原型如下:

  • base:指向要排序的数组的指针,接收数组首元素地址。
  • nmemb:数组中元素的个数。
  • size:数组中每个元素的大小(以字节为单位)。
  • compar:指向比较函数的指针,用于指定元素之间的比较规则。(函数指针)

        比较函数compar接受两个指向元素的指针,返回一个整数值来指示这两个元素的大小关系。如果返回值是负数,则表示第一个元素应该排在第二个元素之前;如果返回值是正数,则表示第二个元素应该排在第一个元素之前;如果返回值是零,则表示两个元素相等。

3.1 qsort函数简单举例1(升序排序)

3.2 qsort函数简单举例2(字符串长度排序)

       当我们调用qsort函数时,需要传递四个参数:要排序的数组指针、数组中元素的个数、每个元素的大小以及比较函数指针。

        假设我们有一个包含字符串的数组,我们想要按照字符串长度进行排序。首先,我们需要定义一个比较函数,该函数将根据字符串的长度来比较两个字符串。

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

// 比较函数,按字符串长度升序排序
int compare(const void *a, const void *b) 
{
    size_t len_a = strlen(*(char **)a);
    size_t len_b = strlen(*(char **)b);

    return len_a - len_b;
}

int main() 
{
    char *arr[] = {"apple", "banana", "orange", "kiwi", "pear"};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(char *), compare);

    for (int i = 0; i < n; i++) 
    {
        printf("%s\n", arr[i]);
    }

    return 0;
}

        在这个例子中,我们定义了一个字符串数组arr,并且定义了一个比较函数compare,用于按照字符串长度升序排序。在比较函数中,我们使用strlen函数获取字符串的长度,并将其转换为size_t类型进行比较。

       在main函数中,我们调用qsort函数对字符串数组arr进行排序,将每个元素的大小(指向字符串的指针)作为sizeof(char *)传递给qsort函数。

3.3 简单讲解 -> 操作符

   -> 操作符,用于访问结构体和联合体类型的成员,通过指向结构体或联合体的指针进行成员访问。它通常用于简化指针访问结构体成员的操作。

       具体来说,如果有一个结构体指针ptr,需要访问它所指向的结构体中的成员变量member,可以使用ptr->member来实现,这样就可以通过指针直接访问结构体中的成员,而不需要先解引用指针再使用 .操作符。示例如下:

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

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

int main() 
{
    struct Person person1;
    struct Person *ptr = &person1;

    // 使用strcpy函数给name成员赋值
    strcpy(ptr->name, "John Doe");
    ptr->age = 25;

    // 输出成员变量name和age的值
    printf("Name: %s, Age: %d\n", ptr->name, ptr->age);

    return 0;
}

 在上面的示例中,ptr->age用于访问结构体Person中的成员变量age,而不需要通过(*ptr).age的方式来访问。

3.4 常见符号的ASCII码值

3.5 简单介绍strcmp函数 

   strcmp函数是C语言中用于比较两个字符串大小的函数,其原型定义在string.h头文件中。该函数用于按字典顺序比较两个字符串,并返回一个整数值来表示比较结果。原型如下:

int strcmp(const char *str1, const char *str2);

      函数接受两个参数,分别是指向要比较的字符串的指针str1str2。它们分别指向以null结尾的C字符串(即以null字符\0作为字符串的结束标志)。 

只要记住: 

1.这个函数比较的是两个字符串对应位置元素的ASCII码值,如果str1对应元素的ASCII码值在str2对应元素之前,则返回一个负整数,在其之后返回正整数,如果相等,则比较下一个元素。

2.该函数是对字符串元素依次进行比较,如果相等则比较下一个,一旦发现不相等的字符就能确定两个字符串的大小关系,后面的元素就不比较了。

3.如果两个字符串长度不相等,且前几个元素ASCII码值相同,那么短的比长的小。(如果短的是第一个字符串则返回负数,如果短的是第二个字符串则返回正数)

3.6 使用qsort排序结构数据
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//定义Stu结构体
struct Stu //学⽣
{
	char name[20];//名字
	int age;//年龄
};

//比较年龄的函数
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

//比较名字的函数
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//按照年龄来排序
void test2()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);

    //打印排序结果
	int i = 0;
	for (i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("Student %d:\n", i + 1);
		printf("Name: %s\n", s[i].name);
		printf("Age: %d\n", s[i].age);
		printf("\n");
	}

}

//按照名字来排序
void test3()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);

//打印排序结果
	int i = 0;
	for (i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("Student %d:\n", i + 1);
		printf("Name: %s\n", s[i].name);
		printf("Age: %d\n", s[i].age);
		printf("\n");
	}
}

int main()
{
	test2();
	test3();

	return 0;
}

4、qsort函数的模拟实现(利用冒泡排序算法)

ps:冒泡排序的基本思想在深入理解指针(五)

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

int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}

void _swap(void* p1, void* p2, int size)
{
	int i = 0;
	for (i = 0; i < size; i++)
	{
		char tmp = *((char*)p1 + i);
		*((char*)p1 + i) = *((char*)p2 + i);
		*((char*)p2 + i) = tmp;
	}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
	int i = 0;
	int j = 0;
//趟
	for (i = 0; i < count - 1; i++)
	{
       //每一趟冒泡排序过程
		for (j = 0; j < count - i - 1; j++)
		{
           //if(arr[j]>arr[j+1]
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
                // int tmp=arr[j];
                // arr[j]=arr[j+1];
                // arr[j+1]=tmp;

				_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;

	bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);

  //打印数组
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

跳转其他页面:

深入理解c指针(一)

深入理解c指针(二)

深入理解c指针(三)

深入理解c指针(四)

深入理解c指针(五)

深入理解c指针(六)

深入理解c指针(七)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做完作业了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值