重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【6/2終了】教えて!gooアプリ版

こんにちは。
現在、C言語でプログラミングをしています。

最近気が付いたのですが、fgetc、fputc、fgets、fputs、fprintfといった関数は、
呼び出されるたびにファイルの現在位置を進めるのですが、
fscanf関数において、scanf集合を使った場合だけは、
何故かいつもファイルの先頭からスキャンを開始するようです。

例えば、適当なテキストファイルtest.txtを作成し、
------------------------------------
FILE *fp;
char str[80];
fp=fopen("test.txt", "r");
while(!feof(fp)){
fscanf(fp, "%[a-zA-Z]", str)
puts(str);
}
------------------------------------
といったコードブロックを試してみると、永遠にforループが終了せず、
最初の英単語が何回も画面に出力されます。
このコードブロックの目的は、test.txtから、英単語だけを取り出して、順番に出力していく事です。

上のコードブロックで、whileループの最後に、fseek(fp, srtlen(str), SEEK_CUR);
といったコードを挿入し、ファイルの現在位置を手動で進めてみたのですが、
どうも上手く行きませんでした。

scanf集合は便利なので、fscanf関数で使っていきたいのですが、こういった不具合があるので困っています。
上のコードブロックを上手く動作させる方法だけでもいいので、何かアドバイスを頂きたいと思います。

では、よろしくお願い致します。

A 回答 (3件)

"%[a-zA-Z]s" って「文字コードが a以上z以下もしくは A以上Z以下のものを『できる限り』読み込む」+「文字 s を読む」って意味だけど, 「文字 s」はその前の %[a-zA-Z] に含まれている (はず) なので最後の s は絶対に読み込めない (はず) です>#1. もちろん %[a-zA-Z] で英字以外のものを読み込んでしまう可能性はあります.



さておき「仕様を確認しろ」には同意.

この回答への補足

自己解決できましたので、その時に行った作業を以下に記述しておきます。
回答して下さった皆さん、ありがとうございました。

test.txtの内容は以下の通りです。
____________________________________________________________
:abc d1f;gh2-@;ijkLMN
OPQ ;:RSTUあいうえお
V3W4X5Y6Z
____________________________________________________________
プログラムを以下の様に修正すると上手く行きました。
char str1[80], str2[80];
while(!feof(fp)){
fscanf(fp, "%[^a-zA-Z0-9]%[a-zA-Z0-9]", str1, str2);
printf("str1:「%s」\t ", str1);
printf("str2:「%s」\n", str2);
}
出力は以下のようになりました。
____________________________________________________________
str1:「:」 str2:「abc」
str1:「 」 str2:「d1f」
str1:「;」 str2:「gh2」
str1:「-@;」 str2:「ijkLMN」
str1:「
」 str2:「OPQ」
str1:「 ;:」 str2:「RSTU」
str1:「あいうえお
」 str2:「V3W4X5Y6Z」
____________________________________________________________
どうやら、fscanf関数も、読み込むたびにファイルの現在位置を進めるようです。
最初に記述していた fscanf(fp, "%[a-zA-Z]", str);というコードは、
「アルファベット以外の文字は全て捨て、連続したアルファベットのみをstrに格納する」
という動作をすると考えていたのですが、どうやら、捨てられた文字が入力バッファに残ったままになることで問題が発生していたようです。
この問題は、fflush(fp); というコードで、ループの度に入力バッファをフラッシュしても解決できませんでした。
そこで考え付いたのが、
「捨てられるべき文字を、他の文字列に格納する」
という方法です。
コードで表すとfscanf(fp, "%[^a-zA-Z0-9]%[a-zA-Z0-9]", str1, str2); の部分です。
これで、str2に英単語のみが格納されます。
ただし、%[^a-zA-Z0-9]%[a-zA-Z0-9]の部分を%[a-zA-Z0-9]%[^a-zA-Z0-9]とすると、上手く行きませんでした。
これは、test.txtが::という数字でもアルファベットでもない文字で始まっているからです。
この問題を解決するには、以下のようなコードブロックをwhileループの前に記述しておくことで解決できました。
____________________________________________________________
char ch;
do{
fscanf(fp, “%c”, &ch);
}while( !isdigit(ch) && !isalpha(ch) );
fseek(fp, -1, SEEK_CUR);
____________________________________________________________
このコードブロックは、数字またはアルファベットが初めて現れる位置までファイルの現在位置を進め、
見つかった所から、現在位置を1つ戻すという作業を行っています。
最初の文字が数字またはアルファベット以外で始まるファイルにも対応できるようになります。

補足日時:2011/08/16 20:46
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

>さておき「仕様を確認しろ」には同意.
一応様々なサイトで仕様は確認したのですが、理解が甘いようです。
fscanf(fp, "%[a-zA-Z]", str);
というコードは、
「test.txtの現在位置(ftell関数で返される所)から、内容をスキャンし、
アルファべットが見つかれば、次にアルファベットでない文字が現れる所までをstrに格納する。」
という動作をするのだと思うのですが、違うのでしょうか?

お礼日時:2011/08/16 19:21

>適当なテキストファイルtest.txt



中身を見せてください。

# scanf集合って何のことかと思ったら、スキャン集合もしくはスキャンセットのことだったのね。
# 'f'は不要。
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

test.txtの内容は以下の通りです。
____________________________________________________________
:abc d1f;gh2-@;ijkLMN
OPQ ;:RSTUあいうえお
V3W4X5Y6Z
____________________________________________________________

お礼日時:2011/08/16 19:15

>fscanf関数において、scanf集合を使った場合だけは、


>何故かいつもファイルの先頭からスキャンを開始するようです。

改行含んだりしていないですよね?
また、例に示したコードだとアルファベットしか許容しませんが。

>fscanf(fp, "%[a-zA-Z]", str);
の戻り値は確認しましたか?
# "%[a-zA-Z]s"じゃないんすかね?
仕様をちゃんと確認しましょう。
改行を含んだファイルなら改行文字の直前までしか読めませんし
連続するアルファベットが80文字を越えると楽しいコトが発生するプログラムです。

便利…ということでscanf()系使う場合は、入力が希望通りでなかった場合の挙動も確認した上で使いましょう。

int num = 1;
while(num != 0){
 scanf("%d", &num);
}
で数字以外を入力した場合にどうなるか、試したコトはありますか?
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

>改行含んだりしていないですよね?
含んでますけど、含んでいたら、まずいのでしょうか?

記述して頂いたコードブロックを参考にし、

int num = 1;
while(num != 0){
scanf("%d", &num);
printf("%d ",num);
}
を試したところ、数字以外の文字、例えばaを入力すると、
1 1 1 1 1...と出力されて、プログラムが止まりませんでした。
こういった経験はこれまでに何度もしてきたので、上手く行かない事は存じているのですが、今回の問題とは何の関係があるのでしょうか?

お礼日時:2011/08/16 19:12

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