[WebP Vol.025] Cプログラミング ~反復構造を理解しよう! while編~

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
【 Webプログラミング Code Sample 】                          Since2001/11/23

          Code025: Cプログラミング 〜反復構造を理解しよう! while編〜

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                                                    Produced by ichikoro.com

           ▼毎週月曜日と金曜日に配信しています。
           ▼等幅フォントでご覧いただくとキレイに見えます。
           ▼登録・解除はこちらから可能です。
               < http://www.ichikoro.com/webp/ >
                  ※バックナンバーへのリンクもあります。
                  ※お友達にもぜひお勧めください(^^)/

─【Contents】───────────────────────────────
    01.Review ................... 前回のおさらい
    02.Guide .................... 反復構造を理解しよう!
    03.Guide .................... 条件式を理解しよう!
    04.Guide .................... 反復構造を理解しよう!:whileの使い方
    05.Guide .................... 反復構造を理解しよう!:処理を追いかけよう
    06.Guide .................... 真偽の考え方
    07.Guide .................... 無限ループ
    08.Guide .................... 等符号は演算子なのです
    09.Guide .................... whileの使用例
    10.Question ................. 今週の問題
    11.From Editor .............. 編集後記


                   【 Webプログラミングは毎週2本立て! 】

             ・月曜日版はWebの実際の活用方法などを特集します。
             ・金曜日版はHTMLやCGIなど一つの分野について最初から
              解説する講座になっています。現在はC言語入門です。


こんにちは、編集者の勝部です。

今週の木曜日は「春分の日」でお休みでしたが、東京には何と桜の満開宣言が!
いつもは大体4月5日ごろだそうですが、今年は気象庁の観測史上最も早い満開
だそうです。ただ、それと時を同じくして風速30メートルを超える台風並みの
春の嵐が吹き荒れました。4月になったら既に葉桜になってたりしないのか不安
です(^^;

去年は三番町に勤めていたので、このシーズンになると会社の人とビール片手
に千鳥ヵ淵を「ホー (・・ )」と眺めながら、靖国神社に参拝なんてことをや
ってました。今は銀座勤務です。うーんどこに行ったらいいのかな?とりあえ
ず日比谷公園あたりかな?

暖かい日差しを浴びながら、桜に囲まれて静かに仕事してみたいですね(笑)
まぁ、そんなこと言おうものなら速攻で P-in持たされて「行って来れば」と
なりそうです。うちの会社(笑)

  ・千鳥ヵ淵
    http://www.ne.jp/asahi/mako/dojikko/01_scene/200104/200104.htm
      ※昼もいいけど夜の方がライトアップされて好き。
        この季節、近くにあるフェアモントホテルは予約で一杯だとか。

  ・日比谷公園の桜
    http://www.pastelnet.or.jp/users/eikoh/rec/hibiya000408.htm
      ※お、このサイトなかなかいいですね!


ではでは今週もいってみましょう。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  01.Review  「前回のおさらい」
──────────────────────────────────────

何か一週間が早いですね(^^;
ついこの間原稿書いたばかりのような気がします。


さて、先週はprintfの使い方から始まって、関数のサワリの部分をご紹介しました。
随分と専門誌っぽくなってきましたね(笑)ところでみなさん、Code015でご紹介した
下記のプログラムを覚えていらっしゃいますか〜?

    #include<stdio.h>

    int main(void)
    {
        int i;

        i = 1;
        while( i <= 100 ){
            printf("M.Katsube\n");

            i = i + 1;
        }

        return(0);
    }

そういえばそんな物もあったなぁという感じでしょうか?(^^;

    ・Code15:Cプログラミング 〜しっかり基礎を固めようシリーズ 定数編〜
      http://www.ichikoro.com/webp/back_list/?cd=00015


ここまでで、まだ解説していないものは後2ヶ所でしょうか。

>        while( i <= 100 ){

whileと、“i <= 100”の部分ですね。
今回はこの2つを取り上げたいと思います。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  02.Guide  「反復構造を理解しよう!」
──────────────────────────────────────

以前Code015でもお話したと思いますが、プログラムには3つの制御構造が存在します。


>そもそもプログラムは大きく分けて3つの制御構造が存在します。制御構造とはプログ
>ラムの“流れ”を意味します。
>
>    ・順次構造
>    ・反復構造
>    ・選択構造
>
>順次構造はその名の通り、順番に処理をすることを意味します。通常上から下に向か
>って処理が流れていくというのはみなさんもう、お分かりですよね?
>
>反復構造はこれもその名の通り、ある処理を何回も繰り返して行うことを指します。
>つまり、「100回表示せよ」という場合は「表示する処理を100回繰り返せ」という
>構造になります。

                                      〜 Webプログラミング Code015より抜粋 〜


逆に言えばこの基本的な3つの制御構造を押さえれば、ほとんどのプログラムを
理解することが可能なわけです。


さぁ、その中でも今回は反復構造に注目してみましょう。
まずは下記のコードを実行してみてください。

    #include<stdio.h>

    int main(void)
    {
        int i;

        i = 1;
        while( i <= 5 ){
            printf("i = %d \n", i);

            i = i + 1;
        }

        return(0);
    }

    ・実行例
        C:\>bcc32 sample.c
        Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
        sample.c:
        Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

        C:\>sample
        i = 1
        i = 2
        i = 3
        i = 4
        i = 5

ポイントはもちろんこの行です。

>        while( i <= 5 ){

ずばり答えを言ってしまうと、

    whileの横についている括弧の中身が正しい間、
    大括弧の間に書かれている処理を実行する

“括弧の中身”とはもちろん

>    i <= 5

のことです。さらに“大括弧の中身”とは

>    printf("i = %d \n", i);
>
>    i = i + 1;

になります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  03.Guide  「条件式を理解しよう!」
──────────────────────────────────────
まずはこれ

>    i <= 5

算数の時間にみなさん等符号は習いましたよね?ことプログラムにおいても、その意
味は全く一緒になります。上の例だと「iが5以下」という意味です。

この他にも

    a >  b        aがbより上
    a >= b        aがb以上

    a <  b        aがb未満
    a <= b        aがb以下

    a == b        aとbが等しい
    a != b        aとbが等しくない

といったように表すことができます。
よく間違えやすいのは、

>    a == b        aとbが等しい

でしょうか。イコールは必ず二つ必要です。これを一つにしてしまうと、変数等への
代入と取られてしまい、致命的なバグになってしまいます。うっかりやっちゃうんで
すよね〜(^^;

試しに下の2種類のプログラムをコンパイラにかけてみてください。

    ■その1
        #include<stdio.h>

        int main(void)
        {
            int i;

            i = 1;
            while( i == 5 ){
                printf("i = %d \n", i);

                i = i + 1;
            }

            return(0);
        }

    →コンパイル例
        C:\>bcc32 sample1.c
        Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
        sample1.c:
        Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

    こちらは何の問題もなく通りました。


    ■その2
        #include<stdio.h>

        int main(void)
        {
            int i;

            i = 1;
            while( i = 5 ){
                printf("i = %d \n", i);

                i = i + 1;
            }

            return(0);
        }

    →コンパイル例
        C:\>bcc32 sample2.c
        Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
        sample2.c:
        警告 W8060 sample2.c 8: おそらく不正な代入(関数 main )
        警告 W8004 sample2.c 11: 'i' に代入した値は使われていない(関数 main )
        Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

    おっと、“おそらく不正な代入”という警告が出てしまいました。
    最近のコンパイラの大部分は、こうした間違いではないかというところには
    キチンとメッセージを出してくれます。必ず見逃さないようにチェックしま
    しょう。


話が横にずれましたが、基本的にはここでご紹介したような条件を記述します。



━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  04.Guide  「反復構造を理解しよう!:whileの使い方」
──────────────────────────────────────
さぁお次です。

>        while( i <= 5 ){

上の2項でも書いている通り、括弧の中の条件が正しい間、大括弧の間に書かれている
処理を実行します。

    while(  条件を記述  ){

        ここに繰り返す処理を記述する

    }

言っていることは、とっても簡単ですよね(^-^)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  05.Guide  「反復構造を理解しよう!:処理を追いかけよう」
──────────────────────────────────────

繰り返しますが、while文は、横にある()の中の条件式が正しい間、{}の間を繰り返
えします。ではiを数字に置き換えて、実際にどういうことが行われているか考えて
みましょう。

    ・実際のソース
        #include<stdio.h>

        int main(void)
        {
            int i;

            i = 1;
            while( i <= 100 ){
                printf("M.Katsube\n");

                i = i + 1;
            }

            return(0);
        }

    ■まずは、変数の宣言です。

>            int i;

        この状態で、iの中に何があるかは不定となっています。
        詳しくはCode19を。
            http://www.ichikoro.com/webp/back_list/?cd=00019


    ■変数iの初期化を行います。

>            i = 1;

        この段階で、変数iの値は1です。



さぁ、この直後のwhileから繰り返し(ループ)が始まります。ポイントは変数iの値が
今いくつかということです。ソースを横に置いて、ゆっくりと処理を追ってみてくだ
さい。


    (1)while文に入りました!

>            while( i <= 100 ){

        この段階で変数iの値は1のため、 1 <= 100  という条件は成立するため、
        大括弧の中身が実行されます。


            (1)printfの実行

>                    printf("M.Katsube\n");

                ここでは普通に表示を行っているだけです。


            (2)変数iの値を+1する。

>                    i = i + 1;

                ここで、変数iの値は2になります。


            (3)ループはここまで。

>                }

                閉じ括弧が出てきましたので、ループはここまでです。
                このまま、whileの位置まで一気に戻ります。


    (2)2回目のwhile文だぞ。

>            while( i <= 100 ){

        この段階で変数iの値は2のため、 2 <= 100  という条件は成立するため、
        大括弧の中身が実行されます。

            (1)printfの実行
            (2)変数iの値を+1し、変数iの値は3になります。
            (3)ループはここまで。whileまで戻ります。


    (3)3回目のwhile文だぞ。

>            while( i <= 100 ){

        この段階で変数iの値は3のため、 3 <= 100  という条件は成立するため、
        大括弧の中身が実行されます。

            (1)printfの実行
            (2)変数iの値を+1し、変数iの値は4になります。
            (3)ループはここまで。whileまで戻ります。

    (4)4回目のwhile文だぞ。

                :
                :
                :
                :
                :
                :

    (99)99回目のwhile文だぞ。

>            while( i <= 100 ){

        この段階で変数iの値は99のため、 99 <= 100  という条件は成立するため、
        大括弧の中身が実行されます。

            (1)printfの実行
            (2)変数iの値を+1し、変数iの値は100になります。
            (3)ループはここまで。whileまで戻ります。

    (100)100回目のwhile文だぞ。

>            while( i <= 100 ){

        この段階で変数iの値は100のため、 100 <= 100  という条件は成立するため、
        大括弧の中身が実行されます。

            (1)printfの実行
            (2)変数iの値を+1し、変数iの値は101になります。
            (3)ループはここまで。whileまで戻ります。

    (101)101回目のwhile文だぞ。

>            while( i <= 100 ){

        この段階で変数iの値は101のため、 101 <= 100  という条件は成立しないため、
        大括弧の中身は実行されません。


最後に return(0) が実行され、プログラムが終了します。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  06.Guide  「真偽の考え方」
──────────────────────────────────────

ここまでは大丈夫でしょうか?
よく分からーんという場合は、もう一度この上の章に戻って順番にプログラムと
にらめっこしてみてください。


さて、実はこれまでの説明にはちょっとした嘘が隠れています。

>    whileの横についている括弧の中身が正しい間、
>    大括弧の間に書かれている処理を実行する

という説明は適切とはいえません。
また、

>    while文は、横にある()の中の条件式が正しい間、{}の間を繰り返
>    えします。

というのは間違いとは言えませんが、正しい説明とも言えません。


では何が正しいかと言うと、

    whileの横についている括弧の中身が【真】の間、
    大括弧の間に書かれている処理を実行する

という説明がベターでしょうか。


さて、この“真”とは何でしょうか?C言語には、よくこの考え方が付きまといます
が、真とは 0 以外のことです。逆に 0 のことを “偽”と言います。というわけで、
whileの横の括弧には、条件式以外も書けるということなのです。

    #include<stdio.h>

    int main(void)
    {

        printf("whileの直前\n");
        while( 0 ){
            printf("whileの中身\n");
        }
        printf("whileの直後\n");

        return(0);
    }


このプログラムを実行すると、下記のようになります。

    C:\>bcc32 loop.c
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    loop.c:
    警告 W8066 loop.c 8: 実行されないコード(関数 main )
    Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

お!キチンと警告が出ましたね。
まさにこの警告が表すとおり、実行してみると

    C:\>loop
    whileの直前
    whileの直後

といった具合にwhileは実行されていません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  07.Guide  「無限ループ」
──────────────────────────────────────

では、逆にこの0の部分を 0以外にして実行するとどうなるでしょうか?
※まだ実行しないでくださいね。

    #include<stdio.h>

    int main(void)
    {

        printf("whileの直前\n");
        while( 1 ){
            printf("whileの中身\n");
        }
        printf("whileの直後\n");

        return(0);
    }

このプログラムは、永久に終わりません。なぜなら、ずっとwhileの中が真のままだ
からです。試しにコンパイルしてみましょう。
すると、

    C:\>bcc32 loop.c
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    loop.c:
    警告 W8066 loop.c 10: 実行されないコード(関数 main )
    Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

さっきと同じメッセージのように見えますが、警告されている行が変わっている
のに注目です。一番最後のprintfは永久に実行されることがないため、このよう
な警告が出ます。

さぁ、では実行してみましょう。
(必ず下の説明を読んでから実行しましょう)

    C:\>loop
    whileの直前
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中身
    whileの中真
    whileの中身
    whileの中身
    whileの中身
    whileの中身

もしこのように「終わらない」プログラムを実行してしまった場合、Windowsなら
コントロールキー(Ctrl)と'C'を同時に押すことで、プログラムを強制終了するこ
とができます。

このように終わらないループの事を「無限ループ」と呼びます。


これが、あなただけが使うパソコンだったら、他の人へ迷惑をかけることはありま
せんが、例えば「終わらないCGI」を作ってしまったとします。そのCGIへ不幸にも
たくさんアクセスがあると、サーバ上では沢山の「終わらないCGI」が起動し続け、
やがてはサーバダウンという事態へつながることになります。


意図しない無限ループにならないように、しっかりとチェックをしてからプログラ
ムは実行するようにしましょう。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  08.Guide  「等符号は演算子なのです」
──────────────────────────────────────

ここまでで、勘のするどい方なら

    「ということは、条件式からは、0 か 0以外が出ていたってこと?」

と思われたことでしょう。
この答えは、もちろん Yes!です。


さぁ疑問に思ったら、まずは証明することを忘れずに。
早速これを確認するためのコードを書いて見ましょう。

    #include<stdio.h>

    int main(void)
    {

        printf("真:%d\n", 10<100);
        printf("偽:%d\n", 10>100);

        return(0);
    }

実行してみると、私の環境では以下のようになりました。

    C:\>bcc32 true_and_false.c
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    true_and_false.c:
    Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

    C:\>true_and_false
    真:1
    偽:0

これで、見事に実証できたしたね!

ここでは真が1となってますが、これは環境によって異なります。残念ながら私は1以
外になっている環境を見たことはないですが、仕様上そうなっていますので、ここは
従っておきましょう。単純に、決めの問題ですからね。


もう一つ追記しておきます。この等符号は「演算子」です。
Code15でご紹介しました、

>C言語では、もちろん四則演算のような計算をすることができます。
>
>    足し算: +
>    引き算: -
>    掛け算: *
>    割り算: /
>    剰余算: %
>
>となります。

と同列のものです。
実際に、等符号とマッチしているか「計算」し演算結果を返しますよね?


ここではそんなに難しく考えず、「ふーん、そうなんだ」程度に覚えておいて
ください。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  09.Guide  「whileの使用例」
──────────────────────────────────────

「括弧の中が真である間繰り返す」というのを利用すると、例えばこんな使い方がで
きますね。

    #include<stdio.h>

    int main(void)
    {
        int i = 1230123;

        /*一番下の桁を一個ずつ取り払っていく*/
        while( i / 10 ){
            printf("i = %d\n", i);

            i = i / 10;
        }

        /*ループが終了した時の条件を見てみる*/
        printf("----------------\n");
        printf("i = %d\n", i);
        printf("i/10 = %d\n", i/10);

        return(0);
    }

    C:\>bcc32 loop.c
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    loop.c:
    Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

    C:\>loop
    i = 1230123
    i = 123012
    i = 12301
    i = 1230
    i = 123
    i = 12
    ----------------
    i = 1
    i/10 = 0


そうそう、 1 / 10 は 0.5 じゃないかと思われた方!するどいですねぇ。これは
以前お話したとおり、int型で宣言した変数は、基本的に整数を扱うことになりま
す。もし、小数点付の数値の場合は、自動的に切り落とされることになります。

これを「暗黙の型変換」と言います。
というわけで次回はこの説明から入ることにしましょう。



まぁもちろん、上の例のように、こんな無理して使うことはないです(^^;
常に分かりやすいコードを書くようにしましょう〜。


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  10.Question  「今週の問題」
──────────────────────────────────────

    Q. 次に示す実行結果になるよう、以下のコードを修正しなさい。

        ■コード

            #include<stdio.h>

            int main(void)
            {
                int i = 1230123;

                /*一番下の桁を一個ずつ取り払っていく*/
                while( i / 10 ){
                    printf("i = %d\n", i);

                    i = i / 10;
                }

                /*ループが終了した時の条件を見てみる*/
                printf("----------------\n");
                printf("i = %d\n", i);
                printf("i/10 = %d\n", i/10);

                return(0);
            }

        ■実行結果
            C:\>bcc32 loop.c
            Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
            loop.c:
            Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

            C:\>loop
            i = 123012
            i = 12301
            i = 1230
            i = 123
            i = 12
            i = 1
            ----------------
            i = 1
            i/10 = 0


キチンと処理の流れを理解できていれば、後はチョコッと頭を回すだけです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                           編    集    後    記
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

毎週問題を考える度に思うのはプログラムってほんとにパズルみたいだなぁという
ことです。今回の問題はカット&ペースト一発で解決しちゃいますしねって、書く
と答えを言ったも同然かな(^^;

うーん、しかしまとまりのない構成になってしまいましたね。
すみませぬ( ^.^)( -.-)( _ _)


今週頭に人事発表があり、見事異動と相成りました。これまでディレクション系のグ
ループだったのですが、元々昔いたプロデュース系というか企画系のグループに戻さ
れました。いや、成績(態度)が悪かったワケじゃないですよ、たぶん(^^;

グループ移されても仕事内容が以前と変わんなかったので、じゃぁ戻そうかという
話になっていたようです。まぁ、どこにいっても自分のやりたい事やるだけですけ
どね。それが最終的に会社の利益になれば、お互いハッピーなワケですし!



そうそう、みなさんSonyのSDR-4Xってご存知ですか?

 ・ソニー、2足歩行ロボットの新モデル「SDR-4X」を発表
    〜不整地面での動作安定性が向上 話者識別も可能に
    http://www.watch.impress.co.jp/pc/docs/2002/0319/sony2.htm

    →動画が見れます!っていうかこりゃ見ないと。
        http://www.sony.co.jp/SonyInfo/News/Press/200203/02-0319/02_0319mv2.html

速攻でハマリそうな人に転送したり、会議の資料の表紙にくっつけたりしてました<おい(^^;

もうー、ムギュッとしたいですね(笑)微妙に顔がかわいくない(私好みじゃない)のですが、
動いているところがなんともキュート。しかも歌って踊れるらしいのですよ。
ちょっと、ねぇ、奥さん(笑)

ただ発売されるとなると高級国産車並に(600〜700万くらいかな?)するとのことですので、
一般庶民にはしばらくお預けですかねぇ。AIBOですら躊躇(ためら)ってしまうと言うの
にー(^^;

う、でも...。は、いかん、いかん。こればかりは「やってもーた」じゃすまないぞ、自分。
といいつつGT-R新車で買ったと思えば...あ、いや、むお〜(笑)


と悶えながらも、今度は月曜日にお会いしましょう (^0^)/~~


■Information
 「Webプログラミングからのお知らせ」

    【相互広告募集のお知らせ】
      読者数を増やしたいメルマガ発行者さんを募集しています。お互いに一定期間(1〜
      3回程度)広告を掲載し合いませんか?詳細はご相談ください(無料)

         お問い合わせ: mm-webp@ichikoro.com

    【コラム募集のお知らせ】
      Webプログラミングでは、寄稿していただけるコラムやプログラムなどを募集して
      います。たくさんの読者の方にあなたをアピールする場にもなります。ぜひ有意義
      な情報やご意見をお送りください。

         お問い合わせ: mm-webp@ichikoro.com


■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

                   【 Webプログラミング Code Sample 】

                    発  行 : ichikoro.com
                発行責任者 : 勝部 麻季人
                              < katsube@ichikoro.com >
                  発行部数 : 1822部(前回)
                 Webサイト : < http://www.ichikoro.com/webp/ >
            お問い合わせ先 : < mm-webp@ichikoro.com >

                            Powerd by まぐまぐ
    All Right Reserved, CopyRight(C) 2001 Webプログラミング Code Sample
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■