C++によるプログラミング入門補足1
constについて前編

 C++入門で言い残したことについていくつかコメントをしようと思います。C++入門のモットーは、楽しいプログラミングでした。(どうでしたか?)私なりにがんばったつもりですが、いくつか気になることもあります。というのは、初心者に、はじめからあまり細かいことを言うと、嫌になると思い、省略した話がいくつかあります。あとは各自勉強してください、、、と思ったのですが、やはりいくつか、補足を書くことにしました。

 今日は、constの話です。ちょっと下のプログラムを見てください。

//const_sample0.cpp
#include <iostream>
using namespace std;

int main()
{
    int suji[5];  //数字

    cout << "5個の数字を入力してください。" << endl;
    for(int i = 0; i < 5; i++)
        cin >> suji[i];

    //本当のプログラムではここで何かやるはずですが、、、
    //簡単のため、単に打ち出すだけにします。

    cout << "数字を打ち出します。" << endl;

    for(int i = 0; i < 5; i++)
        cout << suji[i] << " ";
}

 プログラム自体はおもしろくもなんともないですね。ユーザに数字を5つ入力させ、その数字をまた打ち出しているだけです。実際のプログラムではもう少し複雑なことをするはずですが、説明を簡単にするために上のようなプログラムを作ったのです。例えば、簡易(?)データベースプログラム(名前を入力させ、名簿を作り、それを打ち出すようなやつ)など、ちゃんとしたプログラムを想像しながら、説明を読んでください。
 さて、上のプログラムでは、5つの数字を扱っています。もし、数字の数を7にしたくなったらどうしますか?簡単だよ、、、と思った人は、良く勉強した人です。実際、上のプログラムの5を7に書き直せばよいのですから、簡単です、、、か?本当に簡単ですか?もちろん、この位の短いプログラムなら簡単です。しかし、もっと実際的な長いプログラムが上のように書かれていたら、たぶん、プログラム中にたくさんの数字があって、どれをどうなおすのか混乱すると思います。例えば、1000行以上のプログラムで、必要な数字だけ書き換えることを考えてください。もし、別の文脈で5という数字があれば、その5は7に直すべきではないかもしれません。良く考えなければならないとっても嫌なところです。
 この問題を避けるために、プログラムのはじめの方で

#define TOTAL 5

を使うという方法があります。(最後に「;」は付けません。)このように書くと、プログラム中のTOTALが5と解釈されるのです。ここで、TOTALという名前は、プログラマが勝手に付けて良い名前なので、別の名前でも問題ありません

#define KAZU 5

なら、KAZUが5になります。この#defineを使うと、上のプログラムは

//const_sample1.cpp
#include <iostream>
#define TOTAL 5
using namespace std;

int main()
{
    int suji[TOTAL];  //数字

    cout << TOTAL << "個の数字を入力してください。" << endl;
    for(int i = 0; i < TOTAL; i++)
        cin >> suji[i];

    //本当のプログラムではここで何かやるはずですが、、、
    //簡単のため、単に打ち出すだけにします。

    cout << "数字を打ち出します。" << endl;

    for(int i = 0; i < TOTAL; i++)
        cout << suji[i] << " ";
}

と書けるのです。実行すると、前のプログラムと同じ動作をします。
 この書き方の良さは、わかりましたか?つまり、5個の数字を7個の数字にするために、書き換えるところは、ひとつだけなのです。つまり、#defineのところを、

#define TOTAL 7

とすれば良いのですね。とても簡単です。この方法なら、プログラムがどんなに長くても、大丈夫です。これは、Cでよく使われる手法です。


 しかし、一般に、C++では別の方法が推奨されています。それを見る前に、こんなプログラムを考えたらどうでしょう。

//const_sample2.cpp
//エラー!!!
#include <iostream>
using namespace std;

int total = 5;

int main()
{
    int suji[total];  //数字

    cout << total << "個の数字を入力してください。" << endl;
    for(int i = 0; i < total; i++)
        cin >> suji[i];

    //本当のプログラムではここで何かやるはずですが、、、
    //簡単のため、単に打ち出すだけにします。

    cout << "数字を打ち出します。" << endl;

    for(int i = 0; i < total; i++)
        cout << suji[i] << " ";
}


ありゃ。エラーだ。

 これは上のプログラムとほとんど同じですが、#defineなどというものを使わずに、intを使おうとしているのです。#defineは便利ですが、論理的なミスを見つけにくいという欠点があるのです。それなら、C++(やC)の一部である変数を使えばよいだろうという発想です。変数であれば、何かミスをしたときには、コンパイラが教えてくれるそうだからです。
 変数totalの定義をmainの外でしていますが、このこと自身に問題はありません。これは、あくまでmainという関数の外で(そして、他のどの関数の中でもない場所で)変数を定義しているだけです。
 しかし、実際にコンパイルしてみると、エラーになってしまうのです。int suji[total];のように配列を定義するのに、totalが変数であってはいけないのです。コンパイラはここには定数を使えと文句を言っいるのです。(私は初心者の頃、これでとても悩みました。)CやC++ではそのように決められているのです。
 ところが、この解決方法は、実は簡単です。int total=5;をconst int total=5;と書き直せばよかったのです。くどいですが、ちゃんと書いて見ましょうか。

//const_sample3.cpp
//エラーでない!!!
#include <iostream>
using namespace std;

const int total = 5;

int main()
{
    int suji[total];  //数字

    cout << total << "個の数字を入力してください。" << endl;
    for(int i = 0; i < total; i++)
        cin >> suji[i];

    //本当のプログラムではここで何かやるはずですが、、、
    //簡単のため、単に打ち出すだけにします。

    cout << "数字を打ち出します。" << endl;

    for(int i = 0; i < total; i++)
        cout << suji[i] << " ";
}


コンパイルも実行もオッケー

 constは、以下に定義されている「変数」が実は「定数」であることを示しているのです。そのため、配列の定義にも使えたのです。それは、それが「定数」だからです。
 constはこのようにも使えるキーワードなのです。

 ところで、プログラム中の誤ったコードのおかげで、間違ってデータを書き換えてしまうということがよく起こります。(プログラムをタイプしていて直接データを書き間違うという意味ではなく、「変更したくないデータを書き換えてしまうコード」などを間違って書いてしまうという意味です。)
 そんな、ばかな?いえ、本当です。このような、プログラマが意識していない「データの書き換え」はやっかいです。こういうことが起こると悪夢のデバッグ(エラー直し)がはじまるのです。
 ところで、このデータは絶対に書き換えないぞ、と思っている場合なら、実は、const宣言してしまえば良いのです。こうしておけば、それは定数として扱われるので、変更ができなくなるのです。そのため、あとで知らずにそのデータを書き換えるようなコードを書くと、コンパイラがわかりやすいエラーメッセージで知らせてくれるのです。(初心者はコンパイル時にでるエラーを恐れたりしますが、実は、コンパイル時に出るエラーなんて、ものの数ではないのです。というか、コンパイル時にエラーになってくれた方が、実行中に突然プログラムが暴走したりするのより、ずっと良いのです。)そういうわけでconstはとても重要なのです。


目次のページ
後編