Copyright(C) 16Jan2003 coskx
このページでは「配列」と「文字・文字列」について解説する。
ここで修得して欲しい内容は以下の通りである。
1.配列の宣言の仕方を修得する。
2.配列を使用することのメリットを理解する。
3.forなどの繰返しで配列要素を順に操作する方法を理解する。
4.配列ぼ大きさ(要素数)と要素番号の関係を理解する。
5.ソートのアルゴリズムを追跡できる。(バブルソート,単純ソート)
6.文字が文字コードで内部表現されていることを理解する。
7.文字列の構造(終端に'\0')を理解する。
8.二次元配列のイメージと表現方法を理解する。
4.1.1 配列を利用しない場合の例
複数の身長の平均値を求めることを考えてみよう。これまでの知識では次のようになる。
(身長データはプログラム中で定められていて変更できないが,scanfを使えば,身長データを実行時に設定することが可能である。)
ところで,この例では5名の身長データを扱ったが,1000名のデータを扱おうとしたら,1000個の変数が必要になってします。
List 4.1.1 平均値の計算プログラムと実行結果 |
#include <stdio.h> int main() |
4.1.2 配列を利用した例
もし次のようにひとつの変数名で,内部にたくさんの部屋を持つ変数が使えたら都合がよい。
各部屋は部屋番号がついていて,部屋番号を指定してデータを保存できるようにしたい。
あったらいいなプログラムの一部 |
height[0]=173.2; /*cm*/ |
この例では変数名「height」は,1つの名前しか持たないが,内部に値を格納するための複数の部屋を持っている変数として使われている。そして0から4までの部屋番号を持っている。
このように内部に値を格納する複数の部屋を持っている変数は「配列」と呼ばれている。また個々の部屋のことは「要素」または「配列要素」と呼ばれ,0から4までの部屋番号のことは,「配列要素番号」または単に「要素番号」と呼ばれる。
変数宣言部で
double height[5];
のように書けば,内部に5つの部屋を持つdouble型配列変数
height が宣言される。
(配列要素数5のdouble型配列変数
height と表現される。)
5つの部屋の部屋番号は0号室から4号室である。5号室は存在しないことに注意しよう。
(このことは配列要素番号は0から4であると表現される。)
この配列を利用してList 4.1.1を書き直してみよう。
List 4.1.2 平均値の計算プログラムと実行結果 |
#include <stdio.h> |
配列 double height[5]; が宣言されたときの配列のイメージ(要素番号が0から始まっている)
(未使用と言っても0が入っているとは限らず,何らかの意味不明の値が入っている。)
要素番号
(部屋番号)
0
1
2
3
4
格納されている値
未使用
未使用 未使用 未使用 未使用
このままではあまり「ごりやく」を感じない。さらに要素番号を変数iで与えるように書き直して,
変数の初期化(最初の値の代入)を宣言の時に行なうと次のようになる。
List 4.1.3 平均値の計算プログラムと実行結果 |
#include <stdio.h> |
説明 |
for
(i=0;i<5;i++) { |
追加説明 |
double height[5]={ |
配列
double height[5]={
173.2,
168.5, 178.1, 183.7, 164.2
};
が宣言されたときの配列のイメージは次のようになる。
要素番号
(部屋番号)
0
1
2
3
4
格納されている値
173.2 168.5 178.1 183.7 164.2
配列
double height[]={
173.2,
168.5, 178.1, 183.7, 164.2
};
が宣言されたときの配列のイメージは,上と同じになる。
配列
要素番号
(部屋番号)
0
1
2
3
4
格納されている値
173.2 168.5 178.1 183.7 164.2
double height[10]={
173.2,
168.5, 178.1, 183.7, 164.2
};
が宣言されたときの配列のイメージ (未使用の部屋には何らかの意味不明の値が入っていると考えていたほうが安全。)
要素番号
(部屋番号)
0
1
2
3
4
5
6
7
8
9
格納されている値
173.2 168.5 178.1 183.7 164.2 未使用 未使用 未使用 未使用 未使用
追加説明
例えば変数宣言部で
double height[1000];
のように宣言すると,heightという変数は1000個の要素(部屋)を持つ変数ということになる。
配列要素には番号が付いていて,「第0要素」「第1要素」「第2要素」......「第998要素」「第999要素」という
1000個の要素となっていて,それぞれの要素がdouble型の変数になっている。
配列要素番号は,「第1要素」から「第1000要素」ではなく,「第0要素」から「第999要素」になっていることに
注意すること。
行ないたいこと
C言語での記述
「第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号室)」に格納したい scanf("%lf",&height[799]); height[0],height[1],height[2],... の1つ1つのことを配列heightの要素といい,0,1,2...を要素番号という。
1000は配列heightの要素数という。
注意
height[1000]=160.0;
は「1000号室」に160.0を代入しようとしているが,
この例では「1000号室」が存在しないので誤りである。
4.1.3 配列の活用
配列にデータが入っていると,最大値,最小値も簡単に求められる。
先頭データを最大値,最小値の候補にしておき,ループ中でよりふさわしい候補が見つかったら候補を入れ替える作業を行ない,すべてのデータについてこの作業が終了すると,最大値,最小値が見つかる。
List 4.1.4 平均値の計算と最大最小を求めるプログラムと実行結果 |
#include <stdio.h> |
プログラミング時に正確なデータ数がわかっていない場合のプログラミング
複数の身長データをキーボードから入力する。プログラミング時にはデータ数は100未満であることしかわかっていないとする。
負の数が入力されたら,その値は身長データとしては扱わず,入力の終わりを意味する約束にしておく。
実行例ではデータ数は5である。
List 4.1.5 キーボード入力値の平均値の計算プログラムと実行結果 |
#include <stdio.h> |
4.1.4 配列利用上の注意(不幸なエラーに落ち込む前に)
配列の要素数を無視したプログラムではどうなるか考えてみよう。
List 4.1.6 配列の要素数を無視した配列の読み出し このプログラムは,文法に反していないので,コンパイル時にはエラーにならない。 しかし,array[5],array[6]は存在していないが,変な値が表示される。 この変な値は,その変数が使用中のメモリーの使用状況に依存するため,いつも同じ値が表示されるとは限らない。 |
#include <stdio.h> |
List 4.1.7 配列の要素数を無視した配列の書き込み(その2) |
#include <stdio.h> |
List 4.1.8 配列の要素数を無視した配列の書き込み (その2) このプログラムは,文法に反していないので,コンパイル時にはエラーにならない。 |
#include <stdio.h> |
配列に関する大事な注意事項
配列のサイズを超える番号の配列要素に対する操作は,コンパイル時にはエラーにならないが,実行時に誤った実行結果を得たり,予期せぬ重大な事態が起きたりする。 |
(1)20点満点の英単語テストの得点データが10人分あり,これがint型配列score[10]に次のように格納されているものとする。
int score[10]={15,8,12,18,20,20,9,16,20,17};
これを用いて,次のように棒グラフに表すプログラムを作りなさい。 (p04ex01.c)
次の実行結果をコピー&ペーストでエディタに貼り付けて,スペースの数をよく見て,同じ表示になるようにプログラミングします。
ヒント
<<実行結果>>
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[12]に次のように格納されているものとする。 (p04ex02.c)
int
numberofdays[12]={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 ソートのプログラム |
#include <stdio.h> int main() |
補足説明 |
if (height[0]<height[j]) { |
List 4.2.2 ソートのプログラム |
#include <stdio.h> int main() |
動作理解や動作が思い通りでない時,プログラム中にprintfを使って検査したい変数値を表示させることがある。
これをスナップショットと呼ぶが,この方法で二重ループ中のiとjを表示してみよう。
List 4.2.3 ソートのプログラム中の二重ループでスナップショット |
#include <stdio.h> int main() |
もうすこし,詳しくスナップショットを入れてみよう。実行結果の流れを見て,自分の理解が正しいかどうかチェックしなさい。
List 4.2.4 ソートのプログラム中の二重ループでスナップショット |
#include <stdio.h> |
練習4.1 |
List 4.2.5 自力追いかけプログラム | |
#include <stdio.h> int main() |
このソートは |
補足説明
配列を他の配列にコピーする場合は要素ごとにすべての要素をループを使ってコピーしなければならない。
List 4.2.6 配列を他の配列にコピーする場合 #include <stdio.h>
int main()
{
int a[4]={3,5,7,9};
int b[4];
int i;
for (i=0;i<4;i++) b[i]=a[i];
for (i=0;i<4;i++) printf("%d %d %d\n",i,a[i],b[i]);
return 0;
}
/********************* 実行結果 ********************
0 3 3
1 5 5
2 7 7
3 9 9
****************************************************/注意 次のような記述は出来ない
b=a; のように記述しても配列全体の代入はできない。
この点がC言語の弱点である。
b[4]=a[4]; のように記述しても配列全体の代入はできない。
aの部屋番号4の格納値をbの部屋番号4へ代入するという意味になってしまう。
そもそも,配列要素は0~3までしかない。
(3)次の配列を小さい順に並べて表示しなさい。(p04ex03.c)
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
}並べ替え前の様子と並べ替えた後の様子をよくわかるように下に示すように表示しなさい。
ただし,得られた実行結果は,値10個ごとに改行しなさい。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」とも表現される。
プログラム中で16進法表示を書くときは,「0x」を前につける。(例えば、0x48,0x65,0x6C...)
まずint型変数にこれらの文字コードを代入し,表示するプログラムを作ってみよう。
List 4.3.1では,int型の変数a,b,cを書式を%d,%x,%cのように変えながら表示している。
%xは十六進法表示で,%cは変数値を文字コードと考え,その文字コードが表す文字を表示しているのがわかる。
List 4.3.1 文字の扱い |
#include <stdio.h> int main() { int a=67; int b=65; int c=84; printf("%d %d %d\n",a,b,c); printf("%x %x %x\n",a,b,c); printf("%c %c %c\n",a,b,c); return 0; } |
実行結果 |
67 65 84 43 41 54 C A T |
List4.3.2ではint型の変数a,b,cに値を十六進法表示で設定している。
printfの表示は,List 4.3.1とまったく同じになることがわかる。
List 4.3.2 文字の扱い |
#include <stdio.h> int main() { int a=0x43; int b=0x41; int c=0x54; printf("%d %d %d\n",a,b,c); printf("%x %x %x\n",a,b,c); printf("%c %c %c\n",a,b,c); return 0; } |
実行結果 |
67 65 84 43 41 54 C A T |
List 4.3.3 文字の扱い |
#include <stdio.h> int main() { int a='C'; int b='A'; int c='T'; printf("%d %d %d\n",a,b,c); printf("%x %x %x\n",a,b,c); printf("%c %c %c\n",a,b,c); return 0; } |
実行結果 |
67 65 84 43 41 54 C A T |
List 4.3.4 文字の扱い |
#include <stdio.h> int main() |
補足説明 |
printf("%c",yy[i]); で「%c」は変数yy[i]の値を文字コードに見立てて, その文字コードに対応する文字を表示するという意味になる。 文字コードをint型配列に格納するというのは通常は行なわれない。 これはテストプログラムである。まねをしないこと。 文字コードはchar型配列に格納するのが普通である。 |
文字コード表の文字は32から126の数値で出来ているので,1バイト(=8ビット)あれば格納できる。
そのため,文字コードを格納するにはint型変数ではなくchar型変数が用いられる。
どちらも整数を保存できるが,char型変数を使う方がメモリを節約できるからである。
今後は文字コードを保存するためにはchar型変数を使うこととする。(文字コードは整数である)
char型変数でもint型変数と同じようにforループのカウンタ変数になれる。すなわち
char ch;
for(ch=0x30; ch<0x39; ch++) のように使うことができる。
chをchar型変数として;
ch=65;
ch=0x41;
ch='A';
はすべて同じ意味となる。(文字コード表参照)
'A'のような表現は文字定数と呼ばれる。文字定数はint型の値で内部では文字コードになっている。
文字は「'(シングルクォーテーション)」で囲む。
0x41は16進法の41のことであり,'A'と書いたら65あるいは0x41と書いてあるのと同じである。
同様に
if (ch==65) {
if (ch==0x41) {
if (ch=='A') {
は同じ意味を表す。(文字コード表参照)
また
ch=0x48;
printf("%d %x %c\n",ch,ch,ch); (同じ値を10進法,16進法,文字として表している。)
では「72 48 H」が表示される。(文字コード表参照)
「%x」は整数を16進法で表示する書式である。
コンピュータは,変数に保存されている整数値に関して,整数なのか文字コードなのかは理解していない。
書式指示によって値として扱ったり,文字として扱ったりする。
練習4.2 |
List 4.3.5 自力追いかけプログラム | |
#include <stdio.h> |
|
数値と数字の違い (試験でよくある間違え) |
char ch; ch='6';はch=0x36;またはch=54;と同じになる。 |
数値と数字の違い (ちょっとした工夫) |
(1)数字→数値 (2)数値→数字 (3)文字コードが数字を表しているかどうかの検査 「chが数字文字を表していないなら・・・・」は |
(4)char型変数xを用い,xの値を65から74まで変化させ,
printf(" %c [%2x]\n",x,x)
を用いて部分文字コード表を作りなさい。(p04ex04.c)
ヒント char型変数であっても,for (ch=0x41; ch<=0x4a; ch++) のようにforループを作ることができる。
次のような実行結果が得られるようにしなさい。
A [41]
B [42]
C [43]
D [44]
E [45]
F [46]
G [47]
H [48]
I [49]
J [4a]
(5)char型変数xを用い,xの値を48から57まで変化させ,
printf(" %c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。ただし,改行位置を工夫し,1行に4データを表示しなさい。(p04ex05.c)
(6)char型変数xを用い,xの値を32から126まで変化させ,
printf(" %c [%2x]",x,x)
を用いて部分文字コード表を作りなさい。ただし,改行位置を工夫し,1行に8データを表示しなさい。(p04ex06.c)
4.4 文字列 |
---|
C言語には文字列型変数というのはないので,文字列はchar型の配列に格納する。
文字列は一単語のみで出来ているとは限らない。
printfで文字列を出力するには「%s」の書式を用い,char型の配列の名前を書く。
puts(char型の配列)でも文字列を表示出来る。この時は自動的に改行される。
List 4.4.1 文字列の出力 |
/*文字列の出力*/ |
文字列は「"(ダブルクォーテーション)」で囲む。
(文字は「'(シングルクォーテーション)」で囲んだ。)
文字列の入力はgetsを用いる。ただし入力される文字数より大きな要素数の配列を用意しておかなければならない。
文字列の末尾には最終文字の後に「おわりのしるし」の0('\0'とも表現される)が格納されている。
この文字列の末尾の決まりを用いると,文字列のコピーが出来る。
List 4.4.2 文字列の入出力と文字列のコピー |
/*文字列の入出力と文字列のコピー*/ |
注意 配列のコピーは要素ごとに行なう事になっているので次のような記述は出来ない。 文字列を簡単にコピーする方法は「5.5文字列操作の関数」で述べる。 |
文字列の例を紹介しよう。
配列 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 値 'H' 'e' 'l' 'l' 'o' ',' ' ' 'w' 'o' 'r' 'l' 'd' '.' '\0' 未使用 - - - - 未使用
char mystring[20]="Hello,
world.";
は次のように格納されている。
要素
(号室)
比較対照のために単なる文字コード配列では次のようになっている。
char mychararray[20]={
単なる文字コード配列になっており,文字列の終わりのしるし'\0'がないので,次のようなprintfの表現ではうまく出力できない。 しかし |
次に,文字列の逆コピーをしてみよう。
List 4.4.3 文字列の入出力と文字列の逆コピー |
/*文字列の入出力と文字列の逆コピー*/ |
練習4.3 |
List 4.4.4 自力追いかけプログラム ヒント 「mystring[i-3]」と異なり,「mystring[i]-3」は文字コードから3を引いている 文字コード表を参照すること |
|
#include <stdio.h> |
|
文字列についての補足
int型やdouble型の変数へのscanfでの読み込みでは変数の前に「&」を付けていた。
文字列に関してはこの「&」を付けない。
例えば次のようである。
int kk; double xx; char str[300]; scanf("%d",&kk); scanf("%lf",&xx); scanf("%s",str); |
またscanfで文字列を入力した場合,文字列とは一単語のみ(スペース,タブ,改行などで区切られたところまで)が取得される。
コラム 「scanf+%s」と「gets」 |
|||||||||||
「scanf+%s」を用いても「gets」を用いてもキーボードから文字列を入力することができるが,文字列の終わりの判断が異なる。
|
よくある誤り
int kk; 逆に 文字列は「"(ダブルクォーテーション)」で囲む。 |
C言語の文字列の不便さ
変数宣言時ではなく,実行時に文字型配列に文字列を代入したい場合は関数strcpy()を用いる。
C言語の文字列操作は不便なので,「C.ライブラリ関数の説明」 中の「C.4 文字列操作関数」に便利な関数が紹介されており,よく使われる。C言語の関数はまだ学んでいないので,この段階では,便利な命令がある程度の認識でよい。
char str[20]="Hello"; しかし 一般にstrcpy(str1,str2);と書いたら,文字列str2 を文字列str1にコピーするという意味になる. |
文字列の終端を探す場合に良く使われる短縮表現
これまでの表現(List 4.4.2再掲) | 真偽判定では,非0を真,0を偽と判定することを利用して 次のような表現ができる |
/*文字列の入出力と文字列の逆コピー*/ #include <stdio.h> int main() { char mystring[200]; char mystring2[200]; int i,j; printf("文字列を入力してください\n"); gets(mystring); j=0; while (mystring[j]!='\0') { j++; } mystring2[j]='\0'; j--; i=0; while ( mystring[i]!='\0' ) { mystring2[j]=mystring[i]; i++; j--; } puts("あなたが入力した文字列は"); puts(mystring); puts("逆コピーした文字列は"); puts(mystring2); return 0; } |
/*文字列の入出力と文字列の逆コピー*/ #include <stdio.h> int main() { char mystring[200]; char mystring2[200]; int i,j; printf("文字列を入力してください\n"); gets(mystring); j=0; while (mystring[j]!='\0') { j++; } mystring2[j]='\0'; j--; i=0; while ( mystring[i] ) { mystring2[j]=mystring[i]; i++; j--; } puts("あなたが入力した文字列は"); puts(mystring); puts("逆コピーした文字列は"); puts(mystring2); return 0; } |
(7)文字列をgets()で読み込み,その文字列に含まれる文字「e」の数を表示するプログラムを作りなさい。(p04ex07.c)
次の5例で検証し,実行結果の表示はこの例と同じになるようにしなさい。(青字は入力部分を表す。)
<<実行例1>>
keyin string => abcdefg
abcdefg => 1<<実行例2>>
keyin string => eabcdefg
eabcdefg => 2<<実行例3>>
keyin string => abcdefge
abcdefge => 2<<実行例4>>
keyin string => I'm getting closer to my home.
I'm getting closer to my home. => 3<<実行例5>>
keyin string => Tokyo Japan
Tokyo Japan => 0
(8)2つの文字列をgets()を2回使って読み込み,2つの文字列中,先頭の1文字が等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex08.c)
ただし,2つの文字列を構成する文字数はそれぞれ1文字以上である。次の2例を含む5例ほどで検証し,実行結果の表示はこの例と同じにしなさい。 考え方
<<実行例1>>
str1= robot
str2= atom
robot atom => not equal<<実行例2>>
str1= robot
str2= rocket
robot rocket => equal
(9)2つの文字列をgets()を2回使って読み込み,2つの文字列中,先頭の3文字が等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。(p04ex09.c)
ただし,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つの文字列をgets()を2回使って読み込み,2つの文字列が完全に等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex10.c)
ただし,2つの文字列を構成する文字数は等しいとする。次の2例を含む5例ほどで検証し,実行結果の表示はこの例と同じにしなさい。 考え方
<<実行例1>>
str1= robot
str2= robit
robot robit => not equal<<実行例2>>
str1= robot
str2= robot
robot robot => equal
(11)2つの文字列をgets()を2回使って読み込み,2つの文字列が完全に等しかったら,「equal」,等しくなかったら「not equal」と表示するプログラムを作りなさい。 (p04ex11.c)
ただし,2つの文字列を構成する文字数は等しいとは限らない。次の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.c)
ただし2Jの学生の出席番号だったら「correct」,そうでなかったら「incorrect」と表示すること。番号は1から49までを正当とする。また2J1は正当とは認めず2J01を正当とする。
またプログラムへの入力と判定結果の出力は連続して出来るようにし,文字列「zzzz」が入力されたら,プログラムが終了するものとする。
以下の例でプログラムの動作を検証し,実行結果の表示はこの例と同じにしなさい。 考え方2014.10加筆
実行の様子(必ずここに書いてある文字列 による実行結果をつけること) |
2Jの出席番号を入力してください
>> 2J01 |
(13)キーボードから入力された文字列に,母音字がそれぞれいくつ含まれているか表示するプログラムを作成しなさい。 (p04ex13.c)
入力される文字列の長さは300文字以下とします。なお大文字小文字は区別しないことにします。
答え合わせを以下のように行ないなさい。ただし,getsを用いると,リターンキーを押すまでが文字列として取り込まれるの
で,長い文章の入力途中でリターンキーを押さないようにする。
実行例(2回) |
文字列を入力してください |
これまでに学習した配列は,例えばプログラムの変数宣言部で
int arry[10]={987,654,321,963,852,741};
なら,配列変数の名前がarryで部屋番号が0号室から9号室(部屋数10)まである「長屋」のような整数型配列であり,最初の6部屋が利用されていて,残りの4室は未使用の状態あった。
部屋番号 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
値 |
987 |
654 |
321 |
963 |
852 |
741 |
未使用 |
未使用 |
未使用 |
未使用 |
値は次のように並んでいる。(使っていない部屋もある)
階番号部屋番号 |
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 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
5 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
6 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
例題として,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.1 3科目の試験結果の処理 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <stdio.h> |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
追加説明 int score[10][4]={ /*英・数・国・(合計)の順の個人得点*/ {86,75,60},{75,68,81},{84,98,100},{87,76,48},{82,58,73}, {100,87,98},{64,72,70},{87,68,99},{98,87,68},{87,72,84} }; は次のような2次元配列になる。
|
char型二次元配列で文字列の配列を作る
複数の文字列を扱う場合は二次元配列になる。例えば変数宣言部で
char strings[5][16]={
"Information","Technology","Programming","Language","Computer"
};
と書いた場合には次のような配列が出来る。この二次元配列は大きさ16のchar型の一次元配列が
5個並んでいると考えられる。
階番号部屋番号 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
0 |
'I' |
'n' |
'f' |
'o' |
'r' |
'm' |
'a' |
't' |
'i' |
'o' |
'n' |
'\0' |
未使用 |
未使用 |
未使用 |
未使用 |
1 |
'T' |
'e' |
'c' |
'h' |
'n' |
'o' |
'l' |
'o' |
'g' |
'y' |
'\0' |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
2 |
'P' |
'r' |
'o' |
'g' |
'r' |
'a' |
'm' |
'm' |
'i' |
'n' |
'g' |
'\0' |
未使用 |
未使用 |
未使用 |
未使用 |
3 |
'L' |
'a' |
'n' |
'g' |
'u' |
'a' |
'g' |
'e' |
'\0' |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
4 |
'C' |
'o' |
'm' |
'p' |
'u' |
't' |
'e' |
'r' |
'\0' |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
未使用 |
二次元配列においても,文字列終端は'\0'なのでList4.5.2内の表示方法test1のような表現が最初に思い浮かぶであろう。
test2,3のように文字列の場合は二次元配列なのだけれども表示する時に文字列の一次元配列のような扱いになる。
これは,stringsが大きさ16のchar型の一次元配列が5個並んでいることに起因する。
string[i]は,大きさ16のchar型の一次元配列のi番目(i番目の文字列)という意味になるからである。
List 4.5.2 複数文字列の扱い |
#include <stdio.h> |
課題 4 その5 |
---|
<<実行例1>>
number = 1
1: Sunday<<実行例2>>
number = 3
3: Tuesday
(15)次の動作を行なうプログラムを作成しなさい。整数型の配列(配列要素の数を50としなさい)を宣言し,繰返し処理を用いて,要素の先頭から
1,4,9,16,25,36,49,64,81,...を格納しなさい。そして,先頭から,1つおきに,配列要素を画面に表示しなさい。(1 9 25 ...となる)
(p04ex15.c)
(16)次のプログラムを作りなさい。(p04ex16.c)
int型配列testdata[20]を宣言し,すべての要素に0を代入しなさい。
次に要素番号が「0と2を除く2の倍数」になっている要素すべてに1を代入しなさい。
(ヒント) for (i=2*2;i<20;i=i+2)
testdata[i]=1;
そしてすべての要素の値を表示しなさい。表示にあたっては次の2行を用いなさい。
for(i=0;i<20;i++) printf("%d",testdata[i]);
printf("\n");
(17)次のプログラムを作りなさい。(p04ex17.c)
int型配列testdata[20]を宣言し,すべての要素に0を代入しなさい。
次に要素番号が「0と2を除く2の倍数」になっている要素すべてに1を代入しなさい。
(ヒント) for (i=2*2;i<20;i=i+2)
testdata[i]=1;
そして要素番号が「0と3を除く3の倍数」になっている要素すべてに1を代入しなさい。
(ヒント) for (i=3*2;i<20;i=i+3)
testdata[i]=1;
最後にすべての要素の値を表示しなさい。表示にあたっては次の2行を用いなさい。
for(i=0;i<20;i++) printf("%d",testdata[i]);
printf("\n");
(18)次の手順で「エラトステネスのふるい」を用いて2から1000までの素数を見つけ,表示するプログラムを作成しなさい。
またいくつ見つかったかも表示しなさい。
(p04ex18.c)
(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。
すこし工夫すると作業量が減少する。
なお,表示方法は次の実行例にならって,素数10個ごとに改行し,最後に見つかった素数の数を表示しなさい。
実行例 |
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 prime numbers are found. |