c语言进阶部分详解(指针进阶2)

2023-09-21 21:02:55

大家好!我快马加鞭接着写出指针部分part2部分。第一部分见:c语言进阶部分详解(指针进阶1)_总之就是非常唔姆的博客-CSDN博客

指针初阶部分见:c语言进阶部分详解(指针初阶)_总之就是非常唔姆的博客-CSDN博客 


一.函数指针 

1.讲解与实例 

函数指针: 在C语言中,函数指针是指向函数的指针变量。它可以像其他变量一样存储在内存中,并且可以通过函数指针来调用相应的函数。

声明函数指针:returnType (*pointerName)(parameterTypes);

其中:

  • returnType 是函数的返回类型。
  • pointerName 是函数指针的名称。
  • parameterTypes 是函数的参数类型
// 定义一个函数
int add(int a, int b) {
    return a + b;
}

int main()
{
    // 声明一个函数指针
    int (*funcPtr)(int, int);

    // 将函数指针指向add函数
    funcPtr = add;

    // 通过函数指针调用函数
    int result = funcPtr(2, 3);  // 结果为5   平时调用函数时都是函数名(地址),也可以想通
    int result = (*funcPtr)(2, 3);  // 这两种均可以,funcPtr是地址,通过*解引用来找到
    return 0;
}

 2.《C陷阱和缺陷》中两段经典代码

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

//代码1     ( * ( void  ( * )( ) ) 0 ) ( );

  1. void  ( * )( )这是一个函数指针的类型声明。它表示一个没有参数并且返回类型为void的函数指针
  2. ( void  ( * )( ) )0 这是对0进行强制类型转化,转换为函数指针类型
  3. * ( void  ( * )( ) ) 0 对地址为0的函数地址解引用
  4.  ( * ( void  ( * )( ) ) 0 ) ( ) 调用这个函数

2.2void ( * signal( int , void( * ) ( int ) ) ) (int); 

//代码2 void ( * signal( int , void( * ) ( int ) ) ) (int); 

 

void (*signal(int, void (*)(int)))(int):这是一个函数声明的语法。它表示signal是一个函数,接受两个参数:一个int类型的参数和一个指向接受int类型参数并返回void的函数指针的参数。该函数返回一个指向接受int类型参数并返回void的函数指针的结果


二.函数指针数组

1.讲解与实例

函数指针数组: 函数指针数组是一个数组,其中的每个元素都是一个函数指针。可以将不同的函数指针存储在数组中,并根据需要使用它们 

 

声明函数指针数组:return_type (*array_name[size])(parameter_list); 

  1. return_type:函数指针指向的函数的返回类型。
  2. (*array_name):函数指针数组的名称。它是一个指针,指向一个数组。
  3. [size]:函数指针数组的大小。它表示数组中函数指针的数量。
  4. (parameter_list):函数指针指向的函数的参数列表

 相比于函数指针只是多了一个[ ]在函数名后面而已

// 定义函数1
void func1(int num) {
    printf("This is function 1. Number: %d\n", num);
}

// 定义函数2
void func2(int num) {
    printf("This is function 2. Number: %d\n", num);
}

// 定义函数3
void func3(int num) {
    printf("This is function 3. Number: %d\n", num);
}

int main() {
    // 将函数指针赋值给函数指针数组的元素
    void(*pf[3])(int) = { &func1,&func2, &func3 };

    // 调用函数指针数组中的函数
    for (int i = 0; i < 3; i++) {
        pf[i](i);
    }
    return 0;
}

 

2.使用来实现计算器

 

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 = 1;
    int result = 0;
    int a = 0;
    int b = 0;
    while (input)
    {
        menu();
        printf("请输入:\n");
        scanf("%d", &input);//根据menu来输入数字啦
        int(*pf[5])(int, int) = { NULL,add,sub,mul,div };//第一个是NUll是为了使数字与菜单对应
        if (input >= 1 && input <= 4)
        {
            printf("请输入两个数\n");
            scanf("%d %d", &a, &b);
            result = pf[input](a, b);
            printf("%d\n", result);
        }
        else if(input==0)
        {
            printf("退出计算器");
        }
        else
        {
            printf("输入有误,请重新输入");
        }
    }
    return 0;
}

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

指向函数指针数组的指针是一个 指针,指针指向一个数组 ,数组的元素都是函数指针
 

指向函数指针数组的指针的语法如下:

return_type (*(*pointer_name)[size])(parameter_list);

  1. return_type:函数指针指向的函数的返回类型。
  2. (*pointer_name):指向函数指针数组的指针的名称。它是一个指针,指向一个函数指针数组。
  3. [size]:函数指针数组的大小。它表示数组中函数指针的数量。
  4. (parameter_list):函数指针指向的函数的参数列表

相比与函数指针数组只是在名字前多一个*来说明是指针而已


四.回调函数

1.讲解 

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

 2.事例

int add(int x, int y)
{
    return x + y;
}

// 定义一个回调函数
void callback(int result) 
{
    printf("回调函数被调用,结果为:%d\n", result);
}

// 定义一个函数,接受一个函数指针作为参数
void performOperation(int (*operation)(int, int), int a, int b, void (*callback)(int)) 
{
    int result = operation(a, b);
    callback(result);
}

int main()
{
    // 调用函数,并传递回调函数作为参数
    performOperation(add, 2, 3, callback);
	return 0;
}

 今天的内容先到这里了,下一次不出意外是针对回调函数进行更加详细事例演示及模拟。

感谢大家的支持!!

更多推荐

第十一章:Java集合

目录11.1:java集合框架概述11.2:Collection接口方法11.3:Iterator迭代器接口11.4:Collection子接口一:List11.5:Collection子接口二:Set11.6:Map接口11.7:Collections工具类11.8:增强for循环11.1:java集合框架概述Jav

网络安全(黑客)自学

前言我是去年8月22日才正式学习网络安全的,因为在国营单位工作了4年,在广东一个月工资只有5000块,而且看不到任何晋升的希望,如果想要往上走,那背后就一定要有关系才行。而且国营单位的气氛是你干的多了,领导觉得你有野心,你干的不多,领导却觉得你这个人不错。我才24周岁,实在的受不了这种工作氛围,情绪已经压制了很多久,一

Linux小程序-进度条

进度条我将实现三个版本:1简单原理版本2实际工程实践版本3c语言扩展-设计颜色首先我们需要有一些前置知识:关于行缓冲区和回车换行行缓冲区:c/c++语言会针对标准输出给我们提供默认的缓冲区,这次的角色是输出缓冲区输出的内容不会立马显示,而是放置在输出缓冲区内,只有当缓冲区刷新时我们才会看到输出的内容,而我们平时打印内容

腾讯云16核服务器性能测评_轻量和CVM配置大全

腾讯云16核服务器配置大全,CVM云服务器可选择标准型S6、标准型SA3、计算型C6或标准型S5等,目前标准型S5云服务器有优惠活动,性价比高,计算型C6云服务器16核性能更高,轻量16核32G28M带宽优惠价3468元15个月,腾讯云服务器网分享腾讯云16核CPU服务器可以选择的云服务器CVM规格列表:目录腾讯云16

七天学会C语言-第五天(函数)

1.调用有参函数有参函数是一种接受输入参数(参数值)并执行特定操作的函数。通过向函数传递参数,你可以将数据传递给函数,让函数处理这些数据并返回结果。例1:编写一程序,要求用户输入4个数字,输出前两个数中的最大数、后两个数中的最大数以及四个数中的最大数。#include<stdio.h>doublemax(doublex

jmeter学习文档

JMeter学习(一)工具简单介绍一、JMeter介绍ApacheJMeter是100%纯JAVA桌面应用程序,被设计为用于测试客户端/服务端结构的软件(例如web应用程序)。它可以用来测试静态和动态资源的性能,例如:静态文件,JavaServlet,CGIScripts,JavaObject,数据库和FTP服务器等等

【深度学习实验】线性模型(五):使用Pytorch实现线性模型:基于鸢尾花数据集,对模型进行评估(使用随机梯度下降优化器)

目录一、实验介绍二、实验环境1.配置虚拟环境2.库版本介绍三、实验内容0.导入库1.线性模型linear_model2.损失函数loss_function3.鸢尾花数据预处理4.初始化权重和偏置5.优化器6.迭代7.测试集预测8.实验结果评估9.完整代码一、实验介绍线性模型是机器学习中最基本的模型之一,通过对输入特征进

计算机组成原理——基础入门总结(二)

上一期的路径:基础入门总结(一)目录一.输入输出系统和IO控制方式二.存储系统的基本概念三.cache的基本概念和原理四.CPU的功能和基本结构五.总线概述一.输入输出系统和IO控制方式IO设备又可以被统一称为外部设备~IO接口:由被称为IO控制器、设备控制器:负责协调主机与外部设备之间的数据传输。IO控制器具有统一的

web:[HCTF 2018]WarmUp

题目点进页面,页面只有一张滑稽脸,没有其他的提示信息查看网页源代码,发现source.php,尝试访问一下跳转至该页面,页面显示为一段php代码,需要进行代码审计<?phphighlight_file(__FILE__);classemmm{publicstaticfunctioncheckFile(&$page){/

【操作系统笔记】缓存一致性

CPU核心之间数据如何传播高速缓存中的值被修改了,那么怎么同步到内存中呢?①写直达(Write-Through)②写回(Write-Back)写直达(Write-Through)简单,但是很慢,每次写都需要经过内存总线写回(Write-Back):尽可能推迟更新,只有当替换算法要驱逐这个更新过的缓存块时,才把它写回到内

【管理运筹学】第 7 章 | 图与网络分析(5,最小费用流问题及最小费用最大流问题)

系列文章【管理运筹学】第7章|图与网络分析(1,图论背景以及基本概念、术语、矩阵表示)【管理运筹学】第7章|图与网络分析(2,最小支撑树问题)【管理运筹学】第7章|图与网络分析(3,最短路问题)【管理运筹学】第7章|图与网络分析(4,最大流问题)文章目录系列文章引言五、最小费用流问题5.1基本概念及定理5.2最小费用流

热文推荐