if(fgets(buff, 21, fp) == NULL)
{
  if(!feof(fp))
  {
    rtn_code[0] = '8';
  }
  else
  {
    rtn_code[0] = '4';
  }
}
--------------------------------------

/入力ファイル/
--------------------------------------

1行目 AAAAABBBBBCCCCCDDDD[LF]
2行目 EEEEEFFFFFGGGGGHHHH[LF]
3行目 [EOF]

--------------------------------------
[LF]=改行文字です。
[EOF]=ファイル終端指示子です。

上記のプログラムは、
1行20バイトある入力ファイルから一行だけgetするサブモジュールの一部です。
3回目にこれを実行した時に、EOFになってrtn_codeが'4'で返ってくる予定なのですが、どうしても非EOFになって'8'が返ってきてしまうのです。
なぜなんでしょうか?

そもそも、どうなるとEOF指示子がfpに返ってくるのでしょう?

このQ&Aに関連する最新のQ&A

A 回答 (8件)

解決したのかな~



状況は想像するしかないのですが、多分、No.4 の leaz024 さんの回答で解決する
問題だと思います。

> [EOF]=ファイル終端指示子です。

なんて書いているあたりが、Windows(MS-DOS を引きずっている)っぽい。

で、

> そもそも、どうなるとEOF指示子がfpに返ってくるのでしょう?

についてなんですが、直前の読み込み処理(fgets に限らず fgetc や fread でも
良い)において、既に EOF が検出されていた場合に、ゼロ以外を、そうじゃないとき
にはゼロを返します。

読み込み関数が正常以外を返してきたときに、EOF なのか Error なのかを判別する
ために存在します(ferror の裏)。あなたの考え方であってますよ。
    • good
    • 0

HAIZY@のーみそ・とろ~んだった(過去形)です。



#3 について
はい、逆です。間違えました。ゴメンナサイ。
今回の教訓:
本職(コンピュータ関係)がトラブってるの時は、回答しない方が良い(笑)
混乱を招き、本当に申し訳ございません。


●デバックのツールで解析してみましょう。
トレース と ブレークポイントを駆使し、「監視式」で各変数に何が入っているのか、監視してみる。

if(feof(fp))
を式評価してみる。

if (gets(buff, 21, fp))
buff の最大容量を考慮した上で、21 を大きくしてみる。
結果どうなるか。
buffの値を監視式で見てみる。(16進表示が良い。)

単純なデバッグ作業です。
「わたしなら、こうします」と言う感じです。
参考になれば。
    • good
    • 0

leaz024さんが言われている事は、その通りだと思うのですが、それ以前に、fgetsに問題があります。


fgetsの戻り値がNULLになるのは、ファイルの終端以降を読み込もうとしたか、何らかのエラーが発生した場合です。

特別なエラー処理が必要ないのでしたら、まずはファイルオープンで"rb"を"rt"にして、

if (gets(buff, 21, fp))
{
rtn_code[0] = '8';
}
else
{
rtn_code[0] = '4';
}

というようにされてはどうでしょうか?

それから、EOFがファイルの終端に付加されるかどうかはテキストエディタ及びオプションしだいです。
    • good
    • 0

leaz024さんに加えて、ちょっと指摘しておきます。

[EOF]のコードは正しいですか?MS-DOSでは[EOF]のコードは1AHですが、stdio.hではFFHと定義されているようです。1AHになっているか確認してみてください。

(なお、私はC言語はほとんどわからないのですが、興味があったので昔のパソコンで調べてみました。的外れなアドバイスだったら無視してください)
    • good
    • 0

何やらfeofで揉めてますが、質問にある使い方に問題はないように思えます。



ところで改行文字[LF]と書いてありますが、これは確実ですか?
Cでは改行を[\n]という一文字で片付けてしまいますが、単なるWindowsのテキストファイルだと、実際には[CR][LF]という2バイトになっています。

テキストモードなら、[CR][LF]→[\n]と変換して1バイトで拾ってくれますが、バイナリモードだとそのまま2バイトで拾ってしまいます。

つまり、buffの中身は、
1回目:AAAAABBBBBCCCCCDDDD[CR]\0
2回目:[LF]\0
3回目:EEEEEFFFFFGGGGGHHHH[CR]\0
となり、まだ[LF]が残っているのでfeofは0を返します。

ファイルサイズを見るなどして、改行文字が2バイトになっていないか確認してみて下さい。
    • good
    • 0

ふたたび


if(feof(fp))

あれあれ??
このままじゃ、上のif分って、0 = False じゃ無いですか???(^^;

if(feof(fp)==0)
  rtn_code[0] = '4';
else
  rtn_code[0] = '8';
じゃないと、True返らないですねぇ~~!!

  m( _ _;)m・・・老いたな<俺

でわ~~。

この回答への補足

え?
それって逆ではないんですか?

if(feof(fp)==0)
  rtn_code[0] = '8'; /*ファイルの終わりではない(エラー)*/
else
  rtn_code[0] = '4'; /*ファイルの終わり*/

参考書には
「エンドオブファイル指示子がセットされている時、feof関数は非0を返し、
それ以外は0を返す。」
と、あります。

私は逆の理解をしてるんだろか・・・
(実は自信がないんです、コレに関しては・・・)(--;

補足日時:2001/10/25 20:29
    • good
    • 0

fgets で NULL が帰ってきちゃってるから、


その if 文の中に入ってない。
だから、rtn_code[0] の中身が '8' のままってことなんじゃないですか?
    • good
    • 0

>feof は,指定したストリーム上の最後の入力操作で


>ファイル終了標識が検出されると 0 以外の値を返し,
>ファイル終了標識に達しなければ 0 を返します。

2行目に注目。終了の場合は、0以外です。
何が返ってくるかわからないんですね~。

この条件で、戻り値8を非EOFとしたいならば、

if(!feof(fp))
でなく、

if(feof(fp))
  rtn_code[0] = '4';
else
  rtn_code[0] = '8';


の方が良くないですか?
NOT処理は、ない方が1サイクル分処理が早いですし、なによりバグになりかねません。(多用すると、バグの元です。)
<<0/1 以外の戻り値の場合の動作を考えてみてください。(^^;

でわ。

この回答への補足

Haizyさん、こんばんわ。

確かにNOT処理はよくなかったです。(^^;
で、アドバイスの通りにしてみましたが、
やはり状況は変わりませんでした。

もう丸一日、参考書やWebで調べまくっていろいろやってみたのですが
どうしても解決できないのです。
ここが最後の砦です!

それから質問の補足ですが、ファイルは"rb"(バイナリモード)で
開いています。

補足日時:2001/10/25 17:32
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qname[3] = seq + '0';の意味

オライリーC実践プログラミングのP203、例13-11の例で質問です。
このプログラムでは一時的なファイル名を返す関数、tmp_nameがあるのですが
このプログラム中の以下の行がよく分かりません。
name[3] = sequence + '0';

直感的にsequenceだけでよさそうな気がするのですが以下のように書き直すと
出力結果にsequenceの数字がでずただ"tmp"と出力されるだけでした。
name[3] = sequence;


char型にint型を使うための手段なのでしょうか?
下記にプログラム全体を載せておきます。よろしくお願いします。

#include <stdio.h>
#include <string.h>

char *tmp_name(void)
{
static char name[30];
static int sequence = 0;

++sequence;

strcpy(name, "tmp");

name[3] = sequence + '0';
name[4] = '\0';

return (name);

}

int main()
{
char *tmp_name(void);

printf("%s\n", tmp_name());

return (0);
}

オライリーC実践プログラミングのP203、例13-11の例で質問です。
このプログラムでは一時的なファイル名を返す関数、tmp_nameがあるのですが
このプログラム中の以下の行がよく分かりません。
name[3] = sequence + '0';

直感的にsequenceだけでよさそうな気がするのですが以下のように書き直すと
出力結果にsequenceの数字がでずただ"tmp"と出力されるだけでした。
name[3] = sequence;


char型にint型を使うための手段なのでしょうか?
下記にプログラム全体を載せておきます。よろしくお願いします。

#incl...続きを読む

Aベストアンサー

これは、0から9までの数値をそれに対応する文字に変換するお手軽かつ問題のある手法です。

ご存知かもしれませんが、コンピューターでは文字は内部的には対応する数値で表されています。
ですから、C/C++ではchar形の中にあるのは文字ではなくその文字に対応する数値です。
したがって、
sequence + '0'
は0という文字を表す数値にsequenceを足した値になります。文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっていますので、結果、sequenceが0なら0という文字を表す数値、sequenceが1なら1という文字を表す数値、…という値になります。
参考キーワードとして「ASCIIコード」を調べるといいでしょう。

数値から文字への変換がたった1回の足し算で出来る、とってもお手軽な方法ですよね?

でも、以下のように問題があるのであまり使わないほうがいい方法です。

・0から9までしか使えない
上で書いたとおり、この方法でsequenceが0なら0という文字に、1なら1という文字に変換できます。……では、sequenceが-1だったら?10だったら?

・そもそも前提に疑問が残る
文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっています。……でもあなたの処理系で本当に連続して並んでいますか?将来そのように並んでない処理系への移植がないと100%言い切れますか?

これは、0から9までの数値をそれに対応する文字に変換するお手軽かつ問題のある手法です。

ご存知かもしれませんが、コンピューターでは文字は内部的には対応する数値で表されています。
ですから、C/C++ではchar形の中にあるのは文字ではなくその文字に対応する数値です。
したがって、
sequence + '0'
は0という文字を表す数値にsequenceを足した値になります。文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっていますので、結果、sequenceが0なら0という文字を表す数値、sequenceが...続きを読む

Qint nII[10] = { 0 }について

久々にCを使ってプログラムを組んでいるのですが、基本的な構文を思い出せず
いくつか教えていただきたく質問させていただきました。

1)配列すべてを初期化するのに、宣言時に

int nII[10] = { 0 };

で大丈夫だった(全ての要素が0で初期化)と記憶しているのですが、間違いないでしょうか?

2)構造体の初期化は

struct tm tm;
memset(&tm, 0, sizeof(struct tm))

で大丈夫でしょうか?

3)構造体の宣言は

typedef struct{
int a;
}HOGE, *LPHOGE;

HOGE st; // <- struct HOGE stと同じ
LPHOGE pst; // <- struct HOGE* pstと同じ

で問題ないでしょうか?

以上、3つ質問になって申し訳ないのですが、よろしくお願いします。

Aベストアンサー

1)OK
2)たぶんOK
3)HOGEという名前の構造体はない(当該の構造体には名前がない)ので、
// 以下のコメント記述が誤っています。ただし、

HOGE st;
LPHOGE pst;
という定義そのものはOK

Qchar AA[]{"全角文字"};から"全"という一字を取り出したい

 今晩は、Cの初心者です、宜しくお願いします。
 全角文字の入ったchar AA[]{"全角文字"};から"全"という文字一字を取り出す時にAA[0]とかくとエラーになります。
 どのようにしたら取り出せるのでしょう。
 ポインタを使う方法と使わない方法を教えて下さい。
 宜しくお願いします。

Aベストアンサー

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出す必要があります。

>char AA[]={'全','角'};

char AA[]="全角";
とし
>printf("%s%s\n" , AA[0],AA[1] ) ;

printf("%c%c\n" , AA[0],AA[1] ) ;
とすれば、「全」だけを表示する事が可能と思われます。

日本語を文字列で表示する為の文字コードについては
Shift-JISだけでなく、UnicodeやUTF・EUC・JISなどがあります。

もう少し詳しく記載してあるホームページはないか探してみましたが、ちょっと無理でした。

参考URL:http://marupeke296.com/CPP_charUnicodeWideChar.html

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出...続きを読む

Qfp = fopen(argy[1], "r");の[1]の意味は

https://oshiete.goo.ne.jp/qa/8940272.html
 の11行目に
fp = fopen(argv[1], "r");の[1]の意味が分かりません。
試したいのですが、ソフトがうまく動きません
 よろしくお願いいたします。

Aベストアンサー

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから入力し実行すると、

argc = 5
argv[0] = "test"
argv[1] = "test1"
argv[2] = "test2"
argv[3] = "3"
argv[4] = "4"

と文字列が入ってきます。

以下はサンプル。

void main( int argc , char *argv[])
{
if( argc < 2 )
{
// パラメータ指定がなかった場合の表示
printf( "test に続けて4つまでパラメータを入力できます\n");
exit(0);
}
if( argc > 5 )
{
 // パラメータが5つ以上あった場合の表示
printf( "5つ以上のパラメータは受け付けません\n");
exit(-1);
}

// 正常ルート
printf( "パラメータの数は%d個ですね?ニヤッ\n", argc-1);
printf( "最初のパラメータは%sでしょ?\n", argv[1]);
printf( "残りはargv[2]以降ですが、面倒なので表示しません\n");
}

と言う具合に、引数を活用できます。argv[0]には、実行ファイル名が入ります。
argc は実行ファイルの名前も含めてカウントされます。

プログラムによっては必要な引数の数が変わりますし、
ユーザーのコマンドラインからの入力ミスなどでパラメータがなかったり、
必要なパラメータが不足していたりしますので、
argcとargvを使って最初にシンタックスエラーチェックをするのが常道です。

実行ファイル名の指定がなく、プログラムが実行されることはないと思われます
から、argcは1以上の値になります。

argc, argvの活用は、
実行コマンドを手打ちで打ち込むコンソール形式でよく用いられる基本的な
アプリケーションの開発手法です。

ご質問の箇所は、
第一パラメータにプログラム内で読み込むファイルのファイル名を指定してるの
でしょう。(よくあります)

しかし、Windowsなどのウィンドウを使用するアプリケーションは、
これとは違っておりますので注意が必要です。
(C言語とは別に、Windowsに特化した開発ノウハウの勉強が必要です)

Windows系で上記の様な基本的なプログラムを作成する場合は、
プロジェクトの作成時に(VisualStudioなどで)コンソールアプリケーション
を選んで作成します。実行時にコンソールが開きます。

Linuxの場合は、コンソールがデフォルトになっているでしょうから、
(特殊な設定がなければ)そのまま作成できます。

テキストエディタでソースを記述し、gcc などでコンパイルします。
実行形式ファイルが出来ていれば、想定どおりの動作をするでしょう。

ファイルの読み込みが出来るようになったら、
ファイルの内容を書き換えて保存したり、
ファイル名を変えたり、
ディレクトリ内のファイルを全て表示したり、
ファイル内に含まれる文字列を検索し、該当するファイルをリストしたりなど、

有用なサンプルプログラムを沢山作って練習します。

ファイルを読み込む先は、char型の配列でバイトサイズのメモリーとして確保
します。メモリーと変数の関係を充分に理解することをお勧めします。
殆どのプログラムは、このメモリーの確保やメモリーサイズの計算と格闘する
場合が多くなるからです。

バイナリー形式のファイル(すべてはバイナリー形式として良いのですが)に
ついて理解が深まった後は、
bmpの画像ファイル、wavなどの音声ファイルをあけて、
これの中身を書き換えて遊びます。

特にwavファイルは、音量の変更や周波数フィルタなども掛けれますので、
メモリ、配列、ファイルの関係を(焦らずに)ゆっくり理解するだけで、
今の知識レベルでも面白いことが沢山出来ます。

以上、ご参考に成れば。

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから...続きを読む

Qtry{}catch(){}とデストラクタの関係を教えてください。

try-catchでメモリ確保を含むクラスをスローした場合、デストラクタはどの時点で働くのか、教えてください。たとえば、↓の使いかたは大丈夫でしょうか?

【1】
try{
 throw(CError(100, "エラー情報"));
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
}

【2】
try{
 CError err(100, "エラー情報");
 throw(err); // (1)
}catch(CError& err){
 //ここでerrを参照しても問題ないのでしょうか?
 //まだデストラクタはちゃんと動作するのでしょうか?
 //catchが呼び出し元のメンバであったりしても大丈夫なのでしょうか?
}

宜しくお願いします。

Aベストアンサー

【1】【2】どちらの場合も問題がありません。
コンパイラが必要に応じてerrオブジェクトのコピーを作成します。
デストラクタが呼び出されるタイミングはコンパイラに依存するところもあると思いますが、
例えばVC7.1では【2】は以下のように動作します。
(1) errオブジェクトのコンストラクタが呼び出される
(2) CErrorクラスのテンポラリオブジェクト(以下a)のコピーコンストラクタが呼び出される。
(3) errオブジェクトのデストラクタが呼び出される
(4) catch文まで到達
(5) aオブジェクトのデストラクタが呼び出される。

VC7.1では、【1】は以下のように動作します。
(1) errオブジェクトのコンストラクタが呼び出される
(2) catch文まで到達
(3) errオブジェクトのデストラクタが呼び出される。

コンパイラがオブジェクトのコピーを省略しているようです。


人気Q&Aランキング

おすすめ情報