天花板编程手把手计划-第1期-第8天

上一篇中的课后练习大家普遍反映太简单了。其实,麻雀虽小,五脏俱全。今天我们来看看它的解法。

1. 题目

请编程实现一个功能,输入任意一个日期,计算出那一天是星期几。这道题没有任何限制,你可以设计任何自己喜欢的交互形式,可以使用任何自己能想到的算法。

2. 分析

这道题的题干并不是很具体,它其实是一道从功能开始的设计题。首先要考虑的是交互方法的设计。程序的输入时一个日期,这个日期采用什么形式,怎么输入都是不确定的。

为了Debug方便,我依然用了之前的程序中习惯的方法,从文件读取测试用例。于是,这个题目变成了这样。

给出一个文件input.txt,内容如下:

5
1900-01-01 1
2017-5-24 3
2017-1-1 0
2017-3-6 1
2017-4-20 4

第一行给出的是日期的个数,之后每一行给出两个元素:日期和星期。请编程实现判断日期是星期几,之后用后面的正确答案来判断程序是否执行正确。

这个题目看起来比较奇怪,居然给出了正确答案。其实这是软件开发中常用的一种方法叫做单元测试。我们可以通过这种方法来测试程序实现的功能是否正确。

3. 程序主干

我们首先来实现一个main函数,代码如下:

int main()
{
    int i, cnt;

    freopen("input.txt", "r", stdin);
    scanf("%d", &cnt);

    for (i = 0; i < cnt; i++)
    {
        printf("#%d : ", i + 1);
        if (Process() == 1)
        {
            printf("Right\n");
        }
        else
        {
            printf("Wrong\n");
        }
    }

    return 1;
}

是不是很熟悉,这段程序首先从文件中读取测试用例的个数,保存在cnt变量中。之后循环来判断核心的算法是否正确,正确在屏幕上打印Right,错误打印Wrong。

判断测试核心算法的函数是Process,接下来我们就实现它。

4. 测试函数

Process函数源码如下:

#define MAX 15
char g_arr[MAX];
int Process()
{
    int ret, answer, i;
    int year, month, day;
    int week;
    char* pStr = g_arr;

    scanf("%s", pStr);
    scanf("%d", &answer);

    year = GetNextNum(&pStr);
    month = GetNextNum(&pStr);
    day = GetNextNum(&pStr);

    week = GetWeek(year, month, day);

    if (week == answer)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

这个函数有三部分功能:

4.1 读取数据

这部分很简单,通过scanf从文件中读取数据,这个前面的文章中已经讲过了。这里需要说明的是我们拿到一个类似“2017-01-01”这样的字符串,如何得到它对应的年月日对应的int值呢。这里调用了一个GetNextNum函数,它的实现如下:

// 得到字符串中的第一组数字
int GetNextNum(char** ppStr)
{
    int ret = 0;
    int num;
    char* pStr = *ppStr;
    while (1)
    {
        if (*pStr < '0' || *pStr > '9')
        {
            break;
        }

        num = *pStr - '0';
        ret = ret * 10 + num;

        pStr++;
    }
    pStr++;
    *ppStr = pStr;

    return ret;
}

这个方法应该是教科书的练习题,相信大家都能看懂。需要说明的是,参数使用了char** ppStr这个二维指针,原因在于我们希望每次调用这个函数时,都能够从上一次处理之后的位置开始。如果写成char* pStr,会出现什么样的情况,请大家自己试验。

4.2 判断星期

判断星期时,调用的就是我们要测试的核心算法函数GetWeek,这个函数的功能是输入年月日三个参数,返回一个星期数,0~6表示星期日到星期六。

4.3 判断是否正确

GetWeek函数的结果与文件中的正确结果比较,正确返回1,错误返回0。

5. 判断星期

之前的文章21天C语言代码训练营(第六天)里曾经定义过相关的接口,我们把需要的几个拿过来。

// 判断闰年,是闰年返回1,是平年返回0
int IsLeapYear(int year)
{
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        return 1;
    else
        return 0;
}

// 返回输入年份的1月1日是周几
int GetFirstWeek(int year)
{
    return (35 + year + year / 4 - year / 100 + year / 400) % 7;
}

int g_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

// 返回输入的年份中输入的月份天数
int GetDays(int year, int month)
{
    if (month == 2 && IsLeapYear(year))
    {
        return g_days[month - 1] + 1;
    }
    else
    {
        return g_days[month - 1];
    }
}

这三个函数的功能都很简单,相信一看就能明白。之前有很多人问GetFirstWeek这个函数为什么这样实现,这个是网上找的算法,具体的推导过程我没有留意,只是验证了一下发现能用而已。

有了这几个接口,我们就能很轻松地写出今天的核心函数了:

int GetWeek(int year, int month, int day)
{
    int i;
    int week = GetFirstWeek(year);
    for (i = 1; i < month; i++)
    {
        week += GetDays(year, i);
    }

    week--;

    week += day;
    week = week % 7;

    return week;
}

这个函数的功能是输入年月日三个参数,返回当天是星期几。

好了,现在运行一下程序,看看执行结果。

这个题目虽然简单,但这种通过一段程序测试另一段程序的思想希望大家仔细体会。

6. 课后练习

用你学过的C语言知识,设计一个番茄钟程序。要求满足如下功能:

  • 可以设置倒计时时间
  • 拥有倒计时效果
  • 倒计时结束后有提醒
  • 使用记录保存在文件中

我是天花板,让我们一起在软件开发中自我迭代。
如有任何问题,欢迎与我联系。


上一篇:天花板编程手把手计划-第1期-第7天

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容