#pragma twice

KAB-studio > プログラミング > #pragma twice > 208 Version 11.08 文字列クラスふたたび

#pragma twice 208 Version 11.08 文字列クラスふたたび

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

 Version 11.08
文字列クラスふたたび

『ふたたび?』
「そう。前回は Version 5.22 ( No.087 ) で」
『そういえばそのときも配列とか CString とか使ったね』
「そのときも言ったけど、文字列を配列じゃなくクラスで操作すると、いろ
んなメリットがあります」

・可変長だからサイズを気にしなくていい。
・便利な関数を使うことができる。
・演算子で操作できる。

「対してデメリットは次のようなものがあります」

・文字列を受け取るのが苦手。
・使えない環境もある。
・演算子を使うと間違った操作をすることがある。
・仕組みを知らないで使うと危険。

『デメリットの方が多いじゃん!』
「そうなんだけど」

・可変長だからサイズを気にしなくていい。

「のメリットが計り知れないんです」
『なんで?』
「それはあとのお楽しみ」
『全然楽しみじゃないし……』
「とりあえず、今回は文字列クラスについて慣れておきます。復習も兼ねて
ね」
『はーい』
「まずは普通に使ってみます」

void UseCString()
{
    CString cStr;
    cStr = "あいうえお";
    TRACE( "%s\n", cStr );
    // あいうえお
}

「今回、文字列クラスは CString を使います」
『他にもあるの?』
「うん、 std::string っていうのもあるんだけど、そっちはちょっと上級
者向けだから。で」

    CString cStr;

「で、 CString の変数 cStr を作ります。この中に文字列を入れられま
す」
『入れてるのが』

    cStr = "あいうえお";

『ってわけね。 = で入れられるのは便利よねー』
「それに」

    TRACE( "%s\n", cStr );

「というふうに、文字列として使えるところはすべてそのまま使えます」
『便利よね』
「で、これと同じ事を char の配列で試してみます」
『便利じゃない例ってわけね』

void UseCharAry()
{
    char pch[256];
    strcpy( pch, "あいうえお" );
    TRACE( "%s\n", pch );
    // あいうえお
}

「まず、 char の配列を作ります」

    char pch[256];

「当然、この配列には 256 文字以上は入りません」
『でも CString はそういうの関係なく入ります、と』
「そういうこと。それが CString のアドバンテージのひとつ。次に」

    strcpy( pch, "あいうえお" );

「と、文字列を入れる時にはランタイムを使わなくちゃいけません」
『 CString なら = で簡単にできる、と』
「まぁ最後の TRACE() で出力は同じようにできるってことで」
『たったこれだけで見ると CString の方がむっちゃ便利よねー』
「じゃあ苦手な方もしておこうか。まず、普通に文字列を受け取ることがで
きません」

void UseCStringForRecieveBad()
{
    CString cStr;
    strcpy( cStr, "あいうえお" );
    TRACE( "%s\n", cStr );
}

『あ、エラーだ』

error C2664: 'strcpy' : 
 1 番目の引数を 'class CString' から 'char *' に変換できません。
 この変換を実行可能なユーザー定義変換演算子がないか、
 または演算子を呼び出せません。

「なんでこうなるかっていうと、 strcpy() の型がこうなってるから」

 char *strcpy( char *string1, const char *string2 );

「1番目の引数は char * 、2番目の引数は const char * 。で、 CString 
には const char * が来た時に自動的に中の文字列を渡す機能はあるんだけ
ど、 char * に対する機能はないんです」
『なんで?』
「だって」

    CString cStr;

「この時点で、中に入ってる文字列は空。配列で言えば、この中に入ってる
配列は」

    char pch[0];

『げ、これじゃ文字列受け取れないね』
「そういうこと。受け取るためには」

    char pch[256];

「って感じに領域を確保しなきゃいけないんです。そのためのメンバ関数が
CString::GetBuffer() と CString::ReleaseBuffer() です。というわけで
これを使って文字列を受け取ってみます」

void UseCStringForRecieve()
{
    CString cStr;
    strcpy( cStr.GetBuffer( 256 ), "あいうえお" );
    cStr.ReleaseBuffer();
    TRACE( "%s\n", cStr );
    // あいうえお
}

『お、ちょっと長いけど受け取れてる』
「 CString::GetBuffer() は、引数で渡されたサイズ分、文字列を置く領域
を確保します」
『つまり』

    char pch[256];

『ってするってことね』
「そういうこと。で、この戻り値の型は char * だから、これをそのまま渡
す事ができます」
『で、受け取れるわけね。そのあとの CString::ReleaseBuffer() ってなに
やってんの?』
「これは後始末。たとえば文字列のサイズの取り直しとか」
『文字列のサイズ?』
「 CString の中に持っている〈文字列サイズ〉を取得し直してるんです。
中に入ってる文字列が変わったわけだから、そういう情報も取り直さないと
いけないから」
『なるほどねー』
「で、これをもう一度見て欲しいんだけど」

    strcpy( cStr.GetBuffer( 256 ), "あいうえお" );

『文字列を受け取るために、中身を広げてるとこだね』
「でも、これって無駄なんです。サイズはわかってるんだから」

void UseCStringForRecieveOptimizeSize()
{
    CString cStr;
    strcpy
        ( cStr.GetBuffer( strlen( "あいうえお" ) + 1 )
        , "あいうえお" 
        );
    cStr.ReleaseBuffer();
    TRACE( "%s\n", cStr );
    // あいうえお
}

『 strlen() で文字列のサイズを取得……して、それ使って中身広げれば絶
対に受け取れるサイズになるってわけね。あれ? でもさ、同じ事を配列で
もすればいいんじゃないの?』
「ところが、これは配列では使えないんです」

void UseCharAryBad()
{
    char pch[ strlen( "あいうえお" ) ];
    strcpy( pch, "あいうえお" );
    TRACE( "%s\n", pch );
}

『あ、エラーだ』

error C2057: 定数式が必要です。

「配列のサイズは、コンパイルするときに判っていないといけないんです。
だから、プログラムの途中でサイズを変えたくても変えられないんです」
『でも CString はできてたよね』
「そう、もちろんその方法はあって、でもそれが面倒なんです。というわけ
で次回に続く!」

/*
    Preview Next Story!
*/
『 CString ってやっぱり便利ねー』
「でもそのためには仕組みを知らなくちゃ」
『知らなくちゃいけないの?』
「下手な使い方するとまずいことになるから」
『プログラミングってそういうの多いよね』
「でも、多い割には知られてない事も結構……」
『げ』
「というわけで次回」
< Version 11.09 メモリを動的に確保する >
『につづく!』
「というわけでやっぱり仕組みを勉強してもらいます」
『やっぱり面倒そう……』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。