C言語

【C言語】第3章第9回:配列の境界チェックと安全なコーディング

配列操作における境界チェックを怠ると、プログラムの不具合やセキュリティの脆弱性につながる可能性があります。この章では、配列の境界チェックと安全なコーディング方法について詳しく解説します。

1. 配列の境界チェックとは?

配列の境界チェックとは、配列の要素にアクセスする際に、そのインデックスが配列の範囲内にあることを確認することです。

境界チェックを怠ると、次のような問題が発生します:

  • 予期しないメモリ領域へのアクセス
  • データの破損やプログラムのクラッシュ
  • セキュリティ上の脆弱性(バッファオーバーフロー)

2. 配列の境界を超えたアクセスの例

例:境界外アクセスの危険性を示すプログラム

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};

    // 範囲外アクセス
    printf("numbers[6]: %d\n", numbers[6]); // 未定義の動作を引き起こす可能性

    return 0;
}

解説:

  • 配列numbersは5つの要素を持ちますが、numbers[6]は存在しません。
  • このコードは、プログラムのクラッシュや不正な動作を引き起こす可能性があります。

3. 境界チェックの実装方法

安全なプログラムを書くためには、配列の範囲を超えたアクセスを防ぐチェックを実装する必要があります。

例:境界チェックを実装したプログラム

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};
    int index;

    printf("Enter index (0-4): ");
    scanf("%d", &index);

    if (index >= 0 && index < 5) { // 境界チェック
        printf("numbers[%d] = %d\n", index, numbers[index]);
    } else {
        printf("Error: Index out of range.\n");
    }

    return 0;
}

解説:

  • if (index >= 0 && index < 5)で、インデックスが有効な範囲内にあることを確認します。
  • 無効なインデックスが入力された場合、エラーメッセージを表示します。

4. 境界チェックを伴う配列操作の例

以下の例では、配列全体を操作する際に境界チェックを実装します。

例:配列の全要素を安全に出力するプログラム

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i < 5; i++) { // 境界チェックを含むループ
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    return 0;
}

解説:

  • forループ内で、iの値が配列のサイズ未満であることを確認します。
  • これにより、配列の境界を超えたアクセスが防止されます。

5. 練習問題

以下の課題に挑戦し、配列の境界チェックの重要性と実装方法を学びましょう。

  1. ユーザーからインデックスを入力させ、配列の要素を出力するプログラムを作成してください。ただし、境界チェックを追加してください。
  2. 配列の範囲外アクセスが発生した場合に、適切なエラーメッセージを表示してプログラムを終了するコードを書いてください。
  3. 配列の全要素を逆順で表示するプログラムを作成してください。ただし、安全な境界チェックを行ってください。

6. 練習問題の解答と解説

問1の解答

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};
    int index;

    printf("Enter index (0-4): ");
    scanf("%d", &index);

    if (index >= 0 && index < 5) {
        printf("numbers[%d] = %d\n", index, numbers[index]);
    } else {
        printf("Error: Index out of range.\n");
    }

    return 0;
}

問2の解答

#include <stdio.h>
#include <stdlib.h> // exit()のためのヘッダー

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};
    int index;

    printf("Enter index (0-4): ");
    scanf("%d", &index);

    if (index >= 0 && index < 5) {
        printf("numbers[%d] = %d\n", index, numbers[index]);
    } else {
        printf("Error: Index out of range.\n");
        exit(1); // プログラムを終了
    }

    return 0;
}

問3の解答

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};

    for (int i = 4; i >= 0; i--) { // 配列の逆順でのアクセス
        printf("numbers[%d] = %d\n", i, numbers[i]);
    }

    return 0;
}

7. まとめ

配列の境界チェックは、安全なプログラムを書く上で重要な役割を果たします。未定義の動作やバグを防ぎ、セキュリティ上のリスクを軽減するためにも、正しい境界チェックを実装することを心がけましょう。