【getage.cのソースコード】
/*
* 生年月日から年齢を求めるプログラム getage.c
*
* 日本の民法および年齢計算に関する法律の規定に従い、
* 誕生日の前日で加齢する。
* 1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作する。
* (うるう日対応)
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h> /* strlen(), strcmp(), strcpy(), strcat() */
#include <ctype.h> /* isdigit() */
#define BUF_SIZE 256
/*
* 自作のbool型の定義
*/
typedef enum {
false, /* 0 */
true /* 1 */
} bool;
/*
* 構造体dateの定義
*/
struct date {
int year;
int month;
int day;
};
/*
* ユーザー定義関数の関数原型宣言
*/
void print_title(void);
void input(void);
void input_date(struct date *some_date);
bool is_valid_number(char buf[]);
int get_days_of_the_month(int year,int month);
bool is_leap_year(int year);
void sel_outputto(void);
void calc(void);
void output(void);
void output_result(void);
void foutput_result(char filename[], char oldfilename[]);
void gen_filename(char filename[]);
bool retry(void);
/*
* グローバル変数
*/
char outputto,
filename[BUF_SIZE] = {1}, /* filenameとoldfilenameの初期値を */
oldfilename[BUF_SIZE] = {0}; /* 異なる物に設定する。 */
/* (ファイルへの追記の判断に使用する。) */
struct date refdate, birthdate;
int refmonthday, birthmonthday, pre_birthmonthday, age;
/*
* メイン関数
*/
int main(void)
{
/* 乱数系列の設定 */
srand((unsigned int)time(NULL));
while (1) {
/* 表題・説明の表示 */
print_title();
/* 年齢計算日および生年月日の入力 */
input();
/* 出力先の選択 */
sel_outputto();
/* 計算 */
calc();
/* 出力 */
output();
/* 操作を続けるかどうかの選択 */
if (!retry())
break;
}
return EXIT_SUCCESS;
}
/*
* 表題(プログラムの説明)を表示する関数
*/
void print_title(void)
{
printf("【年齢の計算】\n");
printf("任意の年齢計算日における満年齢を計算します。\n");
printf("(*1)日本では、民法および年齢計算に関する法律の規定により、\n");
printf(" 誕生日の前日に加齢されます。\n");
printf("(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。\n\n");
}
/*
* 年齢計算日および生年月日を入力する関数
* input_date()関数を使用する
*/
void input(void)
{
while (1) {
/* 基準日の入力 */
printf("年齢計算日の日付を入力してください。\n");
input_date(&refdate);
refmonthday = 100*refdate.month + refdate.day;
/* 生年月日の入力 */
printf("生年月日を入力してください。\n");
input_date(&birthdate);
birthmonthday = 100*birthdate.month + birthdate.day;
if (10000*refdate.year+refmonthday < 10000*birthdate.year+birthmonthday) {
printf("日付の指定が無効です。\n");
printf("年齢計算日は、生年月日以降の日付としてください。\n\n");
continue;
} else
break;
}
}
/*
* 日付を入力する関数
* is_valid_number()関数とget_days_of_the_month()関数を使用する
*/
void input_date(struct date *some_date)
{
char buf[BUF_SIZE], zz;
while (1) {
while (1) {
printf("年 = ?(西暦で) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &some_date->year, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("無効な入力です。\n");
printf("半角整数値を入力してください。\n\n");
continue;
} else if (some_date->year < 1582) {
printf("%d年はグレゴリオ暦の範囲外です。\n", some_date->year);
printf("1582年以降の年を入力してください。\n\n");
continue;
} else if (some_date->year > 9999) {
printf("無効な入力です。\n");
printf("9999年以前の年を入力してください。\n\n");
continue;
} else
break;
}
while (1) {
printf("月 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &some_date->month, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("無効な入力です。\n");
printf("半角整数値を入力してください。\n\n");
continue;
} else if ((some_date->month < 1) || (12 < some_date->month)) {
printf("無効な入力です。\n");
printf("1から12の値を入力してください。\n\n");
continue;
} else
break;
}
while (1) {
printf("日 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &some_date->day, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("無効な入力です。\n");
printf("半角整数値を入力してください。\n\n");
continue;
}
if ((some_date->day < 1) ||
(get_days_of_the_month(some_date->year, some_date->month)
< some_date->day)) {
printf("無効な入力です。\n");
printf("%d年%d月は、1日から%d日までです。\n",
some_date->year, some_date->month,
get_days_of_the_month(some_date->year, some_date->month));
printf("1から%dまでの値を入力してください。\n\n",
get_days_of_the_month(some_date->year, some_date->month));
continue;
} else
break;
}
if (10000*some_date->year + 100*some_date->month + some_date->day
< 15821015) {
printf("%d年%d月%d日はグレゴリオ暦の範囲外です。\n",
some_date->year, some_date->month, some_date->day);
printf("1582年10月15日以降の日付を入力してください。\n\n");
continue;
} else
break;
}
}
/*
* 文字列が正しい形式の数値かどうかを判定する関数
* true: 正しい形式である、false: 無効な形式である
*/
bool is_valid_number(char buf[])
{
int i = 0;
/* 最初は符号(省略可) */
if (buf[i] == '+' || buf[i] == '-')
i++;
/* 次に数字(省略不可) */
if (!isdigit(buf[i]))
return 0;
i++;
/* 次に数字列(省略可) */
while (isdigit(buf[i]))
i++;
return buf[i] == '\0';
}
/*
* year年month月に含まれる日数を返す関数
* is_leap_year()関数を使用する
*/
int get_days_of_the_month(int year,int month)
{
int days;
if (is_leap_year(year) && (month == 2)) /* うるう年の2月 */
days = 29;
else if ((!is_leap_year(year)) && (month == 2)) /* うるう年ではない年の2月 */
days = 28;
else if ((month == 4) || (month == 6) || /* 4、6、9、11月 */
(month == 9) || (month == 11))
days = 30;
else if ((month == 1) || (month == 3) || /* 1、3、5、7、8、10、12月 */
(month == 5) || (month == 7) ||
(month == 8) || (month == 10) ||
(month == 12))
days = 31;
else { /* 上記以外 */
printf("月の日数の計算ができません。処理を終了します。\n");
exit(EXIT_FAILURE);
}
return days;
}
/*
* うるう年の判定をする関数
* true: うるう年である、false: うるう年でない
*/
bool is_leap_year(int year)
{
/* 400で割り切れればうるう年 */
/* 400で割り切れず、100で割り切れればうるう年でない */
/* 100で割り切れず、4で割り切れればうるう年 */
/* 4で割り切れなければうるう年でない */
return ((year % 400 == 0) || ((year % 100) && (year % 4 == 0)));
}
/*
* 出力先(outputto)を選択する関数
*/
void sel_outputto(void)
{
char buf[BUF_SIZE], zz;
while (1) {
printf("結果の出力先を1、2、3から選んでください。\n");
printf("1. 画面だけに出力する。\n");
printf("2. ファイルだけに出力する。\n");
printf("3. 画面とファイルの両方に出力する。\n");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &outputto, &zz);
if (((outputto != '1') && (outputto != '2') && (outputto != '3'))
|| (zz != '\n')) {
printf("無効な入力です。\n");
printf("1、2、3のいずれかを入力してください。\n\n");
continue;
} else
break;
}
}
/*
* 年齢の計算をする関数
*/
void calc(void)
{
/* ↓「誕生日の月日の前日」(pre_birthmonthday)の設定、ここから↓ */
/* 誕生日の月日が月初の場合 */
if (birthmonthday % 100 == 1) {
/* 誕生日の月日が1月1日の場合 */
if (birthmonthday / 100 == 1)
/* 年齢計算日の月日を12月31日に設定 */
pre_birthmonthday = 1231;
/* 誕生日の月日が3月1日の場合 */
else if (birthmonthday / 100 == 3) {
/* 年齢計算日が平年の場合 */
if (!is_leap_year(refdate.year))
pre_birthmonthday = 228;
/* 年齢計算日がうるう年の場合 */
else
pre_birthmonthday = 229;
/* 誕生日の月日が1月1日でも3月1日でもない月初の日の場合 */
/* (2月1日、4月1日、5月1日、…、12月1日の場合) */
} else
pre_birthmonthday
= 100*(birthdate.month-1)
+ get_days_of_the_month(birthdate.year, birthdate.month-1);
/* 誕生日の月日が月初以外の日の場合 */
} else
pre_birthmonthday = birthmonthday - 1;
/* ↑「誕生日の月日の前日」(pre_birthmonthday)の設定、ここまで↑ */
/* +++++ */
/* ↓年齢の計算、ここから↓ */
/* 誕生日の月日が1月1日の場合 */
/* (12月31日に加齢される) */
if (birthmonthday == 101)
/* 年齢計算日の月日が12月31日(誕生日の前日)に達している場合 */
/* (すなわち、年齢計算日の月日が12月31日の場合のみ) */
if (refmonthday >= pre_birthmonthday)
age = refdate.year - birthdate.year + 1;
/* 年齢計算日の月日が12月31日(誕生日の前日)に達していない場合 */
/* (すなわち、年齢計算日の月日が1月1日~12月30日の場合) */
else
age = refdate.year - birthdate.year;
/* 誕生日の月日が1月2日の場合 */
/* (1月1日に加齢される) */
else if (birthmonthday == 102)
age = refdate.year - birthdate.year;
/* 誕生日の月日が1月1日でも1月2日でもない場合 */
else
/* 年齢計算日の月日が誕生日の月日の前日に達していない場合 */
if (refmonthday < pre_birthmonthday)
age = refdate.year - birthdate.year - 1;
/* 年齢計算日の月日が誕生日の月日の前日に達している場合 */
else
age = refdate.year - birthdate.year;
/* ↑年齢の計算、ここまで↑ */
}
/*
* 出力をする関数
* output_result()関数とfoutput_result()関数を使用する。
*/
void output(void)
{
switch (outputto) {
case '1':
output_result();
break;
case '2':
foutput_result(filename, oldfilename);
break;
case '3':
output_result();
foutput_result(filename, oldfilename);
break;
default:
break;
}
}
/*
* 結果を画面に出力する関数
*/
void output_result(void)
{
printf("生年月日が%d年%d月%d日の人の",
birthdate.year, birthdate.month, birthdate.day);
printf("%d年%d月%d日現在での", refdate.year, refdate.month, refdate.day);
printf("満年齢は、%d歳です。\n", age);
}
/*
* 結果をファイルに出力する関数
* gen_filename()関数を使用する。
*/
void foutput_result(char filename[], char oldfilename[])
{
FILE *fp;
/* ifによる分岐は、2行目以降を同一ファイルに追記出力させるため */
if (strcmp(filename, oldfilename) == 0) { /* ファイル名が同じなら(2行目以降なら) */
fp = fopen(oldfilename, "a"); /* oldfilenameを開く。 */
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
} else { /* ファイル名が違うなら(初めての出力なら) */
gen_filename(filename); /* 新規にファイル名を生成して */
fp = fopen(filename, "a"); /* そのファイル(filename)を開いて */
strcpy(oldfilename, filename); /* oldfilenameを更新する。 */
if (fp == NULL) {
printf("ファイルを開けません。ファイル出力を中断します。\n");
return;
}
}
fprintf(fp, "生年月日が%d年%d月%d日の人の",
birthdate.year, birthdate.month, birthdate.day);
fprintf(fp, "%d年%d月%d日現在での", refdate.year, refdate.month, refdate.day);
fprintf(fp, "満年齢は、%d歳です。\n", age);
fclose(fp);
}
/*
* 現在日付時刻からファイル名を生成する関数
*/
void gen_filename(char filename[])
{
struct tm *t;
time_t tt;
char snumrand[5];
time(&tt);
t = localtime(&tt);
sprintf(filename, "getage%04d%02d%02d_%02d%02d%02d_",
1900+(t->tm_year), 1+(t->tm_mon), t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
sprintf(snumrand, "%04d", rand() % 10000);
filename = strcat(filename, snumrand);
filename = strcat(filename, ".txt");
}
/*
* 操作を続けるかどうかを選択する関数
* true: 繰り返す、false: 終了する
*/
bool retry(void)
{
bool ret;
char buf[BUF_SIZE], ch, zz;
while (1) {
printf("続けますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if ((ch == 'y' || ch == 'Y') && zz == '\n') {
printf("\n+++++\n\n");
ret = true;
break;
} else if ((ch == 'n' || ch == 'N') && zz == '\n') {
ret = false;
break;
}
printf("無効な入力です。\n");
printf("yまたはnを入力してください。\n\n");
}
return ret;
}
C:\Users\skonishi\Documents>getage
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2023
月 = ? 2
日 = ? 27
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2023
月 = ? 2
日 = ? 28
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2023
月 = ? 3
日 = ? 1
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 2
日 = ? 27
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 2
日 = ? 28
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 2
日 = ? 29
生年月日を入力してください。
年 = ?(西暦で) 2020
月 = ? 2
日 = ? 29
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 12
日 = ? 30
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 1
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 12
日 = ? 31
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 1
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2025
月 = ? 1
日 = ? 1
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 1
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2024
月 = ? 12
日 = ? 31
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 2
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2025
月 = ? 1
日 = ? 1
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 2
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) y
+++++
【年齢の計算】
任意の年齢計算日における満年齢を計算します。
(*1)日本では、民法および年齢計算に関する法律の規定により、
誕生日の前日に加齢されます。
(*2)1582年10月15日以降(グレゴリオ暦の範囲内)、9999年12月31日以前で動作します。
年齢計算日の日付を入力してください。
年 = ?(西暦で) 2025
月 = ? 1
日 = ? 2
生年月日を入力してください。
年 = ?(西暦で) 2024
月 = ? 1
日 = ? 2
結果の出力先を1、2、3から選んでください。
1. 画面だけに出力する。
2. ファイルだけに出力する。
3. 画面とファイルの両方に出力する。
2
続けますか?(y/n) n
生年月日が2020年2月29日の人の2023年2月27日現在での満年齢は、2歳です。
生年月日が2020年2月29日の人の2023年2月28日現在での満年齢は、3歳です。 ←2月29日生まれの人は、2月28日に加齢される。
生年月日が2020年2月29日の人の2023年3月1日現在での満年齢は、3歳です。
生年月日が2020年2月29日の人の2024年2月27日現在での満年齢は、3歳です。
生年月日が2020年2月29日の人の2024年2月28日現在での満年齢は、4歳です。 ←2月29日生まれの人は、2月28日に加齢される。
生年月日が2020年2月29日の人の2024年2月29日現在での満年齢は、4歳です。
生年月日が2024年1月1日の人の2024年12月30日現在での満年齢は、0歳です。
生年月日が2024年1月1日の人の2024年12月31日現在での満年齢は、1歳です。
生年月日が2024年1月1日の人の2025年1月1日現在での満年齢は、1歳です。
生年月日が2024年1月2日の人の2024年12月31日現在での満年齢は、0歳です。
生年月日が2024年1月2日の人の2025年1月1日現在での満年齢は、1歳です。
生年月日が2024年1月2日の人の2025年1月2日現在での満年齢は、1歳です。