Code Fix

言語間比較

配列の範囲外アクセス:例外になる言語・ならない言語・何が起こるか分からない言語

配列の添字を1つ間違えるという、あらゆる言語で起こりうる典型的なミスです。しかし結果は「例外で止まる」「静かにundefinedが返る」「メモリを読み書きしてしまい何が起きるか分からない」の3種類に分かれ、この違いを知らないと他言語からの移行時に大きな事故につながります。

言語ごとの現れ方

Java: ArrayIndexOutOfBoundsException の原因と直し方

 1  public class Main {
 2      public static void main(String[] args) {
 3          int[] nums = {10, 20, 30};
 4          for (int i = 0; i <= nums.length; i++) {
                               ^
 5              System.out.println(nums[i]);
 6          }
 7      }
 8  }
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3exited with code 1

ArrayIndexOutOfBoundsExceptionという専用の例外が飛びます。長さ3の配列の添字は0・1・2までです。

Javaの解説ページで詳しく見る →

Python: IndexError: list index out of range の原因と直し方

 1  nums = [1, 2, 3]
 2  print(nums[3 ])
                ^
Traceback (most recent call last): File "main.py", line 2, in <module> print(nums[3]) ~~~~^^^ IndexError: list index out of range

IndexErrorが飛びます。要素数と同じ値を添字に使うと1つ超えてしまうという、Javaと共通の間違い方をします。

Pythonの解説ページで詳しく見る →

C言語: 配列のループが1つずれて範囲外を読む・最後の要素が抜ける

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int scores[3] = {70, 80, 90};
 5      int sum = 0;
 6      for (int i = 1; i < 3; i++) {
                     ^
 7          sum += scores[i];
 8      }
 9      printf("%d\n", sum);
10      return 0;
11  }
出力: 170期待: 240

境界チェック自体が存在しません。範囲外の添字でも「たまたま」隣の変数の値を読んでしまうだけで、エラーにも例外にもならず気づきにくいのが最大の危険です。

C言語の解説ページで詳しく見る →

C#: Index was outside the bounds of the array の原因と直し方

 1  class Program {
 2      static void Main(string[] args) {
 3          int[] nums = { 1, 2, 3 };
 4          System.Console.WriteLine(nums[5]);
                                          ^
 5      }
 6  }
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array. at Program.Main(String[] args) in Program.cs:line 4

IndexOutOfRangeExceptionが飛びます。Java・Pythonと同じく実行時に確実に気づけます。

C#の解説ページで詳しく見る →

JavaScript: 配列の範囲外アクセスがエラーにならずundefinedになる

 1  const nums = [10, 20, 30];
 2  console.log(nums[5]);
                     ^
出力: undefined期待: 20 (エラーにはなりません)

例外を投げず、静かにundefinedを返します。Java・Python・C#のように例外で気づくことができないため、後続の計算までNaNなどの形で誤りが伝播しがちです。

JavaScriptの解説ページで詳しく見る →

TypeScript: 配列の範囲外アクセスがエラーにならずundefinedになる(TypeScriptでも変わらない)

 1  const nums: number[] = [10, 20, 30];
 2  console.log(nums[5]);
                     ^
出力: undefined

型システムは配列の要素数を追跡しないため、コンパイルエラーにはなりません。実行時の挙動もJavaScriptと同じく静かにundefinedを返します。

TypeScriptの解説ページで詳しく見る →

まとめ

例外を投げる言語(Java・Python・C#)では、テストや実行時にすぐ気づけます。静かにundefinedを返す言語(JavaScript・TypeScript)では、値がNaNや無意味な結果として後工程まで伝播してから発覚することがあります。Cのように境界チェック自体が無い言語では、範囲外アクセスは「たまたま動く」か「後で無関係な場所がクラッシュする」かのどちらかで、最も危険です(この性質はC++にも共通します)。自分が今どの分類の言語を書いているかを意識してください。

広告
広告スロット(未設定)