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

練習 4(提出プログラム名:p1204a.c)

練習 3 で作成したプログラム(p1203a.c)を p1204a.c という別名のファイルにコピーしなさい.
そして,p1204a.c を編集して,コピー元とコピー先のファイル名をコマンドライン引数で指定するかたちに変更しなさい.
さらに,コピー先には(実行例のように)行番号も書き込むようにしなさい.
(桁数は特に気にしなくてもよいが,"%3d: " といった書式にしておくと揃えやすい)
なお,行番号の出力部分はコピー文字数には含めないものとする.

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

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

  • 【プログラムの実行例】赤字は実行時にキーボードから入力する内容
    ※先の sample1203a1.c を使った場合
    ※ Mac 環境の人は a./a.out になります.
a sample1203a1.c aaa.c
aaa.c に sample1203a1.c の内容をすべて大文字にしてコピーしました(501文字)
【実行例を実行後の aaa.c の内容;行番号を “%3d: ” で表示した場合】
  1: #INCLUDE 
  2: 
  3: #DEFINE SIZE 20
  4: 
  5: VOID STRING_COPY(CHAR *TO, CHAR *FROM)
  6: {
  7:   INT I;
  8: 
  9:   I = 0;
 10:   WHILE (FROM[I] != '\0')
 11:   {
 12:     TO[I] = FROM[I];
 13:     I++;
 14:   }
 15:   TO[I] = '\0';
 16: }
 17: 
 18: INT MAIN(VOID)
 19: {
 20:   CHAR A[SIZE], B[SIZE];
 21: 
 22:   PRINTF("文字列(空白無し)を 1 つ入力してください:");
 23:   SCANF("%S", A);
 24: 
 25:   STRING_COPY(B, A);
 26:   PRINTF("コピーした文字列:<%S>\N", B);
 27: 
 28:   STRING_COPY(B, &A[1]);
 29:   PRINTF("1 文字ずらしてコピーした文字列:<%S>\N", B);
 30: 
 31:   RETURN 0;
 32: }
※末尾について “33:” が表示されて終わっても問題ないです(33: が表示されてもされなくても,どちらも正解とします)

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


ミスが無いことを確認したら次の問題へ → [ 練習 5 (p1205a.c) ]