プログラミングについては初心者です;
先日質問した課題の答えを教えてもらったのですが、
その内容が理解できません。ぜひ教えてください
(問題)
あるファイルの内容を書き換えるプログラムを作成します.
前問で作成したファイル "sample.txt" を読み取り,その各行に行番号を付けて再び "sample.txt" に出力するプログラム bango.c を作成しなさい.例えば "sample.txt" の中身が
Hello world.
Good morning.
であれば,bango.c をコンパイル/実行した結果,同じファイル "sample.txt" は
1: Hello world.
2: Good morning.
3:
に書き換えられるものとします(3行目は改行コードのみ).
(答え)
#include <stdio.h>
#define GMAX 50 /* 最大行数 */
#define MMAX 80 /* 1行中最大文字数 */
int main(void)
{
FILE *fp; char s[GMAX][MMAX]; int m, i = 0;
fp = fopen("sample.txt", "r");
while(fgets(s[i++], MMAX-1, fp) != NULL && i < GMAX);
/* 1行の最後は 0 なので,MMAX-1 とする */
m = i - 1; /* ← 全行数 */
fclose(fp); /* ← 必要 */
fp = fopen("sample.txt", "w");
for(i = 0; i < m; i++) fprintf(fp, "%2d: %s", i, s);
fclose(fp); /* ← なくてもよい */
}
char s[GMAX][MMAX]の意味がよくわかりません。
それと、while文の使い方がよくわからないです。これはm = i - 1;というのを繰り返しているんですか?
fgets(s[i++], MMAX-1, fp) != NULL というところの、i++ってあるのですが、iの値はどんどん増えてゆくんですか?
本当にわかんないことだらけで、どなたか教えてください;;
再びですが教えてください!
Re:再びですが教えてください!
defineについては http://www9.plala.or.jp/sgwr-t/c/sec18.html こちらが参考になると思います。 while(fgets(s[i++], MMAX-1, fp) != NULL && i < GMAX); これは確かにわかりにくい書き方ですね。 括弧の無い条件文は次のセミコロンまでがひとまとまりになります。 if(a==1){ a=2; } このプログラムは if(a==1) a=2; と書き換えられますよね。if文による処理を何もさせたくなければ if(a==1) ; こうなります。セミコロンの前の空白を消せば if(a==1); こうなります。よって条件文による処理をしないでいる事になります。 while(fgets(s[i++], MMAX-1, fp) != NULL && i < GMAX); これは 「 fgets関数を実行し、その返り値がNULLで無い かつ iがGMAXより小さい間ループ 」 を意味していますよね。解りやすく書き換えると while(i < GMAX){ if(fgets(s[i++], MMAX-1, fp) == NULL) break; } 処理される順番はかわりますが(特にi)、感覚的にこれと同じ意味になります。 よってループの条件はm = i-1;の文には届きません。 i++; というのは、式が評価された後に1増やすという意味です。これとは逆に ++i; と書けば、式が評価される前に1増やすという意味になります。 i=0; printf("%d ",i++); printf("%d ",i++); printf("%d ",i++); これと i=0; printf("%d ",++i); printf("%d ",++i); printf("%d ",++i); これがどう違うか自分で実行して確認してみてください。
Re:再びですが教えてください!
while(fgets(s[i++], MMAX-1, fp) != NULL && i < GMAX);
このwhile文ではfgets関数でs[i++]と言う配列に入力ファイルからデータを読んで保存しています。
・読み込むファイル fpで指定したファイル
・一度に読み込むデータ量 MMAX-1 =79文字(最後に必ず\0が付くのでその分1バイト減らしている)
・読んだデータを保存する場所 s[i++]
なので、iには読み込んだデータの行数(回数)が入ります。
50行よりも少ない場合fgetsの戻り値がNULLになるので終了条件に当てはまります。
行末にセミコロンがあるのでwhile文はそこで完結します。次の行には影響しません。
char s[GMAX][MMAX]ですが、
入力文字列を保存するための2次元配列です。
s[0][0]~s[0][79]をまとめて指定したことになります。
最後の
for(i = 0; i < m; i++) fprintf(fp, "%2d: %s", i, s);
ですが、コレだと行数が0から始まりませんか?
このwhile文ではfgets関数でs[i++]と言う配列に入力ファイルからデータを読んで保存しています。
・読み込むファイル fpで指定したファイル
・一度に読み込むデータ量 MMAX-1 =79文字(最後に必ず\0が付くのでその分1バイト減らしている)
・読んだデータを保存する場所 s[i++]
なので、iには読み込んだデータの行数(回数)が入ります。
50行よりも少ない場合fgetsの戻り値がNULLになるので終了条件に当てはまります。
行末にセミコロンがあるのでwhile文はそこで完結します。次の行には影響しません。
char s[GMAX][MMAX]ですが、
入力文字列を保存するための2次元配列です。
配列s[/url] MMAX [0][1][2][3][4][5][6][7][8][9][10][11][12]・・・[79] G[0] H e l l o w o r l d . M[1] G o o d m o r n i n g . A[2] X[3] ・ ・ ・ [49]s[0]とだけ書けば・・・
s[0][0]~s[0][79]をまとめて指定したことになります。
最後の
for(i = 0; i < m; i++) fprintf(fp, "%2d: %s", i, s);
ですが、コレだと行数が0から始まりませんか?
Re:再びですが教えてください!
すごくよくわかりました!管理人さん、やそさんありがとうございます!!
>やそさん
実行してみたらおっしゃるとおり0からはじまってしまったので、自分で修正しました。ありがとうございます。
>やそさん
実行してみたらおっしゃるとおり0からはじまってしまったので、自分で修正しました。ありがとうございます。