C言語入門:第1章「まずは慣れよう」
はじめに
もし、物事に慣れるだけで上達するのであれば、それに長く親しんだ人ほど上手になるはずである。ところが、実際はそうとは限らない。たとえばスポーツにおいても、練習を重ねることで悪いフォームが強化され、かえって技術が低下することがある。プログラミングにおいても、ただ慣れるだけでは不十分である。
とはいえ、何かを始めるにあたって、実際に手を動かして体験することは不可欠である。本章では、画面への表示やキーボードからの入力を行うプログラムを通じて、C言語によるプログラミングの基礎に触れていく。
1-1 表示を行う
コンピュータによる計算結果は、画面に表示しなければ確認できない。本節では、画面に結果を表示する方法を学ぶ。
整数の加算の結果を表示
コンピュータは"電子計算機"と呼ばれるように、計算を行うことが主たる役割である。早速、C言語を用いて、整数値15と37を加算してその結果を表示するプログラムを作成する。
エディタを用いて次のList 1-1の内容を入力する。プログラムにおいては、大文字・小文字の区別、全角・半角の使い分けが重要である。記述どおりに入力する必要がある。
List 1-1
/* 整数値15と37を加えた結果を表示 */
#include <stdio.h>
int main(void)
{
printf("%d", 15 + 37); // 整数値15と37を加えた結果を10進数で表示
return 0;
}
実行結果
Note
余白や"*"などの記号は半角で入力すること。スペースはスペースキーまたはタブキーで入力する。
本書で紹介するプログラムは、ホームページからダウンロード可能である。プログラムリストの右上に示される名称は、フォルダ名とファイル名を意味する。
プログラムとコンパイル
読者が入力したのは、単なる文字の並びである。このような人間が読み書きしやすいプログラムはソースプログラム(source program)と呼ばれ、その内容を格納したファイルはソースファイル(source file)と呼ばれる。
Info
source とは「元になるもの」を意味し、ソースプログラムは原始プログラムとも呼ばれる。文字情報を保存したファイルはテキスト形式と呼ばれ、文字データを扱う。
C言語のソースファイルには、拡張子として .c
を付ける慣習がある。たとえば chap01
フォルダ内に List0101.c
という名前で保存するとよい。
重要
ソースファイルは .c
の拡張子を付け、テキスト形式で保存する必要がある。
ソースプログラムは、そのままではコンピュータが理解できないため、ビットの並びに変換する必要がある。
Fig.1-1 ソースプログラムと実行プログラム
Note
コンパイルや実行の手順は処理系により異なる。使用する処理系のマニュアルを参照すること。用語の解説はColumn 1-2に記載されている。
ソースプログラムに綴りの誤りがあると、翻訳時にエラーとなり、コンパイラから診断メッセージが表示される。その際には、プログラムを修正し、再度コンパイルを行う必要がある。
重要
ソースプログラムはコンパイルやリンクを経て実行プログラムに変換されなければ実行できない。
C言語には #
や {
などの記号が頻出するため、最初は戸惑うかもしれないが、徐々に理解を深めればよい。
Info
記号の読み方はp.9にまとめられている。
注釈(コメント)
ここでは、プログラムの構造と注釈について理解を深める。
/* 整数値15と37を加えた結果を表示 */
#include <stdio.h>
int main(void)
{
printf("%d", 15 + 37); // 整数値15と37を加えた結果を10進数で表示
return 0;
}
最初の行を読むだけで、このプログラムが何を行うかが明瞭であろう。
プログラム中にある2箇所の緑色の文字列、すなわち /*
から */
まで、また //
から行末までの部分は、専門用語で「注釈(コメント、comment)」と呼ばれる。これらの注釈はプログラムの動作に影響を与えることはない。
注釈は、プログラム作成者を含む読み手に対し、意図や内容を伝えるために、日本語や英語で簡潔に記述する。
重要
ソースプログラムには、作成者自身や他の読み手に対して意図を伝える注釈を簡潔に記述することが望ましい。
他者が記述したプログラムに適切な注釈が付されていれば、理解が容易となる。また、自分自身が作成したプログラムであっても、内容のすべてを記憶し続けることは困難であるため、注釈の記述は作成者自身にとっても有用である。
Tip
コメントの内容に誤りがあると、読者に誤解を与えるおそれがある。常に正確に記述するよう心掛けるべきである。
C言語では、次の二つの形式の注釈が用意されており、目的に応じて使い分けることができる。
① 伝統的なコメント(/* ··· */
)
/*
で開始し、*/
で終了する形式のコメントであり、以下のような特徴を持つ:
- プログラムの任意の場所に記述可能である。
- 複数行にわたる記述が可能である。
- 閉じの */
を書き忘れたり、開きの /*
を誤って記述すると、以降のすべてがコメントとして扱われる。
Warning
コメントが閉じられないままプログラムの終端まで到達した場合、全体が無効となるため注意が必要である。
② 行末コメント(// ···
)
//
から行の終端までがコメントとして扱われる形式である。以下の特徴がある:
- 行の途中に記述可能である。
- 明示的な終了記号を必要としないため、短い注釈に適している。
Info
//
以降、改行文字の直前までがコメントと見なされる(改行文字自体は含まれない)。
プログラムの決まり文句
注釈を除去したプログラムを以下に示す(Fig.1-2)。現段階では、水色で示した部分を「決まり文句」として扱う。
これらの要素は今後の章で詳しく学習するが、ここでは緑色の部分も含めて、そのまま覚えておくこととする。
決まり文句の部分は固定として扱い、他の部分を各自作成していく。
Tip
stdio
は "standard I/O"(標準入出力)の略である。誤って studio
と記述しないよう注意すること。
プログラムの決まり文句
Fig.1-2 プログラムの決まり文句
printf関数:書式化された表示を行う関数
画面表示を行う部分について、Fig.1-3を参照しながら理解を深める。
この図は、printf
という関数(function)に表示処理を依頼している様子を示す。
Info
printf
は「プリントエフ」と発音される。末尾の "f" は "format"(書式)の略である。
Fig.1-3 printf関数の呼出しによる画面への表示
関数に処理を依頼する行為を「関数呼出し(function call)」と呼ぶ。 関数呼出しの際に与える補助的な指示は、関数名に続く括弧内に記述され、「実引数(argument)」と呼ばれる。
実引数が2個以上ある場合は、カンマ(,)で区切って記述する必要がある。
重要
関数呼出しとは処理の依頼であり、その際に必要な補助指示は、関数名の直後の括弧内に、実引数として与える。複数ある場合はカンマで区切る。
最初の実引数 "%d"
は、後続の実引数の値を「10進数」で表示せよという書式指示である。
続く実引数 15 + 37
の計算結果が、10進数として「52」と表示されるのは、この指示によるものである。
Info
"%d"
における d
は "decimal"(10進数)を意味する。10進数以外の表示形式については、第7章で詳述する。また、printf
関数の詳細は p.376 にて解説している。
文
printf
関数の呼出しおよび決まり文句である return 0;
の末尾には、セミコロン(;
)が付されている。これは、日本語における句点「。」に相当するものである。
日本語の文が句点「。」によって区切られるように、C言語における文(statement)は、セミコロン「;」によって終わる。
重要
文は、原則としてセミコロン(;
)で終了する。
プログラムを実行すると、決まり文句である {
と }
の間に記述された文が順に実行される仕組みである(この点については第6章で詳述する)。
整数の減算の結果を表示
次に、加算ではなく減算(引き算)を行うプログラムを作成する。先に示したプログラムを基に、15から37を減じた値を表示するよう変更する。これをList 1-2に示す。
Tip
List 1-1 を複製し、異なる箇所のみ変更することで、効率的に新しいプログラムを作成できる。
List 1-2
// 整数値15から37を減じた結果を表示
#include <stdio.h>
int main(void)
{
printf("%d", 15 - 37); // 整数値15から37を減じた結果を10進数で表示
return 0;
}
実行結果
このプログラムを実行すると、「-22」と表示される。このように、演算結果が負の場合、先頭にマイナス記号「-」が付加される。
Note
先頭行の注釈は、従来のコメント形式から行末コメント形式に変更されている。以後、主に行末コメントを使用する。
書式文字列と変換指定
単に和や差の数値のみが表示されるのでは、意味が不明確である。より丁寧に結果を表示するよう、プログラムを改良する。それが List 1-3 である。
List 1-3
// 整数値15と37を加えた結果を丁寧に表示
#include <stdio.h>
int main(void)
{
printf("15と37の和は%dです。\n", 15 + 37); // 表示後に改行
return 0;
}
実行結果
printf
関数の第1引数として与えられている水色部分は「書式文字列(format string)」と呼ばれる(Fig.1-4 では点線で囲まれた部分)。
その中に含まれる %d
は、「続く実引数の値を10進数で表示せよ」という指示であり、「変換指定(conversion specification)」と呼ばれる。
書式文字列中において、変換指定でない部分は基本的にそのまま出力される。
ただし、末尾の \n
は「改行(new line)」を意味する特別な文字であり、バックスラッシュ(\
)と n
の組み合わせによって表現される。
Info
\n
は画面上に \
と n
が表示されるのではなく、目には見えない改行動作として出力される。
Fig.1-4 書式文字列・変換指定・改行文字の関係
演習 1-1
整数値15から37を減じた結果を計算し、「15から37を引いた値は-22です。」と表示するプログラムを作成せよ。
書式化を行わない表示
printf
関数は、実引数を1個だけ与えて呼び出すこともできる。その場合、書式文字列の内容がそのまま表示される。List 1-4 でその例を示す。
Tip
各自、自分の名前に変更してプログラムを記述すること。
List 1-4
実行結果
このプログラムを改良して、「こんにちは。」と「私の名前は福岡太郎である。」をそれぞれ別の行に表示するよう変更する。これを List 1-5 に示す。
List 1-5
// 挨拶と自己紹介(別の行に表示・その1)
#include <stdio.h>
int main(void)
{
printf("こんにちは。\n私の名前は福岡太郎です。\n"); // 途中と最後に改行
return 0;
}
実行結果
書式文字列中に配置された \n
によって、改行が実行される。
また、List 1-6 のように、printf
関数の呼出しを2つに分けても同じ出力が得られる。
List 1-6
// 挨拶と自己紹介(別の行に表示・その2)
#include <stdio.h>
int main(void)
{
printf("こんにちは。\n"); // 最後に改行
printf("私の名前は福岡太郎です。\n"); // 最後に改行
return 0;
}
実行結果
Tip
このように関数呼出しを分割することで、プログラムの可読性が向上する。
文字列リテラル
"ABCDEF" や "こんにちは。" のように、一連の文字を二重引用符 " で囲んだものは「文字列リテラル(string literal)」と呼ばれ、文字の並びを表現する。
文字列リテラルを記述する際には、末尾の二重引用符 " を書き忘れないよう注意する。
Info
リテラル(literal)とは「文字どおり」「文字で表現されたもの」を意味する。本書では、文字列リテラルを "茶色の文字" で表記する。文字列リテラルの詳細は、第9章で解説する。
拡張表記(エスケープシーケンス)
改行文字を表す \n
のように、バックスラッシュ \
で始まる特殊な表記は「拡張表記(escape sequence)」と呼ばれる。
たとえば、警報(alert)を発する \a
を使用することで、警報音を出すことができる。List 1-7 に示すプログラムは、「こんにちは。」と表示した後、警報を3回鳴らす。
List 1-7
// 挨拶して警報を3回発する
#include <stdio.h>
int main(void)
{
printf("こんにちは。\a\a\a\n"); // 表示とともに警報を3回発する
return 0;
}
実行結果
Note
実行環境によっては、警報音が鳴らない場合や、三回の警報が一度にまとめて鳴る場合もある。本書では、実行結果における警報を「🔔」で示している。
演習 1-2
以下の出力を行うプログラムを作成せよ。ただし、printf
関数の呼出しは1回限りとする。
演習 1-3
以下の出力を行うプログラムを作成せよ。ただし、printf
関数の呼出しは1回限りとする。
1-2 変数
計算の途中結果や最終的な結果を保持するために用いるのが「変数」である。本節では、変数の基本について学習する。
変数と宣言
これまでのプログラムでは、15 や 37 といった「定数(constant)」を用いた演算が中心であった。より複雑な計算処理を行うためには、定数に加えて「変数(variable)」を使用する必要がある。
まず変数を、次のように捉えるとよい。
Note
変数とは、数値(や文字など)を格納するための『箱』である。
この箱に値を格納しておけば、その箱が存在する限り値は保持される。また、格納した値を取り出したり、書き換えたりすることも自由にできる。
プログラム中に複数の箱が存在する場合、それらを区別するために箱には「名前」が必要となる。そのため、変数を使用するには、あらかじめその「名前」と「型」を指定して宣言(declaration)を行う必要がある。
以下に示すのが変数の宣言である(int
は「イント」と発音する)。
Fig.1-5 に示すように、この宣言によって n
という名前の、整数値を格納可能な変数(箱)が生成される。この変数 n
は「int型」と呼ばれる。
Fig.1-5 変数
重要
変数を使用するには、その「型」と「名前」を事前に宣言する必要がある。
Info
int
は "integer"(整数)に由来する。データ型については主に第2章および第7章で学習する。また、変数名の命名規則については p.108 にて解説する。
次の課題に取り組んでみよう。
Example
二つの変数に適当な整数値を代入し、それらの値を表示する。
そのプログラムを List 1-8 に示す。
List 1-8
// 二つの変数に整数値を代入して表示
#include <stdio.h>
int main(void)
{
int x, y; // xとyはint型の変数
x = 57; // xに57を代入
y = x + 12; // yにx + 12を代入
printf("xの値は%dです。\n", x); // xの値を表示
printf("yの値は%dです。\n", y); // yの値を表示
return 0;
}
実行結果
Tip
本プログラムでは、宣言の直後などに空行を挿入している。このような配慮によって、プログラムの可読性が向上する。
赤字部分が変数の宣言である。ここでは、int
型の変数 x
と y
が一度に宣言され、変数名がコンマ(,
)で区切られている。
もちろん、以下のように二つの変数を個別に宣言しても問題ない。
Tip
各行に1つずつ宣言することで、コメントを付けやすくなり、宣言の追加・削除も容易になる。ただし、行数が増加するという欠点もあるため、状況に応じて使い分けることが重要である。
代入
変数の宣言に続いて行う =
を用いた操作は、「右側の値を左側の変数に代入せよ」という指示である。Fig.1-6 を参照しながら理解を深めよう。
❶ 変数 x
に 57 が代入される。
❷ x
の値 57 に 12 を加えた 69 が y
に代入される。
Note
数学における「x = 57」や「y = x + 12」のような等式とは異なり、ここでは代入操作を意味している。
Fig.1-6 変数への値の代入と取出し
初期化
変数への代入を行わない場合、プログラムはどのような動作を示すかを List 1-9 によって確認する。
List 1-9
// 二つの変数に値を代入せずに表示
#include <stdio.h>
int main(void)
{
int x, y; // xとyはint型の変数
printf("xの値は%dです。\n", x); // xの値を表示
printf("yの値は%dです。\n", y); // yの値を表示
return 0;
}
実行結果(例)
このように、初期化されていない変数は不定値(ガーベッジ値)を持つため、意図しない出力となる。
Fig.1-7 生成時の変数の値
Warning
表示結果は実行環境や処理系によって異なり、エラーが発生してプログラムが中断される場合もある。
初期化を伴う宣言
変数に格納すべき値が事前に分かっている場合は、変数の生成時にその値を入れておく「初期化」が有効である。List 1-10 は、初期化を行うプログラムの例である。
List 1-10
// 二つの変数を初期化して表示
#include <stdio.h>
int main(void)
{
int x = 57; // xはint型の変数(57で初期化)
int y = x + 12; // yはint型の変数(x + 12で初期化)
printf("xの値は%dである。\n", x); // xの値を表示
printf("yの値は%dである。\n", y); // yの値を表示
return 0;
}
=
の右側に記述された初期化子(initializer)は、変数生成時に代入される値を指定するものである。
重要
変数は生成時に不定値が入れられるため、初期化を行うことで安全かつ明確な値を保持する。
Fig.1-8 に示すとおり、変数 x
は 57 で初期化され、変数 y
は x + 12
によって初期化される。
Info
静的記憶域を持つ変数には例外的に 0 が代入されることがある。この点については第6章(p.174)で学習する。
初期化と代入
初期化と代入はいずれも値を格納する操作であるが、そのタイミングに違いがある。Fig.1-8 を参照して理解しよう。
- 初期化:変数の生成と同時に値を代入する操作。
- 代 入:すでに生成された変数に値を代入する操作。
Info
本書では、初期化の =
を黒字、代入の =
を青字で表記する。
Fig.1-8 初期化と代入の比較
演習 1-4
int
型変数の宣言時に実数値(例:3.14や5.7など)を初期化子として与えた場合、どのような挙動となるかを確認せよ。プログラムを作成して検証すること。
1-3 読込みと表示
本節では、整数値をキーボードから読み込んで変数に格納し、それを表示する方法を学習する。
scanf関数:キーボードからの読込みを行う関数
決まりきった値の演算結果を表示するだけでは対話的な処理とは言えない。ここでは、キーボードから数値を読み込んで表示するプログラムを作成する。
List 1-11
// 読み込んだ整数値をそのまま表示
#include <stdio.h>
int main(void)
{
int no;
printf("整数を入力してください:");
scanf("%d", &no); // 整数値を読み込む
printf("あなたは%dと入力したのだな。\n", no);
return 0;
}
実行例
さまざまな数値を入力して挙動を確認してみよう。
Fig.1-9 に示すとおり、キーボードからの入力には scanf
関数を使用する("スキャンエフ" と発音する)。
変換指定子 "%d"
は、printf
と同様に 10 進数の入力を指定するものであり、「10 進数の値を読み込み、それを変数 no
に格納してください」という指示を表している。
Fig.1-9 printf関数による表示とscanf関数による読込み
重要
scanf
関数で変数に読み込む際は、変数名の前に &
を付ける必要がある。
Info
&
の意味については第10章で詳しく学習する。また、int
型に格納可能な値の範囲については第7章で解説する。
プログラムではまず、「整数を入力してください:」と表示して入力を促し、読み込み後に「あなたは ** と入力したのだな。」と画面に出力される(** の部分には no
に格納された値が入る)。
Note
本書では、次のように「」と『』の使い分けを行う。 「ABC」と表示:画面に ABC と表示する。 『ABC』と表示:画面に ABC と表示し、改行も同時に行う(改行文字を出力する)。
乗算を行う
読み込んだ整数値をそのまま表示するのではなく、その5倍の値を表示するプログラムを作成する。これを List 1-12 に示す。
List 1-12
// 読み込んだ整数値の5倍の値を表示
#include <stdio.h>
int main(void)
{
int no;
printf("整数を入力してください:");
scanf("%d", &no); // 整数値を読み込む
printf("その数の5倍は%dです。\n", 5 * no);
return 0;
}
実行例
本プログラムで初めて使用したアスタリスク(*)は、乗算(掛け算)の記号である。なお、5 * no
を no * 5
に置き換えても、同じ結果が得られる。
演習 1-5
読み込んだ整数値に13を加えた値を表示するプログラムを作成せよ。
演習 1-6
読み込んだ整数値から7を減じた値を表示するプログラムを作成せよ。
puts関数:表示を行う関数
変数を用いて、さらに発展的な問題に取り組む。ここでは、二つの整数値を読み込み、その和を表示するプログラムを作成する。
List 1-13
// 読み込んだ二つの整数値の和(加算結果)を表示
#include <stdio.h>
int main(void)
{
int n1, n2;
puts("二つの整数を入力してください。");
printf("整数n1:"); scanf("%d", &n1);
printf("整数n2:"); scanf("%d", &n2);
printf("それらの和は%dです。\n", n1 + n2);
return 0;
}
実行例
本プログラムで初めて用いた puts
関数は、実引数として与えられた文字列を表示した後、自動的に改行を行う。
Fig.1-10 printf関数とputs関数の比較
Info
puts
関数の実引数は1個に限られる。なお、%
文字の表示方法は printf
関数とは異なる(p.25 参照)。
続いて、和の計算結果を変数に格納する形へ書き換えたものを List 1-14 に示す。
List 1-14
// 読み込んだ二つの整数値の和(加算結果)を変数に格納して表示
#include <stdio.h>
int main(void)
{
int n1, n2;
puts("二つの整数を入力してください。");
printf("整数n1:"); scanf("%d", &n1);
printf("整数n2:"); scanf("%d", &n2);
int wa = n1 + n2; // 和を変数waに格納
printf("それらの和は%dです。\n", wa);
printf("すなわちn1 + n2 = %dです。\n", wa);
return 0;
}
実行例
今回のように同じ結果を複数回表示する必要がある場合、計算結果を変数に保持しておくと効率的である。
Info
{}
内には宣言と文を混在させることが可能である(詳細は p.60 を参照)。
演習 1-7
「守」「破」「離」と表示するプログラムを puts
関数を用いて作成せよ。
演習 1-8
二つの整数値の積を表示するプログラムを作成せよ。
演習 1-9
三つの整数値の和を表示するプログラムを作成せよ。
まとめ
- ソースプログラムは文字の並びで作成されるが、そのままでは実行できない。コンパイルやリンクによって実行形式に変換される。
/* ... */
および//
以降の文字はコメントであり、プログラムの動作には影響せず、意図を伝える目的で記述される。- プログラムの水色部分は決まり文句として記憶する。
stdio.h
とstudio.h
を混同しないようにする。- 文はセミコロン(
;
)で終わる。 - プログラム実行時、
{
と}
の間に記述された文が順に実行される。 \n
は改行、\a
は警報(ビープ音)を表す拡張表記である。環境によっては\
が¥
と表示される場合がある。- 文字列リテラルは二重引用符 " で囲んだ文字の並びである。
- 変数はデータを保持するための記憶領域であり、使用には「型」と「名前」を指定した宣言が必要である。
- 変数は生成時に不定値を持つため、初期化が推奨される。
- 初期化は生成時、代入は生成後に行う。
-
複数の変数を一度に宣言する場合はカンマで区切る:
-
関数呼出しは処理の依頼であり、必要な情報は括弧内に実引数として与える。
- 表示には
printf
関数とputs
関数がある。 printf
の第1引数は書式文字列であり、変換指定%d
は整数を10進数で表示する。puts
関数は引数の文字列を表示した後、自動的に改行を行う。scanf
関数はキーボードからの入力を受け取る関数であり、変数の前に&
を付けて指定する。- 加算
+
、減算-
、乗算*
を用いて演算を行う。