C语言函数指针的应用——自制谐波分析软件

文章目录

  • 函数指针简介
  • 格式介绍
  • 颜色头文件
  • 计算机仿真
    • 使用说明
    • 完整代码
    • 部分效果图

函数指针简介

如果在一个大型C语言程序中要反复调用函数,而调用的函数又不明确时,函数指针就是一个非常有用的东西。如果你的函数体内可以传递不同的函数,那就非得用函数指针实现不可。下面我就用一个例子给大家分享一下C语言函数指针的妙用。

格式介绍

格式为:【基类型】(*function)([参数表列])
C语言函数指针就是一个指向函数地址的指针,它和普通的指针一样也具有基类型,例如int *p,double *q,void *malloc与普通指针不同的是,它指向的不是特定类型的变量,而是函数地址,因此它后面有函数的参数表列。使用的时候需要注意,由于指针运算符比括号运算符的优先级低,因此需要把(*function)括起来(否则就是返回指针的函数)。C语言的语法比较复杂,举一个函数指针的例子:

#include <stdio.h>
#include <stdbool.h>
int max(int a,int b);//最大值函数
int min(int a,int b);//最小值函数
int main()
{int a,b;int (*p)(int,int);//函数指针pbool choice;char c[4];//字符串printf("Please enter two integer(separate by space):  ");scanf("%d%d",&a,&b); printf("Please choose a function(0: max,1: min):  ");scanf("%d%d",&choice);if(choice){p=min;c="min"}else {p=max;c="max"};//让函数指针指向选择的函数(地址)printf("%s=%d",c,p(a,b));//完成选择函数的输出return 0;
}

函数指针主要有两种使用方法:

  1. 用函数指针指向某个函数做选择(类似于上述的例子)
  2. 当做函数的参数传递(类似于下面的代码),使程序模块化更强,耦合性更弱当做函数的参数传递,使程序模块化更强,耦合性更弱

下面是我编写的一个计算一个指定方波的程序,里面的双线性积分函数对每一次谐波变量(int n)都一个返回谐波分量double amplify,在这里用到了函数指针,传递一个方波的函数给这个积分函数,如果以后这个函数不是方波而是其他函数,增添和修改代码都会非常方便!
在程序里面我指定的值是电力电子课程里面的三相全桥整流电路带阻感性负载的变压器二次侧电流波形的方波(一周期脉动6次的交流电平),方波应该没有2次和3次谐波,这样只剩下了1次谐波和6k±1(k∈N*)次谐波,每次谐波含有率(和1次谐波的比值)为1/(6k±1),可以看到后面附图里面确实非常准确,1,0.2,0.14286,…分别是1,1/5,1/7,…!
如果我们分析三相电压型桥式逆变电路的Unn’中点电压波形(一周期脉动6次的交流方波信号),可以得出同样的结果。为了让输出的谐波分析更加的美观,我们让谐波含有率低于1e-4的所有的次谐波都标蓝,剩下的白色的才是真正含有的谐波,供我们进行计算机仿真实验验证。

颜色头文件

以下链接为C语言彩色打印字符的相关头文件及其说明:

【博客链接】

计算机仿真

使用说明

在程序的开始界面输入时刻表和对应的电平表,输入分析基频以及最高的分析谐波次数,程序即可进入运算状态。由于使用的是CFT(连续傅里叶积分),可能计算会有点慢,大概3秒算10次谐波。如果谐波含有率很低会用蓝色标识出来,其余的谐波用白色标注,代表实质有的谐波含量,方便大家发现规律。输入时刻表列和电平表列的规则如下:
如果一个方波的电平以-1和1两个电平变化,并且周期为π,则输入周期为π,改变电平的时刻表列为0(不包括2个端点),电平表列为-1 1.
如果一个方波的电平以-1,0,1,0,-1,0,…变化,正负电平的持续时间是0电平的2倍,周期为π,则电平的时刻表列为-5π/12,-π/12,π/12,5π/12(不包括2个端点),电平表列为0 -1 0 1 0。
由于输入的时刻表列不包括两个端点,因此时刻表列总是比电平表列多一个数值,但是如果时刻表列加上2个端点时刻,正好形成和电平表列数目一样多的时间段和电平表列相对应。输入规则就是这样的。

完整代码

//#include <stdio.h>	//color.h已包括
#include <math.h>
#include <ctype.h> 
#include <malloc.h>
//#include <windows.h>	//color.h已包括
#include "color.h"
#define pi 3.14159265
double amplify(double (*function)(double x),int n);//双线性积分函数,参数为函数指针、上界、下界 
double RMS(double (*function)(double x));//对一个函数在周期内求有效值 
double square_wave(double x);
double period;//被分析方波的周期
double time[30]={0};//方波的时间时刻数组,首地址是从0附近的周期最左边的坐标开始的依次改变的电平处的值,只保留一个周期的 
double level[30]={0};//方波的电平数组,表示与时间区别对应的电平
int fund_f;//指定傅里叶分解时的基频 
int count=0;//统计输入个数 
//以上为声明 
int main()
{char t;//用于检测字符是否数字,实现动态输入 int i=0;//扫描计数偏移量int Nc;//截止谐波次数 double *AP=NULL;//用于存放幅值数组的指针 //以上为定义变量部分 printf("***对用户定义的方波进行傅里叶级数展开***\n请输入方波的周期: ");scanf("%lf",&period);fflush(stdin);printf("请输入方波的在(-T/2,T/2)周期改变电平的时间时刻(不含±T/2的时刻,用空格分隔):\n");while((t=getchar())!='\n'){if(isdigit(t)||t=='-')//浮点数都是以负号或者数字开头的 {ungetc(t,stdin);scanf("%lf",time+i);//扫描的浮点数一次存入 count++;//统计输入时间节点的个数 i++; }} *(time+i+1)=period/2;printf("请输入方波的在上述改变时间时刻对应的电平值\n【说明】第一个电平对应(-T/2,t0),最后一个电平对应(tn,T/2),用空格分隔:\n");fflush(stdin);//循环结束,刷新标准输入口 i=0;//偏移量清零 while((t=getchar())!='\n'){if(isdigit(t)||t=='-')//浮点数都是以负号或者数字开头的 {ungetc(t,stdin);scanf("%lf",level+i);//扫描的浮点数一次存入 i++;}} fflush(stdin);//循环结束,刷新标准输入口  printf("请输入傅里叶分解的基频: ");scanf("%d",&fund_f);printf("请输入分析的谐波最高次数: ");scanf("%d",&Nc);AP=(double *)calloc(Nc,sizeof(double));if(AP==NULL){printf("\n\r意外错误:内存分配失败!\n");return 1;}printf("\n\r动态内存分配成功!\n");for(i=0;i<=Nc;i++){AP[i]=amplify(square_wave,i);printf("\r正在计算中...%.2lf%%",100*(float)i/Nc);}printf("\n\r|谐波次数:\t振幅\n");for(i=0;i<=Nc;i++){printf("|%d:\t%8.5lf",i,AP[i]);if((i+1)%5==0)printf("\n");}printf("\n\r|谐波含有率如下:\n");for(i=0;i<=Nc;i++){if(AP[i]/AP[1]<1e-4){setcolor(LIGHTBLUE);//无该次谐波的显示为黄色 printf("|%d:\t%7.3lf%%",i,100*AP[i]/AP[1]);}else{setcolor(WHITE);//有该次谐波显示为蓝色 printf("|%d:\t%7.3lf%%",i,100*AP[i]/AP[1]); 	} if((i+1)%5==0)printf("\n");}setcolor(WHITE);//还原默认色 printf("\n\rRMS=%7.4lf,Fundamental=%7.4lf",RMS(square_wave),AP[1]);system("pause");return 0;
} 
//根据电平数组和时间间隔数组查找对应时间的方波的电平 
double square_wave(double x)
{int i;for(i=0;i<count;i++){if(x<*(time+i))return *(level+i);}return *(level+count);//如果均不是,返回level数组的最后一个值,即[tn,T/2]的值 
} 
double amplify(double (*function)(double x),int n)
{double sin_integral=0,cos_integral=0;//积分值double x0,x1;//双线性积分需要两个变量迭代计算for(x1=-period/2;x1<period/2;x0=x1,x1+=1e-5){sin_integral+=0.5*1e-5*((*function)(x1)*sin(n*2*pi*fund_f*x1/period)+(*function)(x0)*sin(n*2*pi*fund_f*x0/period));cos_integral+=0.5*1e-5*((*function)(x1)*cos(n*2*pi*fund_f*x1/period)+(*function)(x0)*cos(n*2*pi*fund_f*x0/period));} return sqrt(pow(sin_integral,2)+pow(cos_integral,2))/period;
}
double RMS(double (*function)(double x))
{double integral=0;double x0,x1;//采用双线性积分for(x1=-period/2;x1<period/2;x0=x1,x1+=1e-5){integral+=0.5*1e-5*(pow((*function)(x1),2)+pow((*function)(x0),2));		}return sqrt(integral/period);	
} 

部分效果图

输入

输出
希望本文对您有帮助,谢谢阅读。

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

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

相关文章

PHP5.5四种序列化性能对比

2019独角兽企业重金招聘Python工程师标准>>> 结论&#xff1a; 1、小数组用msgpack,无论空间和性能都最好 2、大数组&#xff0c;考虑空间用igbinary,考虑性能用msgpack json_encode&#xff0c;serialize&#xff0c;igbinary&#xff0c;msgpack四种序列化方式&am…

MyBatis Plus 批量数据插入功能,yyds!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone最近 Review 小伙伴代码的时候&#xff0c;发现了一个小小的问题&#xff0c;小伙伴竟然在 for 循环中进行了 insert &#xff08;插入&a…

C语言打印彩色字符——以(枚举法+字符串查找)为例展示

文章目录C语言颜色头文件——自制非常简单的调用函数实战演练——一个基础的枚举变量小程序牛刀小试——查找字符小程序C语言颜色头文件——自制非常简单的调用函数 显然&#xff0c;C语言是不会提供打印彩色字符的标准函数&#xff0c;而我们有时候为了强调C语言打印的部分字…

再见 Spring Task,这个定时任务框架真香!

最近有朋友问到定时任务相关的问题。于是&#xff0c;我简单写了一篇文章总结一下定时任务的一些概念以及一些常见的定时任务技术选型。希望能对小伙伴们有帮助&#xff01;个人能力有限。如果文章有任何需要补充/完善/修改的地方&#xff0c;欢迎在评论区指出&#xff0c;共同…

C语言实现动画控制

文章目录原材料说明一场革命原材料 下载原材料网址: https://www.easyx.cn/downloads/ 下载easyx2014冬至版&#xff0c;将lib文件放在编译器默认的lib文件夹&#xff0c;h头文件放在编译器默认的include文件夹即可 说明 C语言可以用系统内部的定时函数sleep和usleep定时(需…

聊聊redis分布式锁的8大坑

前言在分布式系统中&#xff0c;由于redis分布式锁相对于更简单和高效&#xff0c;成为了分布式锁的首先&#xff0c;被我们用到了很多实际业务场景当中。但不是说用了redis分布式锁&#xff0c;就可以高枕无忧了&#xff0c;如果没有用好或者用对&#xff0c;也会引来一些意想…

MyBatis 批量插入数据的 3 种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone批量插入功能是我们日常工作中比较常见的业务功能之一&#xff0c;之前我也写过一篇关于《MyBatis Plus 批量数据插入功能&#xff0c;yy…

MongoDB: The Definitive Guide

第一章 简介 MongoDB是面向文档的数据库&#xff0c;不是关系型数据库。内置对MapReduce的支持&#xff0c;以及对地理空间索引的支持。 丰富的数据模型容易扩展&#xff0c;它所采用的面向文档的数据模型可以使其在多台服务器之间分割数据丰富的功能&#xff0c;索引、存储Jav…

Python联网下载文件

声明 Python版本2.7.3所需Py文件——urllib22.7.3版本的Python Shell即可直接执行&#xff0c;但需要联网若程序执行成功&#xff0c;则会下载以下网址的txt文本并打印在shell中 http://helloworldbook2.com/data/message.txt 本代码来源于《父与子的编程之旅——与小卡特一起…

如何给SpringBoot配置轻松加密?

在实践中&#xff0c;项目的某些配置信息是需要进行加密处理的&#xff0c;以减少敏感信息泄露的风险。比如&#xff0c;在使用Druid时&#xff0c;就可以基于它提供的公私钥加密方式对数据库的密码进行加密。但更多时候&#xff0c;比如Redis密码、MQ密码等敏感信息&#xff0…

C语言将循环小数/有限小数转换为分数

文章目录数学基础编程思路代码数学基础 早在小学的时候我就对循环小数非常感兴趣&#xff0c;加上初中和高中对循环小数可以说有一定基础研究&#xff0c;因此想到写一个将循环下小数转换为分数的程序&#xff0c;非常有意思&#xff0c;并且对初学者来说&#xff0c;它的输入…

升级了 Windows 11 正式版,有坑吗?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;今天磊哥去公司上班&#xff0c;惊喜的发现 Windows 提示更新了&#xff0c;并且是 Windows 11 正式版&#xff0c;这太让人…

C语言结构体的应用——万年历

文章目录万年历简述代码万年历简述 万年历——就是输入一个日期可以查询是星期几&#xff0c;这个功能看起来很普通&#xff0c;但是如果用程序时间的话&#xff0c;还是药费一番周折: 我们需要保存一个固定的日期&#xff0c;存放它是星期几&#xff0c;输入一个自定义的日期…

@Value竟然能玩出这么多花样

前言对于从事java开发工作的小伙伴来说&#xff0c;spring框架肯定再熟悉不过了。spring给开发者提供了非常丰富的api&#xff0c;满足我们日常的工作需求。如果想要创建bean实例&#xff0c;可以使用Controller、Service、Repository、Component等注解。如果想要依赖注入某个对…

C语言实现线性动态(单向)链表【详细步骤】

文章目录什么是链表为什么不用结构体数组链表的操作创建表删除元素插入元素代码及运行结果什么是链表 链表是数据结构里面的一种&#xff0c;线性链表是链表的一种&#xff0c;线性链表的延伸有双向链表和环形链表。在编程语言中优化数据结构可以在处理大数据时大大降低程序的…

移动前端经验小结

1. 移动端头部标签 head meta <!DOCTYPE html> <!-- 使用 HTML5 doctype&#xff0c;不区分大小写 --> <html lang"zh-cmn-Hans"> <!-- 更加标准的 lang 属性写法 http://zhi.hu/XyIa --> <head><!-- 声明文档使用的字符编码 -->…

再见收费的Navicat!操作所有数据库靠它就够了!

为了快速管理数据库&#xff0c;我们一般都会选择一款顺手的数据库管理工具。Navicat、DataGrip虽然很好用&#xff0c;但都是收费的。今天给大家推荐一款免费、功能强大的数据库管理工具DBeaver&#xff0c;希望对大家有所帮助&#xff01;DBeaver简介 DBeaver是一款开源的数据…

查找两个字符串中相同字符串_使两个字符串相同的最低成本

查找两个字符串中相同字符串Problem statement: 问题陈述&#xff1a; Given two strings string1 and string2 find the minimum cost required to make the given two strings identical. We can delete characters from both the strings. The cost of deleting a characte…

Matlab对指定参数的曲线进行非线性拟合

Matlab拟合曲线的方式 Matlab拟合曲线的方式有很多种&#xff0c;有三次样条插值、线性插值、多项式拟合等等。多项式拟合由于函数由f(x)anxnan−1xn−1...a1xa0f(x)a_nx^na_{n-1}x^{n-1}...a_1xa_0f(x)an​xnan−1​xn−1...a1​xa0​组成&#xff0c;若采用最小二乘法拟合&a…

MyBatis原生批量插入的坑与解决方案!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;前面的文章咱们讲了 MyBatis 批量插入的 3 种方法&#xff1a;循环单次插入、MyBatis Plus 批量插入、MyBatis 原生批量插入…