HSR  

Room "Program language C++"

This is page1

御質問、ご要望を喜んでお受けいたしますので、是非E-mailでお願いいたします。


0.始めに

 プログラム言語というと、言語の名前だけならご存知でもどのようなものなのか見当もつかないという方が多いでしょう。一般的なところで言えばBASIC、C/C++、Pascal。古いもので言うとCOBOL、FORTLANでしょうか。Windows特有のものと言えばVisualBasic、VisualC++、Delphi、C++Builder、JBuilderというものが挙げられます。ネット世界ではPerl、Java、JavaScriptが主流かと思われます。
 どれを知っていればいいのか、という「正解」は誰にも分かりません。今後全く新しい言語が開発されてそれが主流になるかも知れませんから。ただ、一般的な演算の考えかた(アルゴリズム)を理解するにはC(++)言語がいいのではないかと思います。絶対にPascalのほうがいいと言う人もいますが、記述が簡潔であるという観点からC(++)の方が習得しやすいように思います。そこでここではC++を簡単に説明していこうと思います。
 C(++)もしくはC/C++という表現について説明しましょう。この世にはC言語という言語があります。それを拡張してオブジェクト指向といわれるスタイルを持ったC++という言語が作られました。両者を別言語であるというのは無理があるので、まとめて表現されることが多いのです。それがC(++)、C/C++という表現です。
 C++では普通はコンパイラと呼ばれる、プログラムを書いたファイルを読んで実行可能ファイルを作るものが必要です。WindowsやMS-DOSでの話をします。実行可能ファイルというのは「*.exe」や「*.com」(*は「何らかの」の意)です。これらの中身を見てみると、プログラム言語とは程遠い、わけの分からないものになっています。これはマシン語(機械語)と呼ばれるもので、表示された文字や記号自体が意味を持っているわけではありません。それらの文字記号に対応したデータが意味を持っていて、それを文字コードに当てはめた結果がわけの分からない表示なのです。我々はプログラム言語で書いた命令を普通のテキストファイルとして作成し、それをコンパイラという実行可能ファイルに読み込ませて、テキストファイルに書かれている命令に一致するマシン語を出力させるのです。以後、実行可能ファイルをプログラムと呼ぶことがあります。
 WindowsであればBorlandC++Compiler5.5などをBorland Japanで拾うことが出来ますので面倒でも御用意してくださいね。
 また、こちらのSAZABI ver2.05と併用することで便利になると思います。

 環境は問いません。ともかくC++コンパイラのインストール(方法はインストーラ等にあるドキュメントを参照してください)完了後、講習といきましょう。この講習は普通の書籍とはスタイルを異にし、主に私が理解していった順番で進めたいと思います。これこそが最善、と言える教習方法を模索しながらになるでしょう。
 読者は一度に理解しようとも、1日1テーマで理解しようとも構いません。それぞれのスタイルで学習してください。

H-SHIN's rooms



    1.文字表示方法

     まず、新規にファイルを用意いたします。これをテキストエディタなどで開き、
    #include <stdio.h>
    void main(void){
        printf("Hello,world!");
    }
     と書いてください。これを「print.cpp」という名前でセーブしたら、御自分のコンパイラでコンパイル(プログラム言語で書かれたファイルから実行可能ファイルを作成する)してください。コンパイルの方法は……大方「bcc32 print.cpp」(BorlandC++Compiler)や「gcc print.cpp」(UNIX)などでしょう。拡張子cppは「C plus plus」の意で、C++のファイルであることを示しています。ここではC++を説明しますのでどうでも良いことなんですが、仮にC言語のコンパイラ(つまり、拡張されたC++の機能は使えない)で作業を強いられたときには「*.c」と、拡張子をcにします。
     コンパイルが完了すると、「print.obj」と「print.exe」が出来ると思います。必要なのは「print.exe」の方だけです。これを実行してみてください。
    Hello,world!
    と表示される筈です。
     順を追ってプログラムを解説します。
     まず、実行したいプログラム内容はvoid main(void){}の「{」と「}」の中に書いていく決まりです。このvoid main(void)をメイン関数といいますので、前述のことは「実行したい内容はmain関数内に記述する決まり」と言いかえられます。
     そして、文字表示にはprintf();を使います。
     また、このprintf();を使う際には、ファイルの先頭部分に#include <stdio.h>を記述する必要があります。これがないと、コンパイル時に「Call to undefined function 'printf' in function main()」というようなエラーメッセージが出されると思います。このようなことを私は時に「コンパイルで弾かれる」と表現し、逆に問題なくコンパイルできることを「コンパイルが(を)通る」と言います。
     今回は以上です。

    H-SHIN's rooms



    2.変数

     プログラム言語での変数というのは、数学で登場する変数と基本的に同じ物です。例えば、
    void main(void){
        int i;
        i=10;
    }
    と書くことで、整数変数iに値10を代入することになります。細かく説明しますと、まずvoid main(void){}は前述の通り。
     int i;という部分では、整数変数iというものを宣言しています。int(イント)というのは整数(integer)のことです。
     i=10;という部分で10をiに代入しているのですが、この等号(=)は等しいということを示しているのではなくて、代入することを示していて代入演算子と呼ばれます。
     このプログラム、何も面白くないので、
    #include <stdio.h>
    void main(void){
        int i;
        i=10;
        printf("%d",i);/* iの中身(10)を表示 */
    }
    というように変えてみます。
     最初の行の#include <stdio.h>は前述の通り、printf();を使うために記述しています。理由は後々分かりますので深く考えないで下さい。
     最後の行のprintf("%d",i);というのは、「iという変数を10進法で記述する」ということを示しています。%dのdというのは10進法(decimal)の意です。
     printf();の後に続く「/*」と「*/」ですが、これはコメントというもので、これに挟まれた部分は無視をされるというものです。これがあると何をしているのかが明確に分かりますね。また、C++においては「//」と書くと、それ以降改行までコメントと見なされます。
     これをコンパイルし、出来た「*.exe」を実行すると単純に
    10
     と表示されます。

     何故、わざわざint i;などという一見無意味なことを書く必要があるのでしょうか? BASICという言語の場合はそのようなことをせずにi=10という式だけで済むのですが、仮に間違ってiのつもりでjと記述してしまうとどうでしょう。つまり、変数宣言無しでコンパイルが通るようになると
    #include <stdio.h>
    void main(void){// 仮にこれでコンパイルできるものと仮定する
        i=10;
        j=5;// iのつもりで書いてしまっている
        printf("%d",i);
    }
    の結果は「10」となります。これは不本意なので、宣言というものが多くの言語に導入されました。変数宣言のない、FORTLANという言語でプログラムを組まれた金星探査機が変数記述の誤りによって制御不能に陥り大損をしたという逸話があります。それ程に変数宣言は重要なのです。
    #include <stdio.h>
    void main(void){
        int i;// 整数変数iを用意した
        i=10;
        j=5;// iのつもりで書いてしまっている
        printf("%d",i);
    }
    これをコンパイルすると「Undefined symbol 'j' in function main()」や「未定義のシンボル j(関数 main() )」などというように弾かれます。そこで「あ、間違えた」と分かるのです。

     変数には整数だけでなく、小数もあります。これは float(フロート)という呼び名で宣言します。即ち、
    #include <stdio.h>
    void main(void){
        float test;// 小数変数testを用意した
        test=10.1;
        printf("%f",test);
    }
    というようにして用います。私の環境で結果は、
    10.100000
     ここで注意すべき点は2つ。一つは、このtestに10を代入する際には小数であることを明確にするためにtest=10.0というようにするべきであるということです。もう一つはprintf();内での%fです。これはtestを小数として表示させるというもので、仮に%fを%dとしたときすなわち、
    #include <stdio.h>
    void main(void){
        float test;// 小数変数testを用意した
        test=10.1;
        printf("%d",test);// ここの%dに注意
    }
    と書いた場合には正しい表示が保証されません。intやfloatを変数の「型」と言いますが、この変数の型がprintf();での指定に一致していないといけないのです。
     ですから、
    #include <stdio.h>
    void main(void){
        int i;// 整数変数iを用意した
        i=10;
        printf("%f",i);// ここの%fに注意
    }
    と書いてもいけません。  長くなりましたが、今回は以上で締めたいと思います。お疲れ様でした。

    H-SHIN's rooms



    3.レイアウトいろいろ

     プログラムの書き方について説明したいと思います。ここで言う「書き方」というのはレイアウトの事です。C(++)言語では「命令間の半角空白、改行、タブは無視される」という規則があります。命令という表現は曖昧ですが、そのうちに感覚的に理解できるようになります。
     これまで書いてきたスタイルで書くと、
    #include <stdio.h>
    void main(void){
        int i;// 整数変数iを用意した
        i=10;
        printf("%d",i);
    }
    となりますが、実は、
    #include <stdio.h>
    void main(void){int i;i=10;printf("%d",i);}
    でも全く同じことです。
     更に、
    #include <stdio.h>
          void main( void )
    {
    int i;
    
           i = 10;
      printf("%d" , i );
    }
    も同じことです。
     しかし、見易さを考慮して書く必要というものがありますので私は始めのような記述を用います。このスタイルは細かいところまで見ていくと人それぞれですが、大まかなところは極端には変わりませんので私のスタイルに慣れていただければ良いと思います。
     これだけでは説明が足りませんのでまだ続けます。理由は後々分かることになりますが、
    #include <stdio.h> void main(void){
        int i;
        i=10;
        printf("%d",i);
    }
    というように#include <stdio.h>の後に続けて書き込むことは出来ません。改行を挟んで書かないといけないのです。
     注意はまだあります。mainやvoid、int、float、printfなどの、意味を持った言葉を予約語といいます(printfは予約語ではありませんが同様のものとして考えてください)が、この予約語や変数の中に空白などを入れることは出来ません。すなわち、mainをm ainと記述することは出来ないということです。
     最後に、今回のテーマとは外れますが、変数の名前の付け方について注意点を挙げておきます。

    1. 先頭の文字には「a〜z」「A〜Z」「_」が使える
    2. 先頭以外の文字には「a〜z」「A〜Z」「_」「1〜9」が使える
    3. 長さは自由だが、名前として有効な長さは32文字
    4. 大文字小文字の区別がある
    5. 予約語は使えない

     3番目の項目を具体的に説明しますと、変数 abcdefghijklmnopqrstuvwxyz123456789 と abcdefghijklmnopqrstuvwxyz1234567890 や abcdefghijklmnopqrstuvwxyz1234567891 は同じだということです。
     4番目の項目は、変数aと変数Aは異なるものとして見なされるということを意味しています。
     5番目は、int printf;などということが出来ないということです。但し、その中に予約語が含まれる、_printfなどは変数名として有効です。

    H-SHIN's rooms



    4.計算方法(算術演算子)

     計算と言えば一般的には四則演算を指すでしょう。そこでまずは四則演算を紹介します。
     以後a,b,c,...を変数(intでもfloatでも構わない)とします。

    1. 加算 ---- c = a + b;
    2. 減算 ---- c = a - b;
    3. 乗算 ---- c = a * b;
    4. 除算 ---- c = a / b;

     これが表記方法です。全て変数cに変数aとbの演算結果を代入しています。別に方程式になっているわけではありませんよ。飽くまで等号「=」は代入演算子で、右辺の値を左辺に代入するというものです。ちなみに「=,+,-,*,/」などを「演算子」と総称しますので覚えておいてください。
     複数の四則演算の場合、演算順序というものが問題になってきます。すなわち、
    #include <stdio.h>
    void main(void){
    int a=4,b=6,c=10,d=2,e; // 実は変数宣言時に代入が可能
        e=a+b*c/d;
        printf("%d",e); // eの値を表示
    }
    の結果はどうなるかという問題です。50でしょうか、34でしょうか。c(++)においては普通の算数と同じで34です。加算を先に行いたい場合は、e=(a+b)*c/d;としてください。この結果は50になります。括弧を重ねて使うような場合、算数だと中括弧、大括弧などを用いますが、c(++)では通常の括弧しか使わず、f=(a+(b-c)/d)*e;というようになります。括弧はいくつ重ねようともこのスタイルです。余談ですが、この「重ねる」ということを一般的にネストするといいます。括弧に限らない話で登場する用語なので知っておくと便利ですよ。
     四則演算のほかにも(算数の)演算子は存在します。それは剰余です。算術的な記述でいえば「a mod b」ということになるでしょうか。これをc(++)ではc = a % b;と書きます。これによりaをbで(整数の範囲内で)割ったあまりがcに代入されます。この演算子はその特徴からも分かるように演算対象がintに限られますので注意が必要です。
     算術演算子はまだあります。それは、

    1. 加算 ---- a += b;
    2. 減算 ---- a -= b;
    3. 乗算 ---- a *= b;
    4. 除算 ---- a /= b;
    5. 剰余 ---- a %= b;

    というもので、これらはそれぞれ

    1. 加算 ---- a = a + b;
    2. 減算 ---- a = a - b;
    3. 乗算 ---- a = a * b;
    4. 除算 ---- a = a / b;
    5. 剰余 ---- a = a % b;

    と同じことを意味しています。何度も言いますが、方程式ではないので x = x + 1;という式を見ても驚かないで下さいね。「x に、もともと x の持っていた値に1を足した結果を代入する」ということですよ。
     慣れないうちは += などの表記が直感的に分からないかもしれませんが、慣れてくるとこの表記の美しさが分かるようになります。多くの物事はシンプルな方が美しいのです。
     さて、これまで紹介した(算術)演算子は全て両端に値(というよりは項)の書き込まれた「二項演算子」というものです。続いて、通常の算術には存在しないであろう「単項演算子」というものをご紹介します。
    1. インクリメント ---- a++;
    2.         ---- ++a;
    3. デクリメント  ---- a--;
    4.         ---- --a;

     演算子「++」をインクリメント、演算子「--」をデクリメントと呼び、a++;と++a;は a = a + 1;を、a--;と--a;は a = a - 1;を意味します。「++」「--」が項の前にある場合を前置演算、後ろにある場合を後置演算と呼びます。前置演算と後置演算の違いを覚えていただきましょう。
    #include <stdio.h>
    void main(void){
    int a,n;
        n=1; // nを初期化
        a=++n; // 前置演算で代入
        printf("<%d>",a);
        n=1; // 再度 n を初期化
        a=n++; // 後置演算で代入
        printf("<%d>",a);
    }
    この結果は、
    <2><1>
    となります。前置演算では n をインクリメントして(つまり2になる)から a に代入しており、後置演算では n を a に代入して(まだ 1 のまま)からインクリメントしているのです。この感覚を知っておけば、後々私が突然初心者向けではないコードを書いても極端にまごつくことは無いと思います。
     今回の内容はここまでですが、もう一つ話があります。このインクリメント、どこかで見たことありませんか? C++です。意味が分かったでしょうか。C言語を一歩(それ以上のようにも思うのだけれど)進めたものなので、C++とインクリメントしてあるということ。分かる人にしか分からない意味を持った名前だったのです。

    H-SHIN's rooms




    5.関数

     普通の書籍等であれば関数よりも先に条件分岐などを紹介するところですが、関数を先に知っていた方が物の理解が速くなるだろうと考えてこのようにしました。
     関数というものは数学で言うならば、「ある箱に物を入れると、その『箱』と『物』の関係によって決められた結果が出てくる」というものです。ここでの箱を関数、入れるものを引数(ひきすう)、結果を返り値と言います。実際には、
    f( x ) = x - 1
    というような表記で、箱は f()。入れる物が x 。箱の中身(仕組み)が x - 1 というわけです。x が 10 なら返り値は 9 。これは f(10) = 9 と記されます。
     さあ、これがC(++)ではどのように実現されるのでしょう。簡単な例を示しますね。
    #include <stdio.h>
    int f(int x){
        return x-1;
    }
    void main(void){
    int a;
        a=f(10);
        printf("%d",a);
    }
    これは説明が必要ですね。
     f()は私がこの場で作った関数で、その定義は「{」と「}」の中に書かれています。予約語 return は関数の返り値を指定します。また、この return はこの部分で関数が終わることも指定します。int f(int x)の一つ目の int は返り値の型が int であるということを指定するためのもので、二つ目の int は引数が int であることを指定するためのものです。すなわち、引数に int 以外のものを入れるとエラーでコンパイル時に弾かれます。
     main()も関数だということがお分かりいただけると思います。こちらも説明しましょう。void main(void)の一つ目の void は「返り値を持たない」ということを指定しており、二つ目の void は「引数を持たない」ということを指定しているのです。void というのは日本語の「無効」を意味する単語ですからなんとなく意味が分かりますね。
     main関数の定義はf()同様に「{」と「}」の中に書かれています。a=f(10);では、a に f(10)の返り値すなわち 9 を代入しています。勘のいい方なら気付いたかもしれませんが、printf()も関数です。これは引数が2つのタイプなんですが、細かいことは後にします。ただ、printf()の定義が何処にも無い理由は示しておくべきでしょう。実は #include <stdio.h> というのは、この部分に stdio.h というファイル(include というディレクトリにあります)の中身を展開するという命令で、この stdio.h に printf() の定義があるのです。
     実を言うと、引数には関数を入れることもできるので、main の部分は変数 a など使わないで printf("%d",f(10)); としても構いません。むしろこの方が美しいでしょう。
     関数を何処で定義してもいいかというと、そうではありません。関数を使う場合はその定義を、使う場面より上の部分で書かないといけないのです。

     続いて、引数が複数ある場合、関数が複数ある場合の定義の仕方を説明します。
    #include <stdio.h>
    int f(int x,int y,int z){
    int a=1;
        printf("This is function f\n"); // \n は改行を示す
        return x*y+z-a; // ここで関数が終わるので下の行は無視される
        printf("After return");
    }
    float g(float x,float y,float z){
    int a=3;
        printf("This is function g\n");
        return x+y/z-a;
    }
    void main(void){
        printf("%d,%f",f(10,9,1),g(1.2,3.5,2.1));
    }
     さあ、いよいよ複雑になってきました。関数 f() に続いて関数 g() を定義しています。g() は引数、返り値共に float になっていますね。ここで気をつけるべきことは、f()、g() ともに変数 a,x,y,z を持っているということです。変数の名前が有効なのはそれが宣言された関数内のみですので、両者の a,x,y,z は全くの別物なのです。
     あとは f() 内部で return x*y+z-a; の後にまだ命令が続いていますが、return で関数が終わるということを考えればこの命令は無視されるということが分かると思います。
     まだ説明が必要です。printf() 内での \n というものの役割なのですが、これは改行を実現するものです。何もそんなことしなくたっていいじゃないかという意見もありそうですが、御自分で \n を使わずに改行をしてみればいいと思います。
     この例では実際は f() 内部で return の後に命令があるという理由で警告が出てしまうのですが、ともかく結果は
    This is function g
    This is function f
    90,-0.133333
    です。難しいでしょうが、何度も読み返して理解していただきたいと思います。

     さて、次に引数を持たない関数を説明しましょう。
     main関数は引数を持たないものでした。これと同様に記述していくことになります。
    #include <stdio.h>
    int f(void){
        return 8;
    }
    void main(void){
        printf("%d",f());
    }
     実に芸のない例ですが、f() は引数を持たない関数です。当然の如く結果は、
    8
    となります。数学では引数のない関数などありませんが、C/C++ では存在します。こればかりは納得してください。

     もっと納得していただかないと困るのが返り値のない関数です。関数というからには返り値があるべきだと考える方もいるでしょう。でも返り値のない関数、納得してください。
    #include <stdio.h>
    void f(int x){
        printf("%d",x);
        return; // 返り値はないので return のあとには何も書かない
    }
    void main(void){
        f(2);
    }
    またまた無芸な例で済みません。結果が
    2
    となることはお分かりいただけたでしょうか? ただ、ちょっと説明が必要な点があります。
     f() で最後に return; とあります。これは関数の最後を示す return です。ただ、この return; は書かなくても(最初で)最後の命令 printf("%d",x); の後に何もないということで関数の終わりだということを意味しており、全く問題がありません。しかし後々出てくる条件分岐などによって必要性が生じてくるので、敢えて明記しました。誤解を招いては困るので述べておきますが、返り値がある関数の場合は return を省くことは絶対に出来ません。
     長い項目になりましたが何度も読み返して理解を深めてください。お疲れ様でした。

    H-SHIN's rooms



    6.ビットとバイト

     変数は int,float だけではありません。次の項目では全ての(標準的な)変数の型を詳しく紹介します。これを知らないと思いがけないエラーを引き起こすことが考えられますので心して理解してくださいね。その前に準備が必要ですのでこの項目を用意いたしました。
     まずはビット(bit)とバイト(byte)という概念を理解していただきます。昔はパソコンというものは一部のマニアの高価な玩具だったのでこんなことはパソコンユーザーの誰もが知っていたことなのですが、Windowsがはびこっている昨今は基本的なことを知らずに使っている(使えている)方が非常に多いので詳しく説明します。
     bit ですが、これは2値の情報量の単位です。これだけでは全く意味が掴めないでしょう。コンピュータの世界では数値を 0 と 1 で扱うので、2進数というものが基本となります。通常の10進数は 0 1 2 3 ... 9 の次に 10 と桁が上がりますね。これが2進数になると 0 1 の次に 10 と桁が上がります。この時の 10 は「いちゼロ」と読み、持っている値の大きさは(10進数で) 2 です。お分かりいただけるでしょうか? 2進数で数字を数えていくと、4桁でなら、
    0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
    です。当然の如く10進数では、
    0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012 0013 0014 0015
    ですね。
     前置きが長くなりましたが、この2進数の1桁を 1bit と称すのです。1bitは2値(2個分)の情報量を持ちますから、同様のことを先の例で言うなら「4bitsでは 0 から 15 までの16個を表現できる」ということ、言い換えると「4bitsというものは16個分の(ものの)情報量がある」ということになります。データというのはこの数字をあるルールに対応させて成されているもので例えば、0000から1111までをアルファベットに対応させるというルール(0000 -> a , 1111 -> p)のもとでは 1010 は k に対応します。もし a から p までしか使われていない文章を保存する場合、4n bits あればn文字の文章を保存できるということになりますね。実際、パソコンのメモリ等はこのような感じで成っています。
     n bits あると何個のものが区別されて表現できるでしょうか? 4bits で16個でしたから、5bits では最上位の桁が 0 の場合の(残り 4bits の)16個と最上位が 1 の場合の(残り 4bits の)16個を足して32個。同様に考えていけば分かるように 1bit 増す毎に2倍になっていきます。よって n bits では 2n個ということになります。分かり難いでしょうね。(ToT)

     続いて byte についてです。これは非常に簡単。1byte=8bits。これだけです。コンピュータの世界ではこれを単位として考えることが非常に多いのでこれに馴染んでください。8bits ということは 28=256個のものを区別して表現できるということになります。

     もう一つ。これは単位ではなく、考え方なのですが、16進数というものを説明します。プログラムでは良く用いる考え方/表記方法ですので省くわけにはいきません。
     数字は 0,1,...,9 の10個しかありませんので、アルファベットも数字と見なして16進数と言うものを表記します。16進数での数字は 0,1,...,9,a,b,...,f の16個。

    00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
    10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
    ...
    f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff

    2桁ならこのようになり、全部で16*16=256個の表現がなされます。ん? ということはこれは 1byte と同じではないか? というように思った方、天才的です。そう、16進2桁が 1byte になります。
     16進はよく用いられる表現なので10進と簡単に区別できるように、a1 であれば 0xa1 と表記されます。従って 0x10 = 16 ですね。すぐに答えられると便利なのは 0xff = 255 です。もっと言うと、0xffff = 65535 も知っているといいでしょう。

     プログラムを組むにはこういう表記、概念に慣れていないと不便です。プログラミングを訓練する過程で身に付くということも言えるのですが、ここでは講座らしくするためにこの項目を入れた次第です。


    H-SHIN's rooms




Copyright (c) 2003 H-SHIN