はじめに
今回はC言語の分岐、くり返しについて学びます。
通常、C言語では上の方に書いたものから順に下に向かって処理が進みます(上図左)。
プログラムにおいて、何かの状態によって違うことをさせたい場合があり、そういうときにif(イフ)を使って分岐させることができます。
上図中央のように、一度、別々の道に分かれ、そのあと合流するイメージです。
何度か同じようなことをくり返すことをループと呼びます。while(ホワイル)やfor(フォー)を使ってループができます。
上図右のように何度かグルグル回ってくり返し、その後、次の処理に進むイメージです。
分岐やループは他にもやり方があるのですが、特によく使うif、while、forにしぼって学んでいきましょう!
ifを使った分岐
先ほどの分かれ道のイメージとC言語のifの構造を重ね合わせて書くと以下のようになります。
①の部分に条件を書き、①の条件を満たすときに②が実行され、①の条件を満たさないときは③が実行されるという分岐を表しています。
上図はわかりやすくするためにifの部分だけを取り出したものになりますが、実際にプログラムに書く時には以下のようになります。
上図右の状態がプログラム中にifを書いたときの例になります。厳密にはプログラム中に①などと書くとコンパイルでエラーになりますが、大まかに言うとこういう形になるという意味です。
次にもう少し具体的に①~③にはどんなことを書けば良いか、例を使って説明していきます。
①には分岐の条件を書きますが、例えば「変数aの値が5より大きいとき」といったことを条件にする場合を考えます。
aが5より大きいとき”Big”と表示し、それ以外(5以下)のときは”Small”と表示するプログラムを作ってみます。
以下を if1.c として作成します。
#include <stdio.h> void main() { int a; a = 8; if ( a > 5 ) { printf("Big"); } else { printf("Small"); } }
コンパイルして実行すると以下のようになると思います。
$ gcc if1.c $ ./a.exe Big
変数aの中身は8だから5より大きいのでBigと表示されました。
次に以下を if2.c として作成します。前回との違いはaに3を代入していることです。
#include <stdio.h> void main() { int a; a = 3; if ( a > 5 ) { printf("Big"); } else { printf("Small"); } }
コンパイルして実行すると以下のようになると思います。
$ gcc if2.c $ ./a.exe Small
今度はaが5より小さいので、elseの方が実行され、Smallと表示されました。
ifに続くカッコ()内に書いた条件を満たす/満たさないによって、別の内容を表示することができましたね。
これが、ifを使った分岐です。
ifを使った分岐では、elseの方を書かない場合もあります。
#include <stdio.h> void main() { int a; a = 8; if ( a > 5 ) { printf("Big"); } }
上のようにすると5より大きいときはBigと表示し、それ以外のときは何もしないというプログラムになります。
条件部分で数値の比較に使える記号は以下のようなものがあります。
記号 | 使用例 | 意味 |
---|---|---|
< | a < 5 | 左辺が右辺より小さい |
> | a > 5 | 左辺が右辺より大きい |
<= | a <= 5 | 左辺が右辺以下 |
>= | a >= 5 | 左辺が右辺以上 |
== | a == 5 | 左辺と右辺が等しい |
数学ではイコール1つで等しいことを表しますが、C言語でイコール1つは右辺から左辺への代入になります。
C言語で等しいことを表すにはイコール2つになります。ここは間違えやすい部分なので注意してください。
インデント
ここで、少し豆知識をはさみます。豆知識とは言え、結構大事なのでしっかり身につけてほしい内容になります。
これまで出てきたプログラムにおいて、void main()に続く { の次の行から、行の始めに少し空白(スペース)が入っているのに気づいていましたでしょうか?
さらにifに続く { の次の行もさらに空白を入れて段差を付けています。
上図左のような行の始めの空白をインデントと呼びます。これは、実は { と対応する } をわかりやすくするためのものだったのです。
上図右のように全くインデントしないで書いても問題なくコンパイルできて、結果も同じになります。ただ人間が見てわかりにくいというだけです。
しかし、わかりやすくプログラムを書くことは非常に大切です。思ったようにプログラムが動かないときや、コンパイルでエラーが出てしまうときなどに、わかりやすくプログラムを書いていれば問題を見つけやすくなります。
インデントは空白4つがお勧めです。
{ の次の行から対応する } の前までをインデントする(空白を入れる)と覚えておくと良いでしょう。
whileループ
whileを使ったループの説明をします。
whileの構造と本ページ最初に出てきたくり返しのイメージを重ねると以下のようになります。
ifのときと同じようにwhileでも①にはループする条件を書きます。
例を使って説明していきます。条件を満たす間は何度もループします。
例を使って説明します。
変数aにはwhileループが始まる前に0を入れ、ループする条件を「aが5より小さいとき」にして、ループ内ではaの中身を表示してからaに1を足す、という例を考えます。
#include <stdio.h> void main() { int a; a = 0; while ( a < 5 ) { printf("%d¥n", a); a++; } }
上のようにwhileループでも{ ~ }内をインデントします。
このプログラムをコンパイルして実行すると以下のように0から4が連続して表示されます。
$ ./a.exe 0 1 2 3 4
whileループの{ ~ }内のprintfとa++が、aの中身が0から4になるまでくり返し実行されたことがわかります。
さらっとa++と書きましたが、これは a = a + 1 を短く書くやり方でインクリメントと呼ばれます。変数に1を足すことを表しています。
参考までにa–(マイナス2つ)はデクリメントと呼ばれ変数から1を引くことを表します。
もしかして、a = a + 1はおかしいんじゃないか?と思った人がいるかもしれませんね。
確かに数学だとこれは間違っています。
しかし、C言語ではイコールを1つだけ書いたときは代入になることを思い出してください。(イコール2つ==だと等しいの意味)
この場合「a + 1をaに改めて代入する」ということになり、結果aの中身に1を足すということになります。
forループ
forを使ったループの説明をします。whileと同じようにforでもループすることができます。
どんな違いがあるのか見ていきましょう。
whileと比べると、forの後のカッコ()内に入れるものが多いですね。
①は初期値、②はループ条件、③はループ内処理の最後に行う処理、となっています。
whileループのところで書いたプログラムをforを使って書いてみると次のようになります。
#include <stdio.h> void main() { int a; for ( a = 0; a < 5; a++ ) { printf("%d¥n", a); } }
上のようにforループでも{ ~ }内をインデントします。
この場合も実行結果は以下で、whileのときと同じになることがわかります。
$ ./a.exe 0 1 2 3 4
たいていの場合、forの方がわかりやすくループを表現することができます。
下の図のようにwhileとforを比べてみると、書く場所が違うだけで同じことをしているのがわかると思います。
そして、forの方がループの中で変わっていくaについての情報が1か所に集まっていて見やすいと思いませんか?
forの方がわかりやすいなら、なぜwhileがあるの?と疑問に思う人もいるでしょう。
今回のようにループする回数が決まっている場合はforで書く方がわかりやすいのですが、ループ中に毎度変数に1を足すわけではなく、ループする回数があらかじめわからない場合などにwhileを使うと良いと思います。
これで分岐とループを使えるようになりましたね。次回はこれらを使いこなす練習をしたいと思います。
よくあるコンパイルエラー
分岐やループを作ろうとすると、いくつも { } を書く必要がありますが、ついカッコを閉じ忘れるミスはよくあります。
そういう間違いを含んだプログラムをコンパイルしようとすると、エラーとなって実行ファイルa.exeが作成されません。
そんな時はあせらず、エラーのメッセージをたよりにプログラムを直すのが大切です。エラーメッセージの中には、何が問題なのかわかりにくいものもありますので、慣れることも必要です。
カッコの閉じ忘れ
以下のようにwhileの } を閉じ忘れた場合、どうなるか試してみます。
上のプログラムをコンパイルすると次のようなエラーが出ます。 早速わかりにくいですね。(^^;
$ gcc while.c while.c: 関数 ‘main’ 内: while.c:11:1: エラー: expected declaration or statement at end of input } ^
こんなエラーが出たときには { } の対応が間違っていないか、確認してみてください。
正しくインデントしておくと間違いの発見が早くなります。
カッコの開き忘れ
以下のようにforの { を書き忘れた場合、どうなるか試してみます。
上のプログラムをコンパイルすると次のようなエラーが出ます。 これもわかりにくいですね。(^^;
$ gcc for.c for.c:10:1: エラー: expected identifier or ‘(’ before ‘}’ token } ^
こんなエラーが出たときも { } や ( ) の対応が間違っていないか、確認してみてください。
行末セミコロン忘れ
これもよくあるミスですが、行末のセミコロン ; を付け忘れた場合、どうなるか試してみます。
上のプログラムをコンパイルすると次のようなエラーが出ます。 このエラーメッセージは ; があるべきところに a++ が来たよ、という内容です。
$ gcc while.c while.c: 関数 ‘main’ 内: while.c:10:9: エラー: expected ‘;’ before ‘a’ a++; ^
このエラーを見たら、セミコロン忘れがないか確認してみてください。
まとめ
本記事では以下のことを説明しました。
- ifを使った分岐
- インデントはプログラムを見やすくする
- whileループ、forループ
- インクリメントとデクリメント
これらの内容が使いこなせるようになると、様々なプログラムを作れるようになります。
C言語(3) くり返しと分岐の練習問題へ進み、これまで学んだことを使って実際にプログラミングすることに挑戦してみてください!