C言語で ミニ日記アプリを作ろう!(2)

スポンサーリンク
C言語

先回は、とりあえず、簡単な「ミニ日記アプリ」を作ってみた。

今回は、下記の機能を追加したVer.2を作っていこう。

目標:曜日を表示(日本語対応)

さらに、細かな修正も行った。

//ミニ日記アプリver.2(曜日付き) 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <time.h>

#define MAX_INPUT 1024

int main(void)
 {
    // ロケールをUTF-8に設定(MSYS2/UCRT64 なら ja_JP.UTF-8 が有効)
    setlocale(LC_ALL, "ja_JP.UTF-8");

    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);

    // 入力受付(入力は1行のみ)
    printf("今日の日記を入力してください(Enterで終了):\n");
    if (fgets(diary, sizeof(diary), stdin) == NULL) {
        fprintf(stderr, "入力に失敗しました。\n");
        return 1;
    }

    // 改行を取り除く
    size_t len = strlen(diary);
    if (len > 0 && diary[len - 1] == '\n') {
        diary[len - 1] = '\0';
    }

    // 空文字列ならスキップ
    if (strlen(diary) == 0) {
        printf("入力が空です。保存しません。\n");
        return 0;
    }

    // UTF-8で追記(BOMなし)
    FILE *fp = fopen("diary.txt", "a");
    if (fp == NULL) {
        perror("ファイルを開けませんでした");
        return 1;
    }

    fprintf(fp, "[%s]\n%s\n\n", timestamp, diary);
    fclose(fp);

    printf("日記を保存しました。\n");
    return 0;
}

実行例

[2025-08-08(金) 10:11:53]
今日はお天気になりました。

このコードの特徴

特徴内容
ロケール“ja_JP.UTF-8” に設定(MSYS2で正しく日本語処理)
曜日表示日本語で (月) のように出力
ファイル保存BOMなし UTF-8、catでもOK
Windows互換 VSCodeターミナルで動作確認済み
依存ライブラリ標準ライブラリ (stdio.h, locale.h, time.h など) のみ

strftime (オリジナル(ver.1))と、 snprintf (Ver.2)の違い

以下に、オリジナル(Ver.1)の strftime を使ったコードと、Ver.2の snprintf を使ったコードの違いと、それぞれの意味を解説しよう。


オリジナル(Ver.1)

strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", t);

解説

  • strftime は、struct tm 型の日時情報 t を指定したフォーマット文字列に従って文字列に変換する関数である。
  • フォーマット文字列 “%Y-%m-%d %H:%M:%S” は以下の意味となる。
    • %Y:西暦(例:2025)
    • %m:月(01〜12)
    • %d:日(01〜31)
    • %H:時(00〜23)
    • %M:分(00〜59)
    • %S:秒(00〜59)

特徴

  • 標準関数で簡潔。
  • 曜日などの追加情報は含まれない。

Ver.2

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);
解説
  • snprintf は、指定したフォーマットに従って文字列を生成する関数である。
  • t->tm_year + 1900:tm_year は1900年からの年数なので、実際の西暦にするには1900を加算。
  • t->tm_mon + 1:tm_mon は0〜11なので、1を加えて1〜12の月に変換。
  • weekdays_jp[t->tm_wday]:曜日を日本語で表示するための配列(例:{“日”, “月”, “火”, “水”, “木”, “金”, “土”})から取得。
  • tm_hour, tm_min, tm_sec:時・分・秒。
特徴
  • 曜日(日本語)を含めた表示が可能。
  • フォーマットを自由にカスタマイズできる。
  • 日本語表記や装飾(例:括弧)を含められる。

比較まとめ

項目strftimesnprintf
曜日表示❌ 不可(別途処理必要)✅ 日本語で可能
カスタマイズ性🔽 制限あり🔼 自由度高い
標準関数
実装の手軽さ🔽 やや複雑

補足

weekdays_jp の定義例:

const char *weekdays_jp[] = {“日”, “月”, “火”, “水”, “木”, “金”, “土”};


char timestamp[100]; (オリジナル(Ver.1))とchar timestamp[128];(Ver.2 )の違い

オリジナル(Ver.1) char timestamp[100]; とVer.2 char timestamp[128];の違いを解説しよう。

オリジナル(Ver.1):char timestamp[100];

これは、timestamp という文字列バッファを 100バイトの固定サイズ で定義している。

特徴
  • 100バイトまでの文字列を格納可能。
  • 通常の日時フォーマット(例:2025-08-06 13:45:30)には十分なサイズ。
  • ただし、曜日や日本語などを追加すると足りなくなる可能性がある。

Ver.2:char timestamp[128];

こちらは、バッファサイズを 128バイトに拡張したものである。

特徴
  • より長い文字列(例:2025-08-06(水) 13:45:30 のような日本語や装飾付き)にも対応可能。
  • バッファオーバーフローのリスクを減らす目的。
  • 可読性や安全性の向上。

コメント

タイトルとURLをコピーしました