Version 11.15
文字列配列の拡張
「今まで文字列について見てきたけど、結局は CString とかの文字列クラ
スを使うことになります」
『コンストラクタとデストラクタがあるから便利ってことよね』
「もちろんそうなんだけど、文字列クラスを使うとそれ以外にもいっぱいメ
リットがあるんです」
・確保と解放を必ず対にして処理してくれる。
・コンストラクタで領域を確保してくれる。
・デストラクタがで解放してくれるからメモリリークしない。
・リサイズ等について気にしなくていい。
・便利なメンバ関数が揃ってる。
・戻り値として返す事ができる。
・演算子を使って操作する事ができる。
『うわ、かなりいっぱいあるね』
「ただ、デメリットもあります」
・メモリを確保する関数を選べないクラスがある。
・文字コードが違う場合の処理が難しい。
・結局はある程度仕組みを知らないと危険。
・ C 言語では使えない。
『でも少ないね。文字コードとかはまだ先の話っぽいし。メモリを確保する
関数を選べないクラスって?』
「たとえば CString とか」
『つかそれしか知らないからダメじゃん……』
「あと、実は重要なのが C 言語でしか使えないって点。クラスは C++ でし
か使えないからね」
『 C 言語しか使えない状況ってあるの?』
「他の人と一緒にプログラム組むときに、その他の人が C++ 使えなかった
ら?」
『う”……そういうときは C の機能だけでやらなきゃいけないんだ』
「そういうこと。そういうときは malloc() とか使えばいいわけだけど」
『教わってるからあたしもできる?』
「だいたい大丈夫だと思うよ」
『だいたい?』
「たとえば」
char *pch = (char *)malloc( strlen( DATA ) + 1 );
「ってメモリを確保したとします。で、この文字列に別の文字列をくっつけ
たいっていう場合、どうすればいいのか、とか」
『あー、そういうのは教わってないもんね』
「そういうときは、ふたつの文字列の長さを足したサイズだけ malloc() し
て、そこにふたつの文字列をくっつけて入れて、ポインタを置き換えます」
『?』
「やってみた方が早いかな」
void Concat()
{
// このデータが入る領域を確保します。
const char *const DATA = "あいうえお";
// 確保。
char *pch = (char *)malloc( strlen( DATA ) + 1 );
strcpy( pch, DATA );
TRACE( "%s\n", pch );
// これに次の文字列をくっつけます。
const char *const DATA2 = "かきくけこ";
// 両方入るサイズだけ確保します。
char *pchTemp
= (char *)malloc
( strlen( pch )
+ strlen( DATA2 )
+ 1
);
// まず最初の方をコピー。
strcpy( pchTemp, pch );
// 後の方をくっつけます。
strcat( pchTemp, DATA2 );
// 最初に取った方を解放。
free( pch );
// ポインタを置き換えます。
pch = pchTemp;
// これでサイズの拡張が完了しました。
// 出力。
TRACE( "%s\n", pch );
// あいうえおかきくけこ
// 最後にやっぱり解放します。
free( pch );
}
『長!!』
「って言っても、実際には同じ事を2度してるようなもんなんだけどね。前
半部分は前と同じだから飛ばして、まずはここ」
// 両方入るサイズだけ確保します。
char *pchTemp
= (char *)malloc
( strlen( pch )
+ strlen( DATA2 )
+ 1
);
『あ、これがふたつの文字列のサイズを足したの、ってことね』
「そう。これを pchTemp に入れておきます」
『 pch に入れちゃいけないの?』
「だって」
// まず最初の方をコピー。
strcpy( pchTemp, pch );
「って感じに元の文字列をコピーしなきゃいけないんだから」
『そっか。 pch に入れちゃったら前のポインタがなくなっちゃうんだ』
「これで、 pch と pchTemp には同じ文字列が入ってます。次に」
// 後の方をくっつけます。
strcat( pchTemp, DATA2 );
「この strcat() ってランタイムで文字列をくっつけます」
『第1引数のに、第2引数のをくっつける、んだよね』
「そう。これで、 pchTemp の中には "あいうえおかきくけこ" が入ってる
ことになります」
『ってことはこれでオーケー? でもまだなんかやってるよね』
// 最初に取った方を解放。
free( pch );
// ポインタを置き換えます。
pch = pchTemp;
『最初に malloc() してきたのを free() してから、 pch に pchTemp を入
れる……あ! そっか、そうしないと最初に malloc() したのがメモリリー
クするんだ』
「そういうこと。この辺ちょっとわかりづらいからちゃんと見ておこうか。
たとえば」
pch -> 0x00000001
pchTemp -> 0x00001001
「っていう感じにそれぞれにアドレスが入っていたとします。で、それぞれ
のアドレスの場所には」
あいうえお
↑0x00000001
あいうえおかきくけこ
↑0x00001001
「っていう感じにメモリに入ってます」
『で、まず pch の方を free() するんだよね』
「だから、 0x00000001 のメモリ領域が開放されます」
DD DD DD DD DD DD DD DD DD DD
↑0x00000001
あいうえおかきくけこ
↑0x00001001
「 DD が入ってるのはデバッグモードだから、ってことで」
『前回のやつね』
「でも、この時点では」
pch -> 0x00000001
pchTemp -> 0x00001001
『これは変わってないわけね』
「もちろん 0x00000001 は使えないけどね。で、実際に使うポインタは
pch の方だから、 pchTemp のアドレスを入れて」
pch -> 0x00001001
pchTemp -> 0x00001001
「これで、 pch の方に〈あいうえおかきくけこ〉のが入ったことになるわ
けです」
『 pchTemp の方でくっつけたりして、 pch を解放してから pchTemp のと
入れ替え……めんどくさいねー』
「というわけで、 CString を使うと簡単」
void ConcatWithCString()
{
// まず最初の文字列を渡します。
const char *const DATA = "あいうえお";
const char *const DATA2 = "かきくけこ";
CString cStr;
// まず最初の文字列を入れます。
cStr = DATA;
// 次に2番目の文字列をくっつけます。
cStr += DATA2;
// 出力。
TRACE( "%s\n", cStr );
// あいうえおかきくけこ
}
『うわ、簡単すぎる……』
「 CString は = とか += とかで文字列を操作できるからね。なんでできる
のか、というわけで次回に続く!」
/*
Preview Next Story!
*/
『メモリの話のあとは、クラスの話ぃ?』
「ちょっと色々振れすぎてる?」
『さすがにね』
「でも、同じ文字列操作の話なんだよ?」
『どっちも技術的には必要なこと、ってこと?』
「というわけで次回」
< Version 11.16 簡単なクラスを作ってみよう! >
『につづく!』
「作らなくても使えるけど、やっぱり使えなきゃ」
『ってしてるから必要なことが増えるのよー』
「まぁ元々いっぱいあるし、必要なことは」