ファイルの入出力について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ともみん

ファイルの入出力について

#1

投稿記事 by ともみん » 11年前

ファイルの入出力についての課題です。

キーボードから入力した文字列を、(改行と空白を含めて)そのままファイル "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);
	}
}


non
記事: 1097
登録日時: 13年前

Re: ファイルの入出力について

#2

投稿記事 by non » 11年前

一つ目のプログラムから。
最初にcに値が入っていない。だから、aが出たのであれば、それはたまたま。
non

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ファイルの入出力について

#3

投稿記事 by みけCAT » 11年前

二つ目のプログラムのヒントを。
同じファイルに入出力するのはファイルの内容を全てメモリに保存しないといけず、難しいので、
別ディレクトリの"sample.txt"に保存しましょう。
(メモリに保存する代わりに一時ファイルを作ってもいいかもしれません)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ファイルの入出力について

#4

投稿記事 by みけCAT » 11年前

あなたの二つ目のプログラムについて。
break文ですが、文字列の配列のポインタと0を比較しているので、真になる確率は限りなく低いと思います。

コード:

if(s[n][0]==' ' && s[n][1]==' ' && s[n][2]=='\0')break;
みたいな感じでしょうか?

また、出力では行番号の出力しか書いていないので、行番号しか出力されないのは当たり前です。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ともみん

Re: ファイルの入出力について

#5

投稿記事 by ともみん » 11年前

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);
	}
}


non
記事: 1097
登録日時: 13年前

Re: ファイルの入出力について

#6

投稿記事 by non » 11年前

突っ込みどころ満載ですね。

>上記のファイル "sample.txt" を読み取り、その各行に行番号を付けて再び "sample.txt" に出力するプログラム を作成せよ。

同じファイル名に保存するには、今あなたがやっているように、一旦、一時ファイルの配列にいれておいても良いのですが、データ量が
不定なのでお薦めできません。みけCATさんが仰っているように、別ディレクトリに保存しても良いのですが、問題の趣旨からすれば、
元のフォルダに戻す必要があります。であれば、あなたのレベルであれば、まず別名で出力することをお薦めします。その後で、フォルダを
変更するか、リネームするかしましょう。

次に、ファイルから読み込む場合ですが、fgetsで読み込んだとき読み込むデータがないときは、NULLを返します。
>if(s[n-1][0]=='\0' && s[n][0]=='\0')break;
こんな方法ではいけません。fgetsを調べれば例があると思います。
non

アバター
usao
記事: 1887
登録日時: 11年前

Re: ファイルの入出力について

#7

投稿記事 by usao » 11年前

とりあえず誰もつっこまないみたいなので,以下を指摘しておきます.

コード:

fclose;

ともみん

Re: ファイルの入出力について

#8

投稿記事 by ともみん » 11年前

ご指摘ありがとうございます。

プログラミングに対して無知で申し訳ありませんが、お付き合い頂けるとありがたいです。

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.が消えてしまっているのですが、どうしてなのでしょう?

分からないことだらけで、すみません。

non
記事: 1097
登録日時: 13年前

Re: ファイルの入出力について

#9

投稿記事 by non » 11年前

ともみん さんが書きました: フォルダを変更したり、リネームすることは課題では禁止されているみたいで、そのままsample.txtに出力しなければなりません。
そうでしたか。それでは、配列を使うしかないですね。

9行と10行に2回fgetsがあってはいけません。1つにしましょう。
だから、1行目が消えているのです。
non

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ファイルの入出力について

#10

投稿記事 by みけCAT » 11年前

non さんが書きました:
ともみん さんが書きました: フォルダを変更したり、リネームすることは課題では禁止されているみたいで、そのままsample.txtに出力しなければなりません。
そうでしたか。それでは、配列を使うしかないですね。
要素数が不定なので、配列よりリンクリストの方がいいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ともみん

Re: ファイルの入出力について

#11

投稿記事 by ともみん » 11年前

nonさん、ご指摘ありがとうございます。

9行目のfgetsを抜いたところ、正しく実行できました。

しかしなぜfor文で繰り返している文がないのに、フォルダから内容を出力(fgets)できているんでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ファイルの入出力について

#12

投稿記事 by みけCAT » 11年前

ともみん さんが書きました:しかしなぜfor文で繰り返している文がないのに、フォルダから内容を出力(fgets)できているんでしょうか?
意味がわかりません。
for文で繰り返している文はありますし、フォルダから内容は出力できていないと思います。
そのようにコードを変更したのなら、それを提示してください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ともみん

Re: ファイルの入出力について

#13

投稿記事 by ともみん » 11年前

先ほどの件は解決できました。

中途半端な説明で申し訳ありませんでした。

まだまだ知識不足で、もっと学習しなければいけないと痛感しました。

nonさんやご指摘下さった方々、どうもありがとうございました。

M.R

Re: ファイルの入出力について

#14

投稿記事 by M.R » 11年前

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: ファイルの入出力について

#15

投稿記事 by かずま » 11年前

「解決」になってしまったようなので、別解を。
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;
}

閉鎖

“C言語何でも質問掲示板” へ戻る