問題① 標準入力から受け取った西暦年から、現在までの年数を求めるプログラムを作ってください。
たとえば、次のようになります。
#include <stdio.h>
#include <time.h>
int main(void)
{
("西暦年を入力してください。");
putschar buf[40];
int input_year;
(buf, sizeof(buf), stdin);
fgets(buf, "%d", &input_year);
sscanf
// tm構造体の tm_yearメンバは 1900年からの経過年なので、それに合わせる
int year = input_year - 1900;
// 現在の時刻を取得
time_t now_time;
(&now_time);
timeconst struct tm* now_tm = localtime(&now_time);
if (now_tm->tm_year <= year) {
("%d年まであと%d年\n", input_year, year - now_tm->tm_year);
printf}
else {
("%d年は%d年前\n", input_year, now_tm->tm_year - year);
printf}
}
実行結果:
西暦年を入力してください。
2030
2030年まであと12年
現在の時刻を取得するには、結局のところ、まずは time関数を使うしかありません。その後、localtime関数を使って、ローカル時間に変換します。
localtime関数が返した tm構造体のポインタから、tm_yearメンバを参照すれば、そこに 1900年からの経過年があります。
問題② プログラムの処理の進行を、5秒間停止させる方法を考えて、試してみてください。
time関数を使って、実現できます。
#include <stdio.h>
#include <time.h>
static const int STOP_SEC = 5; // 停止させる秒数
int main(void)
{
("%d秒間停止します。\n", STOP_SEC);
printf
time_t begin;
(&begin);
time
for (;;) {
time_t now;
(&now);
time
if (difftime(now, begin) >= STOP_SEC) {
break;
}
}
("終了します。");
puts}
実行結果:
5秒間停止します。
終了します。
停止させる直前で、time関数を呼び出して、その時点のカレンダー時間を取得しておきます。これがあれば、定期的に現在のカレンダー時間を取得して、difftime関数に渡せば、経過秒数を割り出せます。
clock関数を使っても、うまく動くかもしれませんが、clock関数の場合は、他のプログラムが同時に動いていると、正しく計測できない可能性があります。
問題③ 標準入力から受け取った西暦年・月・日から、その日の曜日を求めて表示するプログラムを作ってください。
曜日を直接求める手段はないので、いくつかの標準ライブラリ関数を組み合わせて実現します。
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
static const wchar_t* const WEEK_DAY[] = {
L"日曜日",
L"月曜日",
L"火曜日",
L"水曜日",
L"木曜日",
L"金曜日",
L"土曜日",
};
int main(void)
{
// LC_CTYPE をネイティブロケールに変更
if (setlocale(LC_CTYPE, "") == NULL) {
("ロケールの設定に失敗しました。\n", stderr);
fputsreturn EXIT_FAILURE;
}
// 年・月・日 以外は関係しないので、まとめて 0 を入れておく
struct tm tm_in;
(&tm_in, 0, sizeof(tm_in));
memset
// 年・月・日 を取得
("西暦年・月・日を、半角スペース区切りで入力してください。");
putschar buf[80];
(buf, sizeof(buf), stdin);
fgets(buf, "%d %d %d", &tm_in.tm_year, &tm_in.tm_mon, &tm_in.tm_mday);
sscanf
// 年は 1900年からの経過年にしておく
.tm_year -= 1900;
tm_in
// 月は 0 が起点なので -1
.tm_mon -= 1;
tm_in
// カレンダー時間を取得
time_t t = mktime(&tm_in);
if (t == (time_t)-1) {
("日時の変換に失敗しました。\n", stderr);
fputsreturn EXIT_FAILURE;
}
// 曜日を出力
(L"%ls\n", WEEK_DAY[tm_in.tm_wday]);
wprintf}
実行結果:
西暦年・月・日を、半角スペース区切りで入力してください。
2011 1 1
土曜日
曜日は、tm構造体に、メンバtm_wday として含まれています。本編で触れているように、mktime関数を使えば、tm_wday(とtm_yday)に情報を入れて貰えるので、これを使うのが簡単です。
まず、tm構造体の変数を用意して、西暦年、月、日を表すメンバに情報をセットします。西暦年が 1900年からの経過年、月が 0起点であることに注意してください。その他のメンバには興味がないので、事前にすべて 0 をセットしておきます。
こうして作成した tm構造体の変数を mktime関数に渡せば、その日時を表す time_t型の値が返され、tm構造体の tm_wday、tm_yday が書き換えられます。今回は、戻り値で得られる情報 (time_t型の値) は必要ありませんが、mktime関数は渡す情報の不備によって失敗しやすい関数なので、必ず、戻り値を調べて、エラーチェックを行うようにするべきです。
あとは、曜日の名前を適当に作って出力します。この辺りは、都合の良い標準ライブラリ関数がないので、自分で配列を作って対応しています。
()
の前後の空白の空け方)(
の直後、)
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一)章のタイトルを変更(日付と時間、乱数 -> 日付と時間) 乱数に関する話題を、第54章へ移動。
全面的に文章を見直し、修正を行った。
問題④の解答例に無駄が多かったので修正し、これに合わせて解説も修正。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |