C言語超入門(?)第三回

前回の復習と今回の概要

  1. 「もの」は「型」に分けられる。
  2. 「関数」は「命令の集まり」を実行し、「決められた結果」を返す。
  3. 「引数」は関数にくっつける「もの」。
  4. 関数の側では実際のものはわからないので「仮」引数を書く。
  5. 関数を使用する側では「実」引数を書く。

前回のまとめと微妙に違う?まあ、仕方がない。
今回の内容は大体次の通り。

  1. 関数の「宣言」について。
  2. C言語に「最初からある関数」を使う。「最初からある関数」を組み込み関数という。

では、始めよう。今日は短そうだ。
しかし、ちょっと待とう。今回はもう一つ正確な語を用いる。
「もの」と今まで呼んできたもの(上でもそう呼んでいるが)は、正しくは「値」という。
まあ、数値とかの値、で分かると思うが、「実際のもの」というニュアンスがある。
0がint(整数)の値である、'a'がchar(文字)の値である、などなど・・・

今回の問題提起:画面への表示

前回までのプログラムは、実行しても何も画面に表示してくれない。それもそのはず、「表示してくれ」という命令をしていないからだ。
今回は「表示してくれ」という命令を出したいわけだが、C言語では「命令」のレベルで「表示」をサポートしていない*1
じゃあ何を使うかというと、前回説明した関数を使う。
・・・といったが、前回の説明では「関数を作る方法」と「関数を使う方法」を説明しただけだ。
命令できないから関数を使う、しかしその関数では命令しようがない・・・
つまり、「手で書いた関数だと絶対に表示できない」。
そこで、「手で書かない関数」の存在が現れる。
「手で書かない」とはつまり「我々は中身をしらないが、使える」ことである*2

使うために必要なこと:宣言

関数を使うには、関数の名前がいる*3
前回の説明で、「(仮)引数は関数を使うときに渡さなければいけない値」と書いた*4
つまり、仮引数は「関数を使うときに守らないといけないこと」なので、関数を使うには仮引数も必要だということがわかる*5
まあ、とどのつまり、関数を使うには「中身以外のもの」が全ていることになる。つまり、下みたいになる。

型 関数の名前(引数)

これを関数の「宣言」という。この宣言も一種の命令なので、終わるときには;(セミコロン)が必要。
「手で書かない関数の中身」は言語を実行するときに勝手にくっつく*6ので、これで「手で書かない関数」が使えることになる。
というわけで、「文字」を画面に表示するプログラムを書いてみる。
何かを表示する関数は「手で書かない関数」の代表例で、こんなのは「C言語に元からある関数」であることが多い。「元からある関数」は「組み込み関数」と呼ばれる。
「組み込み関数の一つ」として、putcharという名前の関数がある。引数にcharの値、returnに書かれる値はintである関数で、宣言は以下の通り。

int putchar(char c);

というわけで文字を表示してみる。が、別に実際に動かしている様子は見せないし、実際にしないでもいい。

int putchar(char c);
int main() { putchar('1'); return 0; }

putcharの宣言が、main関数より前に書かれている。C言語では、「作法として」関数宣言を使う場所より前に書く。
上のプログラムがどう動くかイメージがわくだろうか?
main関数が始まって、putcharが実行される。中身は分からないので省略するが、「外(=使っている人)から見ると」1という文字を表示する。
次に、putcharの呼び出しが、「int(整数)の何か」に変わるが、今回は無視する*7
値を命令のように扱うと無視されるだけなので、次の命令に進み、returnが実行されてプログラムが終わる。


さて、今回のプログラムについて注意することは、「プログラムが終わっても改行はされない」点である。
あくまでプログラムは「1という文字を画面に出して終了した」に過ぎない。誰も、改行しろ、とは言っていない。
じゃあ次は「改行しろ」と命令したくなる。
だが、「改行」ってどうやるのか。
実は、答えは複数ある。今回は二つの答えを提示する。
一つ目は「改行文字」という文字を使うことである。この文字は特別な文字で、この文字を画面に出すと「改行」してくれる。
・・・さて、こんなプログラムをイメージしただろうか?(なお、putcharの宣言は省略している。)

int main() { putchar('
'); return 0; }

ちなみに、一応言っておくが、別に書き間違えではなく、表示が崩れているわけでもなく、わざと変に書いている。
'の間には文字はない。ただ、そこで「改行してる」だけである。
・・・残念ながら、これは間違い。そもそもこれがプログラムだとすると、「非常に読みにくい」ことになる*8
正しいプログラムはこちら。

int main() { putchar('\n'); return 0; }

このプログラムを実行すると・・・何も表示されないが、一応改行され(ていることがわか)る。
\nと二文字書いてあるが、C言語ではこれを「改行文字」という一文字として扱う。\(Windowsの日本語環境だと円マークに見える。それ以外の人はバックスラッシュに見える。)は特殊な文字を表すために使われていて、これ以外にも「タブ文字」を表す\t、あとは文字を表すのに使う'を表す\'などがある。
なお、改行とタブはこうやって特殊な表現を使っているが、空白は普通に' 'でよい。


では、二つ目の方法・・・の前に、ちょっとわき道へ。

宣言の集合体:ヘッダファイル

上では、「組み込み関数」を利用するためにputcharの宣言を手で書いた。
しかし、「手で書かない」ということは、「外側から分かる範囲(=関数を使うときに必要な情報)は変わらない」ということなのだから、その関数を作った誰かが上のような宣言を書いているはずである。
だから、本来私たちがこの宣言を手で書く必要はない*9
ただ、「宣言がどこにあるか」を書かなければいけない。
・・・まあ、使いたい関数が一つや二つなら本末転倒に感じるかもしれないが、使いたい関数が10や20になってきたら少しは楽だと思えるだろう。


さて、宣言が集まっているファイルのことを「ヘッダファイル」という。
いきなり「場所」の話をしているのに「ファイル」に変わったが、C言語では「場所≒ファイル」なので気にしない。
このヘッダファイル、「〜〜.h」という名前がつけられる。ちなみに、C言語で書いたプログラムは「〜〜.c」という名前*10
それで、「組み込み関数用の」ヘッダファイルを指定する方法だが、次のような書き方をする。

#include <ヘッダファイルの名前>

#includeというのが「このヘッダファイルの中に書かれてる宣言を使う」という指示なのだが、実際は「ヘッダファイルの中身」が「この指示が書かれている場所」にばかすかと挿入されるだけなので「ヘッダファイルを読み込む」という表現が正しい。
なお、この指示の直後は改行するのが望ましい。そこに文字を書く必要性もないので気にせず改行すればいい。


「組み込み関数用の」と書いた部分がもしかしたら気になったかもしれないので一応補足すると、「自分で書いた」ヘッダファイルの読み込みは少し書き方が違う。
これらを混同している説明もあるので注意してほしいが、注意するより「組み込み関数用の読み込み方を正しく」覚えてほしい。
しばらくプログラムを書かないと、「自分で書いたヘッダファイル」を読み込む機会はないので。


さてさて、これで組み込み関数が使える。閑話休題〜。

文字列の表示:puts関数

タイトルの通り、putsという関数を呼び出す。
puts関数の宣言が書かれたヘッダファイルはstdio.hという。なお、「Standard Input/Output」の略であり、日本語だと「標準入出力」と訳す*11
puts関数は、引数に「文字列」をとる。
「文字列」は前回一応説明したのだが、"(ダブルクオート)で囲んだ(複数)文字のこと。
例えば、"123"や"abcde"などが普通の文字列、ちょっと特殊な文字列としては""という何もない文字列があげられる。
さて、puts関数は「引数の文字列を画面に表示して改行する」という関数である*12
つまり、「改行する方法」の二つ目はこの関数を「何もない文字列を引数にして」呼び出せばよい、ということである。
プログラムにすると、次のようになる。

#include
int main() { puts(""); return 0; }

ちなみに、putsはintの値に変わるが、やはり使わないので無視。
これは期待通り、改行して終わる。
文字列の中には文字が複数かける。だから、こんなプログラムもかける。

#include
int main() { puts("Hello World!\n"); return 0; }

このプログラムは、「Hello World!」と表示した後、二回改行して終了する。\nと、puts関数本来の改行の二回である。

補足:出力関数

今回使ったputchar関数やputs関数は、画面に表示する「出力関数」の一種である。
出力関数には他にもprintfという関数がある。というか、大半のC言語の説明はprintfを先に使う。
ここでprintfを使っていないのは、引数がややこしい、という一点に尽きる。
printf関数の引数を簡単に言うと、文字列とその文字列の内容に応じて必要な値を引数にとる。
・・・既に面倒くさい。
あとは、stdioの意味から少し勘付く人もいるだろうが、「出力」と逆に「入力」関数もある。
これは「文字列をキーボードから読み込む」関数なのだが、これが出てくるのは・・・あと、三回か四回後の話。

まとめ

今回は画面に文字を出すことを目標にした。

  1. 関数の宣言は、関数の書き方から中身を消したもの。宣言もやっぱり命令なので;で終わる。
  2. C言語に元からある関数を組み込み関数という。組み込み関数を使うには、宣言を書けばいい。
  3. 改行やタブなど、通常の文字ではない文字は、\と組み合わせて書く。改行は\n、タブは\tなど。
  4. 宣言が大量に集まったヘッダファイルという。名前は普通「〜〜.h」とつける。なお、C言語のプログラムは「〜〜.c」。
  5. 組み込み関数用のヘッダファイルの読み込みは#include <ヘッダファイル名>。
  6. 文字列は複数の文字が入る。もちろん\で始まる文字も書ける。
  7. putcharは文字を表示する。putsは文字列を表示し、さらに改行までする。

次回予告

次回は、値を一時的に保存するための「場所」である「変数」について。
あとは、簡単な「分岐」を使って、10行程度のプログラムを書く予定。
といっても、まともな計算をするプログラムはその次までお預け。

最後に

・・・今回は短いと思ったんだけど、おおよそ二時間かかった・・・
おかしい・・・
しかも長いし。


puts関数のところ、実際書いてるのは「putsはstdio.hに宣言が書かれていて、文字列を引数にとって、それを表示した後改行する」というだけなのに、紆余曲折してごちゃごちゃだ。
この辺りが、私の説明の技量不足、といったところなんだろうな・・・
途中で説明をあきらめて先に結果を言うべきだっただろうか・・・?

*1:そのような「命令」を見えないように「隠蔽」している。

*2:じゃあ誰が作るのかというと、場合による。多くは「C言語をコンピュータで動かすために必要なもの」を作った人である。

*3:当たり前だが、「お前」とか「君」とか呼びかけられるわけじゃないので、名前を知らないとどうしようもない。

*4:そのときは「値」ではなく「もの」と書いたが。

*5:厳密に言えば、渡すものの種類を示す「型」は必要だが、「名前」は必要ない。名前が何であっても私たちには何も影響がない。

*6:厳密に言えば、実行するときに使うものによってその辺は少し変わる。

*7:もちろんこの「何か」は意味があるのだが、今回説明していたらきりがない。

*8:しかし、ありえない選択ではない。ただ、私の知る(まともな言語の)範囲では、こんな手法をとっている言語はない。

*9:逆に言えば、書いてもいい。例えば上のputcharの例のように。

*10:「〜〜.exe」というのが実際のプログラムだが、「〜〜.c」から「〜〜.exe」にするにはもう一手間かかり、そこは説明したくない。

*11:「スタジオ」とはめったに読まない。studioだからuが足りない。しかし、ごく稀に呼ぶ人がいることは頭に入れておいてもいい。

*12:改行の有無は実は結構面倒くさく、しばしば「どれが改行してどれが改行しないか」といった問題に悩まされる。