3回目の授業
第2章
- 四則演算(和,差,積,商,剰余) +,-,*,/,%
- 整数と浮動小数点数 int型,double型
- 型と演算 int型どうしの演算結果とdouble型どうしの演算結果の違い
- キャスト演算子
C言語の命令文
前回,“C言語ってだいたいこんなかんじ”のなかで,C言語のプログラムの基本は,main()
関数のなかに命令文をずらずらと書いていくことである,と説明をしました。C言語の命令文には,実は大きく分けて次の四つがあります。
- 変数の型宣言のための文
- 式文
- 関数呼び出しのための文
- プログラムの流れの分岐・繰り返しのための制御文
以下に,それぞれの命令文についてもう少し詳しく説明しましょう。
変数の型宣言のための文(Cf. テキスト30ページ)
プログラム言語における変数とは,数値を入れておく(記憶させておく)入れ物の役割をはたすものです。これは,電卓におけるメモリー機能の役割をするようなものです。
電卓のメモリー機能は,せいぜい2個程度の数値しか記憶させることができませんが,プログラム言語では,コンピュータのハードウェアの許す限り,そのような数値を記憶させておくための変数を幾つでも作ることができます。
前回説明したように,C言語においては,プログラム中で使用する予定の変数は全て,最初に型宣言をしておかなければなりません。変数の型宣言は,以下のような形式で書きます。
型名 変数名 ;
例えば,int型(整数型)の変数として,nxという変数名の変数を使いたいときは,
int nx ;
と宣言します。また,double型(浮動小数点型)の変数として,dxという変数名の変数を使いたいときは,
double dx ;
と宣言します。このように型宣言された変数は,プログラム中で
nx = 17 ;
のように書くことによって,自由に数値を代入して記憶させておくことができます。
別のプログラム言語であるBASICなどは,このような型宣言が不必要で,プログラム中でいきなり変数を使用し始めることができます。C言語になれた人の中には,BASICのプログラムを見ると,「変数が湧いて出てくるようで気持ち悪い」と言う人もいます。一方で,BASICの好きな人は,「C言語は変数の型宣言をいちいちしなければならないのでめんどくさい」と言ったりします。
プログラミング言語だけに関わらず,何事も,一長一短,なのです。
エネルギー保存則からいって,全てにおいて都合の良いことばかり,というのは,ありえないのです。
(ある面で都合の良いことが生じていたら,必ず別のどこかに,そのしわ寄せが生じている,というものです。それが人生というものです。その逆もまた真なり。)
(注意その1) int型の変数は,その名のとおり,整数のみを表現することができる変数です。従って,
nx = 17.8 ;
のように代入しても(コンパイルはエラーが出ずにとおりますが),変数 nx
には,17という値しか記憶されません。(小数点以下は切り捨てられます。四捨五入のような親切なことも一切されません。)(Cf. テキスト29ページFig.2-4)
(注意その2) 変数という入れ物の大きさは有限ですので(変数に割り当てられるメモリの範囲は有限ですので),ある変数で表現できる数値の大きさにも限界があります。
- int型の変数の場合は,16bitコンピュータの場合には-32,768〜+32,767の整数値となります。
(32bitコンピュータの場合には-2,147,483,648〜+2,147,483,647の整数値となります。)
- double型の変数の場合には,およそ10-306〜10+306の実数となります。
が,精度が保証される桁数は,高々16桁程度です。
式文
式文については,ほぼ見た目のとおりに理解して間違いないはずです。式文の基本的な書き方は以下のとおりです。
代入先の変数名 = 計算式 ;
計算式には,+,-,*,/
といった四則演算子や,関数呼び出しも使えます。演算子の変わったものとしては,%
と書く演算子があります。これは,割算の余りを求める演算子で,
a = b % c ;
と書くと,b
を c
で割った余りを a
に代入するという計算をします。(例えば,b
の値が17で, c
の値が5の場合には, a
の値は2となります。)
(注意) 演算子を使用するときは,計算結果の型がint型になるかdouble型になるのかを,しっかり意識して,プログラミングをして下さい。(Cf. テキスト32ページ,テキスト33ページList2-8)
- 例1 ― int型 / int型 の計算結果はint型 ―
int b, c ;
double a ;
b = 5 ;
c = 2 ;
a = b / c ;
a
の値は,2.0となる。(b/cを実行した段階で2になってしまう。期待していた2.5にはならない。)
- 例2 ― double型 / double型 の計算結果はdouble型 ―
double a, b, c ;
b = 5.0 ;
c = 2.0 ;
a = b / c ;
a
の値は,2.5となる。(期待どおり)
- 例3 ― double型 / double型 の計算をしても代入先の変数がint型なら切り捨てられる ―
int a ;
double b, c ;
b = 5.0 ;
c = 2.0 ;
a = b / c ;
a
の値は,2となる。(b/cを実行した段階では2.5となっているが,それをaに代入した時点で2になっちゃう。)
ところで,例1の場合に,a
の値を,手っ取り早く,期待どおり2.5にする手立てがあります。それは,キャスト演算子と呼ばれるものを使うことです。(Cf. テキスト35ページTable2-6)
int b, c ;
double a ;
b = 5 ;
c = 2 ;
a = (double)b / (double)c ;
上の例では,キャスト演算子 (型名)
によって,まず b, c
の値が(一時的に)double型となってくれます。double型同士の演算ですので,その計算結果もdouble型となります。さらに代入先の変数である a
はdouble型として型宣言してありますから,結果として,a
の値は期待どおり,2.5となってくれるというわけです。
関数呼び出しのための文
一般的に,関数というものは,何らかのデータを受け取り,それについて何らかの計算をして,その結果を返すものということができます。このとき,
受け取るデータのことを,引数
返す結果のことを,関数値
と言います。
さて,数学の授業でも関数というものを習ったと思います。ある関数を,f(x)と表すとき,引数と関数値の関係は,下図のように表されることになります。
C言語における,関数呼び出しのための文も,このような数学における関数の記述を真似て書かれるようになっています。
代入先の変数名 = 関数名(引数1, 引数2, ...) ;
引数を幾つもらうのかは,それぞれの関数によって変わります。引数をたくさんもらう関数もあれば,全くもらわない関数もあります。main()
関数は,引数を全くもらわない関数の一つです。そのような引数を全くもらわない関数の呼び出しのための文は,以下のように書くことになっています。
代入先の変数名 = 関数名( ) ;
また,代入先の変数が,int型になるのか,double型になるのかも,それぞれの関数によって変わることになります。関数によっては,代入先の変数が不必要な(すなわち,関数値を持たない)ものもあります。printf()
関数は,関数値を持たない関数の一つです。そのような関数値を持たない関数の呼び出しのための文は,以下のように書くことになっています。
関数名(引数1, 引数2, ...) ;
関数については,テキスト第6章でさらに詳しく学ぶ予定です。
プログラムの流れの分岐・繰り返しのための制御文
これは,条件によって異なった計算手続きを実行させたり,あるいは同じ計算手続きを何回も実行させたり,といったようなことをプログラムにさせたい場合に使用するいわば“構文”です。
プログラミング言語を習得するためには,この“構文”についても覚えていかなければなりません。
英語の学習に例えて言うならば,関数名を覚えることが英単語を覚えることに相当し,制御文を覚えることは文型・構文を覚えることに相当します。制御文については,テキスト第3章と第4章で詳しく学びますので,楽しみに待っていてください。
printf()とscanf()の変換指定について
前回の授業において,printf() 関数と scanf() 関数を使って画面表示やキーボード読み込みをするプログラムを書きましたが,そこで変換指定(%の次に書くおまじない)というものが出てきました。
今回,新たな変数の型として,double型(浮動小数点型)を使うプログラムを書くことになります。その場合には,printf() 関数と scanf() 関数の変換指定が少し変わってきます。以下に,それらをまとめておきますので,ソースコードを書くときには注意して下さい。。(Cf. テキスト31ページTable2-5)
引数の型宣言
| printf()の書式
| scanf()の書式
|
int x ;
| printf("%d", x) ;
| scanf("%d", &x) ;
|
double x ;
| printf("%f", x) ;
| scanf("%lf", &x) ;
(%の次の l はエルです。いちではありません。)
|
UNIXのファイルシステム(Cf. 参考書3.1)
UNIXでは,ファイルを管理するためにディレクトリの仕組みを使用しています。これは,たくさんあるファイル群を分割して管理するためのものです。たくさんあるファイル群は,その内容で分類してまとめられ,それらのファイル群のまとまり毎に,ある一つのディレクトリの中に保存されています。
すなわち,キャビネットの中のフォルダと同じような仕組みで,ファイル群が整理されているわけです。
キャビネットの中にはフォルダがたくさんあるように,UNIXのファイルシステムの中でもディレクトリはたくさん存在しています。(ユーザーがディレクトリを新しく追加していくこともできます。) そして,それらのディレクトリは,階層的な構造に整理されています。

UNIXのディレクトリの構成例
この階層的な構造の一番の親にあたるディレクトリのことを,ルートディレクトリと呼びます。UNIXファイルシステムの中では,/ (スラッシュ)で表されます。
ルートディレクトリの下層にあるディレクトリのことをサブディレクトリといいます。サブディレクトリは,それぞれ固有の名前(ディレクトリ名という)を持っています。
このようなルートディレクトリとサブディレクトリの関係を,ツリー(木)構造の関係といいます。UNIXのファイルは,その内容ごとに分類されて,関係のあるサブディレクトリの中にまとめて収められることになります。
ホームディレクトリと作業ディレクトリ
UNIXのユーザーには,一人一人に専用のディレクトリが用意されています。(小学校の教室で生徒一人一人に専用のロッカーが与えられるのと同じです。) これをホームディレクトリといい,そのディレクトリ名にはログイン名と同じものが付けられています。
自分のホームディレクトリの中には,自由にファイルを保存することができます。他のユーザーのホームディレクトリには自由にファイルを保存することはできません。(他人のロッカーに勝手に荷物を入れることはできません。)
また,自分のホームディレクトリの中に,新たにサブディレクトリ(荷物を分類して入れる箱)を作成することもできます。そのようにして,自分のファイル(自分の荷物)を自分のホームディレクトリ(自分のロッカー)内できれいに整理することができます。
UNIXでは,現在の作業対象となっているディレクトリのことを作業ディレクトリといいます。(カレントディレクトリともよばれます。)
じゃあ,現在の作業ディレクトリを知るためには,どうすればいいの? と当然思われるでしょう。
皆さんは,第一回目の授業で,pwd
コマンドを使ったことを覚えていますか? 実はこのコマンドは,現在の作業ディレクトリの名前を表示させるコマンドだったのです。もう一度このコマンドを使って,皆さんの現在の作業ディレクトリの名前を確認してみて下さい。
$ pwd(enter)
ユーザーがログインすると,まず,そのユーザーのホームディレクトリが作業ディレクトリとなります。よって,ログインしてから,特に何も特別なことをしていなければ,pwd
コマンドを実行した結果は,自分のホームディレクトリの名前が表示されることになります。
そして,ユーザーがなんらかのコマンドを入力すると,そのコマンドは作業ディレクトリのファイルを取り扱うことになります。例えば,ls
コマンドを入力すると,作業ディレクトリの中に納められているファイルの一覧が表示される,というぐあいです。(他のディレクトリ内のファイルは表示されません。)
なお,作業ディレクトリは,ディレクトリを移動するコマンドを使用することで変更することができます。(このコマンドについては,後の授業で説明する予定です。)
パスとは
UNIXにおいてファイル操作などの作業を行うためには,当然のことですが操作の対象となるファイルを特定しなければなりません。ファイルはディレクトリ毎に分類して納められていますので,操作の対象となるファイルを特定するためには,
「なんちゃらというファイル」
というような,ファイル名だけの特定の仕方では不十分ですね。
「どこそこにある,なんちゃらというファイル」
というように,ファイルの在り処をUNIXに教えてやらねばなりません。この「どこそこ」をきちんとUNIXに教えてやるためには,そのファイルが納められているディレクトリ名を教えてやればよいのです。
パスとは,あるファイルがどのディレクトリにあるのかを示すものです。ルートディレクトリから目的のサブディレクトリまでのディレクトリ名をすべて列挙することで表現します。ディレクトリ名の区切りには / (スラッシュ)を使います。
例えば,z9st11inというユーザーが,自分のホームディレクトリに,list1-3という名前のファイルを作成したとします。その場合,そのファイルのパス名は以下のように表されます。(これは上記のUNIXのディレクトリの構成例の場合です。)
/home/teacher/z9st11in
このパス名は,
- 最初の / がルートディレクトリを表し,
- その下にhomeという名前のディレクトリがあり,(これはルートのサブディレクトリになっています)
- そのまた下にteacherという名前のディレクトリがあり,(これはhomeのサブディレクトリになっています)
- そのまた下にz9st11inのいう名前のディレクトリがある,(これはteacherのサブディレクトリになっています)
というように解釈することができます。
したがって,list1-3という名前のファイルを,確実に特定してシステムに教えてやるためには,上のパス名も含めてファイル名を指定すればよい,ということになります。
/home/teacher/z9st11in/list1-3
絶対パスと相対パス
ところで,上に表示したパス名は,/ (ルートディレクトリ)から始まっていますが,このようなパス名を,絶対パス名といいます。パス名には,もう一つ相対パス名というものがあります。相対パス名は,作業ディレクトリとの相対的な位置を表すものです。
上の絶対パス名を相対パス名で表すとどうなるでしょうか。例えば,現在の作業ディレクトリがホームディレクトリ(/home/teacher/z9st11in)であったとすると,以下のようになります。
./list1-3
最初の . (ドット)は,どんなときでも現在の作業ディレクトリを表す特殊な記号です。現在の作業ディレクトリはホームディレクトリ(/home/teacher/z9st11in)でしたので,. は/home/teacher/z9st11inに置き換えられてUNIXに解釈される,というわけです。
今日の実習問題と宿題
先週まで言っていたことの繰り返しになりますが,以下のことに十分注意して,実習を行ってください。
(注意その1) ソースプログラムをエディタで作成するとき,日本語以外の部分は必ず半角英数字で(日本語入力システムが終了した状態で)入力してください。日本語を入力してもよいところは," "や/* */で囲まれているところだけです。これ以外のところに日本語(全角文字)が入力されていると,コンパイルエラーがでます。特に,スペースが半角で入力されていること(全角のスペースが入力されていないこと)を十分に確認してください。スペースは目で見ても見えませんから,半角なのか全角なのか分かりませんからね。
(注意その2) アップロードするものは,必ずソースプログラム(〜.cという名前のファイル)にして下さい。コンパイルした結果(実行形式のプログラム)や,プログラムの実行結果(ターミナルに表示された結果)は送らないでください。
以上,よろしくお願いしますね!
(重要) 宿題の締切は,次の授業が始まる前までとします。
戻る