C 言語は世界でもっともポピュラーなプログラミング言語です。以下のような特徴があります。
C 言語は、非常に構造化された言語ですが、コードを書くときは、人間がその構造を見やすいように書かないと、C 言語の利点が極端に減ってしまいます。コードの構造を見やすくするためには、必要に応じて行頭にタブをいれる必要があります(インデント)。また、多くの人にとって見やすいように、一般的な書き方(コーディング)で書かなければいけません。(昔、自分で作ったプログラムが読めなくなることは多くの人が経験します。他人にわかりやすいプログラムとは未来の自分にとってもわかりやすいプログラムになるでしょう。)以下に一般的な注意事項を挙げておきます。それ以外の注意点については、必要なときに適宜言明します。
多くのプログラミング言語と同様に、C 言語も英語をベースとして作られています。そのため、基本的には英語の文章を書くのと同じように、コードを書くことになります。その一つが、コンマ(,)やコロン(:)、セミコロン(;)の後にはスペースを一つ空けるというものです。前にはスペースを入れないことにも注意してください。" "
は特に注意してスペースをとるべき箇所です。
int a, b, c; printf("%d
", a);
{} は文のひとまとまりをあらわしています。この {} によってコードが構造化されるので、{} 内はそれとわかるようにタブまたはスペースを入れてください。タブまたはスペースを入れるときの文字数は、コーディングによって違います。k&r(第二版)ではスペース 4 文字(第一版ではスペース 5 文字)、gnu ではスペース 2 文字です。一般的には、タブの 4 文字または 8 文字、スペースの 4 文字が使われることが多いと思います。大規模(複雑)なソフトウェアでは、タブやスペースが大きすぎると途中で改行が入ってしまい、コードの構造がみにくくなります。そのような時は、タブの大きさを減らしてください。今の段階では、5 文字でも 2 文字でも好きなようにやってもらって構いませんが、同じコード(コード群)の中で、タブの大きさを変えないようにしてください。
int main(void)
{
...;
...;
}
if (...) {
...;
}
変数とは、プログラムの中で情報を一時的にためておく場所(の名前)です。何をためるかによって、変数の型が違います。演算子とは、変数や定数の組み合わせにある処理(演算)を施す文字列です。式とは、変数や定数、演算子の組み合わせのひとまとまりです。
変数には主に以下のような種類があります。
変数は使う前に宣言しなければなりません。コンピュータはメモリという記憶容量のなかに情報をため、必要に応じて取り出して使います。メモリは横長のアパートのようなもので、それぞれに番号(アドレス)がついています。宣言とは、メモリ上の空いている部屋に対して、名前を割り当てる行為です。変数の型によって割り当てる部屋の大きさが変わってきます。(厳密には部屋の大きさではなく部屋の数が変わります。そのとき、変数に対応するアドレスは先頭の部屋のものです。)
補足:C 言語では変数の宣言は、宣言された関数の中においてのみ有効です。つまり、別の関数の中で定義された変数には、同じ名前を使っても違うアドレスが割り当てられます。これについては、第三回の授業で説明します。
演算子とは、変数や定数、関数に作用して式をつくる記号です(式はある決まった値を返します)。演算子には、作用の対象(オペランド)の数によって、単項演算子・二項演算子・三項演算子があります。また、すべての演算子には、作用の方向と優先順位があることを覚えて置いてください。優先順位と作用の方向をあらわす表を下に載せておきます。
順位 | 演算子 | 結合の方向 |
---|---|---|
1 | ( ) [ ] -> . | 左から右 |
2 | ! ~ ++ -- + - * & sizeof キャスト | 右から左 |
3 | * / % | 左から右 |
4 | + - | 左から右 |
5 | >> << | 左から右 |
6 | < <= > >= | 左から右 |
7 | == != | 左から右 |
8 | & | 左から右 |
9 | ^ | 左から右 |
10 | | | 左から右 |
11 | && | 左から右 |
12 | || | 左から右 |
13 | ?: | 右から左 |
14 | = += -= *= /= %= &= ^= |= <<= >>= | 右から左 |
15 | , | 左から右 |
上表のうち覚えておくべきもののみ効果とコーディングを説明しておきます。
順位 1 の "(, ), [, ]"
はそれぞれセットで関数と配列を表す演算子です。演算子とオペランドの間にスペースはとりません。
順位 2 の "!"
は論理否定の単項演算子です。真(0 以外の整数: 基本的には 1)に対しては偽(0)を、偽に対しては真を返します。(例: 式 !0 は 1 を返す。
)演算子とオペランドの間にスペースはとりません。
順位 2 の "++"
はインクリメントの単項演算子です。整数型のオペランドに作用し、その値を 1 加算します。演算子が右からかかると加算後の変数の値、左からかかると加算前の変数の値を返します。(例: a = 1 ならば ++a は 2 を返し a++ は 1 を返す。
)演算子とオペランドの間にスペースはとりません。
順位 2 の "--"
はデクリメントの単項演算子で、整数型のオペランドに作用し、その値を 1 減算します。インクリメントの減算版です。演算子とオペランドの間にスペースはとりません。
順位 2 の "+"
はオペランドの値をそのまま返す単項演算子です(厳密には、文字型のオペランドに対しては整数型に変換された値を返します: Integer promotion)。加算の演算子ではないことに注意してください。演算子とオペランドの間にスペースはとりません。
順位 2 の "-"
はオペランドの値の符号を変えた値を返す単項演算子です。減算の演算子ではないことに注意してください。演算子とオペランドの間にスペースはとりません。
順位 2 の "*"
はポインタ型のオペランドに作用する単項演算子で、そのポインタが指し示すオブジェクトの値を返します。ここはポインタの回で詳しくやります。乗算の演算子でないことに注意してください。演算子とオペランドの間にスペースはとりません。
順位 2 のキャスト演算子は型を () でくくって表現します。オペランドを指定された型に変換した値を返します。たとえば整数型の変数 a を浮動小数点数型の変数 b に代入する際
b = (float) a;
と書きます。演算子とオペランドの間にスペースをとります。
順位 3、順位 4 の "*, /, %, +, -"
はそれぞれ乗算、除算、剰余算、加算、減算の二項演算子です。ここで気をつけるべきことは除算で整数型同士をオペランドとする場合、戻り値も整数型となります。つまり、26 / 8 の値は 26 ÷ 8 の商 3 となります。定数の除算でこれを回避するには、少なくとも一方を浮動小数点型にしてください(26.0 / 8 のように)。変数同士の場合は、上のキャスト演算子を使います。たとえば、整数型の a と b の除算の結果を浮動小数点型の c に入れたいときは c = (float) a / b; とします。演算子とオペランドの間にスペースをとります。
順位 6 と順位 7 の "<, <=, >, >=, ==, !="
は、左右の式の値を比較し、それぞれ小なり、以下、大なり、以上、等しい、等しくない場合に真(1)、そうでない場合に偽(0)を返す二項演算子です。演算子とオペランドの間にスペースをとります。
順位 11 と順位 12 の "&&, ||"
はそれぞれ論理積、論理和をあらわす二項演算子です。&& は左右の式の値の両方が真(0 以外)のとき真(1)を返し、それ以外のとき偽(0)を返します。|| は左右の式の少なくとも一方が真のとき真を返し、それ以外のとき偽を返します。演算子とオペランドの間にスペースをとります。
順位 14 の "="
は代入を表す二項演算子です。左に変数、右に式を取り、変数の値を式の値と一致させ、式の値を返します。= 演算子が値を返すというのは、初心者にはなじみにくいかもしれません。以下のプログラムを作ってみてください。演算子とオペランドの間にスペースをとります。
#include <stdio.h>
int main(void)
{
int a, b, c;
a = 3;
/* () 内の右辺の式の値が 5 なので、
式 (b = a + 2) の値も 5。
つまり、変数 c には 5 が代入される */
c = (b = a + 2);
/* 出力結果は 5。*/
printf("%d
", c);
return 0;
}
順位 14 の残りの演算子は右のような演算をします。演算子 +, -, *, /, %, &, ^, |, <<, >>
を O
と置くと、式 "a O= b"
は、式 "a = a O b"
と等価です。演算子とオペランドの間にスペースをとります。
順位 15 の ","
は前後にオペランドをとり、後のオペランドの値を返す演算子です。この演算子はもっとも優先順位が低いため、式を羅列するときに使います。演算子とその前のオペランドの間にはスペースをとりませんが、後のオペランドとの間にはスペースをとります。
式とは、変数や定数、関数、演算子の組み合わせで作られる文字列です。それぞれの式は、ある決まった値を返します。すべての式に値があることを覚えておいてください(代入文にも値があります)。
入力とは、キーボードやマウスなどの外部機器、またはファイルなどから情報を読み込むことです。出力とは、モニタやプリンタなどの外部機器、またはファイルなどに情報を書き出すことをいいます。C では、入出力に関する命令(厳密には関数)は stdio.h というファイル(拡張子が h のファイルをヘッダファイルといいます)に入っています。入出力に関する命令を使うときは、stdio.h を読み込む必要があります。
文字列を画面に出力するには printf 関数を使います。
#include <stdio.h>
int printf(const char * format, ...);
この書式は、以下のような意味です。「printf 関数は const char * 型の値を引数にとり、int 型の値を返す」。printf 関数の場合は、文字列(""で囲まれた値)を引数にとり、引数に書かれた書式にしたがって文字列を画面に出力します。そして、出力のバイト数を返します(出力に失敗したときは EOF = -1 を返します)。printf 文では関数名 printf と ( の間にスペースをいれません。printf 文を使ったプログラムの例を以下に記します。
#include <stdio.h>
int main(void)
{
int i = 28; /* 整数 */
float f = 2.7; /* 実数 */
char c = 'a'; /* 文字 */
char *s = "abc"; /* 文字列 */
/* 画面に STRING と表示されます。
は改行を表します。 */
printf("STRING
");
/* 画面に 28 と表示されます。
%d は整数を 10 進数で表示することを表します。*/
printf("%d
", i);
/* 画面に 1c と表示されます。
%x は 16 進数で表示することを表します。*/
printf("%x
", i);
/* 画面に 2.7 と表示されます。*/
printf("%f
", f);
/* 画面に a と表示されます。*/
printf("%c
", c);
/* 画面に abc と表示されます。
, の後には *s ではなく s とする点に注意 */
printf("%s
", s);
return 0;
}
キーボードから情報を取得するには scanf 関数を使います。
#include <stdio.h>
int scanf(const char * format, ...);
scanf は、読み込みに成功した変数の数を返します。EOF を読み込もうとしたときは EOF を返します。以下 scanf の例です。
#include <stdio.h>
int main(void)
{
int i, j;
float a, b, c;
/* 整数型の値を読み込み、変数 i にためます。
scanf 文では変数名ではなく変数のポインタを
指定しなければならないことに注意してください。*/
scanf("%d", &i);
/* 二つ以上の値を読み込むには
コンマで区切ります。*/
scanf("%f,%f", &a, &b);
/* 入力についての説明などの文字列を表示するには
scanf の前に printf で出力します。*/
printf("(int) j, (float) c = ");
scanf("%d,%f", &j, &c);
return 0;
}
条件によって処理を変えたいとき、条件文を使います。
if (expression) statement
if (expression) statement else statement
expression は「式」、statement は「文」を表します。expression が真のときに最初の statement を処理し、expression が偽のときに else 以下の statement を処理します。
#include <stdio.h>
int main(void)
{
int i = 2;
if (i == 2)
printf("i == 2
"); /* ここは実行されます */
else
printf("i != 2
"); /* ここは実行されません */
/* 複数の処理をしたいときは
statement を複文にします。*/
if (i == 2) {
printf("i == 2
");
} else {
printf("i != 2
");
printf("i == %d
", i);
}
return 0;
}
switch (expression) statement
以下例文。
#include <stdio.h>
int main(void)
{
int i;
scanf("%d", &i);
switch (i) {
statement /* i の値によらず実行されません。*/
case 0:
statement /* i が 0 のとき実行されます。*/
case 1:
statement /* i が 0 か 1 のとき実行されます。*/
default:
statement /* i の値によらず実行されます。*/
}
switch (i) {
case 0:
statement /* i が 0 のとき実行されます。*/
break; /* switch から抜けます。*/
case 1:
statement /* i が 1 のときのみ実行されます。*/
default:
statement /* i が 0 以外のとき実行されます。*/
}
return 0;
}
計算機にとって一番とくいな作業が、単純作業です。同じ処理を何回も繰り返させるには、繰り返し文を使います。
while (expression) statement
while statement do (expression);
while 文は expression が真(0 以外)の間だけ、statement を繰り返し処理します。条件判断は、expression が読み込まれるときに行われます。したがって、はじめから expression が偽のとき、上の書き方では statement は処理されませんが、下の書き方では処理されます。
#include <stdio.h>
int main(void)
{
int i = 1, j = 0, k, l = 0, m;
/* i = 1, ..., i = 10 と出力されます。*/
while (i <= 10)
printf("i = %d
", i++);
/* 入力した整数の和が 10 を越すと while から抜けます。
複数の処理を書くには、statement を複文にします。*/
while (j <= 10) {
printf("k = ");
scanf("%d", &k);
j += k;
}
/* 前の例と同じ処理をします。
expression は常に真なので、
この while 文は無限ループです。
if 文の中の statement に書いてある
break で while から抜けます。*/
while (1) {
if (l > 10)
break;
printf("m = ");
scanf("%d", &m);
l += m;
}
/* () 内の式が常に偽なので実行しません。*/
while (0)
statement
/* 条件判断は後にあるので、
statement は一度だけ実行されます。*/
do
statement
while (0);
return 0;
}
繰り返しのもう一つの選択肢として for 文があります。
for (expressionopt; expressionopt; expressionopt) statement
for (declaration; expressionopt; expressionopt) statement
for 文の () 内は、最初が初期値を表す式(省略可)または宣言、次に条件を表す式(省略可)、最後に毎回処理をする式(省略可)をかきます。下の二つの文は、まったく同じ意味を表します。
for (clause-1; expression-2; expression-3) statement
{
clause-1;
while (expression-2) {
statement
expression-3;
}
}