C言語では,電卓と同じように,四則演算を行うことができます. しかし,数学ほど自由に記述はできません. 言語仕様で決められた,限られた表現の中で,欲しい計算結果を得る必要があります. また,第2章で学んだ「型」というものも,計算結果に影響を与えます. 本章では,プログラムにおいてどのような四則演算ができ,どのような制約があるかを学んでいきます.
オペレータとオペランド
算数や数学で利用する,足し算のプラス (+) や引き算のマイナス(-)のことを,演算子またはオペレータ (operator)と呼びます.
また,「足される数」や「足す数」のような,演算の対象となるものを,被演算子またはオペランド (operand) と呼びます.
特に,1+2のような複数のオペランドがある計算の場合,オペレータ左側の1を第一オペランド,オペレータ右側の2を第二オペランドと呼ぶことがあります.
これらの単語は,計算機科学の分野でよく使われますので,覚えておいて損はないでしょう.
それでは,実際のC言語の四則演算を見ていきましょう.
下表に,C言語で使うことのできる四則演算子をまとめています.
剰余演算子のみ,被演算子が共に整数型のときしか使えませんので注意しましょう.
それから,0で割り算を実行するのは厳禁です.
| 名前 | 記号 | 用法 | 演算の意味 |
|---|---|---|---|
| 加算演算子 | プラス (+) |
a + b |
aとbの和 |
| 減算演算子 | マイナス (-) |
a - b |
aとbの差 |
| 乗算演算子 | アスタリスク (*) |
a * b |
aとbの積 |
| 除算演算子 | スラッシュ (/) |
a / b |
aとbの商(bは非零) |
| 剰余演算子 | パーセント (%) |
a % b |
aをbで割った余り(bは非零) |
使い方は極めてシンプルです. 次の例を見てみましょう.
#include <stdio.h>
int main(void) {
int a = 10, b = 3;
int c = a + b;
printf("a + b = %d\n", c);
c = a - b;
printf("a - b = %d\n", c);
c = a * b;
printf("a * b = %d\n", c);
c = a / b;
printf("a / b = %d\n", c);
c = a % b;
printf("a %% b = %d\n", c);
return 0;
}
このプログラムの出力は,次のようになります.
a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1
割り算の結果の違和感は,次の節で解説します.
なお,四則演算を利用は,必ずしも代入を必要としません.
例えば,a + bという足し算の結果を出力したいときは,わざわざ新たな変数cを使わずに,
printf("a + b = \%d\n", a + b);
のように書くこともできます. 演算子は,使用された時点で演算を実行します.
演算の順序
C言語においても,四則演算には決まった順序が存在します. 四則演算に限れば,優先順位は数学とおよそ同じで,次のとおりです.
- 小括弧で囲われた中の演算
- 乗除算,剰余演算
- 加減算
例えば,
a = (2 + 3) * 5;
という計算をしたら,aには25という値が入ることになるわけです.
複雑な計算をさせるときは,小括弧を付け忘れないように気をつけましょう.
余談ですが,もっと細かい計算順序を決めたいときには,注意が必要です. もし
a = (1 + 2) + (3 + 4);のような処理をしようとしたとき,全体の計算結果は一意ですが,左の
1 + 2と右の3 + 4の優先度は同列であり,どちらが先に実行されるのかはわかりません.もしこれらに明確な順序付けを行いたい場合は,別の変数を予め用意する必要があります. 今回の例だと,変数`b, c}を用意して
b = 1 + 2; c = 3 + 4; a = b + c;のようにすれば,確実に`1+2}の方が先に計算されるようになります.
複合代入
プログラムを書いていくうちに,aの値をbだけ増やしたい,あるいはaの値をb倍にしたい,といった場面が生じてくることでしょう.
このとき,素直に
a = a + b; // a + bの結果をaへ代入
a = a * b; // a * bの結果をaへ代入
と書いても何ら問題ありません. 一方でC言語では,複合代入 (compound assignment) と呼ばれる操作を行うことができます. 複合代入を用いることで,同じ処理を次のように略記することができます.
a += b; // a + bの結果をaへ代入
a *= b; // a * bの結果をaへ代入
四則演算に関する複合代入の演算子の一覧を,下表に示します.
| 名前 | 記号 | 用法 | 等価な演算 |
|---|---|---|---|
| 加算代入演算子 | += |
a += b; |
a = a + b; |
| 減算代入演算子 | -= |
a -= b; |
a = a - b; |
| 乗算代入演算子 | *= |
a *= b; |
a = a * b; |
| 除算代入演算子 | /= |
a /= b; |
a = a / b; |
| 剰余代入演算子 | %= |
a %= b; |
a = a % b; |
インクリメント・デクリメント
複合代入において,特に整数型の変数の値を+= 1や-= 1をしたいとき,より簡単に記述することができます.
整数型の変数の値を1だけ増やす操作をインクリメント (increment), 逆に1だけ減らす操作をデクリメント (decrement) と呼びます.
以下の3つのコードは全て同じ動作をします.
int a = 0;
a = a + 1;
int a = 0;
a += 1;
int a = 0;
++a;
このプラス(+) を2つ並べた++を,インクリメント演算子と呼びます.
同様に,デクリメントはデクリメント演算子--を用いて,
int a = 0;
--a; // <=> a -= 1; <=> a = a - 1;
と書くことができます. シンプルで,かつわかりやすい記法です.
文献やソースコードによっては,a++;やa--;のように,演算子を後置することがあります.
どちらの記法も,文法上問題はなく,どちらも正しく動くことでしょう.
しかし,前置と後置では,評価順序 (evaluation order) が異なります.
評価順序とは,例えば足し算より掛け算を先に行うようなものです.
※似たような言葉で,演算子の結合順位というものがありますが,これはまた別物ですので注意してください.
この評価順序がなんと前置と後置で変わってしまうので,使用の際には注意が必要になります. 次のプログラムを実行してみましょう.
#include <stdio.h>
int main(void) {
// 前置の場合
int x = 0;
int a = 3 + ++x;
int b = ++x + 3;
// 後置の場合
x = 0;
int c = 3 + x++;
int d = x++ + 3;
printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);
return 0;
}
a,bの値とc,dの値は同じになっているでしょうか?
評価順序について本講習会では詳細は扱いませんが,「確実に動かしたいときはセミコロンを挟もう!」というのが,著者から初心者へのメッセージです.
要はa = 3 + x++;のような,高度な知識がないと結果がわからない書き方をするのではなく,x++;してからa = 3 + x;とすれば,誰でも分かるように1増やされたxが3に足されるわけです.
興味のある方は以下の文献をご参照ください. プログラミングを極める意思があるのであれば,副作用 (side effect) や副作用完了点 (sequence point) といったキーワードを覚えておくと良いでしょう.
GoogleのC++のスタイルガイドは,整数型でのインクリメント・デクリメントはどちらを用いても良いとしています. 著者としては前置記法(
++a)の書き方に慣れておくことを薦めますが,各自の判断で使い分けてください.C言語でインクリメントやデクリメントを使う上では,
- 自分,あるいはチームの中で前置・後置どちらの記法を使うかを決めておくこと
- 演算の優先順位が異なるという事実を認識しながら書くこと
の二点が重要です.
Previous: 変数と型 / Next: 出力関数printf
(c) 2017-2021 Yuki Onishi