WisdomSoft - for your serial experiences.

2.2 はじめてのC言語

プログラムの開始点となる main() 関数の作成と、printf() 関数を用いて画面にテキストを表示する方法を解説します。

2.2.1 最初のプログラム

C 言語は関数と呼ばれる部品が組み合わさって成り立っています。必ず C 言語のプログラムにはひとつ以上の関数が存在し、この関数の中に命令文が記述されています。関数とは、いろんなプログラムの流れがひとつのまとまりとして登録されているものです。

関数は、関数を呼び出し元から何らかの情報を受け取り、情報を処理してその結果を返すことができます。例えば、三角形の面積を計算する関数を作る場合、関数は三角形の底辺と高さを受け取ります。このとき、関数が受け取る情報を引数と呼びます。

関数は受け取った引数から、底辺×高さ÷2 を求め、その結果を呼び出し元に返します。この関数が返す値を戻り値と呼びます。ただし、プログラミングは数学ではないため、関数が受け取る値や返す値は数値だけではありません。文字列だったり、値を受け取らない、返さない関数もありえます。大切なのは、意味のあるまとまった処理を関数としてまとめ、それを再利用する(何度でも呼び出す)ことができるということです。関数について具体的に理解するためには、C 言語の基本を網羅する必要があります。詳しくは「第4章 関数」で解説するので、この場では上記したような関数の基礎概念を理解してください。

関数を作成するには、先ほど説明した引数や戻り値の指定と関数名を指定します。そして関数は中括弧 { } で囲まれた命令文で構成されます。

関数の定義
戻り値の型 関数名仮引数並び)
{
	命令文
}

型とは、値が何バイトで構成されるのかというような情報をコンパイラに知らせるためのものです。型について、詳しくはすぐ後で詳しく説明します。仮引数並びは、関数が受け取る値をカンマで区切った並びです。

このように、関数を作成することを定義するといいます。しかし、これだけではまだ実行されません。関数は、呼び出されてはじめて動きます。 では、C 言語のプログラムはどこから始まるのでしょう?基本的にプログラムは上から下へ流れていきます。しかし、C 言語が実際に実行されるのは main() 関数からという決まりがあります。

main() 関数の定義
int main(void)
{
	命令文
}

このように、必ず C 言語では main() 関数を定義しなければなりません。戻り値型の int は数値データを返すということを表しています。C 言語は大文字と小文字を区別するため Main() や MAIN() と書いた場合コンパイラは認識しないので注意してください。仮引数並びには、値を受け取らないことを表す void を指定しています。

プログラムはこの main() 関数から始まり、この関数から抜けるとプログラムは終了します。main() 関数を呼び出すのはオペレーティングシステムであり、戻り値はオペレーティングシステムに返されます。因みに、オペレーティングシステムが呼び出すべき プログラムの最初の実行地点のことをアプリケーション・エントリーポイントと呼びます。それでは、さっそく世界一簡単な C 言語プログラムを書いてみましょう。

コード1
int main() {
	return 0;
}
実行結果
コード1 実行結果

このプログラムは、何もせずにすぐに終了する簡単なプログラムです。まずはこのプログラムを使って、コンパイラを用いて正しくコンパイルすることができるかどうかを試してください。

return は、関数を終了して呼び出し元に制御を返すことを表すです。つまり、このプログラムは実行直後に return によって制御を呼び出し元に返すため、即座に終了するのです。return 文は次のような構文を持ちます。

return [戻り値];

戻り値には、関数が返す値となる式を記述できます。この式の型は、関数が定義する戻り値型と互換性がなければなりません。

次に、画面に文字を表示させるプログラムを作りたいと思いますが、ショッキングなことに C 言語には画面に文字を表示させるような命令は存在しません。なぜならば、ハードウェアを扱うような処理はプログラミング言語ではなくオペレーティングシステムの役割だと考えられているためです。そのため、画面への文字の出力はオペレーティングシステムのサービスを呼び出さなければなりません。しかし、画面に文字を表示させるためだけに、そのような低水準で複雑なことをしていては、プログラミングになりません。そこで、ANSI C 標準に準拠したコンパイラは、ANSI C 標準が定める標準ライブラリを用意しています。標準ライブラリは、入出力や複雑な処理などを関数として提供しています。 私たちプログラマは、この標準関数を用いて面倒な処理を省略することができるのです。

標準ライブラリ関数を使うためには、ソースにライブラリ関数の定義を取り込まなくてはなりません。他のソースファイルを取り込むためには #include というプリプロセッサディレクティブと呼ばれる命令を使います。プリプロセッサについては、後半で詳しく解説しますが、この場では #include を使うことで、他のソースファイルを取り込むことができるということを知ってください。因みに、他のファイルを取り込むことをインクルードと呼びます。

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

#include の構文は上の2つがありますが、二重引用符は通常、独自のライブラリファイルをインクルードする場合に用い、コンパイラはインクルードを指定したファイルと同じディレクトリを検索します。角かっこを用いた場合は、コンパイラは標準ライブラリファイルが配置されているディレクトリを検索します。通常、標準ライブラリをインクルードする場合は後者の < > を用います。

このようにインクルードして利用されることを想定した関数群を定義したライブラリをヘッダファイルといい、 .H を拡張子として保存されています。その中でもこれから私たちが全てのプログラムで必ず使うであろうライブラリが stdio.h ヘッダファイルです。このヘッダファイルには、文字を画面に表示したり、ファイル入出力などの基本的な入出力をサポートする関数が定義されています。次のプログラムは、関数を用いて画面に文字を表示します。 

コード2
#include <stdio.h>

int main() {
	printf("Kitty on your lap\n");
	return 0;
}
実行結果
コード2 実行結果

このプログラムは標準関数のひとつである printf() 関数を呼び出しています。printf() 関数は引数に文字列を渡すことができ、関数はこの文字を画面に表示します。 C 言語では、文字列を二重引用符で囲みます。二重引用符で囲まれたこの文字列をリテラル文字列と呼びます。 上のプログラムでは "Kitty on your lap" がリテラル文字列です。その結果、このプログラムはコンソールに Kitty on your lap という文字列を表示します。printf() 関数に渡すリテラル文字列の内容を自分の好きな文字列に置き換えて、 コンソールに文字列が表示されるかどうか試してみてください。

文字列内にある \n という記号は、改行を表しています。改行のような、目に見えない特殊な文字を扱うには、このように記号を用いて表現するのです。このような \ で始まる文字列内の記号をエスケープ文字と呼びます。文字として "\" を表現したければ "\\" と記述します。エスケープ文字の詳細については 「2.7 定数」 で詳しく説明します。

また、リテラル文字列は改行することができません。上のプログラムを以下のようにした場合、コンパイラはエラーを発生させるでしょう。改行を表現するために記号を用いる理由が、ここから理解することができます。

コード3
#include <stdio.h>

int main() {
	printf("Kitty on your lap\n
	");
	return 0;
}
実行結果
コード3 実行結果

printf() 関数の引数で指定しているリテラル文字列が途中で改行しています。この場合、コンパイラは二重引用符が閉じられていないと認識し、エラーを出力します。しかし、これでは長い文字列の場合は1行でズラーーっと書くことになります。もちろんそれでも、プログラムは正しく動作しますが、ソースが読みにくくなるというデメリットを持ちます。この場合、解決策が2つあります。

ひとつは、改行文字の前に \ 記号をつけます。この場合、\ は行連結文字として機能し、\ 記号に続く改行文字を無視します。行連結文字は文字列内だけではなく、ソースの全ての場所で用いることができます。

"Kitty on \
your lap";

もうひとつの方法は、単純に文字列を分割して記述する方法です。C 言語では、二重引用符が分割されている場合は、コンパイル時にこれを結合します。

"Kitty on " "your lap"

例えば、上の空白で区切られた 2 つの文字列は "Kitty on your lap" に等しいと考えられるのです。そのため、改行したい場所で一度文字列を閉じ、改行後に続きの文字列を書きます。

コード4
#include <stdio.h>

int main() {
	printf("体は萌えで出来ている。\n\
血潮はオタクで、心はツンデレ。\n");

	printf("幾たびのコミケを超えて不敗。\n"
		"ただの一度も敗走はなく、ただの一度も理解されない。\n");
	return 0;
}
実行結果
コード4 実行結果

このプログラムは、先ほど提示した方法を用いて、文字列の途中で改行を試みています。最初の printf() 関数では、行連結文字を用いて改行文字を排除するという方法を用いています。2番目の printf() は、途中で文字列リテラルを閉じ、改行後に再び文字列の続きを書くという方法を用いてます。後者の方法であれば、文字列を閉じた後、自由にタブ文字などを挿入することができるため、一般的には後者の方法が用いられるでしょう。