C プログラミング (C Programming)

[2020/07/04, H.Aman]

[13] ファイル処理 演習課題

〆切は 7/10(金)14:10 です.

  • 演習 1

    サンプルプログラム①を 別名(ex01.c)にコピーし, 次の指示に従って編集して数当てゲームを作りなさい:
    • データファイルに書いてあった整数(x とする)は表示させない
      代わりに次の操作(1),(2)を do - while 文で繰り返す
      繰り返しの条件は x != y とする.
      (1) 整数を一つ(キーボードから)読み込む(これを y とする).
      (2) x と y が等しければ「正解です!」,
          x の方が小さければ「もっと小さいです」,
          いずれでもなければ「もっと大きいです」と表示する.
    • 上の繰り返しでは,整数 y を読み込むたびに,それが何回目なのかも表示させること.
    自分でデータファイルを用意してもつまらないと思うので,乱数を使ってデータを作り出すプログラムをこちらで用意しました. このプログラム(make_data1.c)をダウンロードしてコンパイルし,次のように実行してもらうと適当な値(1 ~ 1000 の間)がファイルへ書き込まれます.
    ※Mac の人は a ではなく ./a.out です.
     a > data1.txt

    入出力例(キーボードからの入力は赤色
     データファイル名を入力してください:data1.txt
     1 回目:整数を入力してください:100
     もっと大きいです
     2 回目:整数を入力してください:150
     もっと小さいです
     3 回目:整数を入力してください:125 
     もっと小さいです
     4 回目:整数を入力してください:115
     もっと大きいです
     5 回目:整数を入力してください:120
     もっと大きいです
     6 回目:整数を入力してください:122
     もっと大きいです
     7 回目:整数を入力してください:124
     もっと小さいです
     8 回目:整数を入力してください:123
     正解です!
  • 演習 2

    サンプルプログラム②を別名(ex02.c)にコピーし,
    等比数列をファイルに書き込むように書き換えなさい.
    ただし,初項と公比は実数項数は自然数とする.
    出力は以下の実行例の形式に従いなさい.
    なお,実数の表示は %f で行うだけでよく,桁数を指定する必要はない.

    入出力例(キーボードからの入力は赤色
     出力先のファイル名を入力してください:data2.txt
     初項,公比,項数を入力してください:100 0.95 5
     data2.txt に初項 100.000000,公比 0.950000 の等比数列(項数 5)を書き込みました
    (上の実行の結果,data2.txt に以下の内容が入る)
     100.000000
     95.000000
     90.250000
     85.737500
     81.450625
  • 演習 3

    サンプルプログラム③を別名(ex03.c)にコピーし,
    次のように動作するプログラムに書き換えなさい:
    • 名前の代わりに文字列(途中に空白は含まない)を入力させる.
    • さらに,整数 n を入力させる(n は 1 以上と仮定してよい).
    • ログファイルへ上で入力された文字列を n 回繰り返し書き込む.
      ただし,繰り返しの際に 文字列と文字列の間には空白を 1 個挟み込み
      最後には改行も書き込む.
      (ヒント) 「空白文字を書き込む」処理と「文字列を書き込む」処理をそれぞれ用意しておいて, これらを n 回繰り返せばよい.ただし,空白文字の書き込みは 2 回目以降のみ実行するよう場合分けが必要である.

    入出力例(実行 1 回目)(キーボードからの入力は赤色
     追加したい文字列(空白無し)を入力してください:####
     繰り返しの回数を入力してください:3
     log.txt に #### を 3 回繰り返して書き込みました
    入出力例(実行 2 回目)(キーボードからの入力は赤色
     追加したい文字列(空白無し)を入力してください:@
     繰り返しの回数を入力してください:5
     log.txt に @ を 5 回繰り返して書き込みました
    (上の 2 回の実行の結果,log.txt に以下の内容が追加される)
     #### #### ####
     @ @ @ @ @
  • 演習 4

    サンプルプログラム④を別名(ex04.c)にコピーし, 次のように動作するプログラムに書き換えなさい:
    • すべての文字を大文字へ変換してコピーする.
    • 全部で何文字コピーしたのかを表示する.
      (空白文字や改行文字等もすべて数えてよい.つまり, fputc の実行回数を数えればよい.)
      文字数はコピー先に書き込むのではなく,実行画面に表示するようにすること.

    入出力例(キーボードからの入力は赤色
     コピー元のファイル名を入力してください:sample4.c
     コピー先のファイル名を入力してください:aaa.c
     aaa.c に sample4.c の内容をすべて大文字にしてコピーしました(820文字)

余裕のある人は

  • 演習 1【発展課題】

    演習 1 で作ったプログラムを別名(ex01e.c)にコピーし,次のように改良しなさい:
    数字を 8 回答えても正解しない場合は,その時点でプレイヤーの負けとして終了させなさい.
    また,正解した時点あるいは負けが決まった時点で(勝敗に関係なくそれまでの履歴を以下の例のように表示させなさい.

    【履歴の出力例】(これより上の部分は演習1 と同様なので割愛する)
     あなたの負けです
     [履歴]
     100 --> 200 --> 150 --> 110 --> 120 --> 140 --> 130 --> 125 --> 121 --> 122
  • 演習 2【発展課題】

    演習 2 で作ったプログラムを別名(ex02e.c)にコピーし,次のように変更しなさい:
    指定されたファイルには,「フィボナッチ数列の各項」と「直前の項との比」を書き込みなさい.
    両者の間はカンマで区切ること(このような形式のデータを CSV という).
    なお,ここでいう「直前の項との比」とは,フィボナッチ数列の第 k 項を f(k) としたときの「f(k)/f(k-1)」を意味する.ただし,k = 1 の場合は未定義とする.(以下の実行例と結果を参照)
    ※この比率は,黄金比 (1+√5)/2 = 1.6180339887... に収束する.

    入出力例(キーボードからの入力は赤色
     出力先のファイル名を入力してください:data2.csv
     出力するフィボナッチ数列の項数を入力してください:10
     data2.txt にフィボナッチ数列(項数 10)と比率を書き込みました
    (上の実行の結果,data2.csv に以下の内容が入る)
     1,------
     1,1.000000
     2,2.000000
     3,1.500000
     5,1.666667
     8,1.600000
     13,1.625000
     21,1.615385
     34,1.619048
     55,1.617647
    上の実行例ではあえてデータファイル名を data2.csvとしていますが,これには意味があります.こうすることで Excel でそのまま開くことができるのです.
    項数 n を大きくして上述の比が黄金比へ収束する様子を Excel でグラフ化してみるといいと思います.
  • 演習 3【発展課題】

    サンプルプログラム③を 別名(ex03e.c)にコピーし,
    ログイン ID とそのアクセス日時(教科書 339 ページを参考)をログファイルに追加するようにしなさい.
    教科書 339 ページでは「構造体」というものとそれへのポインタを使っているため,講義ではまだ扱っていない内容ではあるが,この課題は日時を書き込むだけなので,とりあえず教科書の真似をして書くだけでよいです.

    入出力例(キーボードからの入力は赤色
     ログイン ID を入力してください: a520987z
     log.txt に a520987z のアクセス履歴を書き込みました
    (上の実行の結果,log.txt に以下のような内容が入る)
     a520987z, 2020 年 7 月 6 日 11:02:08
    上の入出力例の続き(2回目の実行)(キーボードからの入力は赤色
     ログイン ID を入力してください:a520988x
     log.txt に a520988x のアクセス履歴を書き込みました
    (上の実行の結果,log.txt の内容は以下のようになる)
     a520987z, 2020 年 7 月 6 日 11:02:08
     a520988x, 2020 年 7 月 6 日 11:07:06
  • 演習 4【発展課題】

    演習 4 で作成したプログラムを別名(ex04e.c)にコピーし,次のように改良しなさい:
    コピー先には行番号(1:, 2: といった具合いに)も付けなさい.
    ただし,行番号の分はコピー文字数には含めないこと.
    (ヒント)行番号を出力するのは毎回「行の先頭」なので, 繰り返しの中で現在の出力位置が「行の先頭」かどうかを判定できればよいことになる.
    一つの方法としては,これから出力しようとしている文字がその行の何文字目に該当するかを数えておき, 改行文字を出力するたびにそのカウントをリセットするとよい.

    入出力例(キーボードからの入力は赤色
     コピー元のファイル名を入力してください:sample4.c
     コピー先のファイル名を入力してください:aaa.c
     aaa.c に sample4.c の内容をすべて大文字にしてコピーしました(820文字)
    (上の実行の結果,aaa.c の内容は以下のようになる)
     1: #INCLUDE 
     2: 
     3: #DEFINE SIZE 256
     4: 
     5: INT MAIN(VOID){
     6:   CHAR FROM_NAME[SIZE];
     7:   CHAR TO_NAME[SIZE];
     8:   INT C;
     9:   FILE *FROM, *TO;
     10: 
     11:   PRINTF("コピー元のファイル名を入力してください:");
     12:   SCANF("%S", FROM_NAME); 
     13:   PRINTF("コピー先のファイル名を入力してください:");
     14:   SCANF("%S", TO_NAME);
     15: 
     16:   FROM = FOPEN(FROM_NAME, "R");
     17:   IF ( FROM == NULL ){
     18:     PRINTF("[エラー] %S を開けませんでした\N", FROM_NAME);
     19:     RETURN 1;
     20:   }
     21: 
     22:   TO = FOPEN(TO_NAME, "W");
     23:   IF ( TO == NULL ){
     24:     PRINTF("[エラー] %S を開けませんでした\N", TO_NAME);
     25:     RETURN 1;
     26:   }
     27: 
     28:   C = FGETC(FROM);
     29:   WHILE ( C != EOF ){
     30:     FPUTC(C, TO);
     31:     C = FGETC(FROM);
     32:   }
     33: 
     34:   FCLOSE(FROM);
     35:   FCLOSE(TO);
     36: 
     37:   PRINTF("%S に %S の内容をコピーしました\N", TO_NAME, FROM_NAME);
     38: 
     39:   RETURN 0;
     40: }
  • 演習 5【発展課題】

    上の発展課題で作成した ex04e.c を別名(ex05.c)にコピーし, コピー元のファイル名とコピー先のファイル名をコマンドライン引数で指定するように改良しなさい.

    入出力例(キーボードからの入力は赤色) ※Mac や Linu 環境の人は a が ./a.out になります.
     a sample4.c aaa.c
     aaa.c に sample4.c の内容をすべて大文字にしてコピーしました(820文字)