第19章C语言应用实例本章的学习重点◆C语言解决实际问题◆C语言完成数学函数运算◆C语言工程项目建立与完成19.1C语言巧解问题实例C语言可以解决实际生活中许多小问题,小运算。同时,使用C语言也可以仿真和实现许多人工计算和统计难以实现的工作。下面介绍使用C语言解决实际生活中一些常见的计算问题,以展示C语言的实用性。19.1.1求1到1000之内的素数素数,又称为质数,其定义为:只能被1和它本身整除的自然数叫做素数。也就是说,任何一个素数,它除了能表示为其本身和1的乘积外,不能表示为任何其他两个正整数的乘积。例如,自然数7,只能表示为1*7,因此,7是素数。素数是一类特殊的数字,它在实际中也有很多应用,例如使用素数构建素数表,用于进行工程测试,使用素数搭建加密系统,使密码更加难以被破解等。随着数字数值的增加,素数越来越少。在古代,素数的计算主要靠人工计算,繁琐且容易出错,现在,使用C语言则可以很容易的实现素数的统计计算。可以使用for循环遍历自然数,同时,根据素数的定义,对于自然数n,若n不能够被除1以外小于等于的所有自然数整除,则这个数就是素数。19.1.2巧解古代百钱买百鸡问题百钱买百鸡问题是中国古代经典的趣味算术问题,在今天,仍然有很多测试沿用这一题目进行智力测试。这一问题的具体描述是:5吊钱可以买1只公鸡,3吊钱可以买一只母鸡,1吊钱可以买3只小鸡。用100吊钱买100只鸡,没种鸡必须有一只,那么可以买公鸡、母鸡、小鸡各多少只?共有多少种买法?这一问题在现代方程代数数学中可以很容易的解决,可以设100吊钱可以买x只公鸡,y只母鸡,z只小鸡,共100只,则可以使用下面的方程组表示:其中,x,y和z都是正整数,对于这样一个不定方程,只能使用试凑法解决,过程繁琐且容易产生错误。53/2100100xyzxyz19.1.3巧解换钱币问题换钱币问题是外国古代趣味算术问题的经典题目,和我国古代百钱买百鸡问题极为相似,具体问题描述为:用一个1磅金币可以兑换1分、2分和5分金币,试问共有多少种不同的兑换方法。其中,1磅金币=100分金币。这一问题与百钱买百鸡问题可以沿用类似的程序来解决,所不同的是本题并没有限制1分、2分或5分金币的数量。19.1.4求1-20000之间的平方回文数回文数也叫对称数,是指这类数的各位数字具有对称性,例如12121,通常,可以通过使用任何一个数字与其倒序数相加,再依次执行下去获得,例如:96+69=165,165+561=726,726+627=1353,1353+3531=4884。但是也有某些数字目前为止还不能验证是否可以通过上述操作获得回文数,例如数字196。平方回文数是指这类数字即是回文数,又是某个自然数的平方数,例如121,就是11的平方数,同时也是回文数。可以编写程序,通过遍历获得平方回文数19.1.5验证卡布列克常数卡布列克常数是美国数学家卡布列克在进行数学运算时发现的一个有趣的数学规律,他也因此而闻名世界。卡布列克常数是一个非常简单的数字,共有两个,一个是495,一个是6174。这两个数字都具有特殊的规律,对于任何各位数字不全相同的三位数字或四位数字,都可以通过一定规律的运算得到这两个数字。其运算规律为:首先,将所选数的各位数字从大到小排列组成一个新的三位数x,然后,再将各位数字按从小到大排列得到另一个新的三位数y,然后,使用大的数字减去小的数字:x-y=z。得到差值z之后,对得到的结果z继续执行上述运算,直到每次都得到相同的数字为止。例如,数字132,首先将这个数的各位数字从大到小排列组成一个新的三位数321,然后再将各位数字按从小到大排列得到另一个新的三位数123,然后,使用大的数字减去小的数字:321-123=198。继续执行上述操作:981-189=792,972-279=693,963-369=594,954-459=495,954-459=495,……。同样,对于四位数字,也存在这样的规律。有趣的是,除了三位数和四位数,再也没有能够找到符合这一规律的数字。通过编写程序,可以验证四位数字卡布列克常数的正确性。19.2C语言应用实例——计算数学公式C语言工程编译软件VisualC++中有很多函数库,其中数学函数库最为丰富,可以通过包含头文件math.h来调用数学库中的数学函数。对于VisualC++中的数学函数,大部分都是使用C语言编写与实现的,因此,利用C语言实现数学函数逼近及数学公式计算广泛应用于工程运算中。19.2.1C语言实现三角函数sinx逼近数学中曾经介绍过,三角函数可以展开为无穷泰勒级数。而泰勒级数可以通过循环累加实现,而循环累加操作恰好是C语言最容易实现的操作,因此,使用C语言实现三角函数的逼近则变得非常简单而容易实现。sinx可以展开为泰勒级数如下的泰勒级数:通过for循环可以实现对sinx的逼近357210(1)sin...3!5!7!(21)!nnnxxxxxxn19.2.2C语言实现三角函数cosx逼近和正弦函数类似,余弦函数cosx也可以展开为泰勒级数,并通过C语言实现,cosx的泰勒展开式如下:通过循环可以实现cosx的计算。24620(1)sin1...2!4!6!(2)!nnnxxxxxn19.2.3C语言计算排列组合排列组合是统计学应用非常广泛的一个统计运算公式,也是概率论中最基本也最实用的一种抽象概念转化,它为概率论的结果验证提供了强有力的理论依据。排列组合最常用的两个公式是计算排列数和组合数,即全排列数和组合数,下面的公式表示了全排列和组合数的计算公式:!(1)...(1)()!rnnPnnnrnr!!!()!rnnmPnCrrnr19.3C语言编写万年历万年历是日常生活中必不可少的工具,现在,万年历几乎随处可见,计算机系统中、手机里、电子词典中、mp4播放器中、办公桌上、家庭摆设等。万年历之所以随处可见,一方面是由于其在人们日常生活中的重要性,另一方面也因为其易于实现的规律性和特定的算法。本节以编写C语言万年历为例,介绍一个项目的实现过程。19.3.1万年历的实现流程1.C语言万年历项目建立项目的建立是指要建立的项目的定义,文档结构的编写,项目最初始阶段要进行的计划设计等。万年历程序设计项目中,首先要确定该项目的名称,然后设计项目执行计划和流程。本项目名称为“C语言实现简单万年历程序”,如表所示为该项目的执行计划流程图。时间WenseDayThursDayFriDaySaturDaySunDay第一阶段项目建立第二阶段需求分析第三阶段算法设计第四阶段代码编写代码调试第五阶段结果验证代码完善回归验证19.3.1万年历的实现流程2.需求分析需求分析是指项目设计的目的,应明确项目要完成的结果,预期目标等。本次项目要实现C语言的万年历程序,针对项目的实际实现及复杂状态,提出如下设计需求:C语言实现简单万年历程序项目需求:需求1:输入要查询的年和月,输出该月的月历。例如,输入年份为2010,输入月份为7,则输出2010年7月的月历。请输入要查询的年和月,格式为:xxxx-xx2010-7--------------------------------------------------------------------------------------SunMonTueWedThuFriSat12345678910111213141516171819202122232425262728293031--------------------------------------------------------------------------------------需求2:输出格式美观大方。需求3:程序稳定性强,可以长期运行而不出现崩溃。19.3.1万年历的实现流程3.算法设计首先,判断输入年份是平年还是闰年,若输入年份为year,则可以通过下面的算式判断当前年份是否为闰年:if((year%4==0&&year%100!=0)||year%400==0)若if语句内表达式成立,则表示year为闰年,否则为平年。平年和闰年对当前年的2月产生影响,当year为闰年时,2月是28天,当year为平年时,2月是29天。然后,判断当前月份的1号是星期几,可以通过下面的公式来计算:Val=year-1+(year-1)/4-(year-1)/100+(year-1)/400+day式中,year为输入的公元年数,day为当前月份1号距离当前年的元旦的天数,例如,输入2010年2月,则day应该为:day=31+1=32。然后,使用公式:WeekDay=Val%7得到的余数就是当前月份1号为星期几。19.3.1万年历的实现流程4.代码编写与调试代码使用C语言编写,工程编译环境为VisualC++6.0。代码编写过程中同步进行测试及调试。保证函数编写完整无错误产生,工程可以成功运行。5.代码完善及结果验证程序调试完毕后,应抽样验证工程是否运行正常,异常情况处理是否合理等。进一步对代码进行完善,以提高其鲁棒性。19.3.2万年历程序设计流程根据算法设计,完成万年历程序的流程设计。首先,输入要查找的年份和月份,其中,要对输入参数进行检查,以保证输入参数正确,不会对后续程序造成影响。其次,对输入的年份和月份进行处理和计算,判断输入年份是否闰年,若为闰年,则置2月日期为29天,否则,置为28天。然后,计算输入月份的1号距当年元旦的天数,进而计算该月1号是星期几。最后,打印出当月的月历。输入year和month开始Year0&&0month13?YesNoResult=leap(year)Result=1,leapResult=0,no-leap计算month第一天到当年元旦的天数DayNum计算当月第1天是星期几打印月历结束19.3.3万年历程序编写1.参数输入与验证模块对输入参数作验证,若输入参数不合法,则重新输入,允许输入3次,若3次均不正确,则结束程序,代码如下:01printf(请输入要查询的年和月,格式为:xxxx-xx\n);02do03{04scanf(%d-%d,&year,&month);//输入四位数字05Times--;06if((0!=Times)&&(year0||(month0||month12)))//合法性检查07{08printf(对不起,输入错误,请重新输入,您还有%d次尝试机会.\n,Times-1);09}10else11{12break;13}14}while(Times0);15if(0==Times)16{17printf(对不起,尝试失败,请重新启动程序.\n);18return;19}19.3.3万年历程序编写2.year闰年判断模块判断year为闰年还是平年,为后续程序设计作判断。仿照算法设计中的公式,写出闰年判断函数leapFunc(),代码如下:01intleapFunc(intyear)02{03if(year%4==0&&year%100!=0||year%400==0)04{05return1;06}07else08{09return0;10}11}函数判断结束后将返回值,若返回1,表示year为闰年,否则为平年。19.3.3万年历程序编写3.月份日期数计算每个月有多少天需要根据year是闰年还是平年来计算,当year是闰年时,2月有29天,否则有28天,因此,在月份日期数计算过程中,需要调用year闰年判断函数leapFunc()。通过switch语句实现月份日期数的统计,实现函数为monthDays()4.month中1号在一年中天数计算根据输入的month值,计算month第一天在该年中是第多少天,根据算法设计程序代码如下:01intdayNum(intmonth,intyear)02{03intloop=0;04intdaySum=1;05for(loop=1;loopm