Version 9.14
配列を読み解く
「今回は、前回出てきた」
static UINT indicators[] =
{
ID_SEPARATOR, // ステータス ライン インジケータ
ID_INDICATOR_KANA,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
「について見てみます」
『ステータスバーに使うのなんだよね。 MainFrm.cpp の上の方にあるけ
ど、いまいちよくわかんない……配列なんだよね?』
「そう、配列。これは配列のちょっと特殊な作り方の例。えっと、まず復習
してもらおうかな。 Version 4.10 ( No.060 ) でポインタ関係のことを思
い出して」
『結構昔ねー。文字列とかはなんか今は〈 LPCTSTR は読み取り専用、
LPTSTR は書き込み用〉って感覚だけど』
「原理もちゃんと憶えてなきゃダメだからね。 Version 5.03 ( No.068 )
の方もちゃんと読んでおいてね」
『こっちは配列ね。そうそう』
int iAry[3]; // 配列。
iAry[0] = 1;
iAry[1] = 2;
iAry[2] = 3;
『って感じにするのが普通の配列だよね。これと、さっきのって全然違う感
じがする……』
「違うけど、同じ事。だから」
/*
static UINT indicators[] =
{
ID_SEPARATOR, // ステータス ライン インジケータ
ID_INDICATOR_KANA,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
*/
static UINT indicators[5];
「って置き換えて、」
『フツーに配列を作って……』
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
indicators[0] = ID_SEPARATOR;
indicators[1] = ID_INDICATOR_KANA;
indicators[2] = ID_INDICATOR_CAPS;
indicators[3] = ID_INDICATOR_NUM;
indicators[4] = ID_INDICATOR_SCRL;
// 以下略。
「って感じに CMainFrame::OnCreate() の中で値を入れれば」
『お、これでもちゃんと CAPS とか出るね。前の方法でもできるってこと
ねー』
「そう、だから自分で配列を作るときには前の方法でいいと思うよ。でも」
『読めないとダメ?』
「そゆこと。というわけで、ひとつひとつ見ていきます。まず」
static
「から」
『これまたピンポイントね』
「で、これは無視してください」
『なんですと!? いきなり無視ですか』
「そう、これがなぜ付いてるかっていうのはものすごーく難しい話になっ
ちゃうんで今回はパス」
『……ホント?』
「え? なんで?」
『だって、 static って前に出てるじゃない』
「そう、そこが問題。たとえば Version 6.02 ( No.102 ) で」
COver *GetCOver()
{
static COver s_cOver;
return &s_cOver;
}
『そうそう。こうやって static 付けると、関数から抜けても変数がなくな
らないんだよね』
「そうでした。ところが、今回の配列は関数の外に作られてます。そういう
変数をなんというでしょう」
『……問題?』
「問題」
『えっと、グローバル変数だよね』
「そうです。グローバル変数については Version 6.16 ( No.116 ) を参
照。この変数は .cpp ファイルの中ならどこからでも使うことができる、
ってことはなくならないってこと」
『あー、 static 付けなくてもなくなんないんじゃん……ってことは?』
「ということは、グローバル変数に付けた static と、ローカル変数に付け
た static は別の意味になるってことです」
『わ、わけわかんない……』
「で、このグローバル変数に付けたときの機能って、ちょっと込み入った話
になるから今回はパス、ってこと。3章くらいあとに出てくるからそれまで
待って」
『1年くらい後になるわけね』
「やっぱそのくらいは掛かるかな……。で、次」
UINT indicators[]
「これは Version 5.04 ( No.069 ) でやった」
char chAry[] = "ABC";
「の時と同じように、配列の中身の数を省略した書き方」
『そっか、あの文字列のと同じなんだね。あの時は、文字数と、あと \0 が
入ってたから4つ作ってくれたんだよね』
「今回のもそれと同じ、自動的に必要な数だけ確保してもらうための書き
方。で、この」
= "ABC";
「の部分、この文字列の〈文字数+終端文字〉が4文字だから」
『 chAry は4つ分入るわけよね』
「この部分に当たるのが」
{
ID_SEPARATOR, // ステータス ライン インジケータ
ID_INDICATOR_KANA,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
「ってわけ」
『なるほど! ここに5つ分あるから、……』
「文字列じゃないから終端文字とかないよ」
『ってことは5つ分?』
「そゆこと。 indicators は [] にして、 = { 値, 値, ... }; って渡す
と、この5つ分だけ必要ってことで」
『 indicators の配列が5つ分入るようになるわけね』
「そゆこと。もう少し分かりやすく書くと、さっきの」
int iAry[3]; // 配列。
iAry[0] = 1;
iAry[1] = 2;
iAry[2] = 3;
「を今の形式で書くと」
int iAry[] = { 1, 2, 3 };
『なるほどねー。こっちの方がシンプルで分かりやすいかも』
「いや、そうでもないんだけどね……」
『質問!』
「あ、はい火美ちゃん」
『えっと、』
ID_INDICATOR_SCRL,
};
『って、最後に , が付いてるけど、これいーの?』
「うん、この配列のところだけの特例なんだけど、最後の値のあとに , が
あってもなくてもいいようになってます。だから」
int iAry[] = { 1, 2, 3, };
「でもOK」
『 , 付けると、4つって取られたりしない?』
「それは大丈夫、3つ分しか取られないから」
『ただ , が無視されるだけなのね』
「ちなみに付けた方が便利かな。カット&ペーストで順番を入れ替えるとき
とか」
『そういえばそうね。っていうかそのため?』
「かも……」
『もひとつ質問』
char chAry[] = "ABC";
「とさっきのって、似てるよね」
『似てるけど、この "" を使う方法は文字列専用だから。たとえば、これ
を {} を使って書くと』
char chAry[] = { 'A', 'B', 'C', '\0' };
『うわ、めんど!』
「でしょう。だから文字列だけは特別に簡単に配列を作れるようになってる
んです」
『……なんか特例って多くない?』
「多いよ。はっきり言ってその辺は難しいと思うから、ひとつひとつ憶えて
いくしかないかもね」
『ぶー』
「ポインタや配列が難しいって言われる理由のひとつがこの辺かもね。こう
いう特例がいっぱいあるから」
『頭がこんがらがる〜』
「最後に、実際に使ってる部分を見ておこうか」
!m_wndStatusBar.SetIndicators
( indicators
, sizeof(indicators)/sizeof(UINT)
)
『ステータスバーのところなんだよね』
「そう。 CStatusBar::SetIndicators() は第1引数にステータスバーで使
う ID の入った配列、第2引数にその配列の要素の数を受け取ります」
『そうすれば自動的にステータスバーが機能する……って、第2引数って要
素の数、って配列の中身の数だよね、これがそうなの?』
「 Version 5.03 ( No.068 ) で見たように、 sizeof( 配列 ) は」
『全体のバイト数だよね。それを UINT の sizeof() で割ると……』
「 UINT は要素の型。そのバイト数で割れば、要素の数が分かるってわけ」
『おー! なるほど』
「ま、これも配列だからできることなんだけどね」
/*
Preview Next Story!
*/
『うーん、地味』
「じゃあ、次はちょっと面白いのやってみようか」
『面白いの?』
「テキストエディタを作ってみるとか」
『……うそ』
「というわけで次回」
< Version 9.15 ちょっとテキストエディタっぽく! >
『につづく!』
「まじ? まじ作れるの?」
『見た目だけだけど、面白いと思うよ?』