【例 6.25】编写一个程序完成“菜单”功能,提供三种选择途径:其一是求水仙花数(所 谓水仙花数是指三位整数的每一位上数字的立方和等于该整数本身。 例如 153 就是一个水仙花 数:153=1 3 +5 3 +3 3 )。找出 100~999 之间的水仙花数。
其二是查找素数,找出 2~n 之间的素数。
其三是求 Faibonacci 数列前 n 项的值。
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void main() { int m,xz;
void narcissus(); /*声明求水仙花数的函数*/
void prime(); /*声明查找素数的函数*/
void faibonacci(); /*声明求 Faibonacci 数列前 n 项的函数*/
system("cls");
m=0;
while(m==0)
{ printf("\n");
printf("1 求水仙花数\n");
printf("2 查找素数\n");
printf("3 求 Faibonacci 数列前 n 项\n");
printf("输入了非法的数据,退出!\n");
printf("\n");
printf("请输入 1~3 中的一个数字:");
scanf("%d",&xz);
switch(xz) /*用开关语句 switch 进行选择*/
{ case 1:narcissus();break; /*若选择 1,求水仙花数*/
case 2:prime();break; /*若选择 2,求素数*/
case 3:faibonacci();break; /*若选择 3, 求 Faibonacci 数列前 n 项的值*/
default:m=1; /*若选择其他讲 m 置 1,循环结束*/
} } }
void narcissus() /*此函数用于求水仙花数*/
{ int k,a,b,c,d;
for(k=100;k<1000;k++) { a=k/100;
b=k/100/10;
c=k%10;
d=a*a*a+b*b*b+c*c*c;
if(d==k)
printf("%d\n",k);
} }
void prime() /*此函数用于查找素数*/
{ int i,j,k,n,m=0;
printf("请输入一个数:");
scanf("%d",&n);
for(i=2;i<=n;i++) { j=sqrt(i);
for(k=2;k<=j;k++) if(i%k==0)
break;
if(k>j) { m++;
printf("%3d",i);
if(m%10==0) printf("\n");
} } }
void faibonacci() /*此函数用于求 Faibonacci 数列前 n 项的值*/
{ long int f,f1=1,f2=1;
int i,n;
printf("请输入 n: ");
scanf("%d",&n);
printf("%8ld%8ld",f1,f2);
for(i=3;i<=n;i++) {
f=f1+f2;
f1=f2; /*存放第一个数*/
f2=f; /*存放第二个数*/
printf ("%8ld",f);
if(i%6==0) /*为打印整齐,一行打印 6 个数,满 6 个数换行*/
printf("\n");
} }
程序共有 4 个函数,其中主函数提供了主菜单,允许选择三种情况之一,否则就退出。
方法是:先输入选择,然后通过开关语句 switch 进行选择。为了不断地提供菜单,用 while 来 循环。一开始给变量 m 赋初值为 0,m=0 就继续循环,一旦选择了不存在的情况,则将 m 置 为 1,循环就结束,这是一种较为巧妙的程序设计技巧。
【例 6.26】 编写程序,解决万年历问题。
这里,编制的程序只要求解决公历问题,不需要考虑农历。整个程序的功能概括如下:
(1)输入一个年份,输出全年的日历。
(2)输入年份、月份,输出该月的日历。
(3)输入年月日,计算出这天是星期几。
这里将这个功能定义为一个功能模块,在主程序中分别调用,实现不同的功能。
在这个问题中,最主要是闰年的判断和如何确定每年的第一天是星期几。
某一年是闰年的条件为:该年份能被 4 整除但不能被 100 整除,或者能被 400 整除。根 据这个条件,可以写出判断闰年的函数如下:
int isleap(int year)
{return (year%4==0&&year%100!=0||year%400==0);}
对于该函数,给它一个年份,如果返回值是 1 则说明是闰年,如果返回值是 0 则为非闰 年。判断是否为闰年主要是为了确定 2 月份的天数,其他月份的天数是固定的。
确定一年的第一天是星期几的函数如下:
int day(int year) {
long a,b;
if(year<=2000) /*年份在 2000 年之前*/
{
a=2000year;
b=6(a+a/4a/100+a/400)%7;
return b;
}
else /*年份在 2000 年之后*/
{
a=year2000;
b=(a+(a1)/4(a1)/100+(a1)/400)%7;
return b;
} }
在该函数中,对于年份首先判断是在 2000 年之前还是在 2000 之后,然后分别计算,最 后返回该年份的第一天是星期几,这里,返回值 0~6 分别对应是星期天到星期六。
知道了每个月的天数和该年份的第一天是星期几,利用累加就能计算出每一天对应星期 几,也就容易实现万年历系统的功能。
源程序如下:
(1)首先建立头文件 wnl.h,如下所示:
#include"stdio.h"
#define D "Sum Mon Tue Wed Thu Fri Sat"
void print(int n) /*显示 n 个空格*/
{ int i;
for(i=0;i<n;i++) printf(" ");
}
int day (int year) /*确定年份 year 的第一天是星期几*/
{
long a,b;
if(year<=2000) /*年份在 2000 年之前*/
{
a=2000year;
b=6(a+a/4a/100+a/400)%7;
return b;
}
else /*年份在 2000 年之后*/
{
a=year2000;
b=(a+(a1)/4(a1)/100+(a1)/400)%7;
return b;
} }
int isleap(int year) /*判断闰年*/
{
return(year%4==0&&year%100!=0||year%400==0);
}
在文件头中,包含了闰年的判断,确定一年的第一天是星期几,显示 n 个空格等函数,
以及几个宏定义和必需的头文件 stdio.h。
(2)显示一年的日历,定义文件 year.c 如下:
void oneyear() {
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; /*每个月的天数*/
int i,j,k,m,n,f1,f2,year,d;
clrscr();
printf("请输入年份:\n") ; scanf("%d",&year);
printf("你所输入的年份是:%d\n",year);
d=day(year); /*确定该年的第一天是星期几,用变量 d 表示*/
if(isleap(year))
a[2]++; /*如果是闰年则 2 月份的天数加 1*/
for(i=1;i<=12;i+=2) {
m=n=f1=f2=0;
switch(i) /*显示月份*/
{
case 1 :printf("January 1");break;
case 3 :printf("March 3");break;
case 5 :printf("May 5");break;
case 7 :printf("July 7");break;
case 9 :printf("September 9");break;
case 11:printf("November 11");break;
}
print(21);
switch(i+1) /*显示月份*/
{
case 2 :printf("February 2");break;
case 4 :printf("April 4");break;
case 6 :printf("June 6");break;
case 8 :printf("August 8");break;
case 10:printf("October 10");break;
case 12:printf("December 12");break;
}
printf("\n");
printf(D);print(6);printf(D);printf("\n"); /*显示日历的表头*/
for(j=0;j<6;j++) /*显示每一天的日期*/
{
if(j==0) /*第一行*/
{
print(d*4) ; for(k=0;k<7d;k++) printf("%4d",++m);
print(6);
d=d+a[i]%7;
d%=7; /*确定下个月的第一天是星期几*/
print(d*4);
for(k=0;k<7d;k++) printf("%4d",++n);
printf("\n");
}
else /*其他行*/
{for(k=0;k<7;k++) {if (m<a[i])
printf("%4d",++m);
print(4);
if(m==a[i])
f1=1; /*该月显示完毕*/
} print(6);
for(k=0;k<7;k++) {if(n<a[i+1])
printf("%4d",++n);
else
print(4);
if(n==a[i+1])
f2=1; /*该月显示完毕*/
}
printf("\n");
if(f1&&f2)
break; /*两个月显示完毕*/
} }
d=d+a[i+1]%7;d%=7; /*确定下个月的第一天是星期几*/
printf ("");
for(k=0;k<27;k++)
printf("="); /*显示分隔符*/
print(7);
for(k=0;k<27;k++)
printf("="); /*显示分隔符*/
printf("\n");
if(i==5) {getch();
clrscr();}
}
getch();
}
该函数将每年的日历分两屏显示,每屏显示 6 个月,在这个函数中,变量 m,n 分别为同 一行上两个月的日期,利用累加实现。变量 d 用来记录每个月第一天是星期几,通过它确定每 个月显示的位置。
(3)显示每个月的日历,定义文件 month.c 如下:
void onemonth() {
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; /*每个月的天数*/
int i,j,k,m,flag,year,month,d;
clrscr(); /*清屏*/
printf("请你输入年份和月份");
scanf("%d%d",&year,&month); /*输入年份和月份*/
printf("\nThe calendar of %d\n",year); /*输出表头*/
switch(month)
{ case 1 :printf("January 1");break;
case 2 :printf("February 2");break;
case 3 :printf("March 3");break;
case 4 :printf("April 4");break;
case 5 :printf("May 5");break;
case 6 :printf("June 6");break;
case 7 :printf("July 7");break;
case 8 :printf("August 8");break;
case 9 :printf("September 9");break;
case 10:printf("October 10");break;
case 11:printf("November 11");break;
case 12:printf("December 12");break;
}
printf(D);
printf("\n\n");
d=day(year); /*确定该年的第一天是星期几*/
if(isleap(year))
a[2]++; /*如果是闰年,则 2 月的天数加 1*/
for(i=1;i<month;i++) /*确定该月第一天是星期几*/
{d+=a[i]%7;d%=7;}
m=flag=0;
for(i=0;i<6;i++) /*显示该月的日历*/
{
if(i==0) /*显示第一行*/
{
print(4*d);
for(j=0;j<7d;j++) printf("%4d",++m);
printf("\n");
} else
{
for(j=0;j<7;j++)
if(m<a[month]) printf("%4d",++m);
else flag=1;
printf("\n");
if(flag) break;
} } printf(" ");
for(k=0;k<27;k++) /*分隔符*/
printf("=");
printf("\n");
getch();
}
(4)输入年月日,计算出这天是星期几,定义文件 day.c 如下:
void oneday() {
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; /*每个月的天数*/
int i,year,month,dday,d;
clrscr(); /*清屏*/
printf("请你输入年月日");
scanf("%d%d%d",&year,&month,&dday); /*输入年月日*/
printf("你输入的是年月日是%d 年%d 月%d 日", year,month,dday);
d=day(year); /*确定该年的第一天的星期天数目*/
if(isleap(year))
a[2]++; /*如果是闰年,则 2 月份的天数加 1*/
for(i=1;i<month;i++) /*确定该月第一天的星期数*/
{d+=a[i]%7;d%=7;}
d+=(dday1)%7;d%=7; /*确定该天的星期数*/
switch(d) {
case 0: printf("Sunday.\n");break;
case 1: printf("Monday.\n");break;
case 2: printf("Tuesday.\n");break;
case 3: printf("Wednesday.\n");break;
case 4: printf("Thursday.\n");break;
case 5: printf("Friday.\n");break;
case 6: printf("Saturday.\n");break;
}
getch();
}
该函数中首先要确定该年份第一天的星期数,而后计算对应月份第一天的星期数,再计 算出该天的星期数,最后输出结果。
(5)主程序。定义文件 wnl.c 如下:
#include"year.c"
#include"month.c"
#include"day.c"
void main() {
int choice,flag;
while(1)
{
flag=0; /*标志变量赋初值*/
clrscr(); /*清屏,以下是显示功能菜单*/
printf("************************\n");
printf("*Please select the function(03):*\n");
printf("*1 Dispiay the calendar of one year.*\n");
printf("*2 Dispiay the calendar of one month.*\n");
printf("*3 Display the weekday of one day.*\n");
printf("*0.Exit*\n”);
printf("* ***********************\n");
scanf("%d",&choice);
switch(choice) {
case 0:
clrscr ();
printf ("Thank you for use this software.\n"); /*显示信息*/
printf("Welcome to use it again\n");
flag=1;break;
case 1:oneyear();break; /*显示全年*/
case 2:onemonth();break; /*显示某个月*/
case 3:oneday();break; /*确定某一天的星期数*/
default:printf("Your choice wrong,please input again.");
getch();
} /*结束 switch */
if(flag) break;
} /*结束 while*/
} /*结束 main */
程序说明:
(1)该程序包含所有子函数的源文件,根据用户选择的功能调用相应的自定义子函数。
(2)在主程序中,菜单循环显示,用户可以一直使用,直到选择功能键“0” ,退出程序。