ページ 1 / 1
ファイルの入出力について
Posted: 2013年6月09日(日) 18:59
by ともみん
ファイルの入出力についての課題です。
キーボードから入力した文字列を、(改行と空白を含めて)そのままファイル "sample.txt" に出力するプログラムを作成せよ。
条件として、
1.キーボードから入力する際には、標準関数 getc() を用いる
2.入力の終了は、[RET] を2回繰り返すことで指示する
こととする。
また 、上記のファイル "sample.txt" を読み取り、その各行に行番号を付けて再び "sample.txt" に出力するプログラム を作成せよ。
というもので、一応プログラムを書いてみたのですが、どちらも思った通りに動きません。
一つ目のプログラムは実行すると、一番初めにキーボードから入力した文字の前にaが入ってしまいます。
二つ目のプログラムは実行すると、一つ目のプログラムで入れたsample.txtの内容は入っておらず、行番号のみが上限まで入っています。
二つ目のプログラムは最初のfor文の中のbreak文が間違っていると思います。
s[n]に入る文字列が連続して空白の場合に、breakするようにしたいのですが、どう書いたらいいのかさっぱり分かりません。
アドバイスよろしくお願いします。
読みにくい文章とプログラムで申し訳ありません。
一つ目のプログラム
コード:
#include <stdio.h>
int main(void){
FILE *fp; char c,d;
fp = fopen("sample.txt","w");
do{
d = c;
putc(c,fp);
}while((c=getc(stdin))!='\n'||d!='\n');
}
二つ目のプログラム
コード:
#include <stdio.h>
int main(void){
FILE *fp; char s[50][80];
int n,i;
fp = fopen("sample.txt","r");
for(n = 0;n <= 79;n++){
fgets(s[n],79,fp);
if(s[n]=='\0')break;
}
fclose;
fp = fopen("sample.txt","w");
for(i=0;i<=n-1;i++){
fprintf(fp,"%d:",i);
}
}
Re: ファイルの入出力について
Posted: 2013年6月09日(日) 19:09
by non
一つ目のプログラムから。
最初にcに値が入っていない。だから、aが出たのであれば、それはたまたま。
Re: ファイルの入出力について
Posted: 2013年6月09日(日) 21:38
by みけCAT
二つ目のプログラムのヒントを。
同じファイルに入出力するのはファイルの内容を全てメモリに保存しないといけず、難しいので、
別ディレクトリの"sample.txt"に保存しましょう。
(メモリに保存する代わりに一時ファイルを作ってもいいかもしれません)
Re: ファイルの入出力について
Posted: 2013年6月09日(日) 21:41
by みけCAT
あなたの二つ目のプログラムについて。
break文ですが、文字列の配列のポインタと0を比較しているので、真になる確率は限りなく低いと思います。
コード:
if(s[n][0]==' ' && s[n][1]==' ' && s[n][2]=='\0')break;
みたいな感じでしょうか?
また、出力では行番号の出力しか書いていないので、行番号しか出力されないのは当たり前です。
Re: ファイルの入出力について
Posted: 2013年6月10日(月) 23:42
by ともみん
nonさん、みけcatさん、ご指摘ありがとうございます。
一つ目のプログラムは、nonさんのご指摘を受け、do文をwhile文に変えたら、正しく実行できました。ありがとうございました。
二つ目のプログラムについてですが、みけcatさんのご指摘を受け、少しプログラムを書き換えてみました。
そのプログラムを実行したところ、一つ目のプログラムでキーボードから入力した行番号は出てくるようになりました。
例として、一つ目のプログラムで 1234.(改行)2345.(改行)(改行)と入力すると、二つ目のプログラムで、1:2:3:とsample.txtに出力されます。
どうしたらsample.txtに元々入っているデータに行番号を加えることができるのでしょうか?
別のホームディレクトリのsample.txtに保存するには、どうしたらいいのでしょうか?
アドバイスお願いします。
二つ目のプログラム(書き換え後)
コード:
#include <stdio.h>
int main(void){
FILE *fp; char s[50][80];
int n,i;
fp = fopen("sample.txt","r");
for(n = 0;n <= 49;n++){
fgets(s[n],79,fp);
if(s[n-1][0]=='\0' && s[n][0]=='\0')break;
}
fclose;
fp = fopen("sample.txt","w");
for(i=1;i<=n+1;i++){
fprintf(fp,"%d:\n",i);
}
}
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 09:10
by non
突っ込みどころ満載ですね。
>上記のファイル "sample.txt" を読み取り、その各行に行番号を付けて再び "sample.txt" に出力するプログラム を作成せよ。
同じファイル名に保存するには、今あなたがやっているように、一旦、一時ファイルの配列にいれておいても良いのですが、データ量が
不定なのでお薦めできません。みけCATさんが仰っているように、別ディレクトリに保存しても良いのですが、問題の趣旨からすれば、
元のフォルダに戻す必要があります。であれば、あなたのレベルであれば、まず別名で出力することをお薦めします。その後で、フォルダを
変更するか、リネームするかしましょう。
次に、ファイルから読み込む場合ですが、fgetsで読み込んだとき読み込むデータがないときは、NULLを返します。
>if(s[n-1][0]=='\0' && s[n][0]=='\0')break;
こんな方法ではいけません。fgetsを調べれば例があると思います。
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 11:34
by usao
とりあえず誰もつっこまないみたいなので,以下を指摘しておきます.
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 18:14
by ともみん
ご指摘ありがとうございます。
プログラミングに対して無知で申し訳ありませんが、お付き合い頂けるとありがたいです。
NULLはfgetsで読み込んだとき読み込むデータがないときに返されるんですね。
フォルダを変更したり、リネームすることは課題では禁止されているみたいで、そのままsample.txtに出力しなければなりません。
一応書き換えてみました。
コード:
#include <stdio.h>
int main(void){
FILE *fp; char s[50][80];
int n,i,h;
fp = fopen("sample.txt","r");
for(n = 0;n <= 49;n++){
fgets(s[n],79,fp);
if(fgets(s[n],79,fp)==NULL)break;
}
fclose(fp);
fp = fopen("sample.txt","w");
for(i=0;i<=n+1;i++){
fprintf(fp,"%d:%s\n",i+1,s[i]);
}
}
このプログラムを実行すると、hello.(改行)good.という内容が入ったsample.txtが1:good.(改行)2:となります。
どうやら一行目のhello.が消えてしまっているのですが、どうしてなのでしょう?
分からないことだらけで、すみません。
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 18:22
by non
ともみん さんが書きました:
フォルダを変更したり、リネームすることは課題では禁止されているみたいで、そのままsample.txtに出力しなければなりません。
そうでしたか。それでは、配列を使うしかないですね。
9行と10行に2回fgetsがあってはいけません。1つにしましょう。
だから、1行目が消えているのです。
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 21:38
by みけCAT
non さんが書きました:ともみん さんが書きました:
フォルダを変更したり、リネームすることは課題では禁止されているみたいで、そのままsample.txtに出力しなければなりません。
そうでしたか。それでは、配列を使うしかないですね。
要素数が不定なので、配列よりリンクリストの方がいいと思います。
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 21:44
by ともみん
nonさん、ご指摘ありがとうございます。
9行目のfgetsを抜いたところ、正しく実行できました。
しかしなぜfor文で繰り返している文がないのに、フォルダから内容を出力(fgets)できているんでしょうか?
Re: ファイルの入出力について
Posted: 2013年6月11日(火) 21:59
by みけCAT
ともみん さんが書きました:しかしなぜfor文で繰り返している文がないのに、フォルダから内容を出力(fgets)できているんでしょうか?
意味がわかりません。
for文で繰り返している文はありますし、フォルダから内容は出力できていないと思います。
そのようにコードを変更したのなら、それを提示してください。
Re: ファイルの入出力について
Posted: 2013年6月13日(木) 13:10
by ともみん
先ほどの件は解決できました。
中途半端な説明で申し訳ありませんでした。
まだまだ知識不足で、もっと学習しなければいけないと痛感しました。
nonさんやご指摘下さった方々、どうもありがとうございました。
Re: ファイルの入出力について
Posted: 2013年6月13日(木) 13:32
by M.R
fgets は「出力」ではなく「入力」になります。
if(fgets(s[n],79,fp)==NULL)break;
は、ただ判定だけしているのではなく、ここでも fgets の処理がされています。
コード:
for(n = 0;n <= 49;n++){
fgets1回目
if(fgets2回目==NULL)break;
}
となり1回目のfgetsした情報を2回目のfgetsで上書きしてしまっているのです。
(同じs[n]の上に読み込んでいるので)
コード:
for(n = 0;n <= 49;n++){
if(fgets(s[n],79,fp)==NULL)break;
}
の状態で forループでfgetsして、その結果を判定してbreakする、という形になります。
Re: ファイルの入出力について
Posted: 2013年6月14日(金) 00:58
by かずま
「解決」になってしまったようなので、別解を。
fgets の代わりに getc を使っています。
コード:
#include <stdio.h>
char buf[4096];
int main(void)
{
int c, i, n, line = 0;
FILE *fp = fopen("sample.txt", "r+");
if (!fp) return 1;
for (n = 0; n < sizeof(buf) && (c = getc(fp)) != EOF; n++)
buf[n] = c;
if (n == sizeof(buf)) return 2;
fseek(fp, 0, SEEK_SET);
c = '\n';
for (i = 0; i < n; i++) {
if (c == '\n') fprintf(fp, "%7d ", ++line);
c = putc(buf[i], fp);
}
fclose(fp);
return 0;
}