C言語による制御構造の基礎演習:分岐・反復処理の実装例

1. 単一値の階乗計算

nの階乗(n!)を算出する処理では、累積変数に対して反復処理を用いて乗算を適用します。

#include <stdio.h>

int main(void) {
    int target_num = 0;
    int factorial_val = 1;

    printf("計算対象の整数を入力: ");
    scanf("%d", &target_num);

    for (int counter = 1; counter <= target_num; ++counter) {
        factorial_val *= counter;
    }
    printf("計算結果: %d\n", factorial_val);
    return 0;
}

2. 階乗の累積和(1! 〜 10!)

各数値の階乗を独立して計算すると無駄な演算が発生します。直前の階乗結果を変数に保持し、それを次のループで活用することで時間計算量を削減します。

#include <stdio.h>

int main(void) {
    const int limit = 10;
    int current_factorial = 1;
    int total_sum = 0;

    for (int num = 1; num <= limit; ++num) {
        current_factorial *= num;
        total_sum += current_factorial;
    }
    printf("1!から%d!までの総和: %d\n", limit, total_sum);
    return 0;
}

3. 整列済み配列からの値探索(二分探索法)

配列の要素が昇順または降順でソートされている場合、中央値を基準に探索範囲を半減させることで O(log n) の効率性を実現します。

#include <stdio.h>

int main(void) {
    const int data_set[] = {12, 25, 33, 48, 56, 69, 77, 88, 94, 105};
    const int length = sizeof(data_set) / sizeof(data_set[0]);
    int search_val;
    int found_idx = -1;

    printf("検索する数値を入力: ");
    scanf("%d", &search_val);

    int low_idx = 0;
    int high_idx = length - 1;

    while (low_idx <= high_idx) {
        int mid_idx = low_idx + (high_idx - low_idx) / 2;

        if (data_set[mid_idx] == search_val) {
            found_idx = mid_idx;
            break;
        } else if (data_set[mid_idx] < search_val) {
            low_idx = mid_idx + 1;
        } else {
            high_idx = mid_idx - 1;
        }
    }

    if (found_idx != -1) {
        printf("発見: インデックス %d\n", found_idx);
    } else {
        printf("指定された値は存在しません。\n");
    }
    return 0;
}

4. 文字列の両端収束表示処理

コンソール上の文字列を両端から中央へ書き換えるビジュアル効果を実装します。画面のリフレッシュと処理の遅延を組み合わせて動作させます。

#include <stdio.h>
#include <windows.h>
#include <string.h>

int main(void) {
    const char source_text[] = "Convergence Demo";
    char render_buffer[sizeof(source_text)];
    int str_len = strlen(source_text);

    // マスク初期化
    memset(render_buffer, '#', str_len);
    render_buffer[str_len] = '\0';

    int left_ptr = 0;
    int right_ptr = str_len - 1;

    while (left_ptr <= right_ptr) {
        render_buffer[left_ptr] = source_text[left_ptr];
        render_buffer[right_ptr] = source_text[right_ptr];

        printf("%s\n", render_buffer);
        Sleep(400);       // 400ms待機
        system("cls");    // 画面クリア

        ++left_ptr;
        --right_ptr;
    }
    printf("%s\n", render_buffer);
    return 0;
}

補足:Sleep()関数はスレッドを指定ミリ秒間休止させます。system("cls")はWindowsコンソールの表示内容を消去するために使用されます。

5. 試行回数制限付き認証処理

パスワード照合処理を3回に制限し、不一致が続いた場合は強制終了するフローです。C言語では文字列比較に等値演算子(==)が使えないため、標準ライブラリ関数を利用します。

#include <stdio.h>
#include <string.h>

#define ATTEMPT_LIMIT 3
#define VALID_CREDENTIAL "admin_key"

int main(void) {
    char input_buffer[64];
    int auth_passed = 0;

    for (int trial = 1; trial <= ATTEMPT_LIMIT; ++trial) {
        printf("パスワードを入力 (%d/%d): ", trial, ATTEMPT_LIMIT);
        scanf("%s", input_buffer);

        if (strcmp(input_buffer, VALID_CREDENTIAL) == 0) {
            printf("ログイン成功。\n");
            auth_passed = 1;
            break;
        } else {
            printf("認証失敗。\n");
        }
    }

    if (!auth_passed) {
        printf("許容回数を超えたためプログラムを終了します。\n");
    }
    return 0;
}

strcmp()は辞書順比較を行い、完全一致時に0を返します。戻り値の大小判定で文字列の相対順序を評価できます。

6. 乱数生成を用いた数当てゲーム

メニュー表示、乱数シード初期化、およびゲームロジックをモジュール化して実装します。rand()は疑似乱数生成器であるため、実行ごとに異なる値列を得るには時刻情報をシードとして渡す必要があります。

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

void print_menu() {
    puts("================================");
    puts("  [1] 数当てゲームを開始");
    puts("  [0] アプリケーション終了");
    puts("================================");
}

void execute_game() {
    const int target_num = rand() % 100 + 1;
    int player_input;

    puts("1〜100の整数を予想してください。");
    while (1) {
        printf("予想値: ");
        scanf("%d", &player_input);

        if (player_input < target_num) {
            puts("目標値はもっと大きいです。");
        } else if (player_input > target_num) {
            puts("目標値はもっと小さいです。");
        } else {
            puts("正解です。処理を終了します。");
            break;
        }
    }
}

int main(void) {
    srand((unsigned int)time(NULL)); // 乱数ジェネレータの初期化
    int menu_selection;

    do {
        print_menu();
        printf("選択番号を入力: ");
        scanf("%d", &menu_selection);

        switch (menu_selection) {
            case 1:
                execute_game();
                break;
            case 0:
                puts("正常終了。");
                break;
            default:
                puts("範囲外の値です。");
                break;
        }
    } while (menu_selection != 0);

    return 0;
}

7. システムシャットダウン制御スクリプト

OSレベルのコマンドをプログラムから発行し、特定キーワードの入力によって中断可能なカウンタダウン処理を構築します。

#include <stdio.h>
#include <string.h>

int main(void) {
    const char abort_phrase[] = "stop";
    char read_buffer[50];

    // 60秒後にシャットダウンを予約
    system("shutdown -s -t 60");
    puts("システムシャットダウンを実行中...");

    while (1) {
        printf("中止するには '%s' と入力してください: ", abort_phrase);
        scanf("%s", read_buffer);

        if (strcmp(read_buffer, abort_phrase) == 0) {
            system("shutdown -a");
            puts("予約された操作が解除されました。");
            break;
        }
        puts("入力内容が一致しません。");
    }
    return 0;
}

shutdown -s -t [秒数]は指定時間後の電源切断を予約し、shutdown -aは保留中の操作をキャンセルします。実行環境には適切なシステム権限が必要です。

タグ: C言語 制御構造 二分探索 疑似乱数 文字列比較

7月5日 00:38 投稿