
こんにちは。
現在、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関数で使っていきたいのですが、こういった不具合があるので困っています。
上のコードブロックを上手く動作させる方法だけでもいいので、何かアドバイスを頂きたいと思います。
では、よろしくお願い致します。
No.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つ戻すという作業を行っています。
最初の文字が数字またはアルファベット以外で始まるファイルにも対応できるようになります。
御回答ありがとうございます。
>さておき「仕様を確認しろ」には同意.
一応様々なサイトで仕様は確認したのですが、理解が甘いようです。
fscanf(fp, "%[a-zA-Z]", str);
というコードは、
「test.txtの現在位置(ftell関数で返される所)から、内容をスキャンし、
アルファべットが見つかれば、次にアルファベットでない文字が現れる所までをstrに格納する。」
という動作をするのだと思うのですが、違うのでしょうか?
No.2
- 回答日時:
>適当なテキストファイルtest.txt
中身を見せてください。
# scanf集合って何のことかと思ったら、スキャン集合もしくはスキャンセットのことだったのね。
# 'f'は不要。
御回答ありがとうございます。
test.txtの内容は以下の通りです。
____________________________________________________________
:abc d1f;gh2-@;ijkLMN
OPQ ;:RSTUあいうえお
V3W4X5Y6Z
____________________________________________________________
No.1
- 回答日時:
>fscanf関数において、scanf集合を使った場合だけは、
>何故かいつもファイルの先頭からスキャンを開始するようです。
改行含んだりしていないですよね?
また、例に示したコードだとアルファベットしか許容しませんが。
>fscanf(fp, "%[a-zA-Z]", str);
の戻り値は確認しましたか?
# "%[a-zA-Z]s"じゃないんすかね?
仕様をちゃんと確認しましょう。
改行を含んだファイルなら改行文字の直前までしか読めませんし
連続するアルファベットが80文字を越えると楽しいコトが発生するプログラムです。
便利…ということでscanf()系使う場合は、入力が希望通りでなかった場合の挙動も確認した上で使いましょう。
int num = 1;
while(num != 0){
scanf("%d", &num);
}
で数字以外を入力した場合にどうなるか、試したコトはありますか?
御回答ありがとうございます。
>改行含んだりしていないですよね?
含んでますけど、含んでいたら、まずいのでしょうか?
記述して頂いたコードブロックを参考にし、
int num = 1;
while(num != 0){
scanf("%d", &num);
printf("%d ",num);
}
を試したところ、数字以外の文字、例えばaを入力すると、
1 1 1 1 1...と出力されて、プログラムが止まりませんでした。
こういった経験はこれまでに何度もしてきたので、上手く行かない事は存じているのですが、今回の問題とは何の関係があるのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- Excel(エクセル) VBA フォルダ見える化のコードについて 2 2023/06/19 15:04
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- その他(プログラミング・Web制作) python OpenPyXLを使って出力結果をエクセルに書き込み 2 2022/06/04 19:46
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/08/08 11:02
- Visual Basic(VBA) VBAでの共有パスにつきまして 1 2023/03/04 17:24
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ファイル内のデータを1行削除...
-
バイナリファイルをテキストフ...
-
fopen(書き込みモード)でファイ...
-
【VB.Net】バイト型配列に読み...
-
巨大なテキストファイル(可変...
-
C言語 バイナリファイルの読み...
-
EOF判定されない
-
ファイル読み込みについて
-
テキストファイルの行数を取得...
-
0x00をファイル出力
-
テキストファイルから読み込ま...
-
C言語初心者の質問失礼します。
-
Access クエリ実行が急に非常に...
-
どんなプログラムを書いても指...
-
バッファとは何ですか
-
FTPでputすると空ファイルが出...
-
csvファイルを開かずに文字を検...
-
コマンド(例えばls)の出力結果...
-
2つのCSVファイルの比較
-
フルパスから最後のディレクト...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
テキストファイルの行数を取得...
-
ファイル内のデータを1行削除...
-
バイナリファイルをテキストフ...
-
fgetsで2行目から文字化け
-
c言語 2つのファイルを行ご...
-
ファイル読み込みについて
-
巨大なテキストファイル(可変...
-
改行までの一文字ずつのファイ...
-
0x00をファイル出力
-
複数テキストファイルを読み込...
-
EOF判定されない
-
【VB.Net】バイト型配列に読み...
-
変数内の文字列を空にできない
-
[動的配列]C言語の勉強で簡単な...
-
続・EOF判定されない
-
0バイトファイルの作成
-
ファイルサイズ指定し、ファイ...
-
winsock recvでの文字化け
-
int型の値をファイルに保存
-
UNIXシェルプログラム等からバ...
おすすめ情報