第41章 変えてくれるな

 いろいろプログラムを組むようになると、中には値の変わって欲しくないようなデータもでてきます。今回はそんな値を保護するシステムについて話していきます。


 では、今回の要点です。


 では、いってみましょう。


 さぁ、ある関数に配列変数を渡すとします。でも、この配列には手を加えることはしません。その値を使って何らかの作業をするだけです。

 しかし、人とは時に過ちを犯すものです。ついついこの配列の中身を変更するようなコードを書いてしまうこともあるのです。

 例えば、次のような関数は危ないですね。

プログラム
// Const01a.cpp
#include <stdio.h>

int strcnt(char* psz, int letter)
{
    int num;
    for(num = 0; *psz; psz++)
    {
        if(*psz = letter)
            num++;
    }
    return num;
}

int main()
{
    char szPath[] = "C:/Program Files/Robert/BH/BH.exe";

    printf("ファイル %s は、%d 重のフォルダの中に入っています。",
        szPath, strcnt(szPath, '/') - 1);

    return 0;
}
実行結果例
ファイル ///////////////////////////////// は、32 重のフォルダの中に入っています。

 strcnt は、第一引数の文字列の中に第二引数の文字がいくつ含まれているかを数える関数です。いや、そのつもりでした。

 何のビルドエラーも出なかったので安心して実行ボタンを押したものの、結果はこの通りです。数え間違えくらいなら大した問題ではありませんが、元の配列が書き換えられているのは大問題です。

 では、どこに原因があったのでしょうか。それはこの部分です。

if(*psz = letter)

 この部分を

if(*psz == letter)

 にすれば正しく動作します。


 このように、関数に配列を渡すときは本体を渡すことになるので、ミスによる書き換えといった危険が伴ってしまいます。おちおちミスもできません。そしてもちろん、このことは配列に限ったことではありません。

 そこで、C/C++言語には変数の中身を変更できないようにする機能が備わっています。それは、定数です。

 次のプログラムを見て下さい。変更した箇所は一ヶ所だけです。そこは = のところではなく、引数の部分です。

プログラム
// Const01b.cpp
#include <stdio.h>

int strcnt(const char* psz, int letter)
{
    int num;
    for(num = 0; *psz; psz++)
    {
        if(*psz = letter)
            num++;
    }
    return num;
}

int main()
{
    char szPath[] = "C:/Program Files/Robert/BH/BH.exe";

    printf("ファイル %s は、%d 重のフォルダの中に入っています。",
        szPath, strcnt(szPath, '/') - 1);

    return 0;
}
エラーメッセージ
Const01b.cpp(9) : error C2166: 左辺値は const オブジェクトに指定されています。

 このように、const の付けられた変数の中身を変更しようとすると、コンパイラに怒られてしまいます。const を付けると変数でなく定数になるのです。

 ポインタを、配列を扱う際にはこの const を使う必要があるか常に考えておく癖を付けておくとよいでしょう。そうすれば、== と = の間違いなどというミスからも解放されるでしょう。もっとも、const の付け忘れにまでは責任は持てませんが...。


 一度に沢山教えても身に付かないと思いますので、今回はこれで終わります。

 では、今回の要点です。


 次回も定数についてやっていきたいと思います。定数はアドレスを渡す関数に関するバグを追放するための強力な武器ですので、是非早い段階から身につけておいて下さい。

 では、また次回まで。さようなら。


第40章 さらなる計算 | 第42章 変えてくれるな2

Last update was done on 1999.10.5

この講座の著作権はロベールが保有しています