#pragma twice

KAB-studio > プログラミング > #pragma twice > 086 Version 5.21 ファイル読み込みをさらにさらにブラッシュアップ!

#pragma twice 086 Version 5.21 ファイル読み込みをさらにさらにブラッシュアップ!

前のページへ 表紙・目次へ 次のページへ

 Version 5.21
ファイル読み込みをさらにさらにブラッシュアップ!

では前回の続き

    while( !cIFStrm.eof() )
    {
        cIFStrm
            >> i;
        if( cIFStrm.fail() )
        {
            MessageError( IDS_E_NONINT );
            return;
        }
        char chDest[256];
        sprintf( chDest, "%d", i );
        m_cDataLstBox.AddString( chDest );
    }

この chDest を while の前で宣言した方がいいってことなんだよね
そう。まず復習すると、 while のすぐ後にある { と } の塊を〈ネスト〉
って言います
で、変数はネストの中でしか使えないんだよね
なんでだっけ
えーっと、ネストの中でしか寿命がないから、外に出るとなくなっちゃう
んだよね
そういうこと。この〈外に出る〉っていうのがクセモノで、実は while 
のループ1回ごとにネストから外に出る形になります
げ、そうなの!?
これは、 while 自体はネストの外にある、って考えてもいいし、 Ver 2.7 
( No.018 )
 でやったように、ネストを省略すると〈次の行だけループ〉に
なるから
なるから?
なるから、ネスト全体がループの繰り返しの対象、って考えてもいいかな
なるほど。こう見ると、ネストが1行、ってみなされるのかな
そういうところあるかもね。で、なんで chDest は while の前で宣言し
た方がいいんだと思う?
えーっと、 while でループの外に毎回出るんだから、その度に……寿命
が切れちゃう、ってことは変数がなくなっちゃう!
そういうこと。ループの度に chDest が削除されて再び作られて、って繰
り返しになるからね
その繰り返しって結構無駄?
場合によるけど、そんな無駄じゃない
あらら
ただ、やっぱり場合によるからね。 std::ifstream 使ったときに〈削除
されるときに呼ばれる関数〉があるって言ったでしょ
そっか、それが何度も何度も呼ばれることになっちゃうんだ
そういうこともあるから、ある程度は気を付けておいた方がいいかな。あ
と付け加えるとすると
付け加えるとすると?
 int i; の部分も while の直前に置きましょう
えーっと、ずっと cIFStrm 作る直前にあったんだよね。あ、そういえば
while の中に入ってからだね、 i を使うの
そう、だから直前に作ることにします。ファイルがないときは作らずに済
むからね
結構細かいね
ま、それよりは〈使う直前に作る〉方が分かりやすいってのもあるかな。
さて次。今度はバグを直しましょう
ば、バグなんてあるの!?
あるんだよね。データが入ってる Data.txt を開いて
ほい。こーなってるんだよね

100
200
300

最後に改行加えてから実行してみて
ほい。……あ、 IDS_E_NONINT のエラーが出ちゃった!! なんでぇ!?
さて、なんでででょう
それを私に調べろと?
本気でプログラマーになるんなら、そういうことも調べられないとね
ううう……マニュアルに〈最後は改行しないで〉って書くのは
ダメ
やっぱり
ま、そうは言ってもこれは std::ifstream の関係だから、今の段階では
難しいよね
 std::ifstream の問題なんだ
そう、使いやすいってことで採用した std::ifstream だけど、仕組みは
難しいからこういう問題に出遭うとちょっときついかもね
そしたら fopen() とか使った方がいいってことになるのかな
それもいいし、 std::ifstream 一本で色々試していくのも悪くないだろ
うけどね。じゃ、この問題の理由について
うん
まず、 std::ifstream::eof() を呼び出した時に true が返ってくる条件
は?
ファイルの最後だったとき
そう。で、 cIFStrm >> i で整数値を読み込んだとき、最後に改行が入っ
てると、ちょうどファイルの最後に行かないわけ
どゆこと?
 cIFStrm の中に、次はどこから読み取るかが入ってるって言ったでしょ
 Ver 5.12 ( No.077 ) でやったね
最後の 300 を読み込んだとき、その位置が 300 の直後になるわけ
つまり、そのあとに改行が残ってるから、 std::ifstream::eof() でファ
イルの最後になんないんだ!
だから、改行じゃなくて 300 のあとにスペースを入れたりしても同じよ
うな結果になるから
スペース入れて実行、ホントだ
だから、改行やスペースがないときにはループは3回なんだけど、入って
るときは4回になるから
なければ 300 読み込んだときちょうど eof だから、4回目に入るときに
while で引っかかって終わるんだね
デバッグするときには、ブレークポイントを設置してこういった部分を調
べてるといいかな
なんか地道ね……しかもそれが分かっても解決方法分からないし
せかさないせかさない。重要なのは4回目のループ
4回目の cIFStrm >> i で読み込む時って、その改行やスペースしかない
んだもねんね、なに読み込んでるんだろぅ
ここで読み込めないから std::ifstream::fail() で true が返ってくる
わけ
そっか、これでエラー状態になっちゃうんだ!
でも実は、 cIFStrm >> i で読み込んだときに〈ファイルの終端が見つ
かった〉ってことで、 std::ifstream::eof() で true が返ってくる状態に
もなるんです
 std::ifstream::fail() かつ std::ifstream::eof() ってこと?
そういうこと。だから

    int i;
    char chDest[256];
    while( !cIFStrm.eof() )
    {
        cIFStrm
            >> i;
        if( cIFStrm.fail() )
        {
            if( !cIFStrm.eof() )
            {
                MessageError( IDS_E_NONINT );
                return;
            }
        }
        sprintf( chDest, "%d", i );
        m_cDataLstBox.AddString( chDest );
    }

ってすれば解決
ビルドして実行! おーうまくいった!
この、 eof になってるってことに気付くかどうかなんだよね
気付くコツってあるの?
経験と試行錯誤
……。それと、なんか見にくくない?
そうだね、ネストが深くなってるし、 cIFStrm.eof() を2回呼んでるっ
ていうのはちょっと汚いかもね
ネスト深いのってまずいの?
プログラムを追うのが大変になることが多いね。この場合には

        if( cIFStrm.fail() )
        {
            if( cIFStrm.eof() )
            {
                break;
            }
            MessageError( IDS_E_NONINT );
            return;
        }

って書くこともできるかな
これはこれでなんか……あ、別に fail() の必要ないんじゃない?
え?
たとえばさー、あ、これなら while の方も要らないから……

    while( 1 )
    {
        cIFStrm
            >> i;
        if( cIFStrm.eof() )
        {
            break;
        }

        if( cIFStrm.fail() )
        {
            MessageError( IDS_E_NONINT );
            return;
        }
        sprintf( chDest, "%d", i );
        m_cDataLstBox.AddString( chDest );
    }

ってするとか
うお! なぜこんな方法を……
なんか記憶の片隅に……そうそう、 Ver 2.9 ( No.020 ) で教わったよ
あ、そっか。確かにこれも方法のひとつ。でも……うーん
何迷ってんの?
この辺は色々人によってスタイル違うかな。 while に !cIFStrm.eof() を
残しておけば、そのループが〈ファイルの終端まで〉ってことで回ってるの
が分かるからね
無限ループだとどこで抜けるか分かりにくいかもね
ただ、そういうのにこだわると逆に解りにくくなるし、そういうのって個
人差が大きいからね
……で、どうしろと?
臨機応変で行きましょう
なんじゃそりゃ、それが教える立場の人間の言葉ぁ?
でもこれも大事なことだよ? チーム組んで〈無限ループは使わないよう
にする〉って決めたらこういうプログラムは書かないようにする
まわりに合わせろってこと?
じゃなくてー、コーディングスタイルくらい自由に変えられるようにしま
しょうってこと。どんなコーディングスタイルでもプログラムが書ける、そ
れがプロってもんよ
なんかそれプログラムのスキルと違う……

/*
    Preview Next Story!
*/
でも確かに、掲示板とかでこういうのフレーミングしてるよね
僕としては、そういうのは不毛だなーと思うからね
確かになんでこんなことでってことで熱くなる人多いよね
そ、そういうのにはあんまこだわんない方がいいね
というわけで次回
< Version 5.22 文字列クラス >
につづく!
でもこだわらないのってなんか軟弱ぅ
う”
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。