練習 [13] ファイル処理(5/5)

練習 5(提出プログラム名:p1305.c)※必須ではない

この練習問題は必須ではない(提出しなくてもよい)が適切に解けていれば加点の対象とする.

練習 4 で作成したプログラム(p1304.c)を p1305.c という別名のファイルにコピーしなさい.
そして,p1305.c を編集して,次の 2 点を変更・追加しなさい:

(1)コピー元とコピー先のファイル名を scanf で読み込むのではなく
  コマンドライン引数で指定するかたちに変更しなさい.

(2)コピー先には(実行例のように)行番号も書き込むようにしなさい.
  (桁数は特に気にしなくてもよいが,"%3d: " といった書式にしておくと揃えやすい)
  なお,行番号の出力部分はコピー文字数には含めないものとする.

【注意】
例年,上記の(1)と(2)の一方だけしか実現していないのに提出するというミスが見られるので,
自分が該当することのないよう注意せよ.

【ヒント1】コマンドライン引数の使い方
まず,main 関数を
  int main(int argc, char *argv[])
と書いて始めるようにするとコマンドライン引数が使えるようになります.
そして,gcc でコンパイルした後,実行する際に
  a sample4.c aaa.c
として実行した場合(Mac の人は a ではなく ./a.out),
argc には自動的に 3 (実行コマンドも含む個数)が格納されます.
さらに argv[1]"sample4.c" に,argv[2]"aaa.c" になります.
したがって,例えば
  fopen(argv[1], "r")
でもって "sample4.c" を読み出しモードでオープンできます.
こうすることで scanf を使っていちいちファイル名を読み込む必要が無くなります.

【ヒント2】行番号の付け方
行番号を書き込むのは常に「その行の先頭」部分なので,
  これからファイルへ書き込もうとしている文字
  その行の先頭文字ならば先に行番号を書き込む
という処理にしておくとよいでしょう.
例えば,その行での出力文字数をカウントするための変数を用意しておいて,
改行文字('\n')を出力するたびに 0 にリセットすることにしておきます.
そうすれば,その変数の値が 0 の時だけ特別に行番号を出力するようにしておくと
目的を達成できます.

  • 【プログラムの実行例】(その1)赤字は実行時にキーボードから入力する内容
    ※ Mac 環境の人は a./a.out になります.
a sample4.c aaa.c
aaa.c に sample4.c の内容をすべて大文字にしてコピーしました(842文字)

【実行例を実行後の aaa.c の内容;行番号を “%3d: ” で表示した場合】
  1: #INCLUDE <STDIO.H>
  2: #DEFINE SIZE 256
  3: 
  4: INT MAIN(VOID)
  5: {
  6:     CHAR FNAME[SIZE], TNAME[SIZE];
  7:     INT C;
  8:     FILE *FROM, *TO;
  9: 
 10:     PRINTF("コピー元のファイル名を入力してください:");
 11:     SCANF("%S", FNAME);
 12:     PRINTF("コピー先のファイル名を入力してください:");
 13:     SCANF("%S", TNAME);
 14: 
 15:     IF ((FROM = FOPEN(FNAME, "R")) == NULL)
 16:     {
 17:         PRINTF("[エラー] %S を開けませんでした\N", FNAME);
 18:         RETURN 1;
 19:     }
 20: 
 21:     IF ((TO = FOPEN(TNAME, "W")) == NULL)
 22:     {
 23:         PRINTF("[エラー] %S を開けませんでした\N", TNAME);
 24:         RETURN 1;
 25:     }
 26: 
 27:     C = FGETC(FROM);
 28:     WHILE (C != EOF)
 29:     {
 30:         FPUTC(C, TO);
 31:         C = FGETC(FROM);
 32:     }
 33: 
 34:     FCLOSE(FROM);
 35:     FCLOSE(TO);
 36: 
 37:     PRINTF("%S に %S の内容をコピーしました\N", TNAME, FNAME);
 38: 
 39:     RETURN 0;
 40: }
※末尾に “41:” が表示されて終わっても問題ないです(41: が表示されてもされなくても,どちらも正解とします)

【過去にあったミス(減点となり,やり直しを命じられる)】
上に示した実行例を確認せずに提出してしまっている.
 (例1)行番号が適切に出力されていない.
 (例2)コピーした文字数が違っている.
インデントに不備がある(VSCode 上でインデントを自動で揃える作業をやっていない).


第13回(Cプログラミング;3 限目の方)の練習問題は以上の5問です.
p1301.c ~ p1305.c を Moodle から提出してください.※ただし,p1305.c は必須ではないです.
くれぐれも各問題で記載されている注意事項や「過去にあったミス」を見落とさないようにしてください.
なお,コンパイルエラーや無限ループになるプログラムを 1 個でも提出した場合は総合評価を 0 点とするので十分に注意すること.
なお,提出後に間違いに気付いた場合,〆切前であれば差し替え(上書き)は可能です.