【C语言】指针(4)

news2024/12/26 22:11:48

一、回顾

 在这之前,我们学习了很多关于指针的内容,我们先在这里简单的回顾一下。

1、一级指针

int* p;    -- 整形指针-指向整形的指针 

char* p; ...

void* p;...

...

2、二级指针

int** p; 

char** p;

...

3、数组指针 -- 指向数组的指针

int (*p)[ ];

int main(){
	int arr[3] = {1,2,3};
	int (*parr)[3] = &arr;
return 0;
}

4、指针数组 -- 存放指针的数组,本质就是数组。

 int* arr[ ];

int main(){
	int a[] = {1,2,3,4,5};
	int b[] = {2,3,4,5,6};
	int c[] = {3,4,5,6,7};
	int* arr[] = {a,b,c};
	for(int i=0;i<3;i++){
		for(int j=0;j<5;j++){
			printf("%d ",*(arr[i] + j));
		}
    	printf("\n");
	}
	return 0;
}

二、函数指针

 1、理解

指向函数地址的指针

 2、写法

 函数返回类型 (* p)(参数1、参数2、...)

 3、举例

int Add(int x,int y){
	return x + y;
}
int main(){
	int (*p)(int ,int ) = &Add;
	printf("%p\n",&Add);
	printf("%p\n",Add);
	return 0;
}

 在前面一节中将到了  数组名和&数组名的区别、但在这里 函数名 == &函数名。

4、使用

由于 函数名 ==  &函数名。所以可以有多种调用方法。

int Add(int x,int y){
	return x + y;
}
int main(){
	int (*p)(int ,int ) = &Add;
	int ret = (*p)(20,6);
//	int ret = p(20,6);
//	int ret = Add(20,6);
	printf("%d\n",ret);
	return 0;
}

5、试解析下列的一段代码

(*(void ( * ) () ) 0 ) ( ) ;

e832363829ad4b49a9e45762ba6e2e02.png

三、函数指针数组

1、理解

存放函数指针的数组、存放同类型的函数指针。

 2、写法

  函数返回类型 (* pArr [ ])(参数1、参数2、...)

 3、举例  --  简单计算器的实现

void menu(){
	printf("***********************\n");
	printf("*****1、Add    2、Sub**\n");
	printf("*****3、Mul    4、Div**\n");
	printf("*****    0、exit     **\n");
	printf("***********************\n");
}
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 input = 0;
	do{
		int x = 0, y = 0, ret = 0;
		int (*parr[5])(int, int) = {NULL,Add,Sub,Mul,Div};
		menu();
		printf("请选择要实现的功能:");
		scanf("%d",&input);
		if(input >= 1 && input <=4){
			printf("请输入两个操作数:");
			scanf("%d %d",&x , &y);
			ret = (*parr[input])(x,y);
			printf("ret=%d\n",ret);
		}else if(input == 0){
			printf("退出程序\n");
			break;
		}else{
			printf("输入错误,重新输入\n");
		}
		
	}while(input);
	
	return 0;
}

4、* 指向函数指针数组的指针

void test(const char* str ){
	printf("%s\n",str);
}
int main(){
	void (*p)(const char*) = test; //函数指针p
	void (*parr[2])(const char*) = { test , NULL}; //函数指针数组parr
	void (*(*p3)[2])(const char*) = &parr;// 指向函数指针数组的指针
	return 0;
}

四、回调函数

1、概念理解

通过函数指针调用的函数。 ---  把一个函数的地址(指针)作为参数传递给另一个函数,当这个指针被用来调用其所指的函数时,就称它为回调函数。

 2、举例说明 --  库函数 qsort 的使用

#include<stdio.h>
#include <stdlib.h>   // qsort头文件
// qsort 函数
//  void qsort (void* base, //指向待排序的首元素地址。
//			size_t num,     //待排序的元素个数
//			size_t size,	//待排序元素的大小,单位时字节
//			int (*compar)(const void*,const void*)); //待排序元素的比较方式

int compare (const void * a, const void * b)
{
	return ( *(int*)a - *(int*)b );
}
int main ()
{
	int arr[] = {14,78,24,69,10};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort (arr, sz, sizeof(arr[0]), compare);
	for (int i=0; i<sz ; i++)
		printf ("%d ",arr[i]);
	return 0;
}

 3、举例 --  模拟qsort实现冒泡排序升级版

#include<stdio.h>
//   函数实现
void swap(char* a , char* b , int size){
	for(int i=0;i<size;i++){
		char tmp = *a;
		*a = *b;
		*b = tmp;
		a++;
		b++;
	}
}
void bubblePP(void* base,  //指向待排序的首元素地址
			int num,       //待排序的元素个数
			int size,      //待排序元素的大小,单位是字节
			int (*compar)(const void* ,const void* )){  //待排序元素的比较方式 
	for(int i=0;i<num ;i++){
		for(int j=0;j<num - i - 1;j++){
			if(compar((char*)base +j*size , (char*)base + (j+1)*size) > 0){
				swap((char*)base +j*size , (char*)base + (j+1)*size , size);
			}
		}
	}
}

//  用户输入
int compar (const void * a, const void * b)
{
	return ( *(int*)a - *(int*)b );
}

void print(int arr[], int sz){
	for(int i=0;i<sz;i++){
		printf("%d ",arr[i]);
	}
	printf("\n");
}
void test1(){
	int arr[] = {14,78,24,69,10};
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr, sz);                          //排序之前打印
	bubblePP(arr,sz,sizeof(arr[0]),compar);  // 排序
	print(arr, sz);                          //排序之后打印
}
//void test2(){
//	char arr[] = {'w','m','z','d'};
//		int sz = sizeof(arr) / sizeof(arr[0]);
//		print(arr, sz);  // 要使 compar 和 print 的类型参数与这里的相对应
//		bubblePP(arr,sz,sizeof(arr[0]),compar);  // 排序
//		print(arr, sz);
//}
int main(){
	test1();
//	test2();
	return 0;
}

要点分析:

在函数内部,并不知道用户传递给我们的数据类型,所以根据最小的char类型以及待排序的元素大小size,来确定下一个元素的位置。

 这里依然是和上面一样的问题,所以在swap交换的时候采用一字节一字节的交换方式,并以元素大小size为限制表示一个元素是否交换完成。​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1809888.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker Swarm集群部署管理

Docker Swarm集群管理 文章目录 Docker Swarm集群管理资源列表基础环境一、安装Docker二、部署Docker Swarm集群2.1、创建Docker Swarm集群2.2、添加Worker节点到Swarm集群2.3、查看Swarm集群中Node节点的详细状态信息 三、Docker Swarm管理3.1、案例概述3.2、Docker Swarm中的…

拓扑排序-java

主要通过宽度优先搜索&#xff08;BFS&#xff09;来实现有向无环图的拓扑序列&#xff0c;邻接表存储图。数组模拟单链表、队列&#xff0c;实现BFS基本操作。 文章目录 前言 一、有向图的拓扑序列 二、算法思路 1.拓扑序列 2.算法思路 三、使用步骤 1.代码如下&#xff08;示…

【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【西瓜书】大题

1.线性回归 思路&#xff1a;ywxb&#xff0c;w为一维数组&#xff0c;求均方误差MSE&#xff0c;对w和b分别求偏导为0得到关于w和b的闭式求解。预测第十年的代入ywxb求解即可。 2.查准率、查全率 思路&#xff1a;先计算每个算法测试结果的混淆矩阵&#xff0c;再根据混淆矩阵…

Matlab|混合策略改进的蝴蝶优化算法

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序主要对蝴蝶算法&#xff08;BOA&#xff09;进行改进&#xff0c;参考文献《基于改进蝴蝶优化算法的冗余机器人逆运动学求解》&#xff0c;有如下改进策略&#xff1a; 改进1&#xff1a;采用反向学习策…

RK3568平台(显示篇)FrameBuffer 应用编程

一.FrameBuffer介绍 FrameBuffer&#xff08;帧缓冲器&#xff09;是一种计算机图形学概念&#xff0c;用于在显示器上显示图形和文本。在 计算机显示系统中&#xff0c;FrameBuffer 可以看作是显存的一个抽象概念&#xff0c;用于存储显示屏幕上显示 的像素点的颜色和位置信息…

ElementUi el-tree动态加载节点数据 load方法触发机制

需求背景&#xff1a;需要根据点击后获取的数据动态渲染一个 el-tree&#xff0c;同时渲染出来的 el-tree&#xff0c;需要点击节点时才能获取该节点的层数的获取&#xff0c;如图所示&#xff0c;我需要点击“组”节点才能渲染“设备列表”树&#xff0c;同时“设备列表”树的…

Vue16-绑定class样式

一、vue绑定class样式 1-1、需求一&#xff1a;字符串写法 vue实现class样式绑定 1-2、需求二 点击div&#xff0c;随机切换样式。 math.random()&#xff1a;随机数的范围[0, 1) 1-3、需求三&#xff1a;数组写法 样式的追加 1-4、需求四 &#xff1a;对象写法 二、vue绑定…

浅解Reids持久化

Reids持久化 RDB redis的存储方式&#xff1a; rdb文件都是二进制&#xff0c;很小&#xff0c;里面存的是数据 实现方式 redis-cli链接到redis服务端 使用save命令 注&#xff1a;不推荐 因为save命令是直接写到磁盘里面&#xff0c;速度特别慢&#xff0c;一般都是redis…

MySQl基础----Linux下搭建mysql软件及登录和基本使用(附实操图超简单一看就会)

绪论​ 涓滴之水可磨损大石&#xff0c;不是由于他力量强大&#xff0c;而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力&#xff0c;才能够获得那些技巧。 ——贝多芬。新开MySQL篇章&#xff0c;本章非常基础包括如何在Linux上搭建&#xff08;当然上面的SQL语句你在其他能执行…

UnityXR Interaction Toolkit 如何使用XRHand手部识别

前言 Unity的XR Interaction Toolkit是一个强大的框架,允许开发者快速构建沉浸式的VR和AR体验。随着虚拟现实技术的发展,手部追踪成为了提升用户交互体验的关键技术之一。 本文将介绍如何在Unity中使用XR Interaction Toolkit实现手部识别功能。 准备工作 在开始之前,请…

Chat-TTS:windows本地部署实践【有手就行】

最近Chat-TTS模型很火&#xff0c;生成的语音以假乱真&#xff0c;几乎听不出AI的味道。我自己在本地部署玩了一下&#xff0c;记录一下其中遇到的问题。 环境&#xff1a; 系统&#xff1a;windows 11 GPU&#xff1a; Nvidia 4060 Cuda&#xff1a;12.1&#xff08;建议安…

后方碰撞预警系统技术规范(简化版)

后方碰撞预警系统技术规范(简化版) 1 系统概述2 预警区域3 预警目标4 功能需求功能条件5 显示需求6 指标需求1 系统概述 后方碰撞预警系统RCW(Rear Collision Warning)是在后方车辆即将与自车发生碰撞之前,激活危险警告灯以较高频率闪烁,从而吸引后方驾驶员的注意力,避免…

PG 数据库常用参数调整

1.shard_buffers Postgresql使用自己的缓冲区,也使用操作系统缓冲区。这意味着数据存储在内存中两次,首先是 Postgresql缓冲区,然后是操作系统缓冲区。 与其他数据库不同, Postgresql不提供直接IO。这称为双缓冲&#xff08;就是磁盘中的时候读的时候先放在数据库的缓冲区&am…

【Python教程】3-控制流、循环结构与简单字符串操作

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…

Vue17-条件渲染

一、使用v-show属性做条件渲染 控制元素的显示和隐藏 v-show里面也能是表达式&#xff0c;只要表达式的值是boolean就行。 或者 当时结构还在&#xff1a; 二、使用v-if属性做条件渲染 结构也不在了 三、示例 方式一&#xff1a; 方式二&#xff1a; 当元素有很高的切换频率&am…

【web本地存储】storage事件,StorageEvent对象介绍

storage事件 Web Storage API 内建了一套事件通知机制&#xff0c;当存储区域的内容发生改变&#xff08;包括增加、修改、删除数据&#xff09;时&#xff0c;就会自动触发storage事件&#xff0c;并把它发送给所有感兴趣的监听者&#xff0c;因此&#xff0c;如果需要跟踪存…

第十二届蓝桥杯单片机国赛练习代码

文章目录 前言一、问题重述二、主函数总结 前言 第十五蓝桥杯国赛落幕已有十天&#xff0c;是时候总结一下&#xff0c;这个专栏也将结束。虽然并没有取得预期的结果&#xff0c;但故事结尾并不总是美满的。下面是赛前练习的第十二届国赛的代码。 一、问题重述 二、主函数 完整…

万向节锁死(Gimbal Lock)

Gimbal Lock是一个常见的3D动画问题,主要由旋转顺序引起的。我来详细解释一下它的成因: 在三维空间中,任何旋转都可以分解为绕X,Y,Z三个轴的欧拉旋转(Euler Rotation)。每个轴的旋转是按照一定顺序进行的,比如XYZ或ZYX等。 理论上,通过这三个旋转值的组合,可以达到任意的空间…

MATLAB实现磷虾算法(Krill herd algorithm)

1.算法介绍 磷虾算法&#xff08;Krill Herd Algorithm, KH&#xff09;是一种基于生物启发的优化算法&#xff0c;其原理模拟了南极磷虾&#xff08;Euphausia superba&#xff09;群体的聚集行为。该算法旨在通过模拟磷虾个体间的相互作用、觅食行为和随机扩散&#xff0c;来…