#pragma twice

KAB-studio > プログラミング > #pragma twice > 077 Version 5.12 ランタイムは面倒!

#pragma twice 077 Version 5.12 ランタイムは面倒!

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

 Version 5.12
ランタイムは面倒!

じゃ、前回の続き!

    int iError = 0;
    int iTemp = 0;
    while( !feof( pstFile ) )
    {
        char chOneLine[256];
        fgets( chOneLine, 255, pstFile );
        iError = sscanf( chOneLine, "%d", &iTemp );
        if( iError == 0 )
        {
            TRACE( "整数値じゃないです\n" );
            break;
        }
        char chDest[256]; 
        sprintf( chDest, "%d", iTemp );
        m_cDataLstBox.AddString( chDest );
    }

ここが実際に読み取ってるとこよね。 std::ifstream だと >> ってして
るとこ
それに当たるのが、ランタイムの fgets() と sscanf() 
ふたつ必要なんだねー。まず、最初の feof() って、やっぱ End Of File 
かどうか調べるの?
そう、 std::ifstream のときと同じく、ファイルの最後かどうか調べる
ランタイム関数。ここで pstFile 渡してることに注意
ファイルポインタね。これを渡せば、 fopen() したときのファイルを操
作できるってことね
そういうこと。で、中カッコの中、最初の chOneLine はとりあえず1行
ファイルの中の文字列を取っておくための文字配列
例によって 256 文字までなのは適当?
そう、こうしちゃうとファイルの1行が 256 文字以上だと入り切らない
から、ちゃんとしたプログラムじゃ使っちゃダメ
はいはい。次の fgets() はランタイムだって言ってたよね
 fgets() は、ファイルから1行読み込んで文字配列に格納するランタイ
ム関数
第1引数がその文字配列で今作った chOneLine 、第3引数は読み込むファ
イルを指すファイルポインタ。第2引数は?  256 文字と関係ありそう
そう、第2引数は〈取り込む文字数の上限〉。文字配列が 256 文字まで
だから、入りきるように 255 文字ってしときます
なんで1文字少ないの?
……気分
なんじゃそりゃ
どうもきっちりすると不安でね。 [] で指定するのは要素数−1、ってい
うのと関係してるかも
0から始まるもんね。でもなんか適当
適当って言えば、 256 とか 255 とかの直打ちはホントはダメ
 const int だよね。でも実際には、やっぱ動的に変数作る、ってので入
りきるようにするのが一番?
そだね、ファイルサイズを知る方法があるから、それのサイズ分だけ作っ
てまずファイルを全部格納してから、って方法になるかな
だったらそれ教えてくれればいいのに
難しいよ〜?
う”
さて、 fgets() で1行読み込んだら、次は sscanf() の出番
あ、なんか TRACE() ちっく!
 sscanf() はランタイム関数のひとつで、文字列から整数とかを取り出す
もの。どう取り出すかは第2引数で、 sprintf() や TRACE() と同じ書式で
指定します
第1引数はその文字列だよね。なんか sprintf() の逆って感じ。第2引
数が "%d" だから整数値取り出すんだね。あれ? 第3引数の &iTemp っ
て?
その整数値を受け取るための変数。 Ver 4.14 ( No.064 ) を読み返して
なるほど、 iTemp のアドレス渡して、そのポインタ使って iTemp に値を
入れてくれてるわけだ
うまくいけば iTemp に 100 とか 200 とかが入ることになります
うまくいかなかったら?
戻り値に0が返ってきます。それを iError に格納して次の if でチェッ
クしてます
 std::ifstream::fail() の代わりね
ただ、 sscanf() は型のチェックしかしてくれないから。 100 の代わり
に A とかだと
整数値じゃないですって出る
 代わりに 10000000000 だと
整数値じゃないですって……出ない!! エラーになんないんだ、しかも
変な値が出てるし
というわけで、実際には sscanf() の前にこのサイズチェックをしないと
ダメ
いろいろ知ってるからツッコミ入れないけど……
ちなみに std::ifstream では、このチェックはちゃんと行われてます
そゆとこも便利なのね
そのあとの3行は std::ifstream の時と同じ
 sprintf() で文字列に変えて、 CListBox::AddString() でリストボック
スに追加。って、やっぱ無駄骨って感じが……
ランタイムに isdigit() っていう〈文字が数字かどうか〉を調べる関数
があるから、それ使ってもいいかもね
ランタイムって結構色々あるのね
んで中カッコの最後まで行ったら再び while の最初へ。 いきなり
std::ifstream の時の話に戻るけど、 >> を使うと〈ファイルを指し示す針〉
が先に進むって言ったよね
うん言った。これが最後まで行ったら EOF が出てくるんだよね
この辺の仕組みは、ウィンドウズのファイル操作そのものの仕組みだと
思って。ウィンドウズの中に〈ファイルを指し示す針〉があって、それが
ファイルを読み取るごとに進む、って形
それってこの前の fopen() とかで〈ファイルを開く〉とかのと同じシス
テム?
そう、同じ。そういうのがウィンドウズのシステムに備わってるってこと
だね。つまり!
つまり?
 iostream とランタイム、内部的には両方とも同じことをしてるってこと
はー、一方は std::ifstream を使って、もう一方は fopen() とかの関数
を使ってるけど、中身的には同じことしてるんだ
だから、操作方法が違うってだけで、実際にやってることは同じってこと
を憶えておいて
ま、その方が憶えやすいけどね
で、今使ったランタイムのうち、 fgets() の方が読み取る度に〈次に読
み取る位置〉をひとつ進めるから
 fgets() 呼んでその〈次に読み取る位置〉が進んで、 feof() を呼んで
最後かどうか調べて、最後なら while から抜けるって寸法ね
ちなみに、この〈次に読み取る位置〉のこともファイルポインタって呼ぶ
んだよね
げ、それって混乱する!
基本的に別物だから注意してね。僕は、これからは〈読み取りポインタ〉
って呼ぶから
それよし! でもポインタってことは
あー、いわゆるポインタとはちょっと違う……ってことでもないし……
煮え切らないわねー
ま、ファイルのどっかを指し示すポインタで、 fgets() とかしたら次に
'\n' が出るまでポインタが進む、くらいのイメージでいいかな
そういう機能としてポインタみたいなもの、ってことね
あと、読み取りポインタが進むのは fgets() だけ。 sscanf() は進まな
いから
どゆこと?
たとえば文字配列に 100 200 って入ってるときに、 std::ifstream と
>> を使うと、 100 の次に 200 って出てきます
うん、それが普通そう
ところが、 sscanf() の場合には 100 の次に 100 、つまりあくまで先頭
からしか読み込まないから
うわ、使えなさそう
ま、 sscanf() は文字列から読み取るのだからっていうのもあるんだけど
ね。だから、読み取りポインタを進めるのは fgets() の方だけ、ってこと
はーい
とういうわけで、もう一度全体を見ると

void CFileTestDlg::OnBtnShow() 
{
    // ファイルを開きます。
    FILE *pstFile
        = fopen( "Data.txt", "r" );
    if( !pstFile )
    {
        TRACE( "ファイルがない!\n" );
        return;
    }

    int iError = 0;
    int iTemp = 0;
    while( !feof( pstFile ) )
    {
        char chOneLine[256];
        fgets( chOneLine, 255, pstFile );
        iError = sscanf( chOneLine, "%d", &iTemp );
        if( iError == 0 )
        {
            TRACE( "整数値じゃないです\n" );
            break;
        }
        char chDest[256]; 
        sprintf( chDest, "%d", iTemp );
        m_cDataLstBox.AddString( chDest );
    }

    // ファイルを閉じます。
    fclose( pstFile );
    return;

// 以下略。

やっぱ iostream 使うよりはずっと面倒だよね
 fgets() と sscanf() のふたつを呼んでるし、その分とりあえず置いて
おくための変数も作ってるし
あと fclose() 呼んでるのもめんどいかな。こういうのもやっぱ、 C++ 
の機能を使ってるからなの?
そういうことになるね。でも fgets() とかのはちょっと違うかな。この
辺は中身の違いかも
ま、 iostream 使う方が楽そうってのは確かね
でもそうとも限らないけどね。使いこなすとしたら、その C++ の機能を
知らないと
……やっぱ、あたしもそれ知らないとダメ?
もちろん。近々教えるよー
げげ
最後に、今回のファイル操作は、これがすべてってわけじゃないから
さっき〈全部最初に読み込む〉とかって方法言ってたよね
ループ部分だけ見ると、こんなプログラム

    // ファイルから読み込みます。
    char chOut[256];
    int iOneCharTemp;
    for( int iIndex = 0; iIndex < 256; iIndex++ )
    {
        iOneCharTemp = fgetc( pstFile );
        if( feof( pstFile ) )
        {
            break;
        }
        chOut[iIndex] = static_cast< char >( iOneCharTemp );
    }
    chOut[iIndex] = '\0';

む、 for になってる。 feof() は知ってるけど、 fgetc() とか初見
 fgetc() はファイルから1文字ずつ読み込むためのランタイム。 MSDN 
の【ストリーム入出力ルーチン】ってページにいっぱい関数があるでしょ
うおいっぱいある。あ、 fopen() とかそーゆーのがあるね
ここにあるのは、ランタイムの中でもファイル操作をするための関数群。
こういうの使いこなせるようになるだけでも結構色々できるようになるから


/*
    Preview Next Story!
*/
ってことは、来週はその色々?
ぶっぶー。そんな暇はないのです
自分のせいで遅れまくってるくせに
う”
というわけで次回
< Version 5.13  MFC でファイル操作! >
につづく!
げ、水希ちゃんお得意のパターンだ!
いろんなライブラリを知れば、おのずと見えてくるのです!
ヤバイ宗教みたい……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。