情報基礎A 「Cプログラミング」(ステップ2)
このステップの目標
- Cプログラムの定型的なパターンを元に、「直線的」な流れのプログラムが記述できる
- printf()関数, scanf()関数を使った基本的な入出力動作が記述できる
- 変数宣言、式の計算と代入を組み合わせ、変数の値の変化を把握しながら、プログラムを構成できる
1. プログラムの基本形
まずは、世界で一番簡単なCのプログラムを以下に示す。
main( ) { }
実際にこのプログラムは「何もしない」(a.outを実行してもなにも起こらない)。 それは、コンピュータに何も具体的な指示を与えていないからだ。 「何か」仕事をさせるためには、 { と } の括弧の間に、コンピュータへの指示を箇条書きに並べる。 C言語の世界で中括弧は、コンピュータへの指令をひとつのまとまり(文章の段落に相当する単位)を表すために使われる。 そして、最初のmain()は、段落の表題に相当する部分で、「以下の中括弧の中身がプログラムのメインな部分である」ことを表している。
以下の実習では、これをひな形として、中括弧のあいだに指令を書き加える形で、プログラムを発展させてみよう。 その前に、文章にも「文の終わりには句点。を付ける」などのルールがあるように、Cのプログラムにも基本的なルールがあるので、ここでそのいくつか確認しておこう。
ここは結構大切
-
プログラムは原則的に半角英数字で記述すること。プログラムに日本語の文字が混じっているだけでエラーになる(コメントなど、一部、日本語を書いてよい箇所もあります)。特に日本語のスペースには注意すること(見えないので)。
良い例: if (x==y) z = x ; 悪い例: if(x==y)z=x;
- プログラムはたくさんの文 (statement)の集まりである。文はセミコロン(;)で終わる。
例: int x=3 ; x = x + 3 ;
- 文章の段落や章に相当するものをブロック(block)と呼ぶ。ブロックは括弧
{
で始まり、括弧}
で終わる。例: { int x,y ; int z = x + y ; printf("%d+%d=%d\n",x,y,z) ; }
- C言語では大文字と小文字は区別して扱われる。例題などで小文字のところを大文字に書き換えてはいけない。
- コンピュータープログラムの文法は厳密に定義されている。コンマ1つ、大文字と小文字を一カ所、括弧を1つ間違えただけでも、エラーになったり、意図しない動作をする。ただし、「区切りのよい箇所」に空白や改行を入れるのは自由(これを「自由形式」と言う)。
ここで、C言語に限らず、全てのプログラミング言語の共通している「構造」あるいは「パターン」を知っておこう。 基本的に、コンピュータプログラムは
宣言部(以下に記述するプログラム本体に必要な設定など) 計算処理手順の記述1 計算処理手順の記述2 ... |
という形式で記述される。この節の始めの「世界で一番簡単なプログラム」では、宣言部が空で、計算処理手順の記述がmain(){ }
に対応する。
2. 文字の出力
では早速、中身のあるプログラムの例に進んでいきたい。 以下のプログラムをエディタで入力し、コンパイル・実行してみなさい。"Hello !" の部分は、自分の好きな言葉などに変えても構わない。 ファイル名は ex1.c で統一しておこう。
例題1(ex1.c)
/* Example 1 */ #include <stdio.h> main( ) { printf("Hello !\n") ; }
このプログラムの主な見所は以下の通り:
/* Example 1 */
- /* で囲まれている箇所 */ はコメントで、プログラムの実行には一切関係しない。
#include <stdio.h>
動作:ヘッダーファイルの組み込み- このプログラムの宣言部。必要なヘッダファイルを「組み込む(includeする)」。 この例の stdio.h は標準的(standard)な入出力(i/o:input/output)を用いる際のおまじない。コンピュータの世界で「入出力」とは、キーボードから文字を入れたり、画面に文字などを出したりするような、外界とのやり取りの総称である。
main( ) { ・・・・ }
動作:関数の定義- { から } までをmainという名前の関数(処理のひとまとまり)として定義する。
printf("何々・・・") ;
動作:文字列の出力- 画面に「何々・・・」を表示する。「何々」は日本語でも構わない。例題中の
\n
(バックスラッシュ n)は、2文字が1セットで「改行」を表す。改行とは、エディタやワープロでEnterキーを押した際の「あの」動作。
バックスラッシュ($\backslash$) は ¥ キーで
バックスラッシュ $\backslash$ をタイプする際には、日本語キーボードでは¥記号を押す。 その昔、米国のコンピュータを日本に輸入する際、 金額処理にどうしても必要な¥記号を、$\$$記号と入れ替えるわけにもいかなかったため、使用頻度の低かった$\backslash$の文字コードに¥を割り当ててしまった名残である。
アスキーアートは、いかにも ローテクな気もするが、それでいて、結構味わい深い。 ここでの例を参考にすれば、絵心のある人は、アスキーアートを出力するプログラム(UNIXコマンド)を作成することができるはずだ。 その際、日本語文字を用いると、エディターや端末エミュレータの設定によっては、「文字化け」が起こるかもしれないので、注意すること。
練習:「花文字」のプリント
このプログラムを改造して,画面に以下のような「花文字のC」を出してみなさい。
*** ** ** ** ** ** *** |
解説
プログラムのひな形 main() { 何々; }
の何々のところに,セミコロン;で区切りながら 順に指令を書き並べたものが,最も基本的なプログラムの書き方であった。
例えば、
#include <stdio.h> main( ) { printf("1\n") ; printf("2\n") ; printf("3\n") ; }
を実行すると,画面には
1 2 3
と出力される。この一見当たり前にも思える動作を,まず飲み込んでおこう。プログラムの「流れ」の様子を図にすると,左のように描けるだろう。このような図を一般に流れ図(フローチャート)と呼ぶ。 特に指定しなければ,プログラムというのは「上から下へ順番に」実行される。大切なのは、前の文の処理が完了してから次の文の処理に移る、という点だ。
亀場で練習:グラフィックスで文字を描く
補助教材の「亀場」のイントロダクションのページを開き、 同じページのかなり下の辺りにある練習課題 のうち、アルファベットのCをグラフィックスで描画するプログラムを完成させなさい。
3.変数を使った式の計算
以下の例題をエディタで入力して、コンパイル、実行してみなさい(ファイル名は ex2.c にしよう):
例題2(ex2.c)
/* Example 2 */ #include <stdio.h> main( ) { int a,b,s ; printf("2つの整数を入力してください-->") ; scanf("%d %d",&a,&b) ; s = a + b ; printf("合計 = %d\n",s) ; }
プログラムを実行すると、画面に「2つの整数を入力してください-->」と出るので、半角文字で、二つの整数をスペースを区切って入力し、Enterキーを押す。例えば "7 2 <enter>" 。すると、二つの数の和(9)が出力されるはずだ。
解説
C言語の主な変数の型
整数は int
実数は float
文字は char
プログラムの見所は以下のとおり:
int a,b,s ;
動作:整数型の変数 a,b,sの宣言-
コンピュータプログラムでは、計算結果などを記憶しておくための「メモリー」が必要である。
C言語では、このメモリーを、あたかも数学で登場するxやyなどの「変数」のような記号として処理できる。
それぞれのメモリー(変数)は、名前を付けて管理し、その名前を変数名という。
変数名には a, abc, g23 など,英数字を組み合わせて自由に変数名がつけられる。
ただし,日本語文字を含んでいたり(例:変数1),数字で始まっていたり(2011data),特殊な文字が含まれていたり(you&me)してはいけない。
少々厄介なのは、C言語では、扱うデータの種類ごとに変数の「種類」(データ型と呼ぶ)を区別する習わしになっている点だ。データ型には、整数、実数、文字、などがある。 例えば、int
は integer(整数) を、float
はfloating-point number(浮動小数表現の実数)を、char
はcharacter(文字)を、それぞれ表す。
以上をまとめると、この行は、「整数(int)を記憶するためのメモリー(変数、あるいは「箱」)を3つ用意し、それぞれに a, b, s という名前を付けよ」 という指示になる。
-
printf("2つの整数を入力してください-->") ;
動作:画面出力 -
printf("何々");
で、ダブルクォーテーションで囲まれた箇所の文字列を端末画面に出力することができる。 なお、この例のように、キーボードからのデータ入力を促す記号(文)をプロンプト(文)という。
順番が前後するが、setbuf(stdout,NULL)
は、以降のprintf()の結果を「直ちに」画面に反映させるようにする指示。
scanf("%d %d",&a,&b) ;
動作:キーボードから変数の値をセット-
scanf("%d",&整数型の変数名) ;
と書くと,変数にキーボードから入力した値がセットされる。 その発展形として、この例題では、二つの変数(aとb)に「まとめて」値をセットしている。%d
は、セットする先の変数が整数型であることを表している。
s = a + b ;
動作:計算と代入- 「変数 a の内容と b の内容を加算して、その結果を変数 s に代入(セット)する」という意味。= は決して等号ではない点を十分意識すること。 数学的な計算に使う記号(演算子)には、+(加算)のほかに、- (減算)、* (乗算)、/ (除算)がある。 また、計算順序は、括弧 (・・・)を使ってコントロールすることができる。 基本的に、数式は数学の教科書のように記述できるが、乗算記号*が省略できない点に注意。例えばCの計算式として s=(a+b)(c+d);はNG(括弧の間に*が必要)。
printf("合計 = %d\n",s) ;
動作:結果の出力-
printf("何々 %d 何々\n", 整数型の変数名) ;
と書くと,「何々」の中の%d
で指定した位置に変数の値(上の例ではsの値)が表示される。
このプログラムの一連の動作を図で示すと,以下のようになる:
例題2の動作の流れ
練習:べき乗の計算
ある数(実数)を8乗した値を、以下の手順で求めたい。この手順を「素直に」Cのプログラムに翻訳し、動作を確認してみなさい。
1.変数(変数名はxとする)に、キーボードから値をセットする 2.x
の二乗(x*x
)を計算し、その結果を改めてxにセットする(x
には、入力値の2乗がセットされた) 3.x
をさらに二乗し、その結果を改めてx
にセットする(x
には、入力値の4乗がセットされた) 4.x
をさらに二乗し、その結果を改めてxにセットする(x
には、入力値の8乗がセットされた) 5.x
の値(答え)をコンソールに出力する
x
の8乗を求めるには、7回のかけ算(x*x*x*x*x*x*x*x
)を行うのが愚直な
計算方法と言えるが、上の手順ではこれが3回のかけ算に「節約」できている。変数を用いて、中間的な結果を使いながら
計算を進めるところがポイントだ。
ヒント
例題2(ex2.c)をひな形にして作業をはじめるのが良いだろう。
この場合は実数で計算させたいので、それに用いる変数は実数型(float
)で宣言する必要がある。
実数(float)型の変数を扱う際の、 scanf()とprintf()のフォーマット書式
実数型の変数x
に、キーボードから値をセットするには、scanf("%f",&x);
と記述する。
実数型の変数x
の値を、コンソール画面に出力するには、printf("ANSWER= %f\n",x) ;
のように記述する。
発展:三角形の面積
三角形の三辺の長さ(ここではa, b, cとしよう)を入力すると、その面積を計算して画面に表示するプログラムを作成しなさい。
ヒント
ヘロンの公式(Heron's formula)によれば、 s = (a+b+c)/2 とすると、三角形の面積 S は$S = \sqrt{s (s-a) (s-b) (s-c)}$ で与えられる。この公式を活用しよう。
面積は実数値を取るので、整数(int)を使った計算では不十分である。そこで、実数型(float型)の変数の登場となる。float型を使うにあたっての注意点を以下にまとめる:
-
実数型の変数宣言は、
float a,b,c ;
のようにして行う。 -
実数型の変数に(キーボードから)値をセットするには、
scanf("%f", &a);
のように記述する。3つの変数にまとめてセットする方法scanf("%f%f%f",&a,&b,&c);
も可能。整数型の変数を使う場合には%d
であった箇所が、 実数型では%f
になる点を意識せよ。 - 実数値を出力するには printf("%f \n",S) ; のようにする。こちらも、整数型では%dであった箇所が、%fになる点に注意。
平方根(square root)を計算するには、C言語の(標準の)追加機能として用意されているsqrt( )
関数を使う。例えば、z = sqrt(x*x + y*y) ;
と記述すると、x*x+y*y(xの二乗とyの二乗の和)の平方根がzに代入される。sqrt()
等の数学関数を使うには、プログラムの冒頭部に以下の「雛形」ように #include <math.h>
の1行を追加する必要がある(sin(),cos(),tan(),exp()
なども同様)。
数学関数を用いたプログラムのコンパイルをLinuxコマンドを使って行う場合は以下のように、" -lm"
オプション(スペース・マイナス・エル・エム)を付けること(TurtleEditを使う場合は気にせずとも良い)。
cc ファイル名.c -lm
まずは、以下のプログラムの雛形から出発してみなさい:
#include <stdio.h> #include <math.h> main() { float a,b,c ; float s,S ; ????? ????? ????? }
亀場で練習:三角形の描画
3辺の長さa,b,cを与えると、辺がちょうどその長さになっている三角形を亀場に描くプログラムを作成しなさい。
ヒント:
基本的な手順は
- (方向はともかく)距離aだけ進む。
- $\pi$から辺ab間の角度を引いた角度だけ左に回転する。
そうすると、回転角度は $\theta_1 = \pi - \arccos\left(\frac{a^2+b^2-c^2}{2ab}\right)$ラジアン。 - 距離bだけ前進する。
- $\pi$から辺bc間の角度を引いた角度だけ左に回転する。
そうすると、回転角度は $\theta_2 = \pi - \arccos\left(\frac{b^2+c^2-a^2}{2bc}\right)$ラジアン。 - 距離cだけ前進する。
逆余弦関数は、C言語ではacos( )
を用いる。
亀を回転させる際には、角度は(ラジアンではなくて)度で指定する必要がある点にも注意
(ラジアン値*180.0/M_PI
のように計算すればよい。ここで、記号M_PI
には円周率3.141592...があらかじめセットされている)。
「亀場」のタートルグラフィックスのコーナーも参照のこと。 Cプログラムと同じ場所にファイルturtle.hをダウンロードしておくことを忘れずに。
ひな形として、長さa,b,cの辺を120度ずつ左回りしながら描くプログラム例を示す。 このプログラムでは、辺の長さが等しい場合のみ三角形が構成される。
#include <stdio.h> #include <math.h> #include "turtle.h" main() { float a,b,c ; CON("localhost") ; CLR() ; RST() ; printf("a b c ? ") ; scanf("%f%f%f",&a,&b,&c) ; PD() ; FD(a) ; LT(120.0) ; FD(b) ; LT(120.0) ; FD(c) ; }