第04問の答え

答え

引数がchar *だと文字列を書き換えられてしまいそう……。
void Greet(char *pName) {
引数をconst char *にすれば安心して呼び出せる!
void Greet(const char *pName) {

解説

だいたいの場合、関数の引数をポインタにする目的は次の2つのどちらかです。

  • 大きなデータを効率的に参照するため
  • 値を書き込むため

この2つは意味が違うので、constキーワードを使って区別します。つまり、値を参照したいだけのときはconstを付けて、「このポインタはデータを受け取るためのものですよ」という意思表示をするのです。constが付いていない場合は、「このポインタが指しているデータを書き換えますよ」という意思表示になります。

こうした作法は、全体を見渡せる程度の小さなプログラムではそれほど問題にはなりません。でも、プログラムが大きくなってくると、だんだん馬鹿にできなくなってきます。関数を呼び出すときに、いつも中身まで見えるとは限らないからです。

標準関数も、使うときには中身が見えないので、やはり作法に則って作られています。例えば、文字列の長さを数えてくれるstrlen()は、こういう風になっています。

size_t strlen(const char *s);

constが付いているので、文字列を受け取るための引数だということが明確ですね。

では、文字列をコピーするときに使うstrncpy()はどうでしょうか。

char *strncpy(char *dest, const char *src, size_t n)

第1引数はコピー先なのでconstなし、第2引数はコピー元なのでconstありとなっています。constの有無が、関数の使い方を示すさりげないヒントになっていることが分かるでしょう。

こういうさりげない作法ができると、プロって感じがするわよね。
デスヨネ〜。(今度やってみよう)
ここがポイント!
データを受け取るためにポインタを引数にするときは、constを付けよう!

修正後のプログラム

main.c
#include <stdio.h>
#include <stdlib.h>

void Greet(const char *pName) { /* ← const を追加 */
  printf("Hello, %s!\n", pName);
}

int main(void) {
  Greet("Leo");

  return EXIT_SUCCESS;
}
実行結果
Hello, Leo!