C/C++における配列の範囲外アクセスと未定義動作について
Javaのような言語では、配列の範囲外にアクセスすると java.lang.ArrayIndexOutOfBoundsException のような例外が発生し、エラーを検知できる仕組みがあります。しかし、C言語にはこのような機能は存在せず、配列の範囲外にアクセスすると未定義動作(undefined behavior)が発生する可能性があります。
未定義動作とは、プログラムがクラッシュする、意図しない値を読み込む、一見正常に動作しているように見えるなど、動作が保証されない状態を指します。これは非常に危険なバグの原因となるため、注意が必要です。
以下に、C言語で配列の範囲外アクセスがどのような結果をもたらすかを示すプログラムの例を紹介します。
サンプルコード
#include <stdio.h>
int main() {
int arr[] = {1,2,3,4,5};
printf("The elements of array : ");
for(int i = 0; i<6; i++)
printf(" %d",arr[i]);
return 0;
}実行結果
上記プログラムの実行結果は以下の通りです。
The elements of array : 1 2 3 4 5 32765
プログラムの解説
ここで、上記プログラムの動作を詳しく見ていきましょう。
配列 arr には、添字 0 から 4 までの5つの要素にのみ値が代入されています。しかし、ループ条件が i<6 となっているため、存在しない arr[5] にもアクセスしてしまいます。その結果、arr[5] にはメモリ上の隣接領域に残っていた無意味な値(ゴミ値・不定値)である「32765」が出力されました。
該当するコード部分は以下の通りです。
int arr[] = {1,2,3,4,5};
printf("The elements of array : ");
for(int i = 0; i<6; i++)
printf(" %d",arr[i]);範囲外アクセスを防ぐためのポイント
C言語では実行時に配列の境界チェックが行われないため、プログラマ自身が以下の点に注意してコードを書く必要があります。
- ループ処理では、配列のサイズを正しく把握し、
i<sizeof(arr)/sizeof(arr[0])のように要素数を基準に条件を設定する。 - 可能であれば、コンパイラの警告オプション(例:
-Wall)や静的解析ツール(AddressSanitizer など)を活用して、範囲外アクセスを事前に検出する。 - より安全な配列操作が必要な場合は、C++の
std::vectorや.at()メソッドのように、境界チェック機能を持つコンテナの利用を検討する。
このように、C/C++では配列の範囲外アクセスによる未定義動作を防ぐために、開発者自身が慎重なコーディングを心がけることが重要です。
-
マージソートを使って配列の転倒数(反転数)を数えるC/C++プログラム
転倒数(Inversion Count)とは?与えられた配列をソートする際に発生する反転(転倒)の回数を「転倒数(Inversion Count)」と呼びます。転倒数を求める問題は古典的なアルゴリズム問題の一つで、マージソート(Merge Sort)のアルゴリズムを応用することで効率的に解くことができます。この問題では、各要素について「自分より左側にあり、かつ自分より大きな値を持つ要素」の数をすべて数え上げ、その合計を出力します。この処理は、マージソートのマージ(merge)関数の中で実装されます。理解を深めるために、マージ処理で扱う2つの部分配列を例に考えてみましょう。配列の転倒数の定義配列
-
【初心者向け】C/C++における多次元配列の初期化方法をわかりやすく解説
多次元配列とは、次元数が2以上ある配列のことです。本記事では、3×3×3の多次元配列におけるメモリ割り当ての仕組みと、実際に配列を初期化して内容を表示するC++プログラムを紹介します。下図は、次元が3×3×3の多次元配列に対するメモリ割り当ての戦略を示したものです。アルゴリズム多次元配列を初期化するプログラムは、以下の手順で構成されます。Begin 多次元配列の要素を初期化する 配列のサイズを出力する 配列の内容を表示する Endサンプルコード以下は、2行2列の二次元配列を初期化し、そのサイズと内容を出力するC++プログラムです。#include<iostream