• ベストアンサー

配列数を超えてアクセスしたときの処理

 「名簿クラス Meibo」 を自作しようと思っています。 人の名前の配列 person[0]~person[max-1]をフィールド変数に持ちます。 このとき、Meibo から名前を取り出すメソッド  getMemberName(int id) {   return person[id];  } では、「id が max を超えていないか」をチェックした方が良いと思います。 C言語を使っていた時は  getMemberName(int id) {   assert (id < max);   return person[id];  } のように、assert 関数でチェックをしていました。 しかし、調べてみると、java では assert のサポートはバージョン1.4からのようです。 java を使う人たちは、通常こういうときにどうしてきたのでしょうか? (assert 関数を自作する?)

質問者が選んだベストアンサー

  • ベストアンサー
  • kazsharp
  • ベストアンサー率37% (16/43)
回答No.5

「Javaを使う人たちは、通常こういうときどうしてきたのでしょうか?」と聞かれているので、なるべく正確に答えると、「何もしない」となると思います。 通常、Javaでは配列の境界チェックは行わず getMemberName(int id) { return person[id]; } とするのが一般的です。 ここで質問者さんに知ってほしいことが2つあります。 1つはなぜ「何もしない」のかということですが、Javaでは配列の境界チェックはVM側がやってくれるので、配列の範囲を超えたアクセスをすると「ArrayIndexOutOfBoundsException」がスローされます。それに対しC言語では配列のサイズを超えていても「配列があるものとして」アクセスするため、万が一配列のサイズを超えたインデックスを指定してまうと不正なメモリアクセスを行い重大な問題になりかねません。それでassertによって厳しいチェックを行っているのでしょう。 そしてもう一つはJavaで1.4からサポートされているassertは通常、「実行時にはオフ」にします。これはassertは開発中にバグを発見するために主に用いられ、「プログラムが誤っている」状態だと判断するものだと言えるからです。それに対し「例外」は実行時のエラー、プログラムが予期せぬ処理を実行しようとしたときに使われるものだ言えます。この2つを区別しておくことは重要です。 ちなみに、どうしても境界チェックを行いたい場合、私なら if (isAvailableID(id)) { String name = getMemberName(id); } というように、呼び出し元のほうでチェックするようにします。ついでにisAvailableIDメソッドは public boolean isAvailableID(int ID) { reutrn 0 <= ID && ID <= person.length-1; } といった感じでしょうか。

white-tiger
質問者

補足

非常に納得できました。 ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (4)

  • LancerVII
  • ベストアンサー率51% (1060/2054)
回答No.4

よくよく見たらすごい勘違い・・・ 配列の最大数はわかってますね。 呼び出し側の処理でmaxを超えてたらnullを返すとか 空白を返すとかエラーを投げるとか用途によってわけるかもしれません。

white-tiger
質問者

補足

みなさん、ありがとうございます。みなさんのご回答によると ●何もしなくても、ArrayIndexOutOfBoundsException というエラーを java が出してくれる Cより随分便利ですね。 ●だから、呼び出し側で java が出すエラー(か自作のエラー)を拾って処理すればよい。 ●もしくは、return null をする というところが中心でしょうか。 最初は、呼び出し側ではなく Meibo の方で処理が完結すればよいと思っていました。しかし、よく考えたら、呼び出し側も Meibo のエラー処理を知っておく必要があるのですね。

全文を見る
すると、全ての回答が全文表示されます。
  • LancerVII
  • ベストアンサー率51% (1060/2054)
回答No.3

こんにちは。 person.length で配列の要素数がintで返ってくるのでそれで比較してます。 try~catchでArrayIndexOutOfBoundsExceptionを拾うなんてことも 可能ですね。

全文を見る
すると、全ての回答が全文表示されます。
  • kgi03334
  • ベストアンサー率26% (24/90)
回答No.2

2通りあります。 1. if文を使い、id < max のときのみreturnするようにする。 2. getMemberNameを呼ぶところで、try~catchをする。

全文を見る
すると、全ての回答が全文表示されます。
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

> java を使う人たちは、通常こういうときにどうしてきたのでしょうか?  例外をスローするのが一般的じゃないかなぁ。まぁこれは私の流儀なので一般ではないかも知れない。 getMemberName(int id) {   if(id < max)     throw new Exception("配列の範囲を超えています");   return person[id]; }

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • java名簿管理プログラム

    以下の名簿管理プログラムで削除と名前の辞書順ソートのメソッドの作り方を教えていただけませんか? public class Meibo{ private Vector vec; public Meibo(){ vec=new Vector(); } public void insert(Person p){ vec.add(p); } public void delete(String name){ } public void sort(){ } /* PersonオブジェクトではStringで名前を、intで年齢を定義し入力しています */ かなり局部的にしか載せていないので非常に分かり難いとは思いますがどうかよろしくお願いします。

  • javaの配列

    javaの配列なんですが、配列の全要素一気にメソッドを実行させることができますか? 例えば、 Turtle[] hm = new Turtle[3]; for(int i = 0; i < 3; i++){ hm[i] = new Turtle(); } と配列を生成し、fd(int s)←[sピクセル前進]というメソッドを配列の全部の要素を順番ごとにではなく全部同時に実行させたい場合、コードはどのように書けばよいのでしょうか?

    • ベストアンサー
    • Java
  • できているとは、思うのですが。ポインタの配列を

    コンパイラではちゃんと動いてます。 1 2 3 0 1 2 3 という具合です。 気になるのは、printarrayの部分が正しいのか、ちょっと悩んでいます 問題としては main関数では0の値を読み込むまで最大99(MAX-1)個の値を配列 xに読み込んでいる。引数のポインタからの値を、値が0になるまで すべて1行に1つづつ画面に出力する関数printarray()を作成し、 プログラムを完成せよ。 引数はアドレスとして受け取る事。(配列としてでなく) フォーマットは、 "%d¥n" とする。(余計な出力はしない事。) (0は出力しない。) main内部を変更してはならない。 以下がソースです。 ご指摘よろしくお願いします。 #include <stdio.h> #define MAX 5 void printarray(int *); int main() { int x[MAX], i; int *p; x[MAX-1] = 0; for (i = 0, p = x; i < MAX-1; ++i, ++p) { scanf("%d", p); if (*p == 0) { break; } } printarray(x); return 0; } void printarray(int *a) { int i,*p; for(i = 0, p = a; i < MAX-1; ++i,++p) { if(*p == 0){ // continue; break; }else{ printf("%d\n", *(a+i)); } } }

  • 配列渡し後の要素数を知るには・・?

    main関数で定義した配列を他の関数で扱う場合にどうすればいいのかいまいちわかりません・・。 微妙に独学したのですが sizeofで要素数を調べたいのですがどうすればmain以外の関数内で要素数を調べる事ができるのでしょうか。私の書いたソースはこれです。 void dis(int *b){ int i, nx; nx = sizeof(b) / sizeof(b[0]); for(i=0;i<nx;i++){ printf("%d\n", *(b+i)); } } main(){ int a[5] = { 10, 20, 5, 1, -1 }; dis(a); return(0); } どうすればいいでしょうか・・・。どなたか教えていただければ光栄です。ご指導お願いします!

  • 配列で質問があります。

    小さなプログラムを配列を作りました。 3個配列を指定しそのうち2つを返すという ようなプログラムです。 バグがでてしまいメソッドのところで出ます。 Hairetu.java:9: ';' がありません。 int[] hairetu2(int box[0],int box[1]){  エラー1 作成したプログラムは以下です。メソッドの定義など見てみたのですがなぜバグが出るのかよくわかりません。教えて下さいませんか。 class Hairetu{ public static void main (String args[]){ int[] box = new int [3]; box [0] =1; box [1] =2; box [2] =3; int[] hairetu2(int box[0],int box[1]){ return box; } hairetu2 = hairetu2(box[0],box[1]); System.out.println(box); } } ^

    • ベストアンサー
    • Java
  • 自分で作ったクラスのメソッドから、配列が返ってこない

    こんばんは。 自分で作ったクラスのメソッドで、戻り値が配列のメソッドがあります。そのメソッドをメインプログラムから呼び出しても、値が入っていません。(空の配列が返ってくるのか、配列が返されているのかも分かりません)実行時エラーは以下の通りです。 Exception in thread "main" java.lang.NullPointerException at Main.main(Main.java:23) ソースコードは以下の通りです。 以下はメインプログラム // 自分で作成したクラスを使用しています DataProperty dp = new DataProperty( args[0] ); // ここで配列に値を入れています。 int[] intByteSize = dp.getByteSize(); System.out.println( intByteSize[0] ); 以下は自分で作ったプログラムです。 public int[] getByteSize() { if( fileNumber.equals("2004") ) { int[] intByteSize = { 8, 1, 5, 50, 8, 1, 15, 15, 3, 3, 8, 8, 11, 9, 7, 7, 1 }; return intByteSize; } 本などを見ても、構文的に間違いはないと思うんですが。。 だれか、原因の思いつく方は解答をください。よろしくお願いします。

    • ベストアンサー
    • Java
  • ポインタによる関数への配列渡し

    林晴比古さんの「新C言語入門」でC言語を勉強している初心者です。 現在ポインタの勉強をしています。色々教科書の文例等をポインタで書くとどうなるか試しております。 上書P200練習問題2に「配列の最大値を返す(その際配列の長さを渡す)」プログラムがあり、それをポインタで渡すプログラムに直してみました。 仮引数に「maxdata」を設定し、そのアドレスを関数側に渡し、関数側ではポインタとして受け取る(そうすれば関数側からはreturnで値を返す必要がない)、と考え、下記のように書いてみました。 #include <stdio.h> void max_of_array(int n[], int len, int *ans); int main(void) { int dt[6] = {50,20,80,30,10,40}; int maxdata; max_of_array(dt,6,&maxdata); printf("最大値=%d\n", maxdata); return 0; } void max_of_array(int n[], int len, int *ans) { int i; ans = &n[0]; for (i=1; i<len; i++){ if (*ans < n[i]) *ans = n[i]; } } しかしコンパイルすると、何故か「最大値=1」となってしまいます。(正しくは80です) 他にも色々試してみましたがうまくいかず、かなり考えてみたのですがどうしても分かりません。お分かりの方、どうすれば正しくなるのが教えてください、よろしくお願いします。

  • define で 配列

    #defineで配列を定義したいのですがこのようなことは可能でしょうか? ヘッダファイル(test.h)で #define MAX (2) int A[MAX]={20,30}; ソースファイルで #include <stdio.h> #include "test.h" int main(){ int i; for(i=0;i<MAX;i++){ printf("A[%d]=%d\n",i,A[i]); } return 0; } とやれば出来るのですが、このヘッダファイルを複数のソースで参照すると 多重定義であるとおこられてしまいます。 #defineで #define A[MAX] {20,30} のように配列を定義する方法は存在するのでしょうか? どなたか良い方法を御存じの方、ご教授お願いします。

  • 大きな配列を使うには?

    BCCにJavaからポーティングしましたが、配列 int array[max]で、150000程度の大きさを超えると、メモリ不足で止まってしまいます。BCCかリンカのオプションで、ヒープやスタックサイズを変更する具体的な方法、または、大きな配列を上手く使う方法を教えてください。(プログラムはこんな感じ。) #define max_array 140000 /* このサイズを変更したい */ void main() { char array[max_array] ; この後、ヒープも使うのですが、(そのメモリ確保も必要)そこまで 行かない。。。。 (MSのVC++2005でも、同様になりました。) 10数年ぶりにプログラムをしている初心者です。 よろしくお願いします。

  • コンパイル時の静的チェックについて

    次のような配列があります。 static const int ary[]={1,2,3,4,5}; この配列の要素数が5であることは、次の方法でコンパイル時にチェック出来ます。 #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) static_assert(ARRAYSIZE(ary) == 5); では、この配列で4以上の要素数が2であることをコンパイル時にチェックするにはどうしますか? 実行時であれば次のように出来ます。 assert(count_if(ary, ary+sizeof(ary), [](int i)->bool {return (i >= 4); }) == 2); 結果はコンパイル時に確定しているはずなのですが、この方法だとライブラリ関数を使用するので実行時にしかチェック出来ません。 「テスト用プロジェクトを作って...」というのも「コンパイル時に確認」ではないので無しとします。