65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C 语言的日历

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (23投票s)

2014 年 6 月 8 日

CPOL

7分钟阅读

viewsIcon

237949

downloadIcon

5441

C 程序用于显示任意给定月份和年份(mm-yyyy)的日历

引言

和许多人一样,我也是从 C 语言开始学习计算机编程的,C 语言是有史以来使用最广泛的编程语言之一。:)

在这篇文章中,我将解释一个 C 程序,它接受任何月份年份并显示该月份的日历。我们将添加更多功能,例如,如果用户按下

  • 左箭头键 - 转到上个月。
  • 右箭头键 - 转到下个月。
  • 上箭头键 - 转到下一年。
  • 下箭头键 - 转到上一年。
  • I - 插入新的月份年份。
  • P - 将月份打印到文本文件中。
  • Esc - 退出程序。

这个简单的例子对初学者和中级开发人员都很有帮助,可以帮助他们理解一些基本概念,例如声明数组、使用函数、循环、使用 goto 语句、打印输出文件、处理按键等。

请随时分享您的评论/建议并评价这篇文章。:)

背景

  • 我们将通过向用户显示一个输入屏幕来开始程序,该屏幕将以 mm-yyyy 格式接受月份和年份,如下所示

  • 一旦用户输入有效的月份年份并按下 Enter 键,它应该显示输入月份的日历,如下所示

  • 如果用户按下左箭头键,它将显示上个月(即 2014 年 5 月)的日历,如下所示

  • 同样,如果用户按下右箭头键,它将在屏幕上显示下个月(即 2014 年 7 月)

一旦用户按下上箭头键,它将在屏幕上显示下一年的月份(即 2015 年 6 月)

  • 如果用户按下下箭头键,它将在屏幕上显示上一年的月份(即 2013 年 6 月)

  • 如果用户按下 I 键,它将显示用户输入屏幕并要求输入另一个月份年份。
  • 如果按下 P 键,它将把月份详细信息导出到名为“JUN2014.txt”的文本文件中,如下所示

  • 一旦用户按下 Esc 键,程序将关闭。

注意:我使用了 Turbo C++ / C 编译器来创建这个程序。请访问以下链接下载

适用于 Windows XP / 7 / 8 / 8.1 的 Turbo C++ / C 编译器

使用代码

让我们首先在 main() 函数中创建输入屏幕

    textcolor(WHITE);
    clrscr();
    printf("\n\tThis program shows calendar of \n");
    printf("\n\ta given month. Enter month, year...format is mm-yyyy.\n");

代码解释

textcolor() 函数用于更改 C 程序中绘制文本的颜色。

声明:- void textcolor(int color);
其中 color 是一个整型变量。例如,0 表示黑色,1 表示蓝色,2 表示绿色等等。您也可以使用适当的颜色而不是整数。例如,您可以写入 textcolor(YELLOW); 将文本颜色更改为黄色。但只能使用大写字母的颜色。

clrscr() 函数用于清除屏幕。

接下来的两行只是用于在控制台输出上显示消息。

    /* taking input */
    while(TRUE)
    {
        fflush(stdin);
        printf("\n\n\tEnter mm-yyyy: ");
        scanf("%d-%d", &Month, &Year);
        if(Year < 0)
        {
            printf("\nInvalid year value...");
            continue;
        }
        if(Year < 100)
            Year += 1900;
        if(Year < 1582 || Year > 4902)
        {
            printf("\nInvalid year value...");
            continue;
        }
        if(Month < 1 || Month > 12)
        {
            printf("\nInvalid month value...");
            continue;
        }
        break;
    }    /* End of while loop */

代码解释

我们从一个 while(TRUE) 循环开始,这是一个无限循环,因此您必须显式地中断循环。否则它将无限循环。这个循环的原因是为了确保我们接受用户有效的输入。如果用户输入无效,则显示错误消息并再次提示输入。

        fflush(stdin);
        printf("\n\n\tEnter mm-yyyy: ");
        scanf("%d-%d", &Month, &Year);

fflush(stdin); - 此函数用于清除输入缓冲区。

其他行用于接受用户输入到两个变量中,Month 和 Year。

        if(Year < 0)
        {
            printf("\nInvalid year value...");
            continue;
        }
        if(Year < 100)
            Year += 1900;
        if(Year < 1582 || Year > 4902)
        {
            printf("\nInvalid year value...");
            continue;
        }
        if(Month < 1 || Month > 12)
        {
            printf("\nInvalid month value...");
            continue;
        }
        break;

我们编写了一些数据验证代码,例如年份必须大于 0。如果用户输入 yy 格式的年份(例如,98),它将加上 1900 变为 1998。程序将接受 1952 年到 4902 年之间的年份。超出此范围的任何年份都不会被接受为有效年份。

月份必须在 1 到 12 的范围内。超出此范围的任何输入都不会被接受为有效的月份。

如果所有条件都不满足,将执行 break; 语句,程序流程将继续。

注意:在每次验证失败消息之后,都会写入 continue; 语句,以确保循环内的其余代码不会执行。

在继续 main 方法的其余部分之前,让我们声明一些常量并编写所需的函数。

#define LEAP_YEAR ((Year%4==0 && Year%100 != 0)||Year%400==0)
#define TRUE 1
#define CH '-'
#define MAX_NO 91

#define 指令用于在 C 编程语言中定义常量或创建宏。第一条语句定义了一个宏,它接受 Year 作为输入参数并返回 TRUE/FALSE。如果年份是闰年,它返回 TRUE,否则返回 FALSE。

其他三行用于定义常量。

int MonthDay[] = {31,28,31,30,31,30,31,31,30,31,30,31};
char *MonthName[]={"January","February","March","April","May","June","July",
        "August","September","October","November","Decembeer"};
char *MonthName1[]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP",
            "OCT","NOV","DEC"};

我们声明了三个数组。MonthDay[] 将用于确定一个月中的天数。我们将单独处理闰年。*MonthName[]*MonthName1[] 是字符串数组。

注意:字符串数组可以通过两种方式声明

  • char array[ROW][COL]; - 当您知道行数 ROW 和列数 COL 时。
  • char *array[ROW]; - 这种方式,您只需提供行数。如果您在声明时用值初始化数组,则行号变为可选。

在我们的例子中,我们没有提供行数,因为我们只在声明时用值初始化了数组。

让我们继续添加所需的函数

/*================ FUNCTION TO CALCULATE ZELLER'S ALGORITHM =============*/
int getZeller(int Month,int Year)
{
    int Day = 1, ZMonth, ZYear, Zeller;
    if(Month < 3)
        ZMonth = Month+10;
    else
        ZMonth = Month-2;
    if(ZMonth > 10)
        ZYear = Year-1;
    else
        ZYear = Year;
    Zeller = ((int)((13*ZMonth-1)/5)+Day+ZYear%100+
            (int)((ZYear%100)/4)-2*(int)(ZYear/100)+
            (int)(ZYear/400)+77)%7;
    return Zeller;
}

蔡勒算法(Zeller's Algorithm)可用于确定过去、现在或未来任何日期(1582 年至 4902 年之间)的星期几。我们使用此函数来获取给定月份第一天的星期几。

/*==================== FUNCTION TO GET KEY CODE =========================*/
getkey()
{
    union REGS i,o;
    while(!kbhit())
        ;
    i.h.ah = 0;
    int86(22,&i,&o);
    return (o.h.ah);
}

kbhit() - 当用户按下按键时返回整数值的函数。我们将使用此函数来捕获用户输入,例如左箭头键、右箭头键、上箭头键、下箭头键、I、P 等。

void printchar(char c)
{
    int i;
    printf("\n\t");
    for(i=1;i<=51;i++)
        printf("%c",c);
    printf("\n");
}

printchar(); - 它接受一个字符并将其打印 51 次在一行上。此函数将用于对输出进行一些格式化。

void PrintFile(int M,int Y, int Z)
{
    int i, j;
    char filename[12];
    char stryear[5];
    FILE *stream;

    strcpy(filename, MonthName1[M-1]);
    itoa(Y, stryear, 10);
    strcat(filename, stryear);
    strcat(filename, ".txt");

    if((stream=fopen(filename,"w"))==NULL)
    {
        printf("\nError-cannot create file.");
        getch();
        exit(1);
    }

    fprintf(stream, "\n\t\t\t%s %d\n\n\t", MonthName[M-1], Y);

    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");

    fprintf(stream, "\n\tSUN\tMON\tTUE\tWED\tTHU\tFRI\tSAT\n\t");
    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");

    /* setting starting position */
    fprintf(stream, "\n");
    for(i = 1; i <= Z; i++)
        fprintf(stream, "\t -");

    j = Z;

    /* printing dates */
    for(i = 1; i <= MonthDay[M-1]; i++)
    {
        if(j++ % 7 == 0)
            fprintf(stream, "\n");
        fprintf(stream, "\t%2d", i);
    }

    fprintf(stream, "\n\t");
    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");

    fprintf(stream, "\n\n\t\tCreated by: Debabrata Das [debabrata.dd@gmail.com]");
    fclose(stream);
}

代码解释

PrintFile(); - 函数将用于将输出打印到文本文件并保存到磁盘。

    int i, j;
    char filename[12];
    char stryear[5];
    FILE *stream;

变量声明部分,我们声明了两个整型变量 - i, j,两个字符数组 - filename, stryear 和一个 FILE 指针,用于在 C 语言中与文件通信。

    strcpy(filename, MonthName1[M-1]);
    itoa(Y, stryear, 10);
    strcat(filename, stryear);
    strcat(filename, ".txt");

strcpy(des, src); - 此函数用于将 src 字符串复制到 des 字符串。这里月份名称将被复制到 filename 变量。月份名称将用于创建文本文件名。

itoa(); - 用于将整数转换为字符串。我们将给定年份转换为字符串,以便它可以与月份名称连接并形成输出文本文件名。

strcat(str1, str2); - 此函数用于将 str2 连接到 str1。最初我们将月份名称复制到 filename 变量中。现在我们将年份与月份名称连接起来,使文件名如下所示:“JUN2014”

我们再次使用 strcat() 来附加文件的“.txt”扩展名。最终文件名将包含一个完整的文件名,如下所示:“JUN2014.txt”

    if((stream = fopen(filename,"w"))==NULL)
    {
        printf("\nError-cannot create file.");
        getch();
        exit(1);
    }

上述代码将尝试以只写模式("w")打开文件。如果由于任何原因无法打开文件,fopen() 函数将返回 NULL 值。然后我们可以显示消息“Error-cannot create file。”

getch(); - 此函数用于从控制台输入(即键盘)获取一个字符/按键。程序会等待直到用户按下键盘上的任何键。

exit(1); - 将退出程序。

    fprintf(stream, "\n\t\t\t%s %d\n\n\t", MonthName[M-1], Y);
    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");
    fprintf(stream, "\n\tSUN\tMON\tTUE\tWED\tTHU\tFRI\tSAT\n\t");
    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");

    /* setting starting position */
    fprintf(stream, "\n");
    for(i = 1; i <= Z; i++)
        fprintf(stream, "\t -");
    j = Z;
    /* printing dates */
    for(i = 1; i <= MonthDay[M-1]; i++)
    {
        if(j++ % 7 == 0)
            fprintf(stream, "\n");
        fprintf(stream, "\t%2d", i);
    }
    fprintf(stream, "\n\t");
    for(i=1; i<=MAX_NO; i++)
        fprintf(stream, "-");
    fprintf(stream, "\n\n\t\tCreated by: Debabrata Das [debabrata.dd@gmail.com]");

以上几行用于以适当的格式打印该月的日期。

    fclose(stream);

一旦所有内容都写入文件,就会调用 fclose() 函数以正确关闭文件。

现在我们已经完成了所有必需的函数。让我们完成 main 方法中的逻辑。

    do
    {
        /* calculating day of 1st date of given month */
        Zeller = getZeller(Month,Year);
        clrscr();
        printf("\n\n\t\t\t");

        /* printing the corresponding month name */
        textbackground(Month);
        cprintf("%s %d\n",MonthName[Month-1],Year);
        textbackground(BLACK);

        /* adjusting February in case of Leap Year */
        MonthDay[1] = LEAP_YEAR ? 29 : 28;

        /* giving output */
        printchar(CH);

        textcolor(12); /* LIGHTRED */
        printf("\t");cprintf("SUN");
        textcolor(LIGHTGREEN);
        cprintf("     MON     TUE     WED     THU     FRI    SAT");
        textcolor(7);

        printchar(CH);

        /* setting starting position */
        for(i = 1; i <= Zeller; i++)
            printf("\t -");
        j = Zeller;
        /* printing dates */
        for(i = 1; i <= MonthDay[Month-1]; i++)
        {
            if(j++ % 7 == 0)
            {
                printf("\n\t");
                textcolor(12);
                cprintf("%2d",i);
                textcolor(WHITE);
            }
            else
                printf("      %2d",i);
        }

        printchar(CH);
        printf("\n\n\t\t(*) Use Left,Right,Up & Down Arrow.");
        printf("\n\n\t\t(*) Press I for New Month & Year.");
        printf("\n\n\t\t(*) Press P for Print to File.");
        printf("\n\n\t\t(*) Press ESC for Exit.\n\n\n\t\t");

        textcolor(11);
        textbackground(9);
        cprintf("Created by: Debabrata Das [debabrata.dd@gmail.com]");
        textcolor(WHITE);
        textbackground(BLACK);

        KeyCode = getkey();         /* getting Key Code */
        if(KeyCode == 72)           /* Up Arrow */
            Year++;
        if(KeyCode == 80)           /* Down Arrow */
            Year--;
        if(KeyCode == 77)           /* Right Arrow */
        {
            Month++;
            if(Month > 12)
            {
                Month = 1;
                Year++;
            }
        }
        if(KeyCode == 75)            /* Left Arrow */
        {
            Month--;
            if(Month < 1)
            {
                Month = 12;
                Year--;
            }
        }
        if(KeyCode == 25)             /* Code of P */
            PrintFile(Month,Year,Zeller);
        if(KeyCode == 23)             /* Code of I */
            goto Top;
    }while(KeyCode != 1);    /* End of do-while loop */

代码解释

textbackground(); - 此函数用于在文本模式下更改当前背景颜色。

        /* adjusting February in case of Leap Year */
        MonthDay[1] = LEAP_YEAR ? 29 : 28;

如前所述,这里我们正在计算二月份的天数。如果是闰年,则考虑 29 天,否则 28 天。

其余代码非常直观,因此不再解释每一行代码。

让我们编译并执行程序。希望您喜欢这篇文章。请留下您的评论/建议,别忘了评分。:)

编码愉快 :)

 

历史

 

在此处保持您所做的任何更改或改进的实时更新。

© . All rights reserved.