前回は、メニュー方式で「過去2件表示」「新規日記入力」「終了」の3機能を選べる Ver.4を作成した。
今回は、このVer.4 をベースにして、「月ごとの一覧表示」ができるようにしたVer.5を作成していこう。
具体的には、diary.txt から読み取ったすべての記録を、タイムスタンプの年月(例:2025-08)ごとに分類して、一覧表示する。(表示は古い順)
// ミニ日記アプリ ver.5(メニュー+月ごとの一覧付き)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <time.h>
#define MAX_INPUT 1024
#define MAX_ENTRIES 1000
typedef struct {
char timestamp[128];
char content[MAX_INPUT];
} DiaryEntry;
// --- メニュー表示 ---
void show_menu(void) {
printf("\n********** MENU **********\n");
printf("1. 過去2件の日記を表示する\n");
printf("2. 新しい日記を書く\n");
printf("3. 月ごとの一覧を表示する\n");
printf("9. 終了する\n");
printf("***************************\n");
printf("選択した番号を入力してください:");
}
// --- ファイル読み込み ---
int load_entries(const char *filename, DiaryEntry entries[], int max_entries) {
FILE *fp = fopen(filename, "r");
if (!fp) {
return 0;
}
char line[MAX_INPUT];
int count = 0;
DiaryEntry temp = {"", ""};
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '[') {
if (strlen(temp.timestamp) > 0) {
if (count < max_entries) {
entries[count++] = temp;
}
temp.timestamp[0] = '\0';
temp.content[0] = '\0';
}
line[strcspn(line, "\n")] = '\0';
strncpy(temp.timestamp, line + 1, sizeof(temp.timestamp) - 1);
} else if (strlen(temp.timestamp) > 0 && line[0] != '\n') {
line[strcspn(line, "\n")] = '\0';
strncpy(temp.content, line, sizeof(temp.content) - 1);
}
}
if (strlen(temp.timestamp) > 0) {
if (count < max_entries) {
entries[count++] = temp;
}
}
fclose(fp);
return count;
}
// --- 過去2件表示 ---
void show_last_two_entries(void) {
DiaryEntry entries[MAX_ENTRIES];
int entry_count = load_entries("diary.txt", entries, MAX_ENTRIES);
printf("\n【過去2件の記録】\n");
if (entry_count == 0) {
printf("なし\n");
return;
}
int start = (entry_count >= 2) ? entry_count - 2 : 0;
for (int i = start; i < entry_count; i++) {
printf("[%s]\n%s\n\n", entries[i].timestamp, entries[i].content);
}
}
// --- 新規日記作成 ---
void write_new_entry(void) {
char diary[MAX_INPUT];
time_t now = time(NULL);
struct tm *t = localtime(&now);
const char *weekdays_jp[] = {"日", "月", "火", "水", "木", "金", "土"};
char timestamp[128];
snprintf(timestamp, sizeof(timestamp),
"%04d-%02d-%02d(%s) %02d:%02d:%02d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
weekdays_jp[t->tm_wday],
t->tm_hour, t->tm_min, t->tm_sec);
printf("今日の日記を入力してください(Enterで終了):\n");
if (!fgets(diary, sizeof(diary), stdin)) {
fprintf(stderr, "入力に失敗しました。\n");
return;
}
size_t len = strlen(diary);
if (len > 0 && diary[len - 1] == '\n') {
diary[len - 1] = '\0';
}
if (strlen(diary) == 0) {
printf("入力が空です。保存しません。\n");
return;
}
FILE *fp = fopen("diary.txt", "a");
if (!fp) {
perror("ファイルを開けませんでした");
return;
}
fprintf(fp, "[%s]\n%s\n\n", timestamp, diary);
fclose(fp);
printf("日記を保存しました。\n");
}
// --- 月ごとの一覧表示 ---
void show_monthly_list(void) {
DiaryEntry entries[MAX_ENTRIES];
int entry_count = load_entries("diary.txt", entries, MAX_ENTRIES);
if (entry_count == 0) {
printf("\n記録はありません。\n");
return;
}
printf("\n【月ごとの一覧】\n");
char current_month[8] = "";
for (int i = 0; i < entry_count; i++) {
char month[8];
strncpy(month, entries[i].timestamp, 7); // "YYYY-MM"
month[7] = '\0';
if (strcmp(current_month, month) != 0) {
strcpy(current_month, month);
printf("\n=== %s ===\n", current_month);
}
printf("[%s] %s\n", entries[i].timestamp, entries[i].content);
}
}
// --- メイン ---
int main(void) {
setlocale(LC_ALL, "ja_JP.UTF-8");
while (1) {
show_menu();
char choice[10];
if (!fgets(choice, sizeof(choice), stdin)) {
printf("入力エラーです。\n");
continue;
}
int opt = atoi(choice);
switch (opt) {
case 1:
show_last_two_entries();
break;
case 2:
write_new_entry();
break;
case 3:
show_monthly_list();
break;
case 9:
printf("終了します。\n");
return 0;
default:
printf("無効な選択肢です。\n");
}
}
}
Ver.4 から Ver.5 への追加・変更点
項目 | Ver.4 | Ver.5 |
---|---|---|
新機能 | – | 月ごとの一覧表示機能追加 |
メニュー項目 | 1, 2, 9 | 1, 2, 3, 9(3が新機能) |
表示内容 | 過去2件、新規入力のみ | 月ごとに全件を分類して表示(古い順) |
コード構成 | 関数:show_last _two _entries , write _new _entry | 関数追加:show _monthly _list |
ファイル処理 | 共通の load_entries を利用 | 同じく利用して分類処理を追加 |
実行例(月ごとの一覧を表示する)
【月ごとの一覧】
=== 2025-08 ===
[2025-08-05(火) 10:00:00] 夏休みの自由研究をした。
[2025-08-10(日) 15:30:00] プールへ行った。
=== 2025-09 ===
[2025-09-01(月) 09:00:00] 新学期が始まった
コメント