拿捏指针(三)

0f3a2b8bed084b1488aef3e7406bf5b9.jpeg

✨✨欢迎👍👍点赞☕️☕️收藏✍✍评论

个人主页秋邱'博客

所属栏目C语言

(感谢您的光临,您的光临蓬荜生辉)

 前言

在这之前我们学习了《拿捏指针(一)》《拿捏指针(二)》没看过的可以去看看哟,接下里我们将指针最后一篇,《拿捏指针(三)》,看完直接捏爆指针。

函数

 

前面我们已经学过了指针函数,接下里学指针数组,回调函数。

我们先来看看下面这串代码。

计算器

#define _CRT_SECURE_NO_WARNINGS
#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;
}
int main()
{
    int x, y;
    int ret = 0;
    int input = 0;
    do
    {
        printf("************************\n");
        printf("***** 1.Add  2.Sub *****\n");
        printf("***** 3.Mul  4.Div *****\n");
        printf("*******  0.exit  *******\n");
        printf("************************\n");
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
            ret = Add(x, y);
            printf("ret = %d\n", ret);
                break;
        case 2:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
                ret = Sub(x, y);
                printf("ret = %d\n", ret);
                break;
        case 3:
            printf("输入操作数:");
            scanf("%d %d", &x, &y);
                ret = Mul(x, y);
                printf("ret = %d\n", ret);
                break;
        case 4:
            printf("输⼊操作数:");
            scanf("%d %d", &x, &y);
                ret = Div(x, y);
            printf("ret = %d\n", ret);
        case 0:
            printf("退出程序\n");
                break;
        default:
            printf("输入错误\n");
        }
        
    } while (input);
}

虽然我们实现了这个计算器,但是它太过于累赘了,这是我们就可以用函数指针数组。

函数指针数组

数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组,那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组

其实在《拿捏指针(二)》的模拟二维数组里面,我们已经用过函数指针数组了。

定义的格式

int (*p[3])();

 p先和 [] 结合,说明p是数组,数组的内容是 int (*)() 类型的函数指针。

我们现在对上面的代码进行,更改用函数指针数组的方式。

#define _CRT_SECURE_NO_WARNINGS
#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;
}
int main()
{
    int x, y;
    int ret = 0;
    int input = 0;
    int(*p[5])(int x, int y) = { 0, Add, Sub, Mul, Div };
    do
    {

        printf("************************\n");
        printf("***** 1.Add  2.Sub *****\n");
        printf("***** 3.Mul  4.Div *****\n");
        printf("*******  0.exit  *******\n");
        printf("************************\n");
        printf("请选择:");
        scanf("%d", &input);
        if ((input <= 4 && input >= 1))
        {
            printf("输⼊操作数:" );
            scanf("%d %d", &x, &y);
            ret = (*p[input])(x, y);
            printf("ret = %d\n", ret);
        }
        else if (input == 0)
        {
            printf("退出计算器\n");
        }
        else
        {
            printf("输⼊有误\n" );        
        }
    } while (input);
 
}

回调函数

回调函数是一个函数,它作为参数传递给另一个函数,在特定事件发生时被调用。这种机制允许我们将代码模块化,并在需要的时候进行调用。回调函数常用于事件处理、异步编程、并发编程等场景。

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 calc(int(*pf)(int, int))//回调函数
{
    int ret = 0;
    int x, y;
    printf("输⼊操作数:");
    scanf("%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");
        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);

}

qsort()函数

冒泡排序

什么事冒泡排序呢?

冒泡排序是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

动图演示 

f37db5d0b8d041cb9224eb386033674e.gif

我们就用c语言来实现它。

void Swap(int* arr, int sz)
{
	for (int i = 0; i < sz -1; i++)
	{
		for (int j = 0; j < sz - i -1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[10] = { 3,6,8,1,9,4,2,7,10,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Swap(arr,sz);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 输出结果:


 1 2 3 4 5 6 7 8 9 10

这就是冒泡排序的C语言的实现方式,但是它的局限性太多了,比如你要用字符串呢,这就很难实现,所以我们可以用一个函数就是qsort()。

qsort()函数举例

我们先来看看qsort()的声明

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

base       指向数组中要排序的第一个对象的指针,转换为void*。

num       基数指向的数组中元素的个数。Sizet是一个无符号整型。

size        数组中每个元素的字节大小。Size t是一个无符号整型。

compar 指向比较两个元素的函数的指针。这个函数被qsort反复调用以比较两个元素。应遵                循以下原型:Int compare (const void* p1, const void* p2)。

 

 下面我们来对它进行使用

排序整型数据

//整形数据结构
int int_arr(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
	int arr[10] = { 3,6,8,1,9,4,2,7,10,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr,sz,sizeof(arr),int_arr);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

排序结构数据

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>//strcmp函数的头文件
#include<stdlib.h>//qsort函数的头文件
struct people {
	char name[20];
	int age;
};
//数据结构名字比较
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct people*)e1)->name, ((struct people*)e2)->name);
}

//打印
void Print(struct people* p1,int sz)
{
	for (int i = 0; i < sz; i++)
	{
		/*printf("%s %d\n", p1[i].name, p1[i].age);//另一种打印方式*/
		printf("%s %d\n", (p1 + i)->name, (p1 + i)->age);
	}
	printf("\n");
}
//数据结构年龄比较
int cmp_age(const void* e1, const void* e2)
{
	return ((struct people*)e1)->age - ((struct people*)e2)->age;
}
int main()
{
	struct people s[] = { {"tangsan",20},{"lisi",10},{"zhaowu",40},{"laoliu",5} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_name);
	printf("按名字排序\n");
	Print(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_age);
	printf("按年龄排序\n");
	Print(s,sz);
	return 0;
}

输出结果:

按名字排序
laoliu 5
lisi 10
tangsan 20
zhaowu 40

 

按年龄排序
laoliu 5
lisi 10
tangsan 20
zhaowu 40

 

qsort()的模拟

上面我们已经知道了qsort函数的定义和使用,现在我们就来模拟一下qsort函数。

//实现qsort函数
void Swap(char* p1, char* p2,size_t width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}
int bubbl_sort(void* base, size_t num,size_t width,int cmp (const void*p1 ,const void* p2))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}
int int_cmp(const void* p1, const void* p2)
{
	return *(char*)p1 - *(char*)p2;
}

int main()
{
	int base[10] = {2, 7, 3, 8, 1, 9, 1, 5, 6, 0};
	int sz = sizeof(base) / sizeof(base[0]);
	bubbl_sort(base,sz,sizeof(base[0]),int_cmp );
	for (int i = 0; i < sizeof(base) / sizeof(base[0]); i++)
	{
		printf("%d ", base[i]);
	}
	printf("\n");
	return 0;
}

我们这里展现int型的排序。 

sizeof和strlen的对⽐

 

sizeof

前面我们也已经讲过了sizeof,现在我们再来简单的回顾一下,sizeof是一个操作符,用来计算类型的大小,单位是字节。

注意:
sizeof只与类型有关,跟内容没什么关系

int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof a);
	printf("%d\n", sizeof(int));
	return 0;
}

输出结果:

4

4

strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后,\0 之前字符串中字符的个数。 strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。

int main()
{
	char arr1[3] = { 'a', 'b', 'c' };
	char arr2[] = "abc";
	printf("arr1=%d\n", strlen(arr1));
	printf("arr2=%d\n", strlen(arr2));
}

输出结果:

arr1=(随机值,直到遇到\0后停下来)

arr2=3

char arr1[3] = { 'a', 'b', 'c' ,\0"};

这时只需要在后面手动改加上/0就可以了。

结尾 

我们指针以及全部将完了,感谢各位观众老爷的点赞,评论,收藏和关注。

 

 

 

  • 124
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 102
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 102
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值