制御構造
1.単純な分岐 − 等価演算子、関係演算子
単純な分岐とは、条件式に1つの式だけを使った選択構造である。
おもに式としては、等価演算子(=)、関係演算子(< >)が使用される。変数や式が単独で設定されることもある。その場合は、その評価値が0ならば偽、0以外ならば真という判定になる。
例 変数の場合
a = 0;
if(a)
{
printf(“aは0ではありません。\n”);
}
else
{
printf(“aは0です。\n”);
}
<実行結果> aは0です。 |
例 式の場合
a=0,b=1;
if(a*b)
{
printf(“a*bは0ではありません。\n”);
}
else
{
printf(“a*bは0です。\n”);
}
<実行結果> a*bは0です。 |
括弧の用い方に関して、基本的に4つの方法がある。
パスカルスタイル
while
(test)
{
statement;
}
改変パスカルスタイル
while (test)
{
statement;
}
Kernigham、Ritchieスタイル
while (test){
statement;
}
改変Kernigham, Ritchieスタイル
while(test){
statement;
}
どれを用いるかは自由だが、1つのプログラムでは統一した用い方をしなければならない。
2.分岐条件の組み合わせ − 論理演算子
分岐の条件は範囲の指定などのときに、複数組み合わせられる。その組み合わせには、主に論理積&&と、論理和||の演算が用いられる。
例 論理積(&&)の場合:xがaからbの間にある場合
a =1;x=2;b=3;
if(a
<=x && x <=b)
{
printf(“xはaとbの間にある。\n”);
}
else
{
printf(“xはaとbの間にない。\n”);
}
<実行結果> xはaとbの間にある。 |
論理和(||)の場合:xがa以下またはb以上にある場合
a=1;b=2;x=3;
if(x
< a|| b < =x)
{
printf(“xはaとbの間にない。\n”);
}
else
{
printf(“xはaとbの間にある。\n”);
}
<実行結果> xはaとbの間にない。 |
if文:もし〜ならば〜する
このダイアグラムをフローチャートという。フローチャートはJIS規格として規定されているが、プログラムの作り方の研究が進むにつれて、その欠点が指摘され、現在ではあまり使われていない。フローチャートに変わるものとして、NSチャートやHCPチャートなどが開発されている。とはいってもいまだにJIS規格のフローチャートを用いている場合があるので、多少の解説をしておく。フローチャートとは、アルゴリズムの各段階の処理を箱の中に記述し、各箱を線や矢印で結んで、計算順序を示すものである。
例題4.1 if文の例 2数の比較
2つの異なる数字を読み取って比較し、大きい方を求めるプログラム(if文だけを使って)を作成しよう。
実行例
考え方
変数aとbに呼び込んだ値を入れる。つぎに、aとbの値がどちらが大きいかの比較をする。
もしaがbより大きいならばmaxはaである。
もしbがaより大きいならばmaxはbである。
では、プログラムを書いてみよう。
#include <stdio.h> int main () { int max,get_a, get_b; printf(“2つの整数を入力\n”); scanf(“%d %d”,&get_a,&get_b); if (get_a > get_b) { max = get_a; printf(“大きい方は%d\n”,max); } if (get_b > get_a) { max = get_b; printf(“大きい方は%d\n”,max); } } |
if-else
文:そうでなければ〜する
上の例題でget_a > get_bが正しければ、maxはget_a。そうでなければmaxはget_bと直せる。つまりif-else文を用いて書いたほうが分かりやすい。 読んで分かりやすいプログラムを書くように、心がけよう。ソフトウェア工学上、大事なことである。
例題4.2 if-else 文の例 2数の比較
2つの異なる数字を読み取って比較し、大きい方を求めるプログラムを作成しよう。
実行例
考え方
もしaがbより大きいならばmaxはaで、そうでなければmaxはbである。
解答
#include <stdio.h> int main () { int max,get_a, get_b; printf(“2つの整数を入力\n”); scanf(“%d %d”,&get_a,&get_b); if (get_a > get_b) { max = get_a; printf(“大きい方は%d\n”,max); } else { max = get_b; printf(“大きい方は%d\n”,max); } } |
while文:〜の間〜する
例題4.3 素数判定
与えられた数が素数かどうか判定するプログラムを作成せよ。
実行例
考え方
素数とは1とその数自身でしか割ることができない数である。そこで、与えられた数をnとし、nを2から順にn-1までの数で割っていき、割り切れなければ素数であることが示せる。i=2から順に割っていくということをプログラムで書くと、iがnより小さい間は実行するとなるのでwhile(i < n)と表わせる。次に、whileループを実行中あまり(remainder)の最小値(min_remainder)を求める。やがて、iがnに到達しwhileループが終了する。その後、あまりの最小値(min_remainder)の値が0か0以外かを調べれば、nが素数かどうかの判定ができる。プログラムに書くと次のようになる。
解答
/*素数判定*/ #include <stdio.h> int main() { int get_num,min_remainder=1,remainder,index=2; printf("整数を入力してください\n"); scanf("%d",&get_num); if(get_num==1) { min_remainder=0; } while(index < get_num) { remainder = get_num%index; if(remainder < min_remainder) { min_remainder=0; } index++; } if(min_remainder !=0) { printf("%dは素数です\n",get_num); } else {
printf("%dは素数ではありません\n",get_num); } } |
もう少しよく考えてみよう。2で割り切れる数(偶数)は2以外素数ではない。また、素数でない数(合成数)の約数は対になっているので、nの平方根までの数をチェックすればよいことが分かる。この考えを用いて、もう一度プログラムを書いてみよう。
#include <stdio.h> void main(void) { int get_num,index=2,remainder,min_remainder=1; printf("整数を入力してください\n"); scanf("%d",&get_num); if (get_num==1) { min_remainder=0; } if(get_num > 2 && get_num%2 == 0) { min_remainder=0; } while (index*index <= get_num) /* =が必要となる*/ { remainder = get_num%index; if(remainder < min_remainder) { min_remainder=0; } index++; } if(min_remainder != 0) { printf("%dは素数です\n",get_num); } else { printf("%dは素数ではありません\n",get_num); } } |
こういうプログラムを実行させるとき、windowsを用いている人は、その都度エグゼファイル(実行ファイル)を立ち上げなければならず、面倒であると感じたでだろう。そこで、好きな回数だけ実行させられる方法を示す。
int choice=0;
do
{
choice =1;
printf ("続ける場合は0をやめるときは0以外の数字キーを押してください");
scanf(“%d”,&choice)
}while(choice==0);と入れておく。これにより0を押せば続行できるし、止めたければ0以外のキーを押せばよい。
ループからの脱出
while,for,do-while文を用いるとき、気をつけなければならないのは、無限ループにおちいりやすいことである。このようなことを避けるために、ループの条件は点ではなく、区間とするべきである。さて、ループからどうしても脱出する必要があるときには、if文とbreak文を用いる。例えば、キーボードからデータを入力して、0を入力したら終了したい場合を考えよう。このときは、
while(scanf(“%d”,&data))
{
if (data == 0)
{
break;
}
}
または、数字以外を入力したら終了したければ、
while(scanf(“%d”,&data) != 0)
{
}
と書けばよい。whileループの条件はscanf(“%d”,&data)であるが、scanfは呼び込みに成功すると1を返し、失敗すると0を返す関数なので、このループは入力がある限り続行される。次に、入力が0のとき、if文の条件が真となるので、次のbreak文に到達し、ここで、whileループから脱出する。
例題4.4 データをキーボードから入力し、入力したデータの平均、最大値、最小値を求めるプログラムを作成しよう。ただし、0を入力した時点で終了するとする。
実行例
考え方
1. 最大値と最小値を見つけるには、まず、1個データを読んで、その値を最大値と最小値にしておく。これを行うプログラムは次のようになる
int max,min,ini;
scanf("%d",&ini);
max = min = ini;
2. 0を入力したら終了しなくてはならないので、while文の中にif文とbreakを
使ってwhileからの脱出をはかる。関数scanf( )はうまくいけば1を返し、失敗する
と0を返す関数なので、次のようになる。
int data
while(scanf("%d",&data))
{
if(data == 0)
{
break;
}
3. 0以外のときは、新しく読み込んだデータと1個目のデータとを比較し、新し
いデータが1個目より大きければ、それをmaxとおき、小さければminとおく。次に
データを読み込んだときに、読み込んだデータとmax,minを比較する。次のようにな
る。
int max,min;
if(data > max)
{
max = data;
}
if(data < min)
{
min = data;
}
4. 平均は読み込んだデータの和sumを読み込んだ回数nで割ってやればよい。ただ
し、sumもnも整数型なので、平均を出すときには実数型に変えてやらなければならな
い。これはキャストと呼ばれるものを使って行う。次のようになる。
sum = sum + data;
n++;
printf("平均は%d",(float)(sum/n));
以上をまとめると次のようなプログラムになる。
#include<stdio.h> |
Switch文について
C言語にはelse-if文の代わりにswitch文とよばれるものがある。switch文で書けるものはすべてelse-if文で書ける。しかし、逆は真ではない。とは、言うものの、switch文で書かれたプログラムを読むこともあると思うので、簡単にswitch文の紹介をする。
switch (式) { case 定数式:文 case 定数式:文 default:文 } |
switch文の動作
「ステップ1」
式の値を求める
「ステップ2」
式の値が
(1) caseの定数式と等しい場合、
そのcaseに続く文にプログラムの制御が移り、実行される。
(2) どのcaseとも等しくないが、defaultが存在するとき、
defaultに続く文にプログラムの制御が移り、実行される。
(3) どのcaseとも等しくなく、defaultが存在しないとき、
プログラムの制御は、switch文の次の文に移る。
各caseには1つ以上の数値を持つ定数あるいは定数式による名札を付ける。Defaultとい名札の付いたcaseは、他のcaseのどれもが満足されなかったときに実行される。
例題4.5 順位の判定
入賞者の判別を行うプログラムを作成しよう。
実行例
解答
#include <stdio.h> void main (void) { int rank; printf(“あなたの順位は?>>> “); scanf(“%d”,&rank); switch (rank) { case 1: //caseと1の間にはスペースが入る printf(“優勝者には、海外旅行です\n”); break; case 2: printf(“2位のあなたには、国内旅行です\n”); break; case 3: printf(“3位のあなたには、図書券です\n”); break; default: printf(“タオルをどうぞ\n”); break; } } |
else-if文:もし〜ならば〜し、そうでなければ〜し、そうでなければ〜し、。。。そうでなければ〜する。
例題4.6 うるう年の判定
西暦年数yearを入力し、うるう年かを判定するプログラムを作成せよ。
実行例
考え方 うるう年とは400で割り切れる年数。または、4で割り切れ、かつ100で割り切れない年数のことである。
例えば1900年はうるう年ではない。
これをプログラムにするには、if (year % 400 == 0)ならばうるう年。else if (year % 4 == 0 && year % 100 != 0)ならばうるう年。else うる年ではない。ではプログラムを書いてみよう。
解答
#include <stdio.h> void main(void) { int year; printf("西暦年を入力してください\n"); scanf("%d",&year); if(year%400 == 0) { printf("%dはうるう年です",year); } else if(year%4 == 0 && year%100 != 0) { printf("%dはうるう年です",year); } else { printf("%dはうるう年ではありません",year); } } |
if(year%400 == 0)以降は次のように書くこともできる。
if(year%400 == 0 || (year%4 == 0 && year%100 != 0))
やってみよう。
例題4.7 2次方程式の解
ax2 + bx + c = 0の解を求めるプログラムを作成しよう。
実行例
考え方
判別式はD = b2 – 4acで与えられ、解の公式より、解はx = (-b ± √D)/2aで与えられる。よって
「係数aが0であり、係数bが0ならば、 (条件1)
解はない (文1)
「係数aが0であり、係数bが0でなければ(条件2)
x = -c/b (文2)
「係数aが0でなく、判別式が正ならば (条件3)
実数解が2つ (文3)
「係数aが0でなく、判別式が0ならば (条件4)
実数解は1つ (文4)
「係数aが0でなく、判別式が負ならば (条件5)
複素数解が2つ (文5)
これらは全て複数のif文を組み合わせて判断を行わなければ解けない。つまりswitch文では書けないということである。
ではプログラムを書いてみよう。
解答
#include <stdio.h> #include <math.h> void main(void) { double a,b,c,D,x1,x2,x3,x4; printf("ax^2+bx+c=0の実数a,b,cを入力してください\n");
scanf("%lf %lf %lf",&a,&b,&c); D = b*b -4*a*c; x1 = (-b + sqrt(D))/(2*a); x2 = (-b - sqrt(D))/(2*a); if(a == 0.0 && b == 0.0) { printf("解はありません\n"); } else if(a == 0.0 && b != 0.0) { x1 = -c/b; printf("解は%lfです\n",x1); } else if (D >0.0) { printf("解は%lfと%fです\n",x1,x2); } else if(D == 0) { printf("解は重解となり%fです\n",x1); } else { x3 = -b/(2*a); x4 = sqrt(-D); printf("解は%lf+i%fと%lf - i%fです\n",x3,x4,x3,x4); } } |
列挙型を用いたif文
enum {Female,Male} sex;
if(条件= = 真)
{
sex = Male;
}
else
{
sex = Female;
}
これで、列挙変数sexはMaleかFemaleしか取らないことを、文法的にきちんと宣言した。
列挙変数は列挙子に明示的に値が与えられなければ、書かれた順序に「0」から始まる順序数(ordinal number)となる。よって、この例ではFemaleは0、Maleは1となるので、条件が真ならば、sexはMaleとなる。
例題4.8列挙型enum {Female,Male}sex;にscanfで読み込んだ値を代入し、出力するプログラムを作成しよう。
解説 列挙型enum {Female,Male}sex;に入力するには、0または1をキーボードから打つ。
出力するには
printf(“%c”,(self_data.sex = = 0)? ‘F’:’M’;)を用いる。これは3項演算子と呼ばれるもので、次のように用いる。
式1?式2:式3
の形式をとり、式1が真ならば、式2の値が式の値となり、偽ならば式3が式の値となる。
解答
#include <stdio.h> #include <string.h> void main(void) { enum {Female,Male}sex; printf(" 性別> \n"); scanf("%d",&sex); printf("\n SEX\n"); printf("%3c\n",(sex==0)? 'F':'M'); } |