【C语言】指针(4)

一、回顾

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

1、一级指针

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

char* p; ...

void* p;...

...

2、二级指针

int** p;

char** p;

...

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

int (*p) ;

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

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

int* arr ;

cpp 复制代码
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、举例

cpp 复制代码
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 ) ( ) ;

三、函数指针数组

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为限制表示一个元素是否交换完成。​​​​​​

相关推荐
J2虾虾1 小时前
C 语言 sizeof 完全用法指南
c语言·数据结构·算法
xxwxx__2 小时前
51单片机定时器/计数器中断详解(T0和T1)——从入门到精通
c语言·单片机·嵌入式硬件·51单片机
cft56200_ln2 小时前
TDA4时间同步3 网卡添加虚拟时间戳
c语言·开发语言·arm开发·驱动开发·嵌入式硬件·网络协议
189228048612 小时前
NV091固态MT29F16T08EWLCHD8-QJES:C
c语言·开发语言
AI thought2 小时前
C语言企业项目实战(四)
c语言·单元测试·压力测试·企业项目·工程体系
AI科技星2 小时前
《数术工坊:无穷套娃录》 一部用数学套娃写成的“天书小说”
c语言·开发语言·网络·量子计算·agi
m0_547486663 小时前
华南农业大学《C语言程序设计》期末试卷及答案2018-2025年PDF
c语言·开发语言·pdf·c语言程序设计
Hello:CodeWorld14 小时前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法
十月的皮皮16 小时前
C语言学习笔记20260606- 求月份天数三种写法
c语言·笔记·学习
caimouse17 小时前
Reactos 第 5 章 进程与线程 — 5.8 Windows 的 APC 机制
c语言·windows