拿捏指针(三)

2024-03-19 19:20
文章标签 指针 拿捏

本文主要是介绍拿捏指针(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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先和 [] 结合,说明parr1是数组,是 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()函数

冒泡排序

什么事冒泡排序呢?

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

动图演示 

我们就用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就可以了。

结尾 

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

 

 

这篇关于拿捏指针(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/827008

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

C和指针:字符串

字符串、字符和字节 字符串基础 字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。 字符串长度就是字符串中字符数。 size_t strlen( char const *string ); string为指针常量(const修饰string),指向的string是常量不能修改。size_t是无符号数,定义在stddef.h。 #include <stddef.h>

【C++】作用域指针、智能指针、共享指针、弱指针

十、智能指针、共享指针 从上篇文章 【C++】如何用C++创建对象,理解作用域、堆栈、内存分配-CSDN博客 中我们知道,你的对象是创建在栈上还是在堆上,最大的区别就是对象的作用域不一样。所以在C++中,一旦程序进入另外一个作用域,那其他作用域的对象就自动销毁了。这种机制有好有坏。我们可以利用这个机制,比如可以自动化我们的代码,像智能指针、作用域锁(scoped_lock)等都是利用了这种机制。

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

C和指针:结构体(struct)和联合(union)

结构体和联合 结构体 结构体包含一些数据成员,每个成员可能具有不同的类型。 数组的元素长度相同,可以通过下标访问(转换为指针)。但是结构体的成员可能长度不同,所以不能用下标来访问它们。成员有自己的名字,可以通过名字访问成员。 结构声明 在声明结构时,必须列出它包含的所有成员。 struct tag {member-list} variable-list ; 定义一个结构体变量x(包含

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

Qt: 详细理解delete与deleteLater (避免访问悬空指针导致程序异常终止)

前言 珍爱生命,远离悬空指针。 正文 delete 立即删除:调用 delete 后,对象会立即被销毁,其内存会立即被释放。调用顺序:对象的析构函数会被立即调用,销毁该对象及其子对象。无事件处理:如果在对象销毁过程中还涉及到信号和槽、事件处理等,直接 delete 可能会导致问题,尤其是在对象正在处理事件时。适用场景:适用于在确定对象已经不再被使用的情况下,并且不涉及异步处理或事件循环中的

C语言进阶版第8课—指针(2)

文章目录 1. 数组名的理解2. 指针访问数组3. 一维数组传参本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组 1. 数组名的理解 sizeof(数组名)— 这里的数组名代表整个数组,计算的也是整个数组的大小&数组名 — 这里的数组名代表是整个数组,取出的是整个数组的地址除了以上两种,其他任何地方使用数组名,数组名都表示首元素的地址 //数组名