useless tips

「外部変数を 宣言しておく」と 書いたところで、少し ひっかかる人が いるかもしれない。
外部変数を 「定義」する、では ? それに、宣言した ポインタ配列の メモリは 実際に 確保されているのか ?
K&R 2nd を 読むと、

ある状況の下では extern 宣言は 省略可能である。 すなわち、外部変数の定義が 特定の関数で 使われる 以前に そのソースファイルの 中で なされていれば、(外部変数を 使用する) 関数内での extern 宣言は 余分である。

実際、普通の やり方は ソースファイルの 最初で (または ヘッダファイルで) すべての 外部変数を 宣言してしまい、extern 宣言は すべて 省くという 形である。(p40)

今回の ケースも これに 当てはまる。K&R 2nd には、確かに 「外部変数の 定義」 と 書いてある。 また、

外部変数を 参照するのに 宣言定義という 言葉を 使い分けている点に 注意していただきたい。

「定義」とは 変数が 実際に つくられ、あるいは 記憶が 割り当てられたことを 指すのに対し、「宣言」とは 変数の性質は 指定されてはいるが 割り当ては されていないことを 指す。(p41)

と、その違いを はっきり 指摘している。
では、実際は どうなのかと いえば、

char *keyword[MAX_KEY_COUNT];
int key_n;
やはり 宣言しているだけだ。
その回答は、K&R 2nd リファレンスマニュアルの 「外部宣言」 の箇所に 載っていた。

オブジェクト (型をもった 変数) の 外部宣言は、それに 初期値式が あれば (初期化されていれば)、一つの定義に なる。 初期値式を もたず、また extern 指示子を 含まない 外部的な オブジェクト宣言は、仮の定義と 呼ばれる。 (その場合) 仮の定義は すべて 初期値 0 を もつ 単一の 定義となる。(p284)

C では、外部変数の 宣言 すなわち (仮の) 定義と みなされている。
つまり、ポインタ配列 keyword では、その指す先に それぞれ 初期値 0 を もった ポインタ 256個分の メモリが ここで 確保されるわけだ。 当然、不定値が 入り込むことも ない。
うまく できていますネ。