2007年5月31日
C言語習得プロジェクト
課題
これまでC言語習得プロジェクトとして「計算機を思い通りに動かす」という観点から,言語の種類によらない一般論として,1)プログラムとは何か,2)計算機の基本動作原理,3)それを言語として記述するということについて,を学んできました.またC言語として,1)基本的なC言語プログラムの書き方,2)関数の基本的な利用方法,3)変数の定義と利用および型について,4)条件分岐(2分岐)について,5)繰り返し制御について,を学んできました.
今回は,これまでの内容に関する理解を深めるために課題のプログラムを作成することにします.
課題: 九九の表を作成する(但し,掛け算を使用しないこと)
課題の解説
九九表は誰もが知っているように1〜9までの数字から,任意に2つ取り出して掛け算した結果をかけた数字の順番に従って作成した「表」である.このことから次の特徴があることがわかる.
特徴1)計算結果の数
マスの数は 1〜9 までの数字から「重複可」の条件で2つの数字を取りだすため,
1つ目の数字の取り出し方が 9 通り
2つ目の数字の取り出し方が 9 通り
であり,2つの数字の組み合わせが 9×9=81 通りとなる.
ここで,1つ目の数字と2つ目の数字が入れ替わっても計算結果は変わらないことから,入れ替わりを省くことを考えます.ここで注意する点は「同じ数字同士の掛け算」があることです.そこでまず,「同じ数字同士以外の掛け算の数」を考えると
1つ目の数字の取り出し方が 9 通り
2つ目の数字の取り出し方が 8 通り
で入れ替えを除くとその組み合わせの数は (9×8)/2=36 通りとなります.これに「同じ数字同士の掛け算」の組み合わせを足せば,必要な数がわかります.「同じ数字同士の掛け算」は9通りなので,全部の組み合わせは 36+9=45 通りとなります.
この数字は,1+2+3+4+5+6+7+8+9と同じであり,次の図のマスの数を数えることになります.ここで図1を眺めてみると,これは三角形の面積を求めているように見えます.実際には三角形の端が「重なる」のに対して図1は「端が1マス」なので,台形の面積を求めることになります.図1の台形は,上底が1マス,下底が1マス,高さが9マスなので,
((上底 + 下底)×高さ)/2=((1+9)×9)/2=45
となり,45マスあることがわかり,先ほどの組み合わせの数(45通り)と同じ数字が得られます.
図1-1 九九表を作るのに必要な計算結果の数を数える
この結果から,計算するべき個数は45個でよいことがわかります.
特徴2)表の縦と横
次に表の特徴を考えると,縦に並べる掛け算する値が1づつ増えており,横に並べる掛け算する値も1つづ増えています.
C言語の解説
0)プログラムを書き始める前に
C言語は,関数毎に処理を行います.またプログラムが起動されると最初に「main」という関数を実行することになっています.そこで,プログラムを作成するには最初に
int
main()
{
return(0);
}
という「main」という関数の宣言が必要となります.この例では,
関数名 main
引数 無し ← 引数とは処理をするのに必要な値のことです
返り値 整数型 ← 返り値とは処理結果としてどんな値を返すかを意味します
となります.ここで返り値とは「このプログラムを呼び出した相手に渡す値」のことなので,コマンドプロンプトからプログラムを実行した場合はコマンドプロンプトにこの例では「0」という数字を渡すということを意味します.
なお,C言語ではいろいろな関数が予め用意されており,これらをライブラリと呼びます.ライブラリに登録されている関数を使用するには
#include
<使いたいライブラリ名>
となります.これを書いておくと自分でプログラムを作成しなくてもライブラリに登録されている様々な関数を使用することができます.例えば,画面にHelloを表示するプログラムの場合
#include
<stdio.h>
int
main()
{
printf("Hello");
return(0);
}
とすると,自分では printf という関数を作っていなくてもその関数を使って画面にHelloを表示させることができます.なお,printfの中で \n と入れると改行します.
1)変数
C言語で整数を扱うには int 型という「型」で宣言した変数を使います.変数を宣言するには
型名 変数名;
とします.このため,ここでは計算結果を入れるための変数 kekka を用意するには
int
kekka;
とすればよいわけです.また,変数名で必要な個数の変数を用意すると,プログラム中では使いづらいことがあるので,複数の箱に対して「全体」の名前をつけ,個々の箱を「番号」で扱う「配列」があります.例えば,九九表で必要な計算結果が45個(なぜ45個かは課題を理解するための解説を参照)なので,変数全体の名前を kekka として45個の箱を用意するには
int
kekka[45];
とします.箱の番号は「0」番目からとカウントするため,45個の箱があっても箱の番号は
kekka[0] から kekka[44]
までとなり,番号は0から44までとなります.この例では箱を一列に並べたものですが,表は縦と横があるので,例えば九九表全部を入れる箱を用意するならば
int
keka[9][9];
とすると,縦に9個,横に9個づつの箱を並べた全部で81個の箱を用意することができます.
2)繰り返し制御
C言語でよく使う繰り返しをするための関数として
for
while
があります.繰り返しという動作は
最初の状態 ← 初期値と言います
終了条件 ← どうなったら終了するかのことです
変化 ← 1回繰り返したら何をどう変化させるか
が必要となります.forはこの3つを一度に書くことが出来るため
for(最初の状態; 終了条件; 変化)
と書きます.whileは終了条件しか指定しないため
最初の状態;
while(終了条件)
{
変化;
}
とします.whileで変化を書き忘れたり,終了条件と関係しない変化を書いた場合,繰り返しが終了しなくなるため「無限ループ・無限繰り返し」になり,プログラムを実行すると終了することが出来なくなります.
なお,C言語は「最初の;」が見つかるまでを処理の対象とするため,実行したい処理が1つの場合は
for(最初の状態; 終了条件; 変化)
実行したい処理内容;
または
最初の状態
while(終了条件)
変化;
と書くことができます.ここでわかるようにwhileは「必ず処理に変化が必要」であるため,一般に「実行したい処理が2個以上」となります.2つ以上の処理を実行するには処理したい内容を{}でくくり「ここで1つである」ことを明示しなければなりません.すなわち,処理したい内容が「処理A」と「処理B」の2個であった場合,
for(最初の状態; 終了条件; 変化)
{
処理A;
処理B;
}
または
while(終了条件)
{
処理A;
処理B;
変化;
}
となります.
forの特徴は「変化が単純な場合」に適しており,whileは「処理内容によって初期値や変化を変えたい場合」に適しています.例えば1〜9まで順番に変化させるという単純なケースではforが書きやすく,入力された数字が偶数の場合は2倍,奇数の場合は1/2倍に「終了条件に関連する値」を変化させるなどといった複雑なケースではwhileが書きやすいです.
例えば1〜9まで順番に変化させる場合を考えると,
1)今何番目かを入れるための変数が必要
2)初期値は1
3)終了条件は「何番目か」が入っている変数が9になったら
4)変化は「何番目か」の値を1づつ増やす
となります.このため,
int
loop;
for(loop=1:loop<=9;loop++)
printf("%3d",
loop);
または
int
loop;
loop
= 1;
while(loop<=9)
{
printf("%3d",loop);
loop++;
}
とすればよいことになります.この例では画面に横方向に3桁づつ刻みで1〜9までを表示します.
なお,繰り返しの処理として繰り返しを書くこともできます.例えば1〜9までの繰り返しをしている中でもう一つ1〜9までの繰り返しをする場合は
int
loop1,loop2;
for(loop1=1:loop1<=9;loop1++)
for(loop2=1:loop2<=9;loop2++)
printf("loop1の値は%3dでloop2の値は%3dです\n",
loop1,loop2);
または
int
loop1,loop2;
loop1
= 1;
loop2
= 1;
while(loop1<=9)
{
while(loop2<=9)
{
printf("loop1の値は%3dでloop2の値は%3dです\n",
loop1,loop2);
loop2++;
}
loop1++;
}
となります.
今回の課題では九九表を計算するのですが,九九表を作成するのに必要な計算は45個なので,必要なデータは例えば次のように作成することができます.
#include
<stdio.h>
int
main()
{
int
loop1,loop2;
for(loop1=1;loop1<=9;loop1++)
{
for(loop2=1;loop2<=loop1;loop2++)
printf("%3d",loop1*loop2);
printf("\n");
}
return(0);
}
または,
#include
<stdio.h>
int
main()
{
int
loop1,loop2;
loop1=1;
while(loop1<=9)
{
loop2=1;
while(loop2<=loop1)
{
printf("%3d",loop1*loop2);
loop2++;
}
printf("\n");
loop1++;
}
return(0);
}
と書くことができます.
ここで書いた九九表の半分(同じ数字を除いた九九表)のプログラムは
http://www.nbu.ac.jp/~fukushima/first/algorithm_practice_a/1st_kuku.zip
にあります.VisualStudioで作成しているので,Visual Studioがインストールされていれば,種類が「プロジェクトワークスペース」となっているファイルをダブルクリックするだけでプログラムを表示したりコンパイルおよび実行することが出来ます.Visual Studioが無い環境で使う場合は,フォルダ内にある
for_ver.c
while_ver.c
がプログラム本体で,main関数が1つ以上登録できないため,main関数を
kuku.c
に登録し,それぞれのプログラムを実行するように書いてあります.興味のある方はお使いください.
おまけ)もっと他の書き方
課題で for と while を使うように指示されていますが,もっと他の方法で書くとどうなるかを圧縮したファイルの中に
cyclic_ver.c
として入れておきました.これは「再帰関数」を使ったもので,掛け算がそもそも何回足し合わせるかで表現できることに着目して作成したプログラムです.興味のある方は参考にしてください.