4.配列と文字・文字列

Copyright(C) 6Sep2013 coskx

このページでは「配列」と「文字・文字列」について解説する。
ここで修得して欲しい内容は以下の通りである。
1.配列の宣言の仕方を修得する。
2.配列を使用することのメリットを理解する。
3.forなどの繰返しで配列要素を順に操作する方法を理解する。
4.配列ぼ大きさ(要素数)と要素番号の関係を理解する。
5.ソートのアルゴリズムを追跡できる。(バブルソート,単純ソート)
6.文字が文字コードで内部表現されていることを理解する。
7.文字列の構造(終端に'\0')を理解する。
8.二次元配 列のイメージと表現方法を理解する。

このページでの内容は以下を含んでいる。
4.1 配列
4.2 ソート
4.3 文字の取り扱い
4.4 文字列
4.5 二次元配列

  4.1 配列

4.1.1  配列を利用しない場合の例

複数の身長の平均値 を求めることを考えてみよう。(身長データはプログラム中で定められていて変更できないが,getIntなどを使えば,身長データの キーボードに変更が可能である。)

List 4.1.1 平均値の計算プログラムと実行結果

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
  
    XXXX() {
        double heightA=173.2; /*cm*/
        double heightB=168.5; /*cm*/
        double heightC=178.1; /*cm*/
        double heightD=183.7; /*cm*/
        double heightE=164.2; /*cm*/
        double sum; /*合計*/
        double average; /*平均身長 cm*/
        sum=0.0;
        sum+=heightA;  /*sum=sum+heightA と同じ*/
        sum+=heightB;
        sum+=heightC;
        sum+=heightD;
        sum+=heightE;
        average=sum/5.0;
        System.out.printf("average=%f\n",average);
    }
}

/*****実行結果*****
average=173.540000
*******************/


4.1.2 配列を利用した例

4.1.1では5名の身長の平均だが,このままの状態で1000名の平均を求めるには1000個の変数名が必要 になるであろう。
もし次のようにひとつの変数名で,内部にたくさんの部屋を持つ変数が使えたら都合がよい。各部屋は部屋番号がついている。

あったらいいなプログラムの一部

    height[0]=173.2; /*cm*/
    height[1]=168.5; /*cm*/
    height[2]=178.1; /*cm*/
    height[3]=183.7; /*cm*/
    height[4]=164.2; /*cm*/
    sum=0.0;
    sum+=height[0];
    sum+=height[1];
    sum+=height[2];
    sum+=height[3];
    sum+=height[4];
    average=sum/5.0;


この例では変数名「height」は,1つの名前しか持たないが, 内部に値を格納するための複数の部屋を持っている変数として使われている。そして0から4までの部屋番号を持っている。

このように内部に値を格納する複数の部屋を持っている変数は「配列」と呼ば れている。また個々の部屋のことは「要素」または「配列要素」と呼ばれ,0から4までの部屋番号のことは,「配列要素番号」または単に「要素番号」 と呼ばれる。

変数宣言部で

double[] height= new double[5];

のように書けば,内部に5つの部屋を持つdouble型配列変数 heightが宣言される。
配列要素数5のdouble型配列変数 heightと表現される。)

「new」というのは,その後ろに書かれた変数の場所をメモリ上に確保しなさいという意味である。
配列変数は実は参照型(C言語のポインタのような動作をする)であり,実態を正確には表していないが,次のように考えるとよい。
実際のnew double[5]は
double型の変数5個分の領域をメモリ上に確保し,その先頭番地を変数heightに保存する。


5つの部屋は0号室から4号室である。
(このことは配列要素番号は0から4であると表現される。)
この配列を利用してList 4.1.1を書き直してみよう。

List 4.1.2 平均値の計算プログラムと実行結果

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
   
    XXXX() {
        double[] height= new double[5]; /* 配列宣言 */
        double sum; /*合計*/
        double average; /*平均身長 cm*/
        height[0]=173.2; /*cm*/
        height[1]=168.5; /*cm*/
        height[2]=178.1; /*cm*/
        height[3]=183.7; /*cm*/
        height[4]=164.2; /*cm*/
        sum=0.0;
        sum+=height[0];
        sum+=height[1];
        sum+=height[2];
        sum+=height[3];
        sum+=height[4];
        average=sum/5.0;
        System.out.printf("average=%f\n",average);
    }
}

/*****実行結果*****
average=173.540000
*******************/

このままではあまり「ごりやく」を感じない。さらに要素番号を変数iで与えるように書き直して,
配列変数の初期化(最初の値の代入)を宣言と同時に行なうと書き方が多少変化して,次のようになる。

追加説明
例えば変数宣言部で
double[] height= new double[1000];
のように宣言すると,heightという変数は1000個の要素(部屋)を持つ変数ということになる。
配列要素には番号が付いていて,「第0要素」「第1要素」「第2要素」......「第998要素」「第999要素」という
1000個の要素となっていて,それぞれの要素がdouble型の変数になっている。
配列要素番号は,「第1要素」から「第1000要素」ではなく,「第0要素」から「第999要素」になっていることに
注意すること。

行ないたいこと

Javaでの記述

「第54要素(54号室)」に値160.0を格納したい height[54]=160.0;
「第200要素(200号室)」に格納されている値を「第300要素 (300号室)」に格納したい height[300]=height[200];
「第159要素(159号室)」の値を画面に表示したい printf("%f\n",height[159]);
キーボードから値を入力し,「第799要素(799号室)」に格納した い height[799]=getDouble("height=");

height[0],height[1],height[2],... の1つ1つのことを配列heightの要素とい い,0,1,2...を要素番号という。
1000は配列heightの要素数という。

注意

height[1000]=160.0;
は「1000号室」に160.0を代入しようとしているが,この例では「1000号室」が存在しないので誤りであ る。


配列の宣言方法は2通り
(1) 配列の要素数を定めて配列変数を宣言し,後から配列要素に値を代入するとき
    int[] myarray= new int[100];
(2) 配列要素に値を格納した状態で配列変数を宣言するとき
   (配列の大きさすなわち配列要素数は自動的に定まる)
    int[] myarray={10,20,30,40,50,60,70,80,90,100};


4.1.3 配列の活用

配列にデータが入っていると,最大値,最小値も簡単に求められる。
先頭データを最大値,最小値の候補にしておき,ループ中でよりふさわしい候補が見つかったら候補を入れ替える作業を行ない,すべてのデータに ついてこの作業が終了すると,最大値,最小値が見つかる。

List 4.1.3 平均値の計算と最大最小を求めるプログラムと実行結果

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
  
    XXXX() {
        double[] height={
            173.2, 168.5, 178.1, 183.7, 164.2
        };/*cm*/ /*double型配列変数heightを用意して,各要素に(各号室に)
                   順に173.2,168.5,178.1,183.7,164.2 の5つの値を代入するの意味
                   部屋数(要素数)は自動的に5になる*/
        double sum; /*合計*/
        double average; /*平均身長 cm*/
        double tallest; /*最大身長が入るべき変数*/
        double shortest; /*最小身長が入るべき変数*/
        int i;
        sum=0.0;
        tallest=height[0];  /*仮の最大値*/
        shortest=height[0]; /*仮の最小値*/
        /*tallest=shortest=height[0]; は上の2行と同じ意味になる*/
        for (i=0;i<height.length;i++) {
            sum+=height[i];
            if (tallest<height[i]) {
                tallest=height[i];
            }
            if (height[i]<shortest) {
                shortest=height[i];
            }
        }
        average=sum/height.length;
        System.out.printf("average =%f\n",average);
        System.out.printf("tallest =%f\n",tallest);
        System.out.printf("shortest=%f\n",shortest);
    }
}

/*****実行結果*****
average =173.540000
tallest =183.700000
shortest=164.200000
*******************/


複数のデータをキーボードから入力することにして,データの入力を終わりたいときには,負の値を入力することに しておく(実行結果を見なさい)と以下のようになる。ただし,データ総数は100以下とする。実行例ではデータ数は5である。

List 4.1.4 キーボード入力値の平均値の計算プログラムと実行結果

import java.util.*;  // StringTokenizer
import java.io.*;    // BufferedReader

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
  
    XXXX() {
        double[] height= new double[100];/*cm*/
        double sum; /*合計*/
        double average; /*平均身長 cm*/
        double tallest; /*最大身長*/
        double shortest; /*最小身長*/
        int number; /*データ総数*/
        int i;
        i=0;
        height[i]=getDouble("身長データを入力(負なら終了) >>");
        while (0.0<=height[i]) {
            i++;
            height[i]=getDouble("身長データを入力(負なら終了) >>");
        }
        if (i==0) System.exit(1); /*強制終了*/
        number=i;
        sum=0.0;
        tallest=height[0];
        shortest=height[0];
        /*tallest=shortest=height[0]; と書いたら上の2行と同じ意味になる*/
        for (i=0;i<number;i++) {
            sum+=height[i];
            if (tallest<height[i]) {
                tallest=height[i];
            }
            if (height[i]<shortest) {
                shortest=height[i];
            }
        }
        average=sum/number; /*double型÷int型なので,numberはdouble型に自動的に変換され,正しい計算が行なわれる*/
        System.out.printf("average =%f\n",average);
        System.out.printf("tallest =%f\n",tallest);
        System.out.printf("shortest=%f\n",shortest);
    }

    private double getDouble(String prompt){
        BufferedReader bffrd = new BufferedReader(new InputStreamReader(System.in));
        double ret=0.0;
        System.out.print(prompt);
        try {
            ret = Double.valueOf(bffrd.readLine()).doubleValue();
        }
        catch(IOException e) {
            System.out.println("IO Error");
            System.exit(1);
        }
        return ret;
    }
}

/*****実行結果*****
身長データを入力(負なら終了) >>173.2
身長データを入力(負なら終了) >>168.5
身長データを入力(負なら終了) >>178.1
身長データを入力(負なら終了) >>183.7
身長データを入力(負なら終了) >>164.2
身長データを入力(負なら終了) >>-1
average =173.540000
tallest =183.700000
shortest=164.200000
*******************/


4.1. 配列利用上の注意(不幸なエラーに落ち込む前に)

配列の要素数を無視したプログラムではどうなるか考えてみよう。

List 4.1.6 配列の要素数を無視した配列の読み出し

このプログラムは,文法に反していないので,コンパイル時にはエラーにならない。
しかし,array[5],array[6]は存在していないため,実行時にエラーが起こる。

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
  
    XXXX() {
        int[] arry={101,102,103,104,105};
        int i;
        for (i=0;i<7;i++) {
            System.out.printf("i=%d arry[%d]=%d\n",i,i,arry[i]);
        }
    }
}

/******実行結果*****
i=0 arry[0]=101
i=1 arry[1]=102
i=2 arry[2]=103
i=3 arry[3]=104
i=4 arry[4]=105
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
        at XXXX.<init>(XXXX.java:10)
        at XXXX.main(XXXX.java:3)
*******************/

List 4.1.7 配列の要素数を無視した配列の書き込み(その2)

このプログラムは,文法に反していないので,コンパイル時にはエラーにならない。
array[5],array[6]は存在していない
ため,実行時にエラーが起こる。

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] arry= new int[5];
        int i;
        for (i=0;i<7;i++) {
            arry[i]=100+i;
            System.out.printf("i=%d arry[%d]=%d\n",i,i,arry[i]);
        }
    }
}

/******実行結果*****
i=0 arry[0]=100
i=1 arry[1]=101
i=2 arry[2]=102
i=3 arry[3]=103
i=4 arry[4]=104
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
        at XXXX.<init>(XXXX.java:10)
        at XXXX.main(XXXX.java:3)
*******************/


配列に関する大事な注意事項

配列のサイズを超える番号の配列要素 に対する操作は,コンパイル時にはエラーにならないが,実行時に誤った実行結果を得たり,予期せぬ重大な事態が起きたりする。


4.1.5 配列のためのfor文の拡張

配列を対象にしたループ回数は配列要素数に決まっているのだから,
4.1.4のような誤りをしないようにJAVAではfor文が拡張されている。
次のプログラム中

for (int x : array)
は,配列変数arrayから1つずつ取り出してxとして扱ってループの中を実行するという意味となる。

List 4.1.8 for文の拡張
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] array={11,12,13,14};
        for (int x : array) {
            System.out.printf("%d\n",x);
        }
    }
}

/******実行結果*****
11
12
13
14
*******************/

配列をfor文で扱う際の安全プログラミング

for (int x : array)型のfor文(他のプログラミング言語では「for each構文」)は,不幸な実行時エラーを生じさせないために,配列に対する作業では必ず使われるべきである。


4.1.6 配列のコピー

配列変数名は参照型なので,配列を他の配列にコピーする場合は以下の方法を使う。

List 4.1.9 配列を他の配列にコピーする

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] a={3,5,7,9};
        int[] b= new int[4];
        int i;
        for (i=0;i<4;i++)  b[i]=a[i];
        for (i=0;i<4;i++)  System.out.printf("%d %d %d\n",i,a[i],b[i]);
    }
}

/********************* 実行結果 ********************
0 3 3
1 5 5
2 7 7
3 9 9
****************************************************/

注意
    b=a; のように記述しても配列全体の代入はできない。(List4.2.9参照)
  配列を別の配列にコピーする時は,このプログラムのように要素を1つ1つ行なう。

    b[4]=a[4]; のように記述しても配列全体の代入はできない。
  aの部屋番号4の格納値をbの部屋番号4へ代入するという意味になってしまう。
  そもそも,配列要素は0から3までしかない。

List 4.1.10 配列を他の配列にコピー(2) arraycopyを使う
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] a={3,5,7,9};
        int[] b= new int[4];
        int i;
        System.arraycopy(a,0, b,0, 4);
        for (i=0;i<4;i++)  System.out.printf("%d %d %d\n",i,a[i],b[i]);
    }
}

/********************* 実行結果 ********************
0 3 3
1 5 5
2 7 7
3 9 9
****************************************************/
System.arraycopy(a,0, b,0, 4);を一般化すると
 System.arraycopy(a,n1, b,n2, m);になるが
 配列aの第n1要素からはじまるm個の要素を,
配列bの第n2要素からはじまるm個の要素
 にコピーするという意味になる。

 これを使う場合はb= new int[4] が必ず必要。
List 4.1.11 配列を他の配列にコピー(3) clone()を使う
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] a={3,5,7,9};
        int[] b;
        int i;
        b=a.clone();
        for (i=0;i<4;i++)  System.out.printf("%d %d %d\n",i,a[i],b[i]);
    }
}


/********************* 実行結果 ********************
0 3 3
1 5 5
2 7 7
3 9 9
****************************************************/

b=a.clone()は,配列aの完全コピーを作ってbに代入するの意味
この場合,bの宣言は
int[] b= new int[4]; ではなく int[] b: だけでよい。
(配列変数aのコピーを作り,bがコピーされた実体を指すようになる。)

配列コピーの失敗例

以下のプログラムの前半の様にb=aで配列全体を代入しようとするとおかしなことが起こる。
配列変数名が参照型(C言語のポインタ変数)であるので,b=a;により,
配列変数bが配列変数aの実体を指すようになり,aもbも同じ配列実体を指すことになる。

このプログラムの後半は,配列変数aの実体のコピーを配列変数bが指すようになるため,
a,bそれぞれが別の実体を指すようになっていうのでおかしなことは起こらない。

List 4.1.12 配列を他の配列にコピーしたつもりの失敗(前半)と実体コピーに成功(後半)の例
/* Arraytest.java */
public class Arraytest {
    public static void main(String[] args) {
        Arraytest mainprg = new Arraytest();
    }
 
    Arraytest() {
        int[] a={1,2,3};
        int[] b=new int[3];
        b=a;
        System.out.printf("a:%d %d %d\n",a[0],a[1],a[2]);
        System.out.printf("b:%d %d %d\n",b[0],b[1],b[2]);
        a[0]=6;
        a[1]=7;
        a[2]=8;
        System.out.printf("a:%d %d %d\n",a[0],a[1],a[2]);
        System.out.printf("b:%d %d %d\n",b[0],b[1],b[2]);
        b[0]=11;
        b[1]=12;
        b[2]=13;
        System.out.printf("a:%d %d %d\n",a[0],a[1],a[2]);
        System.out.printf("b:%d %d %d\n",b[0],b[1],b[2]);
       
        int[] c={1,2,3};
        int[] d=new int[3];
        d=c.clone();
        System.out.printf("c:%d %d %d\n",c[0],c[1],c[2]);
        System.out.printf("d:%d %d %d\n",d[0],d[1],d[2]);
        c[0]=6;
        c[1]=7;
        c[2]=8;
        System.out.printf("c:%d %d %d\n",c[0],c[1],c[2]);
        System.out.printf("d:%d %d %d\n",d[0],d[1],d[2]);
        d[0]=11;
        d[1]=12;
        d[2]=13;
        System.out.printf("c:%d %d %d\n",c[0],c[1],c[2]);
        System.out.printf("d:%d %d %d\n",d[0],d[1],d[2]);
    }
}


/********************* 実行結果 ********************
a:1 2 3
b:1 2 3
a:6 7 8
b:6 7 8
a:11 12 13
b:11 12 13
c:1 2 3
d:1 2 3
c:6 7 8
d:1 2 3
c:6 7 8
d:11 12 13

****************************************************/
前半の失敗についての補足
C言語では配列変数にはアドレスが格納されていた。Javaでは参照型変数と呼ばれるが,
同様に考えると考えやすい。
(実際の動きとは異なるかも知れないが,C言語と同じ動作をしていると考える。)

        int[] a={1,2,3};
        int[] b=new int[3];
の段階で,次のようになっている。
変数 変数の中身
a 「1,2,3」が入ったメモリブロックの先頭アドレス*1
b 3つの整数を保存できるメモリブロック*2の先頭アドレス
メモリ上に「1,2,3」が入ったメモリブロックが作成され,その先頭アドレスが配列変数aに入っている。
また配列変数bはアドレスを代入される変数として存在するものの,初期化されていない状態である。

        b=a;
により,配列変数bにも配列変数aと同じアドレスが入ることになり,次のようになる。
変数 変数の中身
a 「1,2,3」が入ったメモリブロックの先頭アドレス
b 「1,2,3」が入ったメモリブロックの先頭アドレス
その結果,aに対する操作でも,bに対する操作でも,同じメモリブロックに対して行われることになる。
この時点で*2のメモリブロックはどこからも参照されなくなり,やがて捨てられる。
*1ここで先頭アドレスと書いたが,C言語既習の読者向けである。実際にはメモリブロックの先頭を表す
参照と表現するのが正しい。

参考までに後半のd=c.clone()においても,dの宣言時に確保されたint型3個分のメモリブロックもどこからも参照されなくなり,
やがて捨てられる。それ故,dの宣言は
 int[] d= new int[4];
ではなく
 
int[] d:
だけでよい。




 課題4 その1

(1)20点満点の英単語テストの得点データが10人分あり,これがint型配列scoreに次のように格納されているものとする。
    int[] score={15,8,12,18,20,20,9,16,20,17};
これを次のように棒グラフに表すプログラムを作りなさい。 (p04ex01.java)

<<実行結果>>
 1 15 :****|****|****|
 2  8 :****|***
 3 12 :****|****|**
 4 18 :****|****|****|***
 5 20 :****|****|****|****|
 6 20 :****|****|****|****|
 7  9 :****|****
 8 16 :****|****|****|*
 9 20 :****|****|****|****|
10 17 :****|****|****|**

(2)平年の1月から12月までの各月に含まれる日数がint型配列numberofdaysに次のように格納されているものとする。 (p04ex02.java)
    int[] numberofdays={31,28,31,30,31,30,31,31,30,31,30,31};
キーボードから月日を次のように入力させ,1月1日から数えて何日目か答えるプログラムを作りなさい。
次の例で(1月25日と3月2日,4月10日,12月31日)で検証しなさい。

<<実行例1>>
month day = 1 25
25

<<実行例2>>
month day = 3 2
61

<<実行例3>>
month day = 4 10
100

<<実行例4>>
month day = 12 31
365



  4.2 ソート(並び替え)

配列を使うと,ソート(「大きい順に並び替え」または「小さい順に並び替え」)が出来る。
配列内のデータの交換だけで,第0要素には最大値を求め,第1要素には第1要素以降の最大値を,第2要素 には第2要素以降の最大値を...
という作業を繰り返して行なえば,ソート(並び替え)が出来る。

List 4.2.1 ソートのプログラム

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        double[] height={
            173.2,168.5,178.1,183.7,164.2
        };/*cm*/
        double tmp;
        int i,j;
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
        /*ソート(大きい順に並び替え)部 第0作業
        (第0要素が最大値になるようにする)*/
        for (j=1;j<5;j++) {
            if (height[0]<height[j]) {
                tmp=height[0];
                height[0]=height[j];
                height[j]=tmp;
            }
        }
        /*ソート(大きい順に並び替え)部 第1作業
        (第1要素が第1要素以降で最大値になるようにする)*/
        for (j=2;j<5;j++) {
            if (height[1]<height[j]) {
                tmp=height[1];
                height[1]=height[j];
                height[j]=tmp;
            }
        }
        /*ソート(大きい順に並び替え)部 第2作業
        (第2要素が第2要素以降で最大値になるようにする)*/
        for (j=3;j<5;j++) {
            if (height[2]<height[j]) {
                tmp=height[2];
                height[2]=height[j];
                height[j]=tmp;
            }
        }
        /*ソート(大きい順に並び替え)部 第3作業
        (第3要素が第3要素以降で最大値になるようにする)*/
        for (j=4;j<5;j++) {
            if (height[3]<height[j]) {
                tmp=height[3];
                height[3]=height[j];
                height[j]=tmp;
            }
        }
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
    }
}

/*****実行結果****************
173.2 168.5 178.1 183.7 164.2
183.7 178.1 173.2 168.5 164.2
******************************/

補足説明

if (height[0]<height[j]) {
    tmp=height[0];
    height[0]=height[j];
    height[j]=tmp;
}

「もし(height[0]<height[j])なら
height[0]の格納値とheight[j]の格納値を交換する」
の意味となる。

もし
if (height[0]<height[j]) {
    height[0]=height[j];
    height[j]=height[0];
}
と書いたら交換できるだろうか?


List4.2.1は二重ループにするとList4.2.2のようにプログラムが短くなる。
よく理解できない時は次のプログラムリストList4.2.3とその次のプログラムリストList4.2.4を見てみよう。
このソート方法は「単純選択ソート」あるいは「選択ソート」と呼ばれる。
ソートアルゴリズムの可視化アプリで鑑賞しよう

List 4.2.2 ソートのプログラム

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        double[] height={
            173.2,168.5,178.1,183.7,164.2
        };/*cm*/
        double tmp;
        int i,j;
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
        /*ソート(大きい順に並び替え)部*/
        for (i=0;i<4;i++) {
            for (j=i+1;j<5;j++) {
                if (height[i]<height[j]) {
                    tmp=height[i];
                    height[i]=height[j];
                    height[j]=tmp;
                }
            }
        }
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
    }
}

/*****実行結果****************
173.2 168.5 178.1 183.7 164.2
183.7 178.1 173.2 168.5 164.2
******************************/

動作理解や動作が思い通りでない時,プログラム中にprintfを 使って検査したい変数値を表示させることがある。
これをスナップショットと呼ぶが,この方法で二重ループ中のiとjを表示してみよう。

List 4.2.3 ソートのプログラム中の二重ループでスナップショット

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        double[] height={
            173.2,168.5,178.1,183.7,164.2
        };/*cm*/
        double tmp;
        int i,j;
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
        /*ソート(大きい順に並び替え)部*/
        for (i=0;i<4;i++) {
            for (j=i+1;j<5;j++) {
                System.out.printf("(%d,%d) ",i,j);
                if (height[i]<height[j]) {
                    tmp=height[i];
                    height[i]=height[j];
                    height[j]=tmp;
                }
            }
            System.out.printf("\n");
        }
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
    }
}

/*****実行結果****************
173.2 168.5 178.1 183.7 164.2
(0,1) (0,2) (0,3) (0,4)
(1,2) (1,3) (1,4)
(2,3) (2,4)
(3,4)
183.7 178.1 173.2 168.5 164.2
******************************/

もうすこし,詳しくスナップショットを入れてみよう。実行結果の流れを見て,自分の理解が正しいかどうかチェックしなさい。

List 4.2.4 ソートのプログラム中の二重ループでスナップショット

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        double[] height={
            173.2,168.5,178.1,183.7,164.2
        };/*cm*/
        double tmp;
        int i,j;
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
        /*ソート(大きい順に並び替え)部*/
        for (i=0;i<4;i++) {
            for (j=i+1;j<5;j++) {
                System.out.printf("(%d,%d) ",i,j);
                System.out.printf("[%.1f,%.1f]-> ",height[i],height[j]);
                if (height[i]<height[j]) {
                    tmp=height[i];
                    height[i]=height[j];
                    height[j]=tmp;
                }
                System.out.printf("[%.1f,%.1f]\n",height[i],height[j]);
            }
        }
        /*表示部*/
        for (double h: height) {
            System.out.printf("%.1f ",h);
        }
        System.out.printf("\n");
    }
}

/**********実行結果****************
173.2 168.5 178.1 183.7 164.2
(0,1) [173.2,168.5]-> [173.2,168.5]
(0,2) [173.2,178.1]-> [178.1,173.2]
(0,3) [178.1,183.7]->
[183.7,178.1]
(0,4) [183.7,164.2]-> [183.7,164.2]
(1,2) [168.5,173.2]->
[173.2,168.5]
(1,3) [173.2,178.1]->
[178.1,173.2]
(1,4) [178.1,164.2]-> [178.1,164.2]
(2,3)
[168.5,173.2]-> [173.2,168.5]
(2,4) [173.2,164.2]-> [173.2,164.2]
(3,4) [168.5,164.2]-> [168.5,164.2]
183.7 178.1 173.2 168.5 164.2
***********************************/

練習4,1

次のプログラムの実行結果を予想しなさい。
List 4.2.5 自力追いかけプログラム  

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] exam={
            70,64,80,95,84
        };
        int tmp;
        int i,j,k;
        for (int ex: exam) {
            System.out.printf("%d ",ex);
        }
        System.out.printf("\n");
        for (i=0;i<4;i++) {
            for (j=0;j<4-i;j++) {
                k=j+1;
                System.out.printf("[exam[%d]=%d,exam[%d]=%d]-> ",j,exam[j],k,exam[k]);
                if (exam[j]<exam[k]) {
                    tmp=exam[j];
                    exam[j]=exam[k];
                    exam[k]=tmp;
                }
                System.out.printf("[exam[%d]=%d,exam[%d]=%d]\n",j,exam[j],k,exam[k]);
            }
        }
        for (int ex: exam) {
            System.out.printf("%d ",ex);
        }
        System.out.printf("\n");
    }
}

 

このソートは
「バブルソート」
と呼ばれる

ソートアルゴリズムの可視化アプリ
で鑑賞しよう


 課題4 その2

(3)次の配列を小さい順に並べて表示しなさい。(p04ex03.java)
並べ替え前の様子と並べ替えた後の様子をよくわかるように下に示すように表示しなさい。

int myarray[100]={
    467, 41,334,500,169,724,478,358,962,464,
    705,145,281,827,961,491,995,942,827,436,
    391,604,902,153,292,382,421,716,718,895,
    447,726,771,538,869,912,667,299, 35,894,
    703,811,322,333,673,664,141,711,253,868,
    547,644,662,757, 37,859,723,741,529,778,
    316, 35,190,842,288,106, 40,942,264,648,
    446,805,890,729,370,350,  6,101,393,548,
    629,623, 84,954,756,840,966,376,931,308,
    944,439,626,323,537,538,118, 82,929,541
}

実行結果

before
467  41 334 500 169 724 478 358 962 464
705 145 281 827 961 491 995 942 827 436
  :

after
  6  35  35  37  40  41  82  84 101 106
118 141 145 153 169 190 253 264 281 288
  :


  4.3 文字の内部表現と,char型変数

コンピュータは数値を変数に格納することが出来る。文字も数値に変換して覚えさせればよい。文字を数値に変換したものを文字コードと呼ぶ。 この文字コード表みると,どの文字がどのような文字 コードになっているかわかる。
例えば「Hello!」は「72,101,108,108,111,33」(十進数)のようになる。コンピュータプログラムでは十六進数がよ く用いられ,「48,65,6C,6C,6F,21」とも表現される。
まずint型変数にこれらの文字コードを代入し,表示するプログラムを作ってみよう。

List 4.3.1 文字の扱い

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int[] xx={
            72,101,108,108,111,33
        }; /*十進数の表現*/
        int[] yy={
            0x48,0x65,0x6C,0x6C,0x6F,0x21
        }; /*十六進数の表現*/
        int i;
        for (i=0;i<xx.length;i++) {
            System.out.printf("%c",xx[i]);
        }
        System.out.printf("\n");
        for (i=0;i<yy.length;i++) {
            System.out.printf("%c",yy[i]);
        }
        System.out.printf("\n");
    }
}

/****実行結果****
Hello!
Hello!
*****************/

補足説明
System.out.printf("%c",yy[i]);
で「%c」は変数yy[i]の値を文字コードに見立てて,
その文字コードに対応する文字を表示するという意味になる。

文字コードをint型変数に格納するというのは通常は行なわれない。
これはテストプログラムである。まねをしないこと。
文字コードはchar型変数に格納するのが普通である。
Javaでの文字コードはUTF-16が使われている。

chをint型変数として;

ch=65;
ch=0x41;
ch='A';
はすべて同じ意味となる。(文字コード表参照)

0x41は16進法の41のことであり,'A'と書いたら65あるいは0x41と書いてあるのと同じである。
同様に
if (ch==65) {
if (ch==0x41) {
if (ch=='A') {
は同じ意味を表す。(文字コード表参照)
また
ch=0x48;
System.out.printf("%d %x %c\n",ch,ch,ch);
では「72 48 H」が表示される。(文字コード表参照)


文字コードを格納するには
char型変数が用いられる。

chをchar型変数として;

ch=65;
ch=0x41;
ch='A';
はすべて同じ意味となる。(文字コード表参照)

0x41は16進法の41のことであり,'A'と書いたら65あるいは0x41と書いてあるのと同じである。
同様に
if (ch==65) {
if (ch==0x41) {
if (ch=='A') {
は同じ意味を表す。(文字コード表参照)
また
ch=0x48;
System.out.printf("%d %x %c\n",(int)ch,(int)ch,ch);
では「72 48 H」が表示される。(文字コード表参照)

練習4.2

次のプログラムの実行結果を予想しなさい。
List 4.3.2 自力追いかけプログラム  

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        int mychar;
        for (mychar=65;mychar<68;mychar++) {
            System.out.printf("%d %x %c\n",mychar,mychar,mychar);
        }
        for (mychar=0x44;mychar<0x47;mychar++) {
            System.out.printf("%d %x %c\n",mychar,mychar,mychar);
        }
        for (mychar='G';mychar<'J';mychar++) {
            System.out.printf("%d %x %c\n",mychar,mychar,mychar);
        }
    }
}

 


List 4.3.3 List4.3.2でmacharをint型からchar型に変更すると,表示時に型変換が必要
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        char mychar;
        for (mychar=65;mychar<68;mychar++) {
            System.out.printf("%d %x %c\n",(int)mychar,(int)mychar,mychar);
        }
        for (mychar=0x44;mychar<0x47;mychar++) {
            System.out.printf("%d %x %c\n",(int)mychar,(int)mychar,mychar);
        }
        for (mychar='G';mychar<'J';mychar++) {
            System.out.printf("%d %x %c\n",(int)mychar,(int)mychar,mychar);
        }
    }
}

/* 実行結果
65 41 A
66 42 B
67 43 C
68 44 D
69 45 E
70 46 F
71 47 G
72 48 H
73 49 I
*/

数値と数字の違い (試験でよくある間違え)

int ch;
に対して
ch=6;

ch='6';
は異なる。

ch='6';はch=0x36;またはch=54;と同じになる。

数値と数字の違い (ちょっとした工夫)

(1)数字→数値
char ch;
int value;
に対して
ch='6';
value=ch-(int)'0';
でvalueの値は6になる。(文字 コード表参照)
この表現は「数値を表す文字コード」を「数値」に変換するの によく使われる。

(2)数値→数字
逆に
value=8;
ch=(char)(value+(int)'0');
でchは文字'8'を表す値(8の文字コード)になる。(文字コード表参照)

(3)文字コードが数字を表しているかどうかの検査
「chが数字文字を表しているなら・・・・」は
if (ch=='0'||ch=='1'||ch=='2'||ch=='3'||ch=='4'||ch=='5'||ch=='6'||ch=='7'||ch=='8'||ch=='9') {
でも良いが,次のように表す。
if ((int)'0'<=ch && ch<=(int)'9') {

「chが数字文字を表していないなら・・・・」は
次のように表す。
if (ch<
(int)'0' || (int)'9'<ch) {

 課題4 その3

(4)int型変数xを用い,xの値を65から74まで変化させ,
printf("%c [%2x]\n",x,x)
を用いて部分文字コード表を作りなさい。(p04ex04.java)

(5)int型変数xを用い,xの値を48から57まで変化させ,
printf("%c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。(p04ex05.java)

(6)int型変数xを用い,xの値を32から126まで変化させ,
printf("%c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。ただし,改行位置を工夫しなさい。(p04ex06.java)


 

  4.4 文字列

4.4.1 文字列

C言語では文字列は文字型変数の配列として扱われていた。
Javaでは文字列型(String型)の変数として扱われる。

List 4.4.1 文字列の出力

/*文字列の出力*/
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1= "Hello, world.";
        String mystring2= "Tomorrow is another day.";
        System.out.printf("mystring1=<<%s>>\n",mystring1);
        System.out.println(mystring2); /*文字列mistring2を表示し改行する*/
        System.out.println(mystring2);
    }
}

/******* 実行結果 **********
mystring1=<<Hello, world.>>
Tomorrow is another day.
Tomorrow is another day.
****************************/

文字列の入力はgetStringを作って用いる。
文字列の代入でコピーができる。

List 4.4.2 文字列の入出力と文字列のコピー,文字列の連結

/*文字列の入出力と文字列のコピー*/
import java.util.*;  // StringTokenizer
import java.io.*;    // BufferedReader

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1;
        String mystring2;
        String mystring3;
        int i;
        /*キーボードから文字列を入力してもらい,mystring1に取り込む*/
        mystring1=getString("文字列を入力してください\n");
        /*文字列のコピー*/
        mystring2= mystring1;
        /*文字列の連結 「+」を使って連結する*/
        mystring3= mystring1+" Tommorw is another day.";
        /*作業結果の表示*/
        System.out.println("あなたが入力した文字列は");
        System.out.println(mystring1);
        System.out.println("コピーした文字列は");
        System.out.println(mystring2);
        System.out.println("連結した文字列は");
        System.out.println(mystring3);
    }

    private String getString(String prompt){
        BufferedReader bffrd = new BufferedReader(new InputStreamReader(System.in));
        String ret=new String();
        System.out.print(prompt);
        try {
            ret = bffrd.readLine();
        }
        catch(IOException e) {
            System.out.println("IO Error");
            System.exit(1);
        }
        return ret;
    }
}

/****************** 実行結果 *********************
文字列を入力してください
The love you get is equal to the love you make.
あなたが入力した文字列は
The love you get is equal to the love you make.
コピーした文字列は
The love you get is equal to the love you make.
連結した文字列は
The love you get is equal to the love you make. Tommorw is another day.
**************************************************/


4.4.2 文字列操作

次に,文字列の逆コピーをしてみよう。

List 4.4.3 文字列の入出力と文字列の逆コピー

/* Reversestr.java */
/*文字列の入出力と文字列の逆コピー*/
import java.util.*;  // StringTokenizer
import java.io.*;    // BufferedReader

public class Reversestr {
    public static void main(String[] args) {
        Reversestr mainprg = new Reversestr();
    }

    Reversestr() {
        String mystring1;
        String mystring2;
        int i,num;
        /*キーボードから文字列を入力してもらい,mystring1に取り込む*/
        mystring1=getString("文字列を入力してください\n");
        /*文字列の逆順取出しと合成*/
        num=mystring1.length();
        mystring2="";    /*空の文字列*/
        for (i=num-1; 0<=i; i--) {
            mystring2+=mystring1.charAt(i);
        }
        /*作業結果の表示*/
        System.out.println("あなたが入力した文字列は");
        System.out.println(mystring1);
        System.out.println("逆順文字列は");
        System.out.println(mystring2);
    }

    private String getString(String prompt){
        BufferedReader bffrd = new BufferedReader(new InputStreamReader(System.in));
        String ret=new String();
        System.out.print(prompt);
        try {
            ret = bffrd.readLine();
        }
        catch(IOException e) {
            System.out.println("IO Error");
            System.exit(1);
        }
        return ret;
    }
}

/****************** 実行結果 *********************
文字列を入力してください
Boy, You're gona carry the weight for long time.
あなたが入力した文字列は
Boy, You're gona carry the weight for long time.
逆順文字列は
.emit gnol rof thgiew eht yrrac anog er'uoY ,yoB
**************************************************/

mystring1.charAt(i)は,文字列mystring1のi文字目を取り出すの意味
mystring2+=mystring1.charAt(i);は取り出した文字を文字列mystring2の末尾に連結するの意味

練習4.3

次のプログラムの実行結果を予想しなさい。
List 4.4.4 自力追いかけプログラム
ヒント
mystring1.charAt(i-3)」と異なり,「(char)((int)mystring1.charAt(i)-3)」は文字コードから3を引いている
文字コード表を参照すること
 

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1="1xr|#hyro#L#nhhz#d#v|dg#wkjlH";
        String mystring2;
        String mystring3;
        int num,i;
        mystring2="";
        num=mystring1.length();
        for (i=0; i<num; i++) {
            mystring2+=(char)((int)mystring1.charAt(i)-3);
        }
        mystring3="";
        for(i=num-1; 0<=i; i--) {
            mystring3+=mystring2.charAt(i);
        }
        System.out.println(mystring1);
        System.out.println(mystring2);
        System.out.println(mystring3);
    }
}

 

よくある誤り

int kk;
の時
kk='A';
は kk=0x41; あるいは kk=65; と同じなので正しいが
kk="A";
は "A"が文字列(長さは1)を表すため正しくない。

逆に
String st="ABC";
は正しいが
Styring str='ABC';
は正しくない。


4.4.3 その他の文字列操作

(1)文字列の検索(文字列中の指定した文字列の位置を得る)

List 4.4.5 indexOf
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring="Yesterday all my troubles seemed so far away";
        String key="troubles";
        int x;
        x=mystring.indexOf(key);
        System.out.printf("\"%s\" is at %d in \"%s\"\n",key,x,mystring);
    }
}

/****************** 実行結果 *********************
"troubles" is at 17 in "Yesterday all my troubles seemed so far away"
**************************************************/

(2)文字列の検索(文字列が指定した文字列で始まっているかどうか)

List 4.4.6 startsWith
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring="Yesterday all my troubles seemed so far away";
        String key1="Yesterday";
        String key2="troubles";
        System.out.println(mystring);
        System.out.printf("starts with \"%s\"  >>",key1);
        if (mystring.startsWith(key1)) {
            System.out.printf("yes\n");
        } else {
            System.out.printf("no\n");
        }
        System.out.printf("starts with \"%s\"  >>",key2);
        if (mystring.startsWith(key2)) {
            System.out.printf("yes\n");
        } else {
            System.out.printf("no\n");
        }
    }
}

/****************** 実行結果 *********************
Yesterday all my troubles seemed so far away
starts with "Yesterday"  >>yes
starts with "troubles"  >>no
**************************************************/

(3)大文字,小文字変換

List 4.4.7 toLowerCase, toUpperCase
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1="Hey Jude, don't make it bad";
        String mystring2;
        String mystring3;
        mystring2=mystring1.toUpperCase();
        mystring3=mystring1.toLowerCase();
        System.out.println(mystring1);
        System.out.println(mystring2);
        System.out.println(mystring3);
    }
}

/****************** 実行結果 *********************
Hey Jude, don't make it bad
HEY JUDE, DON'T MAKE IT BAD
hey jude, don't make it bad
**************************************************/

(3)文字列の比較 
   よく間違えるので注意 文字列の一致を「==」で判定してはならない
   「==」を使うと,2つの変数が指している実体のID(アドレス)が等しいかどうかを調べていて,
   実体の中の文字列が等しいかどうかは調べていない。

List 4.4.8 失敗例 「==」を使う
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1="Hey Jude, don't make it bad";
        String mystring2=mystring1;
        String mystring3="Hey Jude, ";
        mystring3 += "don't make it bad";
        if (mystring1==mystring2) {
            System.out.println("mystring1,mystring2は等しい");
        } else {
            System.out.println("mystring1,mystring2は等しくない");
        }
        if (mystring1==mystring3) {
            System.out.println("mystring1,mystring3は等しい");
        } else {
            System.out.println("mystring1,mystring3は等しくない");
        }
    }
}

/****************** 実行結果 *********************
mystring1,mystring2は等しい
mystring1,mystring3は等しくない
**************************************************/
List 4.4.9 成功例 「equals」を使う
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }
 
    XXXX() {
        String mystring1="Hey Jude, don't make it bad";
        String mystring2=mystring1;
        String mystring3="Hey Jude, ";
        mystring3 += "don't make it bad";
        if (mystring1.equals(mystring2)) {
            System.out.println("mystring1,mystring2は等しい");
        } else {
            System.out.println("mystring1,mystring2は等しくない");
        }
        if (mystring1.equals(mystring3)) {
            System.out.println("mystring1,mystring3は等しい");
        } else {
            System.out.println("mystring1,mystring3は等しくない");
        }
    }
}

/****************** 実行結果 *********************
mystring1,mystring2は等しい
mystring1,mystring3は等しい
**************************************************/

これ以外にも文字列に関しては有用な機能があるので,「Java String メソッド」で検索しなさい。


4.4.4 文字列の配列

複数の文字列を扱う場合は文字列配列になる。例えば変数宣言部で
String[] mystring={
    "Information","Technology","Programming","Language","Computer"
};
と書いた場合には次のような配列が出来る。

部屋番号
保存されている文字列
0
Information
1
Technology
2
Programming
3
Language
4
Computer


この配列を用いて,これらの文字列を表示するプログラムを作ってみよう。

List 4.4.10 複数文字列の扱い

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }

    XXXX() {
        String[] mystring={
            "Information","Technology","Programming","Language","Computer"
        };
        int i;
        for (i=0;i<mystring.length;i++) {
            System.out.printf("%s\n",mystring[i]);
        }
    }
}

/************実行結果************
Information
Technology
Programming
Language
Computer
*********************************/

List 4.4.11 複数文字列の扱い for文の拡張を使った場合
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }

    XXXX() {
        String[] mystring={
            "Information","Technology","Programming","Language","Computer"
        };
        for (String str : mystring) {
            System.out.printf("%s\n", str);
        }
    }
}

/************実行結果************
Information
Technology
Programming
Language
Computer
*********************************/



 課題4 その4

(7)文字列をキーボードから読み込み,その文字列に含まれる文字「e」の数を表示するプログ ラムを作りなさい。(p04ex07.java)
次の3例を含む5例ほどで検証しなさい。

<<実行例1>>
abcdefg
1

<<実行例2>>
I'm getting closer to my home.
3

<<実行例3>>
Kunugidamachi Hachioji Tokyo
0

(8)2つの文字列をキーボードから読み込み,2つの文字列中,先頭の1文字が等し かったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex08.java)
ただし,2つの文字列を構成する文字数はそれぞれ1文字以上である。次の2例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= atom
robot atom => not equal

<<実行例2>>
str1= robot
str2= rocket
robot rocket => equal

(9)2つの文字列をキーボードから読み込み,2つの文字列中,先頭の3文字が等し かったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。(p04ex09.java)
ただし,2つの文字列を構成する文字数はそれぞれ3文字以上である。次の3例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= root
robot root => not equal

<<実行例2>>
str1= speaker
str2= speech
speaker speech => equal

<<実行例3>>
str1= time
str2= game
time game => not equal

(10)2つの文字列をキーボードから読み込み,2つの文字列が完全に等しかった ら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex10.java)
ただし,2つの文字列を構成する文字数は等しいとする。次の2例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= robit
robot robit => not equal

<<実行例2>>
str1= robot
str2= robot
robot robot => equal

(11)2つの文字列をキーボードから読み込み,2つの文字列が完全に等しかった ら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex11.java)
ただし,2つの文字列を構成する文字数は等しいとは限らない。
また,Stringクラスのメンバ関数equals()をここでは使ってはならない。
次の4例を含む5例ほどで検証しなさい。
 考え方

<<実行例1>>
str1= robot
str2= robotics
robot robotics => not equal

<<実行例2>>
str1= robotics
str2= robot
robotics robot => not equal

<<実行例3>>
str1= robot
str2= robot
robot robot => equal

<<実行例4>>
str1= time
str2= game
time game => not equal

(12)文字列をキーボードから読み込み,その文字列が2Jの学生の出席番号として正当かどうか調べ,正当か不正かを表示するプログラムを作成しなさい。  (p04ex12.java)
ただし2Jの学生の出席番号だったら「correct」,そうでなかったら「incorrect」と表示すること。番号は1から49までを正当とする。また2J1は正当とは認めず2J01を正当とする。
またプログラムへの入力と判定結果の出力は連続して出来るようにし,文字列「zzzz」が入力されたら,プログラムが終了するものとす る。
以下の例でプログラムの動作を検証しなさい。
 考え方

実行の様子(必ずここに書いてある文字列 による実行結果をつけること)

2Jの出席番号を入力してください >> 2J01
2J01 => correct
2Jの出席番号を入力してください >> 2J13
2J13 => correct
2Jの出席番号を入力してください >> 2J29
2J29 => correct
2Jの出席番号を入力してください >> 2J30
2J30 => correct
2Jの出席番号を入力してください >> 2J49
2J49 => correct
2Jの出席番号を入力してください >> 2J1
2J1 => incorrect
2Jの出席番号を入力してください >> 2J9
2J9 => incorrect
2Jの出席番号を入力してください >> 2J50
2J50 => incorrect
2Jの出席番号を入力してください >> 2J123
2J123 => incorrect
2Jの出席番号を入力してください >> 2J00
2J00 => incorrect
2Jの出席番号を入力してください >> 2J
2J => incorrect
2Jの出席番号を入力してください >>
zzzz

(13)キーボードから入力された文字列に,母音字がそれぞれいくつ含まれているか表示するプログラムを作成しなさい。  (p04ex13.java)
入力される文字列の長さは300文字以下とします。なお大文字小文字は区別しないことにします。

答え合わせを以下のように行ないなさい。ただし,文字列入力時にはエンターキーを押すまでが文字列として取り込まれるの
で,長い文章の入力途中でリターンキーを押さないようにする。

実行例(2回)

文字列を入力してください
hello!
入力された文字列は次のものです。
hello!
集計結果
number of vowels A,a=   0
number of vowels E,e=   1
number of vowels I,i=   0
number of vowels O,o=   1
number of vowels U,u=   0

文字列を入力してください
Over this year, I have seen many Japanese entertainment show on television that
are obviously supposed to make people laugh and have a good time. However, some
of these shows are not funny at all.

入力された文字列は次のものです。
Over this year, I have seen many Japanese entertainment show on television that
are obviously supposed to make people laugh and have a good time. However, some
of these shows are not funny at all.
集計結果
number of vowels A,a= 16
number of vowels E,e= 25
number of vowels I,i= 7
number of vowels O,o= 16
number of vowels U,u= 4


  4.5 二次元配列

これまでに学習した配列は,例えばプログラムの変数宣言部で

int[] myarray={987,654,321,963,852,741};

なら,配列変数の名前がmyarrayで部屋番号が0号室から5号室(部屋数6)まである「長屋」のような整数型配列であった。

部屋番号

0

1

2

3

4

5

987

654

321

963

852

741


また,プログラムの実行部でmyarray[0]は 987,myarray[1]は654を示す。これは一次元配列と呼ばれる。

これに対し,「高層マンション」のように4階8号室とか12階6号室のように表現される配列は二次元配列と呼ぶ。
例えばプログラムの変数宣言部で

int[][] myarray={
    {32,65,98,21,54,87},
    {96,63,85,52,74,41,10,20},
    {7,8,9,4,5,6},
    {10,20,30,40,50,60,70,80,90,100},
    {100,200,300}
};

なら,0階から6階(7フロアある)までの高層マンションで,各階には定義されただけの部屋がある。

値は次のように並んでいる。

階番号部屋番号

0

1

2

3

4

5

6

7

8

9

0

32

65

98

21

54

87

未定義

未定義

未定義

未定義

1

96

63

85

52

74

41

10

20

未定義

未定義

2

7

8

9

4

5

6

未定義

未定義

未定義

未定義

3

10

20

30

40

50

60

70

80

90

100

4

100

200

300

未定義

未定義

未定義

未定義

未定義

未定義

未定義


またプログラムの実行部でmyarray[2][3]は4,myarray[4][2]は300を表す。この配列を表示するプログラムを作ってみよう。

List 4.5.1 2次元配列のテストプログラム
public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }

    XXXX() {
        int[][] myarray={
            {32,65,98,21,54,87},
            {96,63,85,52,74,41,10,20},
            {7,8,9,4,5,6},
            {10,20,30,40,50,60,70,80,90,100},
            {100,200,300}
        };
        int i,j;
        for(i=0; i<myarray.length; i++) {
            for(j=0; j<myarray[i].length; j++) {
                System.out.printf("%5d",myarray[i][j]);
            }
            System.out.printf("\n");
        }
    }
}

/************実行結果************
   32   65   98   21   54   87
   96   63   85   52   74   41   10   20
    7    8    9    4    5    6
   10   20   30   40   50   60   70   80   90  100
  100  200  300
*********************************/
myarray.lengthは配列変数myarrayの行数を表し,
myarray[i].length
は配列変数myarrayの第i行の列数を表す。


例題として,10人の学生の英語・数学・国語のテストの点(0~100)の処理を考えよう。学生番号を0~9とし,英語・数学・国語の科目番号を0,1,2とする。科目ごとの平均と各学生の3科目合計点を求める事にする。学生番号 4の英語・数学・国語の得点をpoint[4][0],point[4][1],point[4][2]とし,合計点はpoint[4] [3]にしまうことにする。得点はあらかじめ2次元配列にしまっておくことにする。
処理内容は,個人の3科目の合計点,各科目の平均点および個人合計点の平均点の算出とする。

List 4.5.2 3科目の試験結果の処理

public class XXXX {
    public static void main(String[] args) {
        XXXX mainprg = new XXXX();
    }

    XXXX() {
        int[][] score={ /*英・数・国・(合計,最初は0を入れておく)の順の個人得点*/
            {86,75,60,0},{75,68,81,0},{84,98,100,0},{87,76,48,0},{82,58,73,0},
            {100,87,98,0},{64,72,70,0},{87,68,99,0},{98,87,68,0},{87,72,84,0}
        };
        int[] sum= new int[4];
        double[] average=new double[4]; /*英・数・国・(合計)の順の平均値*/
        int i,j;
        for (i=0;i<10;i++) {
            for (j=0;j<3;j++) {
                score[i][3]+=score[i][j];
            }
        }
        for (j=0;j<4;j++) {
            sum[j]=0;
            for (i=0;i<10;i++) {
                sum[j]+=score[i][j];
            }
            average[j]=sum[j]/10.0;
        }
        System.out.printf("学生番号 英語 数学 国語 合計\n");
        for (i=0;i<10;i++) {
            System.out.printf("%6d    %3d   %3d   %3d   %3d\n",
                i+1,score[i][0],score[i][1],score[i][2],score[i][3]);
        }
        System.out.printf("   平均    %.1f  %.1f  %.1f %.1f\n",
            average[0],average[1],average[2],average[3]);
    }
}

/************実行結果************
学生番号 英語 数学 国語 合計
     1     86    75    60   221
     2     75    68    81   224
     3     84    98   100   282
     4     87    76    48   211
     5     82    58    73   213
     6    100    87    98   285
     7     64    72    70   206
     8     87    68    99   254
     9     98    87    68   253
    10     87    72    84   243
   平均    85.0  76.1  78.1 239.2
*********************************/



二次元配列の宣言方法は2通り
(1) 配列の要素数を定めて配列変数を宣言し,後から配列要素に値を代入するとき
    int[][] myarray= new int[100][10];
(2) 配列要素に値を格納した状態で配列変数を宣言するとき
   (配列の大きさすなわち配列要素数は自動的に定まる。この例では4行3列)
    int[] myarray={ {10,20,30}, {40,50,60}, {70,80,90}, {100,110,120} };




 課題 4

(1)20点満点の英単語テストの得点データが10人分 あり,これがint型配列scoreに次のように格納されているものとする。
    int[] score={15,8,12,18,20,20,9,16,20,17};
これを次のように棒グラフに表すプログラムを作りなさい。 (p04ex01.java) (再掲)

<<実行結果>>
 1 15 :****|****|****|
 2  8 :****|***
 3 12 :****|****|**
 4 18 :****|****|****|***
 5 20 :****|****|****|****|
 6 20 :****|****|****|****|
 7  9 :****|****
 8 16 :****|****|****|*
 9 20 :****|****|****|****|
10 17 :****|****|****|**

(2)平年の1月から12月までの各月に含まれる日数が int型配列numberofdaysに次のように格納されているものとする。 (p04ex02.java) (再掲)
    int[] numberofdays={31,28,31,30,31,30,31,31,30,31,30,31};
キーボードから月日を次のように入力させ,1月1日から数えて何日目か答えるプログラムを作りなさい。
次の例で(1月25日と3月2日,4月10日,12月31日)で検証しなさい。

<<実行例1>>
month day = 1 25
25

<<実行例2>>
month day = 3 2
61

<<実行例3>>
month day = 4 10
100

<<実行例4>>
month day = 12 31
365


(3)次の配列を小さい順に並べて表示しなさい。 (p04ex03.java) (再掲)
並べ替え前の様子と並べ替えた後の様子をよくわかるように下に示すように表示しなさい。

int myarray[100]={
    467, 41,334,500,169,724,478,358,962,464,
    705,145,281,827,961,491,995,942,827,436,
    391,604,902,153,292,382,421,716,718,895,
    447,726,771,538,869,912,667,299, 35,894,
    703,811,322,333,673,664,141,711,253,868,
    547,644,662,757, 37,859,723,741,529,778,
    316, 35,190,842,288,106, 40,942,264,648,
    446,805,890,729,370,350,  6,101,393,548,
    629,623, 84,954,756,840,966,376,931,308,
    944,439,626,323,537,538,118, 82,929,541
}

実行結果

before
467  41 334 500 169 724 478 358 962 464
705 145 281 827 961 491 995 942 827 436
  :

after
  6  35  35  37  40  41  82  84 101 106
118 141 145 153 169 190 253 264 281 288
  :

(4)int型変数xを用い,xの値を65から74まで変化させ,
printf("%c [%2x]\n",x,x)
を用いて部分文字コード表を作りなさい。(p04ex04.java) (再掲)

(5)int型変数xを用い,xの値を48から57まで変化させ,
printf("%c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。(p04ex05.java) (再掲)

(6)int型変数xを用い,xの値を32から126まで変化させ,
printf("%c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。ただし,改行位置を工夫しなさい。(p04ex06.java) (再掲)

(7)文字列をキーボードから読み込み,その文字列に含 まれる文字「e」の数を表示するプログラムを作りなさい。(p04ex07.java) (再掲)
次の3例を含む5例ほどで検証しなさい。

<<実行例1>>
abcdefg
1

<<実行例2>>
I'm getting closer to my home.
3

<<実行例3>>
Kunugidamachi Hachioji Tokyo
0

(8)2つの文字列をキーボードから読み込み,2つの文字列中,先頭の1文字が等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex08.java) (再掲)
ただし,2つの文字列を構成する文字数はそれぞれ1文字以上である。次の2例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= atom
robot atom => not equal

<<実行例2>>
str1= robot
str2= rocket
robot rocket => equal

(9)2つの文字列をキーボードから読み込み,2つの文字列中,先頭の3文字が等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。(p04ex09.java) (再掲)
ただし,2つの文字列を構成する文字数はそれぞれ3文字以上である。次の3例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= root
robot root => not equal

<<実行例2>>
str1= speaker
str2= speech
speaker speech => equal

<<実行例3>>
str1= time
str2= game
time game => not equal

(10)2つの文字列をキーボードから読み込み,2つの文字列が完全に等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex10.java) (再掲)
ただし,2つの文字列を構成する文字数は等しいとする。次の2例を含む5例ほどで検証しなさい。 考え方

<<実行例1>>
str1= robot
str2= robit
robot robit => not equal

<<実行例2>>
str1= robot
str2= robot
robot robot => equal

(11)2つの文字列をキーボードから読み込み,2つの文字列が完全に等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex11.java) (再掲)
ただし,2つの文字列を構成する文字数は等しいとは限らない。
また,Stringクラスのメンバ関数equals()をここでは使ってはならない。
次の4例を含む5例ほどで検証しなさい。
 考え方

<<実行例1>>
str1= robot
str2= robotics
robot robotics => not equal

<<実行例2>>
str1= robotics
str2= robot
robotics robot => not equal

<<実行例3>>
str1= robot
str2= robot
robot robot => equal

<<実行例4>>
str1= time
str2= game
time game => not equal

(12)文字列をキーボードから読み込み,その文字列が 2Jの学生の出席番号として正当かどうか調べ,正当か不正かを表示するプログラムを作成しなさい。  (p04ex12.java) (再掲)
ただし2Jの学生の出席番号だったら「correct」,そうでなかったら「incorrect」と表示すること。番号は1から49 までを正当とする。また2J1は正当とは認めず2J01を正当とする。
またプログラムへの入力と判定結果の出力は連続して出来るようにし,文字列「zzzz」が入力されたら,プログラムが終了するものと する。
以下の例でプログラムの動作を検証しなさい。 考え方

実 行の様子(必ずここに書いてある文字列による実行結果をつけること)

2Jの出席番号を入力してください >> 2J01
2J01 => correct
2Jの出席番号を入力してください >> 2J13
2J13 => correct
2Jの出席番号を入力してください >> 2J29
2J29 => correct
2Jの出席番号を入力してください >> 2J30
2J30 => correct
2Jの出席番号を入力してください >> 2J49
2J49 => correct
2Jの出席番号を入力してください >> 2J1
2J1 => incorrect
2Jの出席番号を入力してください >> 2J9
2J9 => incorrect
2Jの出席番号を入力してください >> 2J50
2J50 => incorrect
2Jの出席番号を入力してください >> 2J123
2J123 => incorrect
2Jの出席番号を入力してください >> 2J00
2J00 => incorrect
2Jの出席番号を入力してください >> 2J
2J => incorrect
2Jの出席番号を入力してください >> zzzz

(13)キーボードから入力された文字列に,母音字がそ れぞれいくつ含まれているか表示するプログラムを作成しなさい。  (p04ex13.java) (再掲)
入力される文字列の長さは300文字以下とします。なお大文字小文字は区別しないことにします。

答え合わせを以下のように行ないなさい。ただ し,文字列入力時にはエンターキーを押すまでが文字列として取り込まれるの
で,長い文章の入力途中でリターンキーを押さないようにする。

実 行例(2回)

文字列を入力してください
hello!
入力された文字列は次のものです。
hello!
集計結果
number of vowels A,a=   0
number of vowels E,e=   1
number of vowels I,i=   0
number of vowels O,o=   1
number of vowels U,u=   0

文字列を入力してくだ さい
Over this year, I have seen many Japanese entertainment show on television that
are obviously supposed to make people laugh and have a good time. However, some
of these shows are not funny at all.
入力された文字列は次のものです。
Over this year, I have seen many Japanese entertainment show on television that
are obviously supposed to make people laugh and have a good time. However, some
of these shows are not funny at all.
集計結果
number of vowels A,a= 16
number of vowels E,e= 25
number of vowels I,i= 7
number of vowels O,o= 16
number of vowels U,u= 4

(14)1週間の曜日がString型配列に格納されているとする
     String[] dayofweek={
         "Sunday","Monday","Tuesday",...,"Saturday"
     };
週の第何日目かをキーボードから読み込み,その曜日を表示するプログラムを作りなさい。(p04ex14.java)
全ての曜日が表示されることを検証しなさい。

<<実行例1>>
number = 1
Sunday

<<実行例2>>
number = 3
Tuesday

(15)次の動作を行なうプログラムを作成しなさい。整数型の配列 (配列要素の数を50としなさい)を宣言し,繰返し処理を用いて,要素の先頭から 1,4,9,16,25,36,49,64,81,...を格納しなさい。そして,先頭から,1つおきに,配列要素を画面に表示しな さい。(1 9 25 ...となる)
 (p04ex15.java)

(16)次のプログラムを作りなさい。(p04ex16.java)
int型配列testdata,配列要素数20を宣言し,すべての要素に0を代入しなさい。
次に要素番号が「2を除く2の倍数」になっている要素すべてに1を代入しなさい。
(ヒント)    for (i=2*2;i<20;i=i+2) testdata[i]=1;
そしてすべての要素の値を表示しなさい。表示にあたっては次の2行を用いなさい。

for(i=0;i<20;i++) System.out.printf("%d",testdata[i]);
System.out.printf("\n");

(17)次のプログラムを作りなさい。(p04ex17.java)
int型配列testdata
,配列要素数20を宣言し,すべての要素に0を代入しなさい。
次に要素番号が「2を除く2の倍数」になっている要素すべてに1を代入しなさい。
(ヒント)    for (i=2*2;i<20;i=i+2) testdata[i]=1;
そして要素番号が「3を除く3の倍数」になっている要素すべてに1を代入しなさい。
(ヒント)    for (i=3*2;i<20;i=i+3) testdata[i]=1;
最後にすべての要素の値を表示しなさい。表示にあたっては次の2行を用いなさい。

for(i=0;i<20;i++) System.out.printf("%d",testdata[i]);
System.out.printf("\n");

(18)次の手順で「エラトステネスのふるい」を用いて2から1000までの素数を見つけ,表 示するプログラムを作成しなさい。
またいくつ見つかったかも表示しなさい。
 (p04ex18.java)
(0,1は素数ではない)この手法では,2から1000までの数を素数候補としておき,2の倍数を候補からはずし,3の倍数を候補からは ずし,4の倍数を候補からはずし,5の倍数を候補からはずし,....とすると最後に残るのが素数になるという考え方を行なう。
まずint型の配列sieve,要素数1001を宣言する。このとき配列要素は0から1000の設定となる。
配列要素sieve[0],sieve[1]には0を格納し,そのほかの要素には,1を格納する。(1が格納されているとこの要素の要素番号は素数候補を意味する。現時点では2以上の整数はすべて素数候補である。)この後次の作業に入る。
1)「2以外の2の倍数」の要素番号の要素に0を代入する。すなわちsieve[4],seive[6],seive[8],....に 0を代入。これらの要素番号は2の倍数なので素数候補からはずした。
2)「3以外の3の倍数」の要素番号の要素に0を代入する。すなわちsieve[6],seive[9],seive[12],.... に0を代入。これらの要素番号は3の倍数なので素数候補からはずした。
3)「4以外の4の倍数」の要素番号の要素に0を代入する。すなわち sieve[8],seive[12],seive[16],....に0を代入。これらの要素番号は4の倍数なので素数候補からはずし た。
4)「5以外の5の倍数」の要素番号の要素に0を代入する。すなわち sieve[10],seive[15],seive[20],....に0を代入。これらの要素番号は5の倍数なので素数候補からはず した。
 :
これを繰返して,999まで行って,1が残った要素が素数である。そして次のように表示できたらOK。
すこし工夫すると作業量が減少する。

実行例

  2   3   5   7  11  13  17  19  23  29
 31  37  41  43  47  53  59  61  67  71
 73  79  83  89  97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349
353 359 367 373 379 383 389 397 401 409
419 421 431 433 439 443 449 457 461 463
467 479 487 491 499 503 509 521 523 541
547 557 563 569 571 577 587 593 599 601
607 613 617 619 631 641 643 647 653 659
661 673 677 683 691 701 709 719 727 733
739 743 751 757 761 769 773 787 797 809
811 821 823 827 829 839 853 857 859 863
877 881 883 887 907 911 919 929 937 941
947 953 967 971 977 983 991 997
168 primenumbers are found.