おさえておきたいプログラミングの基本
条件分岐で処理の流れを変えてみましょう。
変数やprintf()を用いれば、ある程度基本的な計算や画面への出力が出来ます。
しかし、プログラムとしてはいまひとつ物足りないというのも事実です。これまでやってきた処理はプログラム中に記述された様々な処理をその順番とおり実行するだけのものでした。こういった処理を順次処理(じゅんじしょり)と言います。(図3-1)
図3-1.順次処理しかし、プログラムは、順次処理だけでは出来上がりません。様々な状況に応じて、違った処理を行わなくてはなりません。例えばゲームプログラムを作っているとしたら「もし、敵に当たったらゲームオーバー」など といったような、条件に応じた処理の分岐が必要になります。こういったように、ある条件で処理の流れが変わる処理を、分岐処理(ぶんきしょり)と言います。(図3-2)
図3-2.分岐処理C言語では分岐処理を記述するための命令としてif(イフ)文と、switch(スイッチ)文という命令が用意されています。ここでは、それらについて解説します。
では、まず手始めに繰り返し処理の最も基本的な処理である、for(フォー)文について学んでいくことにしましょう。
では、まず手始めに条件分岐の最も基本的な処理である、if文について学んでいくことにしましょう。ifとは、英語で、「もしも」という意味を表す単語で、「もしも~だったら、…する」といった処理を行うために用います。まずは、以下のプログラムを実行してみてください。
list3-1:main.c#include <stdio.h>
int main(int argc,char** argv){
int a;
printf("数値を入力:");
// キーボードから整数を入力
scanf("%d",&a);
// 入力した値が、正の数かどうかを調べる
if(a > 0){
printf("入力した値は正の数です。\n"); // 正の数だった場合に実行
}
return 0;
}
プログラムを実行すると、コンソール画面に「数値を入力:」と表示され、横にカーソルが出てキーボードからの入力モードに移行するはずです。まずここでキーボードから正の数を入力してみましょう。
実行結果1(正の数を入力した場合)すると上のように「入力した値は、正の数です。」と表示されプログラムが終わります。また、同じプログラムでも0もしくは負の数を入力すると次のように何も表示されません。
実行結果2(0および負の数を入力した場合)実際に、何度か正の数や負の数を入力して試して見ましょう。
では、一体、このプログラムはどのような仕組みになっているのでしょう。順を追って説明していきましょう。まず、5行目に出てくる以下の関数からみてみましょう。
scanf関数※scanf()(スキャンエフ)関数は、キーボードから文字列を入力する際に用いる関数です。
整数型変数aに値を入れるには、先頭に&(アンパサント)をつけ、"で囲まれた部分には、%dと記入します。 どうしてこのような記述の方法になるかは、ポインタとアドレスに関する知識が必要なので、ここではそのようなものだと思って使ってください。
※ scanf()関数について、より詳しい解説は、こちらを参考にしてください。
次に、条件分岐で用いる、if文の書式について説明します。if文は、次のような書式になっています。
if文の書式()内の条件式が成立した時、{}に囲まれた処理を実行するのがif文です。
list3-1では、a>0、つまりaが0よりも大きい時に条件が成立し、{}内のprintf()文が実行されるわけです。「>」は比較演算子(ひかくえんざんし)と言います。比較演算子は、以下のようなものがあります。(表3-1)
表3-1:比較演算子演算子 | 意味 | 使用例 |
---|---|---|
> | より大きい | a > 0 |
>= | 以上 | a >= 0 |
< | より小さい | a > 0 |
<= | 以下 | a <= 0 |
== | 等しい | a == 0 |
!= | 等しくない | a != 0 |
以上よりこのプログラムが、キーボードから入力された数値が正の整数のときは「入力した値は、正の数です。」と表示され、そうでない場合は何も表示されないのです。
ただ、出来ることならば正の数以外の値が入力された時にも何らかのメッセージを表示したいものです。そこで次はそれをできる仕組みを紹介しましょう。(図3-3)
図3-3.list3-1のフローチャート※注意
VisaulStudio2022では、通常セキュリティー上の理由から、scanf関数は使えません。
しかし、かわりにscanf_s関数を用いるか、プロジェクト作成時にSecurity Development Lifecycle(SDL)チェックのチェックを外すことによって、使用可能になります。
if文はある条件が成り立た場合の処理を記述することはできますが、成り立たない場合にも処理をしたい場合どうすればよいのでしょうか。その時に便利なのがif~else文です。
list3-2:main.c#include <stdio.h>
int main(int argc,char** argv){
int a;
printf("数値を入力:");
// キーボードから整数を入力
scanf("%d",&a);
// 入力した値が、正の数かどうかを調べる
if(a > 0){
printf("入力した値は、正の数です。\n"); // 正の数だった場合に実行
}else{
printf("入力した値は、正の数ではありません。\n"); // 0か負の数だった場合に実行
}
return 0;
}
このプログラムの実行結果は、実行後正の整数を入力した場合は変わりません。しかし、負の数を入力した場合は、以下のような実行結果になります。
実行結果(0および負の数を入力した場合)ここで出現した、if~else文は、以下のような書式になっています。
if~else文の書式if文の()内の条件式が満たされた時には、処理①が実行されるのは、if文単体の時と変わりません。
しかしそれ以外の場合、つまり条件式が満たされなかった場合は、else(エルス)文以下の処理②が実行されます。
したがってこのプログラムは、aが正の整数ではない、つまり0か負の値であるのならば、「入力した値は、正の数ではありません。」と出力されるのです。
図3-4.list3-2のフローチャートifとelseを用いた場合、ある条件が成り立つ場合と、そうでない場合の処理が書けました。しかし、実際には、条件が複数から成る場合も多く存在します。そういう時はどのようにすればよいのでしょうか?
その時に役に立つのが、else if(エルスイフ)です。まずは、以下のサンプルを実行してみましょう。
list3-3:main.c#include <stdio.h>
int main(int argc,char** argv){
int num;
printf("1~3の値を入力してください:");
// キーボードから整数を入力
scanf("%d",&num);
// 入力した値が、正の数かどうかを調べる
if(num == 1){
printf("one\n"); // numが1だった場合の処理
}else if(num == 2){
printf("two\n"); // numが2だった場合の処理
}else if(num == 3){
printf("three\n"); // numが3だった場合の処理
}else{
printf("不適切な値です。\n"); // それ以外の値が入力された場合の処理
}
return 0;
}
このプログラムの実行結果は、実行後正の整数を入力した場合は変わりません。しかし、負の数を入力した場合は、以下のような実行結果になります。
実行結果1(1から3の値が入力された場合)実行した結果、1を入力すれば「one」、2を入力すれば「two」、3を入力すれば「three」と表示されることが分かります。
それ以外の値を入力すれば「1~3の値を入力してください」と表示されます。
ifとelseだけでは一つの条件が成り立った時とそれ以外の場合の処理しか実行できませんが、else ifを用いれば、複数の条件の場合についての場合分けが可能です。else ifを含むif文の書式は以下の通りになっています。
if~else if~else文の書式条件式①が成り立てば処理①が、条件式②が成り立てば処理②が実行され、そのどちらの条件も成り立たなければ、処理③が実行されます。なお、else ifは、ifの後に何個でも追加することができます。なので、いくつでも条件を追加することが可能です。
そのため、list3-3の処理の流れを記述すると、以下のようになるのです。(図3-5)
図3-5.list3-3のフローチャートつぎは、if文の知識を組みあわせて、更に複雑なifの構文を作り上げてみましょう。
次のサンプルを入力して実行してみてください。
list3-4:main.c#include <stdio.h>
int main(int argc,char** argv){
int dice;
// サイコロの目を入力
printf("1から6の数値を入力してください:");
scanf("%d",&dice);
// 値が、サイコロの目の範囲内かどうかを調べる
if(1 <= dice && dice <= 6){
// さいころの目が、偶数か、奇数かで、処理を分ける。
if(dice == 2 || dice == 4 || dice == 6){
printf("丁(チョウ)です。\n"); // 偶数ならば丁(チョウ)
}else{
printf("半(ハン)です。\n"); // 奇数ならば半(ハン)
}
}else{
printf("範囲外の数値です。\n");
}
return 0;
}
このプログラムの実行結果は、大きく分けて3通りに分けられます。まず一つ目が、1から6の間の偶数、つまり、2,4,6といった値を入力した場合です。 以下のように、「丁(チョウ)です。」と表示され、プログラムは終了します。
実行結果1(2,4,6が入力された場合)次に、同じく1から6の間で、今度は、1,3,5といった奇数を入力すると、「半(ハン)です。」と表示され、プログラムは終了します。
実行結果2(1,3,5が入力された場合)最後に、1から6以外の整数、つまりさいころの目に該当しないような数値を入れると、「範囲外の数値です。」と表示されて、プログラムが終了します。
実行結果3(範囲外の数値が入力された場合)このプログラムを見ると、if文の中に更にif文が入っています。これをif文のネストと言います。
ネストとは入れ子構造のことで、if文に限ったことではなくこの後紹介する繰り返し処理などでもしばしば見られる書式です。「何かの処理の中に、さらに何かの処理が入っているのがネストである」と理解すると良いでしょう。
if文のネスト条件式①が成り立っているとき、さらに条件式②が成り立てば処理が実行されます。
仮に条件式①が成り立っていても条件式②が成り立たなければ処理は実行されません。また、条件式①が成り立たなければ中のif文も実行されません。
このようにif文はネストが可能ですが、三重以上にネストをすることも可能です。ただあまりネストを多用するとプログラムが複雑になり、わかりずらくなるので気をつけましょう。
また、次に注目したいのが9行目と11行目のif文の中身です。ここでは||や、&&が間に挟まって、複数の条件式が出ています。
これらの記号は、論理演算子(ろんりえんざんし)と言い、if文などで複数の条件を調べるときには欠かせないものです。なお、C言語で用いられる論理演算子は、以下のとおりです。(表3-2)
表3-2:論理演算子演算子 | 名称 | 意味 | 使用例 |
---|---|---|---|
&& | 論理積(ろんりせき) | AND(アンド) | a == 0 && b == 0 // aが0かつ、bが0ならば |
|| | 論理和(ろんりわ) | OR(オア) | a == 0 || a == 1 // aが0か1ならば |
! | 否定(ひてい) | NOT(ノット) | !(a == 0) // a==0でない場合、真となる |
例えば、&&は、AND(アンド)と言い、複数の条件がすべて成り立っていることが必要となります。9行目の例で言うと、「変数diceの値が1以上であり、かつ6以下」ということになります。
diceが1以上であり、かつ6以下また、||は、OR(オア)と言い、複数の条件のうち、どれかが成り立っていればよいというものです。11行目の例で言うと、「変数diceが2か、4か、6であれば」ということになります。
diceが2か、4か6の場合さらに1から6の範囲の数値で、2,4,6以外の値となると、必然的に残りは、1,3,5となり、これが、「半(はん)」となることから、else文での処理は、「半(ハン)です。」と表示することになります。
これら一連の流れの流れを記述すると、以下のようになるのです。(図3-6)
図3-6.list3-4のフローチャート最後にif文以外の条件分岐を記述する方法であるswitch(スイッチ)を学びましょう。
list3-3のような、else ifを用いた多数に分岐する条件分岐は、値が整数値であれば、switch文を用いて以下のように書くことができます。
list3-5:main.c#include <stdio.h>
int main(int argc,char** argv){
int num;
printf("1~3の値を入力してください:");
// キーボードから整数を入力
scanf("%d",&num);
// 入力した値が、正の数かどうかを調べる
switch(num){
case 1:
printf("one\n"); // numが1だった場合の処理
break;
case 2:
printf("two\n"); // numが2だった場合の処理
break;
case 3:
printf("three\n"); // numが3だった場合の処理
break;
default:
printf("不適切な値です。\n"); // それ以外の値が入力された場合の処理
break;
}
return 0;
}
実行結果はlist3-3と同じなので省略します。
switch文の書式は次のようになります。
switch文の書式switch文は、後の()内の値によって、条件を分岐させる命令です。
条件は、case(ケース)で書き、そのあとに値が来ます。最後にある、default(デフォルト)という条件は、caseで出てきたいずれの条件にも当てはまらない場合を示しています。
case、defaultの後に出てくるbreak(ブレイク)というのは処理の終了を意味しswitch文から抜け出します。
つまり、()内の値が値①なら処理①が、値②ならば処理②が実行され、いずれのcaseにもあてはならない場合には処理③が実行され処理が終了します。
以上を踏まえてlist3-5の処理を説明しましょう。
例えば、num=2の場合、「case 2:」に処理が飛びます。そのあと、「two」と表示し、そのあとbreakで処理を抜けます。(図3-6)
図3-7.list3-5のswitch文の処理の流れ同様にnum=1なら「case 1:」、num=3なら「case 3:」に処理が飛び、それぞれの処理を実行した後にbreakで処理を抜けます。
numが1,2,3以外の場合はdefaultの部分が実行されます。
例えば、「case 2:」の処理の最後のbreakが抜けていると、そのまま「case 3:」の処理が実行されます。(図3-8)
このような処理はフォールスルーと呼ばれ、エラーではありませんがプログラムがわかりにくくなるため使うことは推奨されていません。
図3-8.フォールスルー練習問題 : 問題3.
一週間でわかるC言語・C++言語がオンライン講座になりました!動画と音声によってさらにわかりやすくなりました!! 1講座で2つの言語を学ぶことができる上に、練習問題の回答もダウンロードできます。
Read →本講座が「1週間でC言語の基礎が学べる本」として書籍化されました!サイトの内容プラスアルファでより学習しやすくなっています!Impressより発売中です!!
Read →