情報処理技術者試験対策講座
|
次のCプログラムの説明及びプログラムを読んで、設問に答えよ。
〔プログラムの説明〕
生年月日と今日の日付を読み込み、生年月日から今日までの日数を計算して出力するプログラムである。
(1) 標準入力から生年月日と今日の日付を入力する。生年月日、今日の日付はそれぞれ、年月、日の順に並んだ、空白で区切った整数の組である。
** 生年月日を入力してください **
1972 1 1
** 今日の日付を入力してください **
1994 10 16
|
図1 入力データの例
(2) 年月日は西暦とし、入力できる年月日は西暦1800年1月1日以降とする。
年月日が正しい範囲内にないときは、入力データ誤りとみなしメッセージを出力して終了する。生年月日が今日の日付より後のときも、誤りとみなしメッセージを出力して終了する。
(3) 生年月日から今日の日付までの日数を、次の式によって計算する。
(生年月日から今日の日付までの日数)=
(西暦1年1月1日から今日の日付までの日数)
-(西暦1年1月1日から生年月日までの日数)
(4) 日数の計算及び入力データの誤りの検出では、うるう年を考慮する。うるう年は次のように判定する。
・4で割り切れかつ100で割り切れない年、及び400で割り切れる年はうるう年である。
(5) 生年月日から今日までの日数を標準出力へ出力する。
1972年1月1日から今日までの日数は
8234日です
|
図2 結果の出力例
プログラム
#include <stdio.h>
#define leap(y) ( a )
typedef struct{
int year;
int month;
int day;
} Tdate;
long calcd(Tdate *);
int check(Tdate *);
int table[24] = {31,28,31,30,31,30,31,31,30,31,30,31,
31,29,31,30,31,30,31,31,30,31,30,31};
main()
{
long total;
Tdate today, birthday;
printf("** 生年月日を入力してください **\n");
scanf("%d %d %d" ,&birthday.year, &birthday.month,
&birthday.day);
printf("** 今日の日付を入力してください **\n");
scanf("%d %d %d", &today.year, &today.month, &today.day);
if ( b )
if ((total = calcd(&today) - calcd(&birthday)) >= 0 )
printf(" %d年%d月%d日から今日までの日数は\n"
" %ld日です\n",
birthday.year, birthday.month, birthday.day,
total);
else
printf("** 生年月日が今日の日付より後になっています **\n");
else
printf ("** 入力した年月日が正しい範囲内にありません **\n");
}
/* 西暦1年1月1日からの日数を計算する */
long calcd(Tdate *dayp)
{
int i;
int offset;
long years = c ;
long days = dayp->day;
days += years * 365;
days += years / 4 - years / 100 + years / 400;
/* 前年までのうるう年の数の合計を加える */
if (leap(dayp->year))
offset = 12;
else
offset = 0;
for (i = 0; d ; i++)
days += e ;
return days;
}
/* 入力データの誤りを検出する */
int check(Tdate *dayp)
{
int offset;
int dlimit;
if (leap(dayp->year))
offset = 12;
else
offset = 0;
dlimit = table[dayp->month + offset - 1];
if (dayp->year < 1800 ||
dayp->month < 1 || dayp->month > 12 ||
dayp->day < 1 || dayp->day > dlimit)
return 1; /* 年月日が正しい範囲内にないとき1を返す */
else
return 0; /* 年月日が正しい範囲内のとき0を返す */
}
設問 プログラムの中の に入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア y % 4 == 0 && y % 100 != 0 || y % 400 == 0
イ y % 4 == 0 && y % 100 != 0 && y % 400 == 0
ウ y % 4 == 0 || y % 100 != 0 || y % 400 == 0
エ y % 4 == 0 || y % 100 != 0 && y % 400 != 0
bに関する解答群
ア check(birthday) == 0 && check(today) == 0
イ check(birthday) != 0 || check(today) != 0
ウ check(&birthday) == 0 && check(&today) == 0
エ check(&birthday) != 0 || check(&oday) == 0
cに関する解答群
ア dayp->year + 1
イ dayp->year
ウ dayp->year - 1
エ dayp->year - 4
dに関する解答群
ア i < dayp->month - 1
イ i < dayp->month
ウ i <= dayp->month
エ i < 12
eに関する解答群
ア table[i]
イ table[i + offset -1]
ウ table[i - 1]
エ table[i + offset]
a-ア b-ウ c-ウ d-ア e-エ
うるう年であるどかの判定には、関数形式マクロを利用しています。
関数checkは、読み込んだ日付が正しい範囲内であるかどうかを判定します。ここでは、誕生日と今日の日付の両方が正しいか、すなわち0が返されるかを判定します。関数checkは、構造体Tdate型へのポインタを受け取るため、呼び出し側は、そのアドレスを渡さなければなりません。したがって、実引数には&演算子が適用されていなければなりません。
さて、関数calcdは、引数daypが指す日付の、西暦1年1月1日からの日数daysを計算します。この手順は、以下のようになっています。以下、()内は、西暦1998年11月18日を例にとった値です。
(1) daysを今日の日とする(18となる)。
(2) (1)で求めたdaysに、日付daypまでの年数に365を乗 じたものを加える(18に1997×365を加えて、729,270となる)。
(3) うるう年の調整を行う(西暦1998年までにうるう年は696回あるため、この値を加えて、 266,183,550となる)。
(4) その年の、前月までの経過日数を加える(西暦1998年は、うるう年でないため、1月から10月までの日数、すなわち31+28+31+30+31+30+31+31+30+31を加えて、 266,183,854となる)。
これは、上記の手順(2)を実現する箇所です。西暦2年であれば1×365を加え、西暦1998年であれば1997×365を加えなければなりません。すなわち、(年 - 1)でなければなりません。
これは、上記の手順(4)を実現するための繰返しの制御式です。1月を0とみなしていることに注意しましょう。dayp->monthが11月であれば、10月までの合計を求めるために、0から9まで繰り返さなければなりません。
これは、上記の手順(4)での加算を実現する箇所です。
- うるう年でない年の各月の日数(31,28,31,…)は、table[0]~table[11]に格納されている。
- うるう年である年の各月の日数(31,29,31,…)は、table[12]~table[23]に格納されている。
戻る