答え
const char *names[] = {
"Leo",
"Yuki"
};
解説
これは、「ポインタの配列」についての問題でした。一つ一つの要素がポインタなので、それぞれが別々のデータを指すことができます。
配列は、同じサイズの要素を隙間なく並べたデータ構造です。例えば、次のような整数の配列があったとしましょう。
int numbers[] = {
123,
456
};
ここで、123
と456
はどちらもint
型の値なので、サイズも同じです。そのため、1つの配列にまとめることができています。このことは、次のように各要素を間接的に書き直してみれば明確になるでしょう。
int number0 = 123;
int number1 = 456;
int numbers[] = {
number0,
number1
};
さて、問題の穴埋め部分は次のような配列でした。
/* ここに入るコードは? */ = {
"Leo",
"Yuki"
};
一見すると「文字列の配列」のように見えますが、これが実際には「文字列を指すポインタの配列」なのです。このことが明確に分かるよう、各要素を間接的に書き直してみましょう。
const char *name0 = "Leo";
const char *name1 = "Yuki";
/* ここに入るコードは? */ = {
name0,
name1
};
"Leo"
や"Yuki"
は、文字列リテラルです(第05問でも出てきましたね)。実行時に書き換えられない文字列なので、これらを指すポインタの型はconst char *
となります。
したがって、穴埋めの答えは次のようになります。
const char *names[] = {
"Leo",
"Yuki"
};
問題のプログラムには、「ポインタの配列」を「ポインタのポインタ」として受け取る関数が出てきていました。
void GreetTo(int nameIndex, const char **ppNames) { /* ← ポインタのポインタとして受け取る */
……
}
int main(void) {
const char *names[] = {
……
};
GreetTo(0, names); /* ← ポインタの配列を渡す */
……
}
C言語では、配列を引数にして関数を呼び出すと「配列の先頭要素のアドレス」が引き渡されます。この例では要素の型が「文字列を指すポインタ」なので、受け取る側は「文字列を指すポインタのポインタ」になるのです。
この動作は変数に代入するときも同じです。
const char *names[] = {
"Leo",
"Yuki"
};
const char **ppNames = names; /* ← ポインタの配列を、ポインタのポインタに代入 */
printf("Hello, %s!\n", ppNames[0]);
printf("Hello, %s!\n", ppNames[1]);
少しややこしく感じるでしょうか?その場合は、整数の配列に戻って考えてみるとイメージがわいてくるかもしれません。
int numbers[] = {
123,
456
};
int *pNumbers = numbers; /* ← 整数の配列を、整数のポインタに代入 */
printf("Number = %d\n", pNumbers[0]);
printf("Number = %d\n", pNumbers[1]);
const char *names[]
っていう文法がややこしいだけなのよ。
typedef
を使うのも一つの方法ね。
typedef const char *StringLiteral;
StringLiteral names[] = {
"Leo",
"Yuki"
};
ちなみに、main()
関数でコマンドライン引数を受け取るときに使うargv
も、今回の配列とよく似たデータ構造です。
int main(int argc, char *argv[]) {
……
}
char *argv[]
だと、引数なのに「ポインタのポインタ」になってないですけど……
char **argv
って書くのと同じになるわ。
int main(int argc, char **argv) {
……
}
char *argv[]
と書けば「このポインタは配列を指すよ」っていう意図が伝わりやすくなるでしょ。
修正後のプログラム
#include <stdio.h>
#include <stdlib.h>
void GreetTo(int nameIndex, const char **ppNames) {
printf("Hello, %s!\n", ppNames[nameIndex]);
}
int main(void) {
const char *names[] = {
"Leo",
"Yuki"
};
GreetTo(0, names);
GreetTo(1, names);
return EXIT_SUCCESS;
}
Hello, Leo!
Hello, Yuki!