前回「EOF判定されない」で回答、アドバイスしていただいた
a-kumaさん、Haizyさん、inthefloiさん、anisolさん、leaz024さん、cherry-moonさん
本当にありがとうございました。頂いたアドバイスを試行してみましたが、なぜか、ダメでした。(T-T)
環境が悪いのかもしれませんね。

あれから、feof関数を使わずにファイルの終わりを算出して判定するなどの方法を試みましたが、EOF判定だけのために妙に複雑になってしまい、自分でも納得がいかなかったので、再度こちらで皆さんの意見をもらおうと投稿させてもらいました。

今回は質問の仕方を変えて、モジュールの仕様を挙げますので、それから「自分ならこうする」というようなお答えを頂けたらと思っています。
feof関数を使用しても、その他の方法でもなんでもアリです。(^^)

「ファイル一行入力モジュール」(仕様)
1.このモジュールは実行されると「inputfile.txt」から一行だけ(改行まで)読み込み、終了します。次に実行された時は、その次の行を読み込みます。
2.ファイルの終端に達したら、リターンコードに'4'を設定し、終了する。
以上これだけ。(^^;

「inputfile.txt」(仕様)
インプットファイルは、テキストファイルで、一行30バイトの文字列を格納しています。ファイルの総バイト数は不定です。
文字コードは「Shift-JIS」「改行=CR+LF」、ファイルの最後にEOF制御文字を設定しています。

「インプットファイルの内容」

 1行目 AAAAAAAAAABBBBBBBBBBCCCCCCCCC[改行文字]
 2行目 DDDDDDDDDDEEEEEEEEEEFFFFFFFFF[改行文字]
          ・
          ・
          ・
n-1行目 XXXXXXXXXXYYYYYYYYYYZZZZZZZZZ[改行文字]
 n行目 [EOF]

「ここはこうしたらいいんじゃないかな?」的な事でかまいませんので、是非みなさんの意見を聞かせてください。

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

A 回答 (8件)

問題がでそうなところと言うと,[EOF](^Z)を追加しているところと、ファイルのオープン方法でしょうか。




まず、WindowsとかMS-DOS環境の場合は,
fopenを使い,テキストモードにしておけば問題無いように思います。

f=fopen("inputfile.txt","r");
while( fgets(buff,sizeof(buff),f) );
if ( feof(f) )printf("EOF\n");

みたいにするとこちらではEOF検出してます。

a-kumaさんのが仕様に忠実にできていて正しく動きそうですね。
わがままな私はこの仕様に不満があるので書きませんが(笑)


ところでテキストモードですが、元々unixとのライブラリの整合性をとるためのエミュレーションモードみたいなものです。
これは、DOSやWindowsがunixと改行コードが違ったり,EOFコードがあったりしても
同じプログラムで動作するようにしたものですから、
unixはそういう変換は不要でそもそも区別する必要がなく、モードが存在しないのです。

改行等がからむ物はテキストモードにするのが簡単で間違いないですし、そのままunixでも動作させられます。
バイナリモードでオープンしてfgetsで読むとどうなるか等調べないとわからないような物は面倒です(^^;;


また、EOFコードは確かCP/Mかなんかの名残であるもので、本来は不要なコードです。
必要だったのは,ファイルシステムにファイルサイズが存在しないためです。(クラスタ単位でしかわからない)
    • good
    • 0

補足ありがとうございます。

素人ですが、もうちょっと調べてみました。私の前の回答は的外れだったみたいです……。

feof()と[EOF]の組み合わせは使わないほうがいいかもしれません。というのは、feof()で[EOF]を認識させることはバイナリモードではできないようです。またUNIXではfopen()はバイナリモードしかないようで、機種依存的になります。[EOF]のコードを使わず、単純にファイルの終わりをfeof()で調べるのはだめですか?

とりあえず、今まで調べた結果なので間違っているまたは的外れだったらごめんなさい。
    • good
    • 0

私も前回の回答を見たらトホホでした。



29文字+CR+LFの31バイトに確実に固定されていて、ウィンドウズ系以外のOSであるならば、fgetsを使わずに、

char buff[31];
if (fread(buff, 1, 31, fp) < 31)
{
 if (feof(fp))
 {
  rtn_code[0] = '4';
 }
 else
 {
  rtn_code[0] = '8';
 }
}
else
{
 buff[29] = '\n';
 buff[30] = '\0';
}

というような、やり方もあるかなと思います。
    • good
    • 0

こんにちは。



前回は、とろけていてゴメンナサイ。

さて、前回の最後の投稿で、触れたかもしれませんが、「改行=CR+LF」ということなので、これ自身が ”2バイト” 食っていると思います。
ですので、fgetsの第二引数(何文字読み込むか)を第一引数の限界も考慮しつつ、大きくする事が有効ではないかと思います。
【#3の例】
>char buf[1024]
完璧です。
>fgets(buf, sizeof(buf), in) ・・・・
sizeof(buf) が、文句なしの完璧です。さすがッス。こんな感じです。

同時に16進で、監視式によりbufの値を監視してみてください。
動きが変だと、ココでわかると思います。

でわ、失礼します
    • good
    • 0

前回の質問、解決したのか気になって、夜も寝られませんでした(嘘)。

早めに補足を行ってくださいね……。

ところで、
・[EOF]はどのような方法で書きこんでいるのでしょうか。またそのコードは何ですか。
・Windowsベースでのプログラムですか、またはUNIXベースですか。
・単純に[EOF]だけ書きこんだファイルで、fgets(buff, 2, fp) およびfeof(fp)を実行したとき、EOF判定はされますか。(この点は重要かも)

以上お手数ですが補足していただけますか。ちょっと情報が少なすぎますので。

この回答への補足

毎度毎度説明不足でスイマセン(--:

・EOF制御文字は、秀丸エディタのオプションで「保存する時に、EOF制御文字を付加する。」にチェックを入れることでファイルに保存されています。
バイナリエディタで見ると'1A'となっています。
・Windowsベースのプログラムです。
次に、
EOFだけを書き込んだファイルですが、秀丸では文字が記述されていないと保存できずに削除しようとするので、他のバイナリエディタを使用し1Aとだけ書いて保存しました。

それから説明不足がもう二つあります。(ホントすいません)

1.fgetsの第二引数にunsigned long型のlengthという箱を使ってます。
で、このlengthにrecord_lngsをstrtolでlong型に変換して代入しています。

unsigned long length;
char record_lngs[5]; ←これには00020という文字列が格納されています。
char *endptr;
char buf[32756];

length = strtol(record_lngs, &endptr, 10);

if (fgets(buf, length, in) == NULL) {
   if (feof(in)) {
     return 4;
   }
}
こんなかんじで実行しましたが、4は返ってきませんでした。
lengthに入ってるの20じゃダメじゃん!?と、お思いでしょうがなぜかこれでgetは正常に行われます。lengthに1や2を足してgetすると、何も読みこまれなくなります。これも謎ですね。

2.inputfile.txtは1レコード(一行)の大きさが32756バイトです。今回その1レコード(一行)に入っているデータは固定長の20バイトですが、他にも5000や,32756バイト入っている場合もあります。
こんな粗悪な説明でわかりますでしょうか?また何か説明が必要でしたら書き込んでください。(うう、もっと文章力つけとけばよかった)

補足日時:2001/10/31 14:07
    • good
    • 0

ん~、何がうまくいかないのか、よく分からんです。



と、いうわけで、提示された仕様に忠実にデータを抱えてしまっていますし、
エラーチェックもしてませんが、こんな感じの関数で良いんじゃないですか?

#include <stdio.h>

int xxx()
{
  char buf[1024];
  static FILE* in = NULL;
  if (in == NULL) {
    in = fopen("inputfile.txt", "r");
  }
  if (fgets(buf, sizeof(buf), in) == NULL) {
    if (feof(in)) {
      return 4;
    }
  }
  return 0;
}

/* テストコード */
int main()
{
  int ret;
  int i;
  for (i = 0 ; (ret = xxx()) == 0 ; ++i) { printf("%d\n", i); }
  printf("ret = %d\n", ret);
  return 0;
}
    • good
    • 0

訂正!回数間違えました!!



従ってfgetsは4回行われますが、3回目で1文字以上を格納し、かつ、EOFを検出しています。つまりfgetsはNULLを返していません。このときにfeofを実行すれば「EOF検出」となるのですが、4回目を実行したためにfeofは「非EOF検出」となっています。

以上です(汗)
    • good
    • 0

前回の質問を今さら見ました。



まず、fgetsの使い方が間違ってます。第2引数は読みとる文字数+1なんです。つまり、テキストモードで開いた場合、20文字+改行文字で21キャラですから「22」以上を指定しなければなりません。これは、読みとった文字列の最後にナル文字を格納するためです。
従ってfgetsは5回行われますが、4回目で1文字以上を格納し、かつ、EOFを検出しています。つまりfgetsはNULLを返していません。このときにfeofを実行すれば「EOF検出」となるのですが、5回目を実行したためにfeofは「非EOF検出」となっています。

対策としては、充分な格納領域buffと読みとり文字数を引数にして、最後の行に改行があることを信じないで、毎回EOF判定する。

こんなとこでしょうか?
    • good
    • 0

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

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

このQ&Aを見た人はこんなQ&Aも見ています

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

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

Qchar *name1[4] とchar name2[][4] の違いについて

C言語のことで質問があります。

char *name1[4]は
char *name1[4] = {"abcdefghi","jkl","l","mn"};
と宣言でき,ポインタを4つ確保した形となりました。

char name2[][4]は
char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"};
と4文字以内の文字列を初期化した数だけ確保した形となりました。

この結果からchar *name1[4]の意味は,char name2[][4]ではなくchar name2[4][]に近いと思いました。
しかし,char name2[4][]ではポインタを4つ確保した事にはならないみたいでコンパイルが通りません。
*name1[4]では4つのポインタを確保できるのに~と思ってしまいます。

ポインタと配列は別物と考えるべきなのでしょうか?
訳の分からない質問かもしれませんが,
何卒ご指導いただくようよろしくお願いします。

Aベストアンサー

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり、この場合のa1は、
変数ではなく、定数のようなものなのです。

複合的なケースについて見てみましょう。
char **q1; ポインタへのポインタ
 q1,*q1,**q1,q1[0],*q1[0],q1[0][0] のいずれも変数として
 扱うことができます。(値を代入することが文法的に許されます。
 ただし、実行時にはアクセス違反になる場合もあります。)
char q2[4][4]; 二次元配列
 q2,q2[0]は変数として扱うことができません。q2[0][0]のように
 して、初めて変数として扱えるようになります。
char *q3[4]; ポインタの配列
 q3は変数として扱うことができませんが、q3[0],*q3[0],q3[0][0]
 はいずれも変数として扱うことができます。
 なお、この定義は char *(q3[4]); とした場合と全く同じ意味です。
char (*q4)[4]; 配列へのポインタ
 q4,(*q4)[0],q4[0][0]はいずれも変数として扱うことができます。
 しかし、*q4,q4[0]は変数として扱うことができません。

char *name1[4]; と char name2[4][]; は確かに似ています。しかし
違うところもあります。それは、name1[0] が変数として扱えるのに
対し、name2[0] には値を代入できないという点です。(データの
具体的な構造については、inthefloiさんが書いておられる通りです。
> char name2[4][]ではポインタを4つ確保した事にはならないみたい
というのも、全くその通りで、配列の定義では、ポインタ変数の領域
を確保する余地はないのです。

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり...続きを読む

Q[VC++][MFC][SDI]ダイアログコントロールもしくわツールバー!!詰まってます!!

現在VC++6.0でMFCを使いSDIのプログラムを作っているのですが、フォームにダイアログバーを張っています。

これをツールバーのように自由に動かしたり、左右上下にドッキングさせたり。
これって実現可能でしょうか?

色々ためしてみたんですが無理でした。
やっぱ不可能ですかね?

これが無理なんであればデフォルトで作成されるツールバー([新規作成][開く][保存]等が入ってる)にコントロール(ボタンやリストボックス)を追加して使用、と考えているのですがこれも難しい!!!


まだまだ未熟者なのですがどうかご存知の方おられましたらご教授ください!!
よろしくお願いします!!

Aベストアンサー

Dannerです。
参考URL(英語)を載せておきます。

参考URL:http://www.codeguru.com/Cpp/controls/toolbar/placingcontrolsintoolbars/article.php/c2505/

Q処理の速い当たり判定について[WINSOWS][C]

いつもお世話になっております。
WINDOWSプログラミングを勉強しています。

現在当たり判定について勉強しているのですが、調べてみたところいろいろなやり方があるようです。

私が今作ろうとしているのはアクションゲームなのですが、接地、ダメージ等々の当たり判定があり、毎フレームでこのような判定を繰り返すと重くなってしまうのでは、と危惧しています。

ここで質問なのですが、WINDOWSまたはCプログラムでなるべく速く処理ができる当たり判定を教えていただけないでしょうか?
また、初心者向けなものをお願いします。

我儘を言って申し訳ありませんが、ご指導よろしくお願いします。

Aベストアンサー

> 壁や床や敵の当たり判定は種類別にして構造体を配列にいれて判定をすればいいのですか?
> だとしたら毎フレームこれらのリージョンと自機のリージョンを判定するのでしょうか?

毎フレーム判定すれば良いと思います。
大まかな判定を先にして、それにヒットすれば細かく判定するというようにすると良いですよ。
たとえば、丸形の当たり判定は先に矩形で行ってからすると言った具合です。

> スクロールするステージを作成する予定なので、床や壁は結構多くなってしまうのですが・・・

そんなものじゃないでしょうか?
2Dのアクションゲームの場合、重くなる原因は、計算よりもむしろ描画処理だと思います。

Q[コンパイラ]xpでプログラミングの練習[フリーソフト]

大学でLINUXのemacsでプログラミングの学習をしている者です。

前からXPでそれらの練習やコンパイラに適したソフトが欲しいと思っていたのですが、
何かいいソフト、HPを紹介願えませんか?

どうかよろしくお願いします。

Aベストアンサー

 WindowsでC言語を勉強するなら、例えばコンパイラはフリーの
「Borland C++ Compiler 5.5」
を使用します。
 まず、下記からコンパイラを入手します。

http://www.borland.co.jp/cppbuilder/freecompiler/bcc55download.html

 そして、下記ページなどを参考にしてインストールします。
http://www.chem.scphys.kyoto-u.ac.jp/nonnonWWW/ogawara/lecture/borland.html

 エディッタはメモ帳でも良いですが、TeraPadというフリーソフトがお勧めです。
http://www5f.biglobe.ne.jp/~t-susumu/library/tpad.html

 TeraPadをインストール後に、
「表示」→「編集モード」→「C/C++」と
「表示」→「オプション」→「基本」→「オートインデント」
を設定すると使いやすいと思います。
 それでは、C言語の勉強頑張ってください。

参考URL:http://www5f.biglobe.ne.jp/~t-susumu/library/tpad.html

 WindowsでC言語を勉強するなら、例えばコンパイラはフリーの
「Borland C++ Compiler 5.5」
を使用します。
 まず、下記からコンパイラを入手します。

http://www.borland.co.jp/cppbuilder/freecompiler/bcc55download.html

 そして、下記ページなどを参考にしてインストールします。
http://www.chem.scphys.kyoto-u.ac.jp/nonnonWWW/ogawara/lecture/borland.html

 エディッタはメモ帳でも良いですが、TeraPadというフリーソフトがお勧めです。
http://www5f.biglobe.ne.jp/~t-susumu/libra...続きを読む

Qp[-3][-4]にアクセス出来るようにしたい

ポインタのポインタをうまく使って、p[-3][-4]のようなアクセス(が有効に行われるように)したいのですが、うまくいきません。
ご教授願えないでしょうか。

以下のコードで p[-3][0] を a[0][0] を参照させる(?)ようにはできました。
後ろ側の添え字のマイナスシフトができないのです。
つまり p[-3][-4] が a[0][0] を参照させるようにするギミックが知りたいのです。よろしくお願いします。

-------------------------------------

int **a;

// 領域の動的確保 ( [12][18] )
a = new int*[12];
for(int i = 0; i < 12; i++)
a[i] = new int[18];


int **p;

p = &(a[3]) ;

for (int y=0; y<12;y++)
for (int x=0; x<18;x++)
a[y][x] = 1;

p[-3][0] = 99; //a[0][0]が99になる。


//領域の解放
for(int i = 0; i < 12; i++)
delete [] a[i];

delete [] a;

ポインタのポインタをうまく使って、p[-3][-4]のようなアクセス(が有効に行われるように)したいのですが、うまくいきません。
ご教授願えないでしょうか。

以下のコードで p[-3][0] を a[0][0] を参照させる(?)ようにはできました。
後ろ側の添え字のマイナスシフトができないのです。
つまり p[-3][-4] が a[0][0] を参照させるようにするギミックが知りたいのです。よろしくお願いします。

-------------------------------------

int **a;

// 領域の動的確保 ( [12][18] )
...続きを読む

Aベストアンサー

どうしてもp[-3][-4]がa[0][0]を参照するようにしたいのでなければ、次のようにしてはどうでしょう。

-------------------------
int **a;

// 領域の動的確保 ( [12][18] )
a = new int*[12];
for(int i = 0; i < 12; i++)
 a[i] = (new int[18]) + 4; // ← 変更点

int **p;

p = &(a[3]) ;

for (int y=0; y<12;y++)
 for (int x=0; x<18;x++)
  a[y][x] = 1;

p[-3][0] = 99; //a[0][0]が99になる。

//領域の解放
for(int i = 0; i < 12; i++)
 delete [] (a[i] - 4); // ← 変更点

delete [] a;
-------------------------

上のコードでは、p[-3][-4]がa[0][-4]を参照することになりますが、目的は満たせるのではないでしょうか。

どうしてもp[-3][-4]がa[0][0]を参照するようにしたいのでなければ、次のようにしてはどうでしょう。

-------------------------
int **a;

// 領域の動的確保 ( [12][18] )
a = new int*[12];
for(int i = 0; i < 12; i++)
 a[i] = (new int[18]) + 4; // ← 変更点

int **p;

p = &(a[3]) ;

for (int y=0; y<12;y++)
 for (int x=0; x<18;x++)
  a[y][x] = 1;

p[-3][0] = 99; //a[0][0]が99になる。

//領域の解放
for(int i = 0; i < 12; i++)
 delete [] (a[i] - 4); // ← 変更...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報