问题简介

有这样一个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
某人三天打渔两天晒网,假设他从1990年1月1日开始打渔三天,然后晒网两天,请编程回答任意的一天他在打渔还是晒网。
A boy works for 3 days while has a 2 days off. If he is working on 1st, Jan, 1990, then for a date entered from the keyboard, please write a program to determine what the boy is doing, working or resting?
Examples of input and output:
1)Input:
1990-01-05
Output:
He is having a rest.
2)Input:
1990-01-07
Output:
He is working.
3)Input:
1990-01-33
Output:
Invalid input.
***输入数据格式***:"%4d-%2d-%2d"
***输出数据格式***:"Invalid input."或"He is having a rest." 或"He is working."

该题的参考答案如下,主要使用的是switch语句来进行判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <stdio.h>
#include <stdlib.h>

int main()
{
int y, m, d;
int sum = 0;
scanf("%4d-%2d-%2d", &y, &m, &d);
if (y < 1990)
{
printf("Invalid input.");
return 0;
}
if ((y % 100 != 0 && y % 4 == 0) || (y % 400 == 0))
{
switch (m)
{

case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (d > 31 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
case 2:
if (d > 29 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
case 4:
case 6:
case 9:
case 11:
if (d > 30 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
default:
printf("Invalid input.");
return 0;
break;
}
}
else
{
switch (m)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (d > 31 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
case 2:
if (d > 28 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
case 4:
case 6:
case 9:
case 11:
if (d > 30 || d < 1)
{
printf("Invalid input.");
return 0;
}
break;
default:
printf("Invalid input.");
return 0;
break;
}
}
int i;
if (y > 1990)
{
for (i = 1990; i < y; i++)
{
if ((i % 100 != 0 && i % 4 == 0) || (i % 400 == 0))
{
sum = sum + 366;
}
else
{
sum = sum + 365;
}
}

}


int i1;
if (m > 1)
{
for (i1 = 1; i1 < m; i1++)
{
if ((y % 100 != 0 && y % 4 == 0) || (y % 400 == 0))
{
switch (i1)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
sum = sum + 31;
break;
case 2:
sum = sum + 29;
break;
case 4:
case 6:
case 9:
case 11:
sum = sum + 30;
break;
}
}
else
{
switch (i1)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
sum = sum + 31;
break;
case 2:
sum = sum + 28;
break;
case 4:
case 6:
case 9:
case 11:
sum = sum + 30;
break;
}
}
}
}
sum = sum + d;
sum = sum % 5;
if (sum == 0 || sum == 4)
{
printf("He is having a rest.");
}
else
{
printf("He is working.");
}
return 0;
}

但是,该题既然和时间有关,那也一定可以通过时间戳来完成。

时间戳

时间戳记或称为时间标记(英语:timestamp)是指字符串或编码信息用于辨识记录下来的时间日期。国际标准为ISO 8601。

时间戳记的范例如下:

2016-12-25T00:15:22Z
2005-10-30 10:45 UTC
Sat Jul 23 02:16:57 2005
2016年12月25日 (日) 00:14 (UTC)

时间戳转换工具:https://tool.lu/timestamp/

C语言中时间戳的转化

C 库函数 - mktime()

描述

C 库函数 time_t mktime(struct tm *timeptr) 把 timeptr 所指向的结构转换为自1970 年 1 月 1日以来持续时间的秒数,发生错误时返回-1。

声明
下面是 mktime() 函数的声明。

1
time_t mktime(struct tm *timeptr)

参数

timeptr – 这是指向表示日历时间的 time_t 值的指针,该日历时间被分解为以下各部分。下面是 timeptr 结构的细节:

1
2
3
4
5
6
7
8
9
10
11
struct tm {
int tm_sec; /* 秒,范围从 0 到 59 */
int tm_min; /* 分,范围从 0 到 59 */
int tm_hour; /* 小时,范围从 0 到 23 */
int tm_mday; /* 一月中的第几天,范围从 1 到 31 */
int tm_mon; /* 月份,范围从 0 到 11 */
int tm_year; /* 自 1900 起的年数 */
int tm_wday; /* 一周中的第几天,范围从 0 到 6 */
int tm_yday; /* 一年中的第几天,范围从 0 到 365 */
int tm_isdst; /* 夏令时 */
};

返回值

该函数返回自 1970 年 1 月 1 日以来持续时间的秒数。如果发生错误,则返回 -1 值。

实例

下面的实例演示了 mktime() 函数的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <time.h>

int main () {
int ret;
struct tm info;
char buffer[80];

info.tm_year = 2021 - 1900;
info.tm_mon = 7 - 1;
info.tm_mday = 4;
info.tm_hour = 0;
info.tm_min = 0;
info.tm_sec = 1;
info.tm_isdst = -1;

ret = mktime(&info);
if( ret == -1 ) {
printf("Error: unable to make time using mktime\n");
} else {
strftime(buffer, sizeof(buffer), "%c", &info );
printf(buffer);
}

return(0);
}

让我们编译并运行上面的程序,这将产生以下结果:

1
Sun Jul  4 00:00:01 2021
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* 输入日期判断是周几 */
#include <stdio.h> /* printf, scanf */
#include <time.h> /* time_t, struct tm, time, mktime */

int main ()
{
time_t rawtime;
struct tm * timeinfo;
int year, month ,day;
const char * weekday[] = { "周日", "周一","周二", "周三","周四", "周五", "周六"};

/* 用户输入日期 */
printf ("年: "); fflush(stdout); scanf ("%d",&year);
printf ("月: "); fflush(stdout); scanf ("%d",&month);
printf ("日: "); fflush(stdout); scanf ("%d",&day);

/* 获取当前时间信息,并修改用户输入的输入信息 */
time ( &rawtime );
timeinfo = localtime ( &rawtime );
timeinfo->tm_year = year - 1900;
timeinfo->tm_mon = month - 1;
timeinfo->tm_mday = day;

/* 调用 mktime: timeinfo->tm_wday */
mktime ( timeinfo );

printf ("那一天是:%s\n", weekday[timeinfo->tm_wday]);

return 0;
}

让我们编译并运行上面的程序,这将产生以下结果:

1
2
3
4
年: 2018
月: 7
日: 26
那一天是:周四

C 库函数 - localtime()

描述

C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。timer 的值被分解为 tm 结构,并用本地时区表示。

声明

下面是 localtime() 函数的声明。

1
struct tm *localtime(const time_t *timer)

参数

1
timer -- 这是指向表示日历时间的 time_t 值的指针。

返回值
该函数返回指向 tm 结构的指针,该结构带有被填充的时间信息。下面是 tm 结构的细节:

1
2
3
4
5
6
7
8
9
10
11
struct tm {
int tm_sec; /* 秒,范围从 0 到 59 */
int tm_min; /* 分,范围从 0 到 59 */
int tm_hour; /* 小时,范围从 0 到 23 */
int tm_mday; /* 一月中的第几天,范围从 1 到 31 */
int tm_mon; /* 月份,范围从 0 到 11 */
int tm_year; /* 自 1900 起的年数 */
int tm_wday; /* 一周中的第几天,范围从 0 到 6 */
int tm_yday; /* 一年中的第几天,范围从 0 到 365 */
int tm_isdst; /* 夏令时 */
};

实例
下面的实例演示了 localtime() 函数的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <time.h>

int main ()
{
time_t rawtime;
struct tm *info;
char buffer[80];

time( &rawtime );

info = localtime( &rawtime );
printf("当前的本地时间和日期:%s", asctime(info));

return(0);
}

让我们编译并运行上面的程序,这将产生以下结果:

1
当前的本地时间和日期:Thu Aug 23 09:12:05 2012

附:部分习题

第一题

求 s = a+aa+aaa+… …+aaa…a的值,其中a是一个数字,如2+22+222+2222,a的值和加数个数n,均从键盘获取。要求a属于[1,9],n小于10(如果不满足此条件,就重新输入)。
输入:输入a值和n值
输入提示信息:“Please input a:”
输入格式:"%d"
输入提示信息:“Please input n:”
输入格式:"%d"
如:
Please input a:8
Please input n:9
输出:算式及和
输出提示信息:
“Sum=算式“,输出格式”%ld“
”Sum=和,输出格式”%ld“
循环n次,i=0时输出用”%ld",其他输出用"+%ld"(或者前面输出用"%ld+",最后一次输出用"%ld")
如:
Sum=8+88+888+8888+88888+888888+8888888+88888888+888888888
Sum=987654312

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>

int consnum(int a, int n);

int main(){
int a,time,i,sum;
sum = 0;
printf("Please input a:");
scanf("%d",&a);
printf("Please input n:");
scanf("%d",&time);
printf("Sum=");
for(i=0;i<time;i++){
printf("%d",consnum(a,i+1));
if(i+1!=time)printf("+");
else printf("\n");
sum += consnum(a,i+1);
}
printf("Sum=%d",sum);
}

int consnum(int a, int n){
int i,sum;
sum =0;
for(i=1;i<=n;i++){
sum += a * pow(10,i-1);
}
return sum;
}

第二题

统计正整数中指定数字的个数
从键盘输入一个正整数number,求其中含有指定数字digit的个数。例如:从键盘输入正整数number=1222,若digit=2,则1223中含有 3个2,要求用函数实现。函数原型为:int CountDigit(int number,int digit);

程序运行结果示例1:
Input m,n:
1222,2↙
3

程序运行结果示例2:
Input m,n:
1234,6↙
0

输入格式: “%d,%d”
输出格式:
输入提示信息:“Input m,n:\n”
输出格式:"%d\n"

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int CountDigit(int number, int digit);

int main() {
int num, digit;
printf("Input m,n:\n");
scanf("%d,%d", &num, &digit);
num = CountDigit(num, digit);
printf("%d\n", num);
}

int CountDigit(int number, int digit) {

int temp;
int ans = 0;
do {
temp = number % 10;
if (temp == digit)ans += 1;
number /= 10;
} while (number > 0);
return ans;
}

第三题

编写计算组合数的程序。要求输入数据要有容错功能。
**输入格式要求:"%d,%d" 提示信息:“Input m,k (m>=k>0):”
**输出格式要求:“p = %.0f\n”
程序运行示例1如下:
Input m,k (m>=k>0):3,2
p = 3
程序运行示例2如下:
Input m,k (m>=k>0):2,3
Input m,k (m>=k>0):3,3
p = 1
Input m,k (m>=k>0):-2,-4
Input m,k (m>=k>0):4,2
p = 6

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int Fac(int i) {
int sum = 1;
for (i; i > 1; i--) {
sum *= i;
}
return sum;
}

int main() {
int m, k;
float ans;
loop:
printf("Input m,k (m>=k>0):");
scanf("%d,%d", &m, &k);
//printf("%d", Fac(m));
if (m < 0 || k<0 || k>m)goto loop;
ans = (float)Fac(m) / (Fac(k) * Fac(m - k));
printf("p = %.0f\n", ans);
}

第四题

写一个程序,输入为一个整数,输出为该整数的打头数字。例如123的打头数字为1,-123的打头数字为-1。

**输入格式要求:"%d" 提示信息:“请输入一个整数:”
**输出格式要求:“该整数以%d打头!\n”

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <math.h>

int main()
{
int num;
int i = 0;
printf("请输入一个整数:");
scanf("%d",&num);
while(num != num % (int)pow(10,i)){
i++;
}
num = num /(pow(10,i-1));
printf("该整数以%d打头!\n",num);
}

第五题

编程求解汉诺塔问题。
汉诺塔(Hanoi)是必须用递归方法才能解决的经典问题。它来自于印度神话。上帝创造世界时作了三根金刚石柱子,在第一根柱子上从下往上按大小顺序摞着64片黄金圆盘,如图7-3所示。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放到第二根柱子上,并且规定,每次只能移动一个圆盘,在小圆盘上不能放大圆盘。有人预言说,这件事完成时宇宙会在一瞬间闪电式毁灭,也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。
**输入格式要求:"%d" 提示信息:“Input the number of disks:”
**输出格式要求:“Steps of moving %d disks from A to B by means of C:\n” “Move %d: from %c to %c\n”
程序运行示例如下:
Input the number of disks:3
Steps of moving 3 disks from A to B by means of C:
Move 1: from A to B
Move 2: from A to C
Move 1: from B to C
Move 3: from A to B
Move 1: from C to A
Move 2: from C to B
Move 1: from A to B

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
void Hanoi(int n, char a, char b, char c);
void Move(int n, char a, char b);
int main()
{
int n;
printf("Input the number of disks:");
scanf("%d", &n);
printf("Steps of moving %d disks from A to B by means of C:\n", n);
Hanoi(n, 'A', 'B', 'C'); /*调用递归函数Hanoi()将n个圆盘借助于C由A移动到B*/
return 0;
}
/* 函数功能:用递归方法将n个圆盘借助于柱子c从源柱子a移动到目标柱子b上 */
void Hanoi(int n, char a, char b, char c)
{
if (n == 1)
{
Move(n, a, b); /* 将第n个圆盘由a移到b */
}
else
{
Hanoi(n - 1, a, c, b); /* 递归调用Hanoi(),将第n-1个圆盘借助于b由a移动到c*/
Move(n, a, b); /* 第n个圆盘由a移到b */
Hanoi(n - 1, c, b, a); /*递归调用Hanoi(),将第n-1个圆盘借助于a由c移动到b*/
}
}
/* 函数功能: 将第n个圆盘从源柱子a移到目标柱子b上 */
void Move(int n, char a, char b)
{
printf("Move %d: from %c to %c\n", n, a, b);
}

第六题

根据最大公约数的如下3条性质,采用递归法编写计算最大公约数的函数Gcd(),在主函数中调用该函数计算并输出从键盘任意输入的两正整数的最大公约数。
性质1 如果a>b,则a和b与a-b和b的最大公约数相同,即Gcd(a, b) = Gcd(a-b, b)
性质2 如果b>a,则a和b与a和b-a的最大公约数相同,即Gcd(a, b) = Gcd(a, b-a)
性质3 如果a=b,则a和b的最大公约数与a值和b值相同,即Gcd(a, b) = a = b
要求如下:
(1)从键盘任意输入的两整数
主函数调用Gcd()函数,并输出两整数的最大公约数。
(2)Gcd函数原型为:
int Gcd(int a, int b);
如果输入的数不是正整数,则返回-1,否则,返回两个数的最大公约数。
(3)**输入提示信息格式要求:“Input a,b:”
输入格式:"%d,%d"
**输出提示信息要求:
若输入不是正整数,则输出"Input number should be positive!\n"
否则输出"Greatest Common Divisor of %d and %d is %d\n"
注:不允许使用goto语句

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int Gcd(int a,int b)
{
if(a == b)return a;
else if (a > b)return Gcd(a-b,b);
else if (b > a)return Gcd(a,b-a);
}

int main()
{
int a,b;
printf("Input a,b:");
scanf("%d,%d",&a,&b);
if(a<1||b<1)printf("Input number should be positive!\n");
else
{
printf("Greatest Common Divisor of %d and %d is %d\n",a,b,Gcd(a,b));
}
}