指针进阶2 – 指针和函数

1. 函数指针

函数名 VS &函数名

对于数组而言,数组名=首元素地址,&数组名=整个数组的地址

那么函数名和&函数名等于什么

#include <stdio.h>
void test()
{
	;
}
int main()
{
	test();
	printf("%p\n", test);
	printf("%p\n", &test);

}

注:函数名和&函数名不能+-整数

指针进阶2 - 指针和函数

结论是:函数名和&函数名一样 = 函数的地址

 

什么是函数指针

既然函数名=函数地址,就可以用一个变量进行存储

这个变量就是函数指针,存储一个函数地址的变量 

#include <stdio.h>
int test(int x, int y)
{
	;
}
int main()
{
	int(*ptr)(int, int) = test; 
}

这里的ptr就是一个函数指针

(*ptr),表示ptr是一个指针变量 ,(int, int), 表示ptr存储的是一个函数的地址,这个函数有两个int类型的参数,(*ptr)前面的int, 表示这个函数的返回类型为int整形

 

函数指针的应用

#include <stdio.h>
int test(int x, int y)
{
	return x + y;
}
int main()
{
	int(*ptr)(int, int) = test;
	int ret = (*ptr)(1,2);
	printf("%d\n", ret);
}

 指针进阶2 - 指针和函数

*ptr表示通过地址访问空间 ---> 得到函数的地址 ---> 传值(1,2) ---> 得到结果3 ---> 打印

 

函数指针作为参数

// 使用冒泡排序,排序任意类型数组
#include <string.h>
#include <stdio.h>
struct Stu
{
	char name[10];
	int age;
};

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

// 以年龄比较
int cmp_by_name(const void* e1,const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
// 以名字比较
int cmp_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

// 交换
void swap(char* buf1, char* buf2, int width)
{
	while (width--)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

// 排序
void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 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);
			}
		}
	}
}

 //排序整形数组
void sort_int()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
}

// 排序结构体数组
void sort_struct()
{
	struct Stu t1[5] = { {"c",5 }, { "a",4 }, { "b",3 }, { "e",2 }, { "d",1 } };
	int sz = sizeof(t1) / sizeof(t1[0]);
	bubble_sort(t1, sz, sizeof(t1[0]), cmp_by_name); // 以名字排序
	//bubble_sort(t1, sz, sizeof(t1[0]), cmp_by_age);// 以年龄排序

}

int main()
{
	//sort_int();
	sort_struct();
}

 

2. 函数指针数组

什么是函数指针数组

首先梳理一下概念,数组是一组相同类型元素的集合,函数指针是存储函数地址的变量

所以函数指针数组,就是存储一组函数地址的集合

#include <stdio.h>
void test1()
{
	;
}
void test2()
{
	;
}
void test3()
{
	;
}
int main()
{
	void(*ptr[3])() = { test1,test2,test3 };
}

void (* ptr[3] )() , 如何理解 ?

ptr首先会与[3]结合,表示ptr是一个数组,数组有3个元素

void (* ptr[3] )() ---> void (*)(),

(*) 表示数组的每一个元素是一个指针,()表示这个指针是一个函数指针且函数没有参数,void表示函数返回值为空

 

函数指针数组的应用

#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;
}
void menu()
{
	printf("1.add	2.sub\n");
	printf("3.mul	4.div\n");
}

int main()
{
	int(*ptr[5])(int, int) = { 0,add,sub,mul,div }; //函数指针数组
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do 
	{
		menu();
		printf("输入: ");
		scanf("%d", &input);
		if (input > 4 || input <= 0)
		{
			printf("退出程序\n");
		}
		else
		{
			printf("输入x: ");
			scanf("%d", &x);
			printf("输入y: ");
			scanf("%d", &y);
			ret = (ptr[input])(x, y); //通过input,锁定函数地址,最后传参得到结果
			printf("%d\n", ret);
		}
	} while (input);
}

 

3. 指向函数指针数组的指针

直接看代码

#include <stdio.h>
int main()
{	
	int arr[10] = { 0 }; // 整形数组
	int(*pa)[10] = &arr; // 数组指针,指向数组的指针

	int(*pf[10])(int, int); // 函数指针数组
	int(*(*ppf)[10])(int,int)= &pf // 指向函数指针数组的地址	 
}

既然可以用&操作符取出一个整形数组的地址,那么也可以取出一个函数指针数组的地址

所以,指向函数指针数组的指针就是存储整个函数指针数组的地址的变量

int (* (*ppf) [10] ) (int, int)   如何理解 ?

(*ppf), 表示ppf是一个指针, [10]表示这个指针存储一个数组的地址,数组有10个元素,int (*) (int, int), 表示数组的每一个元素是一个函数指针

原文链接:https://www.cnblogs.com/xumu11291/p/17134666.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:指针进阶2 – 指针和函数 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • C++操作SQLite简明教程

    C++操作SQLite简明教程 本教程将介绍如何使用C++操作SQLite数据库,包括数据库的创建、表的创建、数据的插入、查询和更新等常见操作。 安装SQLite 在开始之前,需要先安装SQLite。SQLite是一个轻型数据库,可以在各个操作系统上使用。在Ubuntu系统上,可以通过以下命令安装: sudo apt-get install sqlite3 …

    C 2023年5月22日
    00
  • C++ assert()函数用法案例详解

    C++ assert()函数用法案例详解 什么是assert()函数 assert()函数是C和C++中的一个标准库函数,用于在程序运行过程中对一个条件进行判断,如果该条件为假,则触发一个断言错误(Assertion Failed),程序会停止运行并输出错误信息,方便程序员进行调试。 assert()函数使用起来简单,其语法如下: void assert(i…

    C 2023年5月23日
    00
  • C++计数排序详解

    C++计数排序详解 什么是计数排序? 计数排序是一种非比较型排序算法,它的基本思想是统计所有元素的出现次数,然后根据每个元素的出现次数,依次将这些元素放入数组中,从而得到排好序的数组。 计数排序的基本原理 计数排序利用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素个数。然后根据数组C来将A中的元素排到正确的位置。例如,如果C[3]=4,那么值…

    C 2023年5月22日
    00
  • C语言超全面讲解函数的使用方法下

    C语言超全面讲解函数的使用方法下 简介 函数是C语言中重要的组成部分,它可以将代码分解成小的模块,提高代码的可维护性,也可以提高代码的可重用性。在本攻略中,我们将全面讲解C语言中函数的使用方法,包括函数定义、函数调用、函数参数、函数返回值等方面。 函数定义 函数定义包括函数头和函数体两部分。函数头一般包括函数的返回值类型、函数名和函数参数。如下所示: int…

    C 2023年5月24日
    00
  • 拳皇14跳出0xc000007b怎么解决_跳出0xc000007b的解决方法(必看)

    拳皇14跳出0xc000007b怎么解决_跳出0xc000007b的解决方法(必看) 问题描述 拳皇14是一款非常受欢迎的格斗游戏,但是有些玩家在启动游戏时会遇到0xc000007b的错误提示,导致游戏无法正常运行。那么这个问题怎么解决呢?本文将为大家提供详细的解决方法。 解决方法 方法一:安装/修复DirectX 首先请确认您的电脑上已经安装了最新的Dir…

    C 2023年5月23日
    00
  • 编写C语言程序进行进制转换的问题实例

    编写C语言程序进行进制转换的攻略可以分为以下几个步骤: 1. 确定需要实现的进制转换 要进行进制转换,首先需要确定要转换的进制类型,如十进制、二进制、八进制、十六进制等。可以根据需求选择要转换的进制类型。 2. 设计算法并实现程序代码 经过确定要转换的进制类型,就需要设计转换的算法。通常,将一个进制的数转换为另一个进制的数可以借助中间进制完成,例如将二进制数…

    C 2023年5月23日
    00
  • C++线程中几类锁的详解

    C++线程中几类锁的详解 前言 在多线程编程中,锁是一种重要的同步机制,可以保证多个线程在访问共享资源时的安全性。C++提供了多种类型的锁,本篇文章将对常用的几种锁进行详解。 互斥锁(mutex) 互斥锁是最常用的一种锁,它保证同一时刻只有一个线程可以访问共享资源。当一个线程获得锁时,其他线程将一直等待直到拥有锁的线程释放锁为止。 创建互斥锁 C++标准库提…

    C 2023年5月22日
    00
  • VC实现五子棋游戏的一个算法示例

    VC实现五子棋游戏的一个算法示例 为了实现五子棋游戏的算法,我们需要考虑以下几个方面: 棋局的表示(即如何存储棋盘上每个位置的状态)。 玩家和计算机的策略(即如何判断胜负,如何实现搜索算法或者其他的博弈树算法)。 玩家和计算机的交互(即如何实现用户与计算机的交互和界面显示)。 棋局的表示 通常情况下,我们可以用一个二维数组来存储五子棋盘的状态。数组的每个元素…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部