b1) 4つの要素を持つdouble型配列にキーボードから数値列を読み込み,合計と平均を求めるプログラムを作成しなさい.
【ポイント】 たとえばint a[N];と宣言した配列は、a[0]からa[N-1]までのN個の要素を持つ。a[N]は存在しないので注意。intでなくても同じ。
int a[10]; a[10] = 3; /* 誤り!! */上記は誤りだが、通常Cコンパイラはこれを検出しない。しかし、実行時に意味不明の挙動を示す原因となるので決してしてはならない。
★b2) キーボードから10個の整数を読み込み,最後に入力とは逆の順番に表示して終了するプログラムを作成しなさい。ループ(forまたはwhile)を使うこと。
★b3) キーボードから10個の整数を読み込んだ後、平均以上の数値と平均未満の数値を別々に分けて表示する(つまり,最初に平均以上の数値だけを並べて表示し,次に平均未満の数値だけを並べて表示する)プログラムを作りなさい。
b4) scanfを用いて,自分の出身地(都道府県など)をローマ字で読み込み,表示するプログラムを作成しなさい。
【ポイント】 文字列の文字配列への読み込みには、%sを用いる。このとき,読み込める最大文字数(配列のサイズ−1)を指定するべきである。
char str[128]; /* 読み込める長さを指定しないやり方 */ scanf("%s", str); /* 読み込める長さを指定したもっと好ましいやり方 */ scanf("%127s", str);
★b5) 文字型の配列を自分の名前のローマ字で初期化し(変数の宣言時に代入し)、その配列中の文字の文字コード(文字番号)を縦に並べて1文字分づつ画面に表示するプログラムを作成しなさい。
【ポイント】 文字列の最後は、ヌル文字('\0': 終端文字)で終わる。よって、文字列を格納するためには、その文字列の長さ+1文字分の領域(charの配列)が必要である。
char str[] = "Tamagawa";の場合、下記のように9文字分の領域を取る。
0 1 2 3 4 5 6 7 8 str[] ['T'|'a'|'m'|'a'|'g'|'a'|'w'|'a'|'\0']
また,C言語における1文字の実態は整数の文字コード(要するに「文字番号」)である。通常使われるASCIIコードでは,A〜Z,a〜zに,それぞれ連続した番号が割り当てられている。例えば上記の例を文字コードで示すと以下のようになる。
0 1 2 3 4 5 6 7 8 str[] [ 84| 97|109| 97|103| 97|119| 97| 0 ]
bx1) キーボードから、double型の配列v[2]およびw[2]を読み込み、これらを2次元ベクトルと考えて、和と内積を表示するプログラムを作成しなさい。
bx2) キーボードから、10個の整数を要素とする配列aと、整数xを読み込み、xがaに含まれているかどうか,aの先頭から順に調べて結果を表示するプログラムを作成しなさい。
i→ →| iを0から9まで変化 0 1 2 3 4 5 6 7 8 9 a[] [__|__|__|__|__|__|__|__|__|__] a[i]とxを比較
bx3) キーボードからアルファベットからなる文字列を読み込み,先頭文字と同じ文字の個数を数えるプログラムを作成しなさい。たとえば,「application」ならばaが2個あるので2が結果となる。
bx4) ROT13暗号とは,欧文に含まれる文字を1文字ずつ,下記の図に示すようにアルファベット順で13文字後ろの文字に“ずらす”ことによって,文章を暗号化するものである。
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G ... A→→→→→→→→→→→→ N H→→→→→→→→→→→→ U N→→→→→→→→→→→→ A Q→→→→→→→→→→→→ D
Aの13文字後はN,HはU,NはA,QはDへと変換され,例えば「HELLO」は「URYYB」と暗号化される。すると,「ABCDEFGHIJKLM」の各文字は「NOPQRSTUVWXYZ」の各文字と交換されることがわかる(小文字は小文字同士で交換)。
キーボードから読み込んだ文字列を,ROT13暗号によって暗号化するプログラムを作成しなさい。また,暗号化された文字列を復号化(元に戻すこと)して,ちゃんと暗号化されていたことを確認しなさい。
【ポイント】 スペースを含む文字列を1行読み込む関数にはgets()があるが,近年ではこれは使わないほうがよい。かわりに,scanf()の書式 %[^\n] を用いるとよい。
char str[128]; scanf("%127[^\n]", str);
bx5) スタックとは、先入れ後出し方式のデータ構造である。データを上に積み重ねていくような形式のデータ構造であり、一番最後に積んだデータを一番最初に取り出すことができる。一番最初に積んだデータは、後から積んだデータを全部取り出さないと、取り出すことができない。 以下のような動作をするプログラムを作成しなさい。
● xを積む(push) ↓ 0 1 2 3 4 5 6 7 8 9 stack [●|●|●|●|●|__|__|__|__|__|.... ↑ 次の空き(sp) 0 1 2 3 4 5 6 7 8 9 stack [●|●|●|●|●|●|__|__|__|__|.... ↑ 次の空き(1増えたsp)
次の空き(sp) ↓ 0 1 2 3 4 5 6 7 8 9 stack [●|●|●|●|●|●|__|__|__|__|.... ↓ 取り出す(pop) 次の空き(1減ったsp) ↓ 0 1 2 3 4 5 6 7 8 9 stack [●|●|●|●|●|__|__|__|__|__|.... ↓ ●
なお、スタックにデータをしまう操作をpushといい、データを取り出す操作をpopという。また、スタックの中の次の空き位置(または現在の最後の位置)を保存する変数spをスタックポインタという。
以下のbz1)とbz2)の好きなほうを解きなさい。もちろん両方解いてもよい。
bz1) トランプゲームのブラックジャック(簡略版)を作成したい。以下の手順で動作するプログラムを作成しなさい。
準備
int cards[52]; /* トランプのカード52枚を格納する配列 */ int player[10]; /* プレイヤーの手札 */ int dealer[10]; /* コンピュータの手札 */ int n_drawn; /* 既に束から引いたカードの枚数 */ int n_player; /* プレイヤーの手札の枚数 */ int n_dealer; /* コンピュータの手札の枚数 */
n = 0; for (i = 1; i <= 13; i++) { cards[n++] = i; cards[n++] = i; cards[n++] = i; cards[n++] = i; }
/* rand()使用前に1度だけ実行 */ srand((unsigned) time(NULL)) for (i = 0; i < 300; i++) { n = rand() % 52; m = rand() % 52; temp = cards[n]; cards[n] = cards[m]; cards[m] = temp; }
ゲーム
bz2) az1)の戦闘プログラムを改良して,複数対複数で戦えるようにしなさい。とはいっても,いきなり“乱戦”を実現するのは難しいので,柔道の団体戦のように1人ずつ順番に対戦する勝ち抜き戦を実現しなさい。
... 味方2 味方1 味方0 →×← モンスター0 モンスター1 モンスター2 ...
主人公たちは,狭い洞窟の通路を,たいまつを灯しながら1列になって進んでいる。そのとき,前方から咆哮が聞こえ,凶暴なモンスターのグループが襲ってきた!
前回同様,乱戦に対応させるなど,これも改良自由である。