スポンサード リンク

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

スポンサード リンク
-- : -- : -- | スポンサー広告 | page top↑
スポンサード リンク

配列の添え字チェック(安全なJavaと自己責任のC言語)

次のコードをご覧下さい。for文の継続条件をi<a.lengthとすべきところで、i<=a.lengthとしてしまうという、プログラミングを始めたばかりの頃にありがちな?コードです。(*1)


public class Index {
    public static void main(String args[]) {
	int[] a = new int[10];
	for(int i=0; i<=a.length; i++) a[i] = i;
	for(int i=0; i<=a.length; i++) 
	  System.out.println(a[i]);
    }
}

これをコンパイルして実行すると次のようになります。


$ java Index
Exception in thread "main"
 java.lang.ArrayIndexOutOfBoundsException: 10
        at Index.main(Index.java:4)

Javaは実行時に配列の添え字をチェックしているため、1つでもオーバーすると"java.lang.ArrayIndexOutOfBoundsException"が投げられます。

では、C言語ではどうでしょうか?

次のコードは先程のJavaのプログラムをC言語で書き直したものです。これをコンパイルして実行してみましょう。


#include < stdio.h >
#define SIZE 10

int main() {
  int i, a[SIZE];
  for(i=0; i<=SIZE; i++) a[i] = i;
  for(i=0; i<=SIZE; i++) printf("%d\n", a[i]);
  return 0;
}

$ ./a
0
1
2
3
4
5
6
7
8
9
10

宣言した配列要素数を1つだけオーバーしているにもかかわらず、C言語の場合は何の警告もなく実行できてしまいます。次のコードのように、もう少し多めにオーバーしても警告が出ることなく実行されてしまいます。


#include < stdio.h >
#define SIZE 10
#define OVERSIZE 90

int main() {
  int i, a[SIZE];
  for(i=0; i<=SIZE; i++) a[i] = i;
  for(i=0; i<=SIZE+OVERSIZE; i++) printf("%d\n", a[i]);
  return 0;
}

$ ./a
0
1
2
3
4
5
6
7
8
9
2280680
1628303575
1628878522
47
1628704768
(中略)
4198480
2273776
2293640
1627407504
2280912
0
(0が連続)
0

では、どこまでも参照することができてしまうのでしょうか?次のプログラムを用いて検証してみました。


#include 
#define SIZE 10

int main(int argc, char* argv[]) {
  int i, a[SIZE], oversize = atoi(argv[1]);
  for(i=0; i<=SIZE; i++) a[i] = i;
  for(i=0; i<=SIZE+oversize; i++) printf("%d\n", a[i]);
  return 0;
}

その結果、6000をすぎたあたりでようやくSegmentation faultで止まりました。


     10 [main] a 2956 _cygtls::handle_exceptions:
 Error while dumping state (probably corrupted stack)
Segmentation fault (core dumped)

このように、C言語はよほど大胆に配列サイズをオーバーしない限りエラーが吐かれることはなく、コードミスの検知が遅れてしまいます(*2)特に、配列サイズを少しだけオーバーしてしまった場合など、間違ったか所の発見が困難になることがあります。

C言語の入門書

新版 明解C言語 入門編
新版 明解C言語 入門編柴田望洋

ソフトバンククリエイティブ 2004-08-28
売り上げランキング : 8980
おすすめ平均star


Amazonで詳しく見る
by G-Tools

Javaの入門書

明解Java 入門編
明解Java 入門編柴田 望洋

ソフトバンククリエイティブ 2007-08-08
売り上げランキング : 803
おすすめ平均star


Amazonで詳しく見る
by G-Tools

*1:まあ、このコードでは4行目と5行目を一つにすることができるので不可解な点はありますが・・・4行目は配列のinitで、実際には4行目と5行目の間で配列要素に対して何らかの演算をしているものと思って下さい(^-^;)

*2:OVERSIZE 90のプログラムの実行結果に、謎の値(たまたまメモリの中に格納されている値)が出力されていることが確認できるように、明らかに不正な値が得られてミスに気付くことはあるかもしれません。


スポンサード リンク

テーマ:プログラミング - ジャンル:コンピュータ - ソーシャルブックマーク: この記事をクリップ! Yahoo!ブックマークに登録

00 : 52 : 36 | プログラミング-C/C++ | トラックバック(0) | コメント(0) | page top↑
<<Wiresharkで見る-Webページが表示されるまでのパケットの流れ | ホーム | 「ループはポインタ使った方が速い」とは限らない>>
コメント

コメントの投稿














管理者にだけ表示を許可する

トラックバック
トラックバックURL
http://networkprogramming.blog18.fc2.com/tb.php/13-b8d1f9ed
この記事にトラックバックする(FC2ブログユーザー)
| ホーム |

プロフィール

TBVector

Author:TBVector

プロフィール

メールフォーム

記事検索

Google

最近の記事

人気の記事

過去の記事

カテゴリー

タグランキング

リンク

最近のコメント

最近のトラックバック

アクセスカウンタ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。