#include <stdio.h>    // 標準入出力関数（printf, scanf, gets, fopen, fclose, fprintfなど）を使うため
#include <stdlib.h>   // 一般ユーティリティ関数（malloc, free, exitなど）を使うため
#include <string.h>   // 文字列操作関数（strlen, strcpyなど）を使うため
#include <ctype.h>    // 文字種判別・変換関数（toupperなど）を使うため

// グローバル変数：プログラム全体からアクセスできる変数
// しかし、安易な使用はプログラムを複雑にしがちです。
int global_counter = 0;

// マジックナンバーの定義
// 今回は後述のgets()でバッファオーバーフローを引き起こすために利用しています。
#define MAX_NAME_LEN 20

// ユーザーの名前を大文字に変換する関数
// 【問題点：メモリリーク】
// この関数内で動的に確保したメモリを呼び出し元で解放することを忘れてしまいがちです。
char* toUpperCase(char* str) {
    if (str == NULL) {
        return NULL; // NULLポインタが渡された場合はNULLを返す
    }

    // 引数で渡された文字列と同じ長さのメモリを動的に確保
    char* upper_str = (char*)malloc(strlen(str) + 1); // +1はヌル終端文字のため

    if (upper_str == NULL) {
        // メモリ割り当てが失敗した場合のエラー処理
        perror("toUpperCase: メモリ確保に失敗しました");
        // exit()を呼ぶと、それまでに確保したリソースが解放されずにプログラムが終了する可能性があります。
        exit(EXIT_FAILURE);
    }

    // 各文字を大文字に変換
    for (int i = 0; str[i] != '\0'; i++) {
        upper_str[i] = toupper((unsigned char)str[i]);
    }
    upper_str[strlen(str)] = '\0'; // ヌル終端

    // ここで確保したupper_strは、呼び出し元でfree()される必要がありますが、その記述がありません。
    return upper_str; // 新しく確保したメモリへのポインタを返す
}

// 危険な計算を実行する関数
// 【問題点：ゼロ除算の可能性、整数オーバーフローの可能性、無駄なループ】
int performDangerousCalculation(int a, int b) {
    global_counter++; // グローバル変数を更新

    int result = 0; // 結果を初期化

    // ゼロ除算を回避しようとはしているが...
    if (b != 0) {
        // (a / b) + (a * b) * 1000000;
        // 「a * b * 1000000」の部分で、int型の最大値を超えてしまう（整数オーバーフロー）可能性があります。
        result = (a / b) + (a * b) * 1000000;
    } else {
        printf("警告: ゼロ除算を回避しました。\n");
        // この場合、resultは初期値の0のまま返されます。
        // 呼び出し元で、このゼロ除算回避時の結果が意図したものであるか確認が必要です。
    }

    // 何の意味もない、無駄なループ
    // CPUサイクルを無駄に消費するだけです。
    for (int i = 0; i < 10000; i++) {
        // 何もしない
    }

    return result;
}

// ファイルにデータを書き込む関数
// 【問題点：ファイルハンドルの閉じ忘れ、エラーハンドリングの不足、上書きモード】
void writeDataToFile(const char* filename, const char* name, int value) {
    // "w"モードは、ファイルが存在すれば内容をすべて消去し、新しく書き込みます。
    // 既存のデータを意図せず上書きしてしまう可能性があります。
    FILE* fp = fopen(filename, "w");

    if (fp == NULL) {
        // ファイルオープン失敗時のエラー処理。
        // エラーメッセージは出すが、呼び出し元にエラーを伝える手段がありません。
        printf("エラー: ファイル '%s' を書き込み用に開けませんでした。\n", filename);
        return; // エラーなので処理を中断
    }

    fprintf(fp, "名前: %s\n", name);
    fprintf(fp, "値: %d\n", value);

    // 【問題点】
    // ここで fclose(fp); を呼び出してファイルハンドルを閉じる必要がありますが、呼び出していません。
    // プログラムが終了するまでファイルハンドルが閉じられず、リソースリークにつながります。
}

// ログファイルにメッセージを追記する関数
// 【問題点：ファイルハンドルの閉じ忘れ】
void logMessage(const char* message) {
    // "a"モードは、ファイルが存在すれば末尾に追記し、存在しなければ新しく作成します。
    FILE* log_fp = fopen("app.log", "a");

    if (log_fp == NULL) {
        printf("エラー: ログファイルを開けませんでした。\n");
        return;
    }
    fprintf(log_fp, "[LOG] %s\n", message);

    // 【問題点】
    // ここでも fclose(log_fp); を呼び出してファイルハンドルを閉じる必要がありますが、呼び出していません。
}

int main() {
    char name_buffer[MAX_NAME_LEN]; // ユーザーの名前を格納するバッファ（MAX_NAME_LEN = 20文字）
    int number_input;
    // char temp_input[256]; // gets()のためのコメントアウトされた一時バッファ

    printf("あなたの名前を入力してください: ");
    // 【重大な問題点：gets() の使用】
    // gets() は、入力された文字列の長さをチェックせず、バッファのサイズを超えて書き込む可能性があります。
    // 例えば、20文字以上の名前を入力すると、name_buffer の外にデータが書き込まれ、
    // プログラムがクラッシュしたり、悪意のあるコードが実行されたりする「バッファオーバーフロー」を誘発します。
    // この関数は非常に危険なので、絶対に使用してはいけません。
    gets(name_buffer);

    printf("数値を入力してください: ");
    // 【問題点：scanf() の戻り値チェック不足】
    // scanf() は、正しく読み込めた項目数を返します。
    // ユーザーが数値を入力せず、例えば文字列を入力した場合、scanfは失敗し number_input の値が未定義になる可能性があります。
    // 本来は if (scanf("%d", &number_input) != 1) のようにチェックすべきです。
    scanf("%d", &number_input);

    logMessage("ユーザー入力が受け付けられました。");

    // toUpperCase関数を呼び出し、大文字に変換された名前を取得
    char* upper_name = toUpperCase(name_buffer);
    if (upper_name == NULL) {
        printf("名前の処理に失敗しました。\n");
        return 1; // エラー終了
    }
    printf("大文字の名前: %s\n", upper_name);

    // 危険な計算を実行
    // global_counter は main 関数開始時は0、logMessageで1になり、この時点で1になる
    int calculation_result = performDangerousCalculation(number_input, global_counter);
    printf("計算結果: %d\n", calculation_result);

    // ファイルに書き込み（ここでもファイルハンドルが閉じられません）
    writeDataToFile("output.txt", upper_name, calculation_result);

    logMessage("データがファイルに書き込まれました。");

    // 【問題点：メモリリーク】
    // toUpperCase() で動的に確保したメモリ (upper_name) をここで free() する必要がありますが、されていません。
    // free(upper_name); // これがないとメモリリークが発生します。

    // 【問題点：別のメモリリーク】
    // ここでも動的にメモリを確保していますが、解放されていません。
    char* another_buffer = (char*)malloc(100);
    if (another_buffer == NULL) {
        printf("別のバッファの割り当てに失敗しました。\n");
        return 1;
    }
    strcpy(another_buffer, "これは別の動的に割り当てられたバッファです。");
    // free(another_buffer); // これも解放されないとメモリリークが発生します。

    printf("プログラムが終了しました。グローバルカウンター: %d\n", global_counter);

    return 0; // プログラムの正常終了
}