joho1-2016の日記

情報処理実習1の解説ブログです.皆さんが課題を解く時の助けになれば幸いです.

第12回 構造体と共用体

以下,5組の課題のヒントです.

5組

 各課題のヒントの前に,学生の皆さんがプログラムを書いている姿を見て気になった事があるので,それについて言及したいと思います.
あくまで個人的な意見ですので,少し長くC言語プログラムに触れている先輩からのアドバイス程度に捉えて下さい.

皆さんが課題を解くとき,以下の手順でやっていくと思います.

  1. プログラムを書き,保存
  2. コンパイル
  3. 実行

このうち,問題を1問解くときに1~3の手順を何回繰り返していますか?
本講義が始まって間もない頃は,1つのプログラムで書くコードはシンプルで短いものが多かったので,上記手順を1回だけやって終わったと思います.しかし,最近はどうでしょう?1問につき,複数個の課題(例えば,ファイルを開いて,表示して,文字を種類毎にカウントする,等)がありますよね.このような問題を解くのに,一気にプログラムを書いてしまってから,コンパイルと実行が1回だけで果たして大丈夫でしょうか?もちろん,それでコンパイルが通り,実行結果もうまく表示されているのなら何も言うことはありません.
しかし,もしコンパイルエラーが起こったらどうでしょう?コンパイルは通ったものの,実行結果が期待したものでは無かった場合はどうでしょう?
一体プログラムコードのどこに間違い(バグ)があるのか,見つけられますか?

このような事態にならないようにするために,皆さんにはコンパイルと実行はこまめに行って欲しいです.
今回の課題1を例に考えてみます.

1.このファイル document.txt に書かれた文章を,まずそのまま画面に表示し, その後に,同文章を構成するアルファベット,数字,記号の個数を表示せよ. なお,英文字は大文字と小文字は区別せずにカウントすること.

//実行例
Ubuntu is a Debian-based Linux operating system,
with Unity as its default desktop environment.
It is based on free software and named after
the Southern African philosophy of ubuntu (literally, "human-ness"),
which often is translated as "humanity towards others" or
"the belief in a universal bond of sharing that connects all humanity".
...........


a は 153 個ありました.
b は  37 個ありました.
c は  76 個ありました.
d は  62 個ありました.
e は 217 個ありました.
...........

この課題は,問題文を読んだだけでも,

  • ファイルの中身を画面に表示
  • 文章を構成するアルファベット,数字,記号の個数を表示

の2つがやるべき事としてありますね.こういった場合,まずはファイルを読み込んで表示するところまでコードを書き終えたら,コンパイルをして実行してみます.ここまでうまく実行できている事が確認できれば,もし後半の個数を表示するところまで書き終えてコンパイル・実行した時にうまくいかなくても,前半部分がうまく機能している事は確認できているので,ダメな部分は後半書いたコードのどこかに絞れるわけです.このようにこまめにコンパイル・実行をする事で,一見無駄に時間をかけているように思えても,結果的には効率的にプログラムコーディングが出来るのです.騙されたと思って,ぜひ一度試してみてください!

 では,課題のヒントに入ります.

課題1の問題文は上で記述しているので,省略します.この課題のポイントは,
 ①ファイルの中身を読み込んだ際の処理
 ②アルファベット,数字,記号のカウント方法
です.①に関しては,もし表示するだけならfgetc( )やfgets( ),fscanf( )をそのままprintf関数で表示するだけでいいですが,今回は文章中の文字についてカウントする処理が②にあります.なので,文字列(char型の配列)に代入しておくのが良いでしょう.
②に関しては,①で文章を格納した文字列に対して,繰り返し処理でアルファベット,数字,記号のそれぞれどれに属するのかを1文字ずつ条件判定させていき,個数をカウントする変数をprintf関数で表示させると,この問題は解決です.

2.以下のリンクからテキストファイルinputdata.txtをダウンロードせよ.
このファイルを読み込み,一行ごとの数値(5個のデータ)の平均値を行の最後に追加し,別のファイルに書き込むプログラムを作成せよ.
出力するファイル名は,outputdata.txt とする.

【ヒント】上記ファイルには,1行に5個の数値データが格納されている.今回は,データ個数が事前に分かっているとしてよい.
【ヒント】最初に画面に表示するようにプログラムをつくり,うまく出来るようになったら同じ内容をファイルに書くようにすれば比較的短時間でできる.

この課題のポイントは,
 ①ファイルの中身を読み込んだ際の処理
 ②代入する配列のサイズ
です.課題1と同様,読み込んだファイルの中身をただ表示するわけではないので,①に関して,配列に代入した方が良いでしょう.
②に関して,用意する配列の要素数はどうするべきでしょう?ヒントの通り,1行5個のデータ個数だから,要素数も5個で良いでしょうか?問題文を見ると,「一行ごとの数値の平均値を行の最後に追加」とありますね.それなら,初めから6個分(読み込むデータ個数+1個)の要素数の配列を宣言するのが良いかと思います.

3.このファイルは test_result.csv 内には,各行に生徒の名前と3科目のテストの点数がカンマ( , )区切りで記述されている.
このファイルの中身を読み取り,各生徒の合計点数を算出してその値が大きい順に並べてファイル test_rank.csv に出力するプログラムを作成せよ.
ヒント:fscanf関数を用いて1行分のデータを読み込むには,ファイル内のデータに合わせて書式指定文字列に,"%s,%d,%d,%d" を使用すればよい. (test_rank.csvの各行に,名前と合計点をカンマ区切りで記し,最後の行に平均点を追加すること.)

//出力ファイルの中身
Yuma,285
Alicia,276
Clarice,274
Jean,273
《中略》
Flora,214
Elena,206
Kate,165
average,247.13

この課題のポイントは,
 ①fscanf関数を使う際の代入する配列
 ②合計点数の大きい順に並び替え
です.課題1,2でも処理したように,この問題でもやはりファイルの中身を読み込む時に代入する配列を用意するのが適当です.しかし,今回は1列目が文字列,2列目以降は整数と,型が違うため,配列1つでは足りません.それぞれに対応した配列を用意しましょう.②に関して,これまでも並び替えを行うswap関数を自作したと思います.そのため,詳しい処理は省きますが,並び変えるのは名前の配列と合計点の配列の2つがあるので注意しましょう.

4.ファイル lyrics.txt を読み込み,"*iller"が含まれる行全体だけを抜き出して表示するプログラムを作成せよ(*は任意の文字).

//出力の例
'Cause this is thriller, thriller night
You know it's thriller, thriller night
You're fighting for your life inside a killer, thriller tonight
・・・

この課題のポイントは,
 ①"*iller"を含む行の判定
です.この課題は行単位で判断していけばいいので,読み込みにはfgets( )を使えば良いと思います.そして①に関して,1文字ずつ判定するのも悪くはないのですが,どうせなら文字列処理関数の中の検索できる関数を使いましょう!どんな関数があるのかは,「C言語 文字列処理関数」で検索してみよう.