プロが教える店舗&オフィスのセキュリティ対策術

大変お世話になっております。
C言語についてお聞きしたいことがあります。
テキストファイルをデータとして読み込み、その数などを計算した結果をテキストファイルにしたいのです。簡略して次のような手順を歩みたいと思います。catalog.txtは数行からなり、各行の34文字目から38文字目までが実数で、これを抽出して各行の実数データを計算したいのですが、作成されたファイルは一行目の計算が無限にループしています。
以下がプログラムです。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

main(){
FILE *fp, *fp2;
char str[1024];
char buf[256];
double i, kekka;

if((fp = fopen("catalog.txt", "r")) == NULL){
printf("file open error1\n");
exit(1);
}

if((fp2 = fopen("kekka.txt", "w")) == NULL){
printf("file open error2\n");
exit(1);
}

while( fscanf(fp, "%[^\n]", str) != EOF ){
strncpy(buf, &str[33], 5);
buf[5] = '\0';
i = atof(buf);
kekka = 2 * i;
fprintf(fp2, "%lf\n" ,kekka);
}
}


毎度すいませんがこの解決方法をご教授ください。よろしくお願いします。

A 回答 (5件)

★私も素直に『fgets』関数を使うべきだと思います。


・ソースや他の回答者の方より、行単位で読み込んで行単位で処理していますので、
 『fgets』関数を使う方が良いと思います。
・それから、各行の 34 文字目から 38 文字目が実数でこれを抽出したいのならば、
 今回の場合に限っては『strncpy』関数を使わなくても出来ます。
 つまり、39 文字目に NULL 文字をセットして 34 文字目のアドレスから1つの実数
 文字列として『atof』に渡せます。
・下に『fgets』関数を利用した場合と抽出法のサンプルを載せます。

サンプル:
FILE *fp, *fp2;
char str[ 1024 ];

中略

while ( fgets(str,sizeof(str),fp) != NULL ){ ←行単位で文字列を読み込む
 str[ 38 ] = '\0'; ←39 文字目に NULL 文字をセット
 i = atof( str + 33 ); ←『atof( &str[33] );』でも良い
 kekka = 2 * i;
 fprintf( fp2, "%lf\n" ,kekka );
}

最後に:
・ちょっとしたアドバイスで、英語で『結果』は『result』という単語があります。
 ローマ字の『kekka』が分かりやすければいいですが、英語で統一するならば『result』の
 単語を使ってみましょう。
・あと『fgets』関数はエラーが起きた場合も NULL をリターンしますので、エラー対策を
 行いたい場合は NULL が返された時に while 文を抜ける以外に『ferror(fp);』関数で
 エラーかどうかを調査して下さい。→『feof(fp);』でファイルの最後(EOF)かも調査できます。
・以上。おわり。→私は『fscanf』よりも『fgets』関数の利用をお勧めします。

参考URL:http://oshiete1.goo.ne.jp/qa2625434.html
    • good
    • 0
この回答へのお礼

ご丁寧な解説ありがとうございました。
直接渡す方法も大変参考になりました。元のソースでははいくつかの列があり、それぞれ読み込む必要があります。
kekkaのご指摘のほうもありがとうございます。元のソースを改変して簡略化しましたが、不十分になってしまい、申し訳ありませんでした。<math.h>もこれでは必要ないですしね・・・。

お礼日時:2007/03/04 00:26

> 各行の34文字目から38文字目までが実数で



それがわかっているのなら、わざわざfgetsを使って処理を煩雑にしなくても、

fscanf(fp, "%*33c%5lf%*[^\n]%*c", &i);

とすれば、一発でかたがつきます。

fgetsを用いた方が細かなエラーチェックができますが、その分、コードは煩雑になります。ただし、細かなエラーチェックをするつもりなら、atofは論外なのでお勧めしません。strtodにしましょう。
また、printf系でdoubleを出力するときの書式は%lfではなく%fです。(あまりにも間違う人が多いので、C99では%lfもOKになってしまいましたが...)
    • good
    • 0

「%[^\n]」とすると、改行の直前まで読み取ってくれます。


直前なんで改行は読み取りませんし、
次に読み込む文字が改行だと、何も読み込みません。

なので、入力バッファに改行文字が入ったままになるので、
何も読み込まない作業をずっと続けてしまいますね。

私も空白を読み込みたいために、この手法をたまに使います。
そのときは「%[^\n]%*c」という記述を使っています。
改行まで読み込んで、改行文字はスキップするというものです。

一番良い方法かどうかはわかりませんが、少しでも参考になればと思います。
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。
そういう性質なのですね。
代案も参考になりました。

お礼日時:2007/03/04 00:19

>while( fscanf(fp, "%[^\n]", str) != EOF ){



の部分の"%[^\n]"はどういったことをしようとしているの
でしょうか?

%sとかではだめなのでしょうか?

一行の途中に空白がある場合で、行あたりの文字数が固定なら
下記のようなfgets使用のものはいかがでしょうか?
while( fgets(str, 128, fp) >0 ){
strncpy(buf, &str[33], 5);
buf[5] = '\0';
i = atof(buf);
kekka = 2 * i;
fprintf(fp2, "%lf\n" ,kekka);
}
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。
説明不足でしたが、お察しの通り、一行には文字、数字、空白があったのでこうしました。
fgetsを試してみたいとおもいます。

お礼日時:2007/03/04 00:18

while( fscanf(fp, "%[^\n]", str) != EOF ){


で読み残した、\nが永久に残ります。

素直にfgets()を使うべきです。
while (fgets(str, 1024, fp) != 0) {
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。
やはりそこでしたか。
fgetsも検討していましたが、fscanfのほうが使いやすそうだったので・・・
早速試してみたいと思います。

お礼日時:2007/03/04 00:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!