演算子と式
演算子はキッチンの道具のようなものです——包丁で切り、フライパンで焼く。異なる材料には異なる道具が必要で、異なる計算には異なる演算子が必要です。
算術演算子
C言語には最も一般的な数学計算のための 7 つの基本算術演算子があります。
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
+ |
加算 | 5 + 3 |
8 |
- |
減算 | 5 - 3 |
2 |
* |
乗算 | 5 * 3 |
15 |
/ |
除算 | 7 / 2 |
3 |
% |
剰余 | 7 % 2 |
1 |
+ |
単項プラス | +5 |
5 |
- |
単項マイナス | -5 |
-5 |
整数除算の落とし穴
2 つの整数を除算すると、結果も整数になります——小数部分は切り捨てられ、四捨五入ではありません。
#include <stdio.h>
int main(void) {
int a = 7;
int b = 2;
printf("%d / %d = %d\n", a, b, a / b);
printf("%d %% %d = %d\n", a, b, a % b);
return 0;
}
7 / 2 = 3
7 % 2 = 1
7.0 / 2 なら 3.5 になります。
剰余演算子の用途
剰余演算子 % は整数にしか使えません。実用的な使い方がいくつかあります:
- 偶数・奇数の判定:
n % 2が 0 なら偶数 - 末尾の桁を得る:
n % 10で 1 の位が得られる - 循環インデックス:
i % sizeでインデックスを 0 ~ size-1 の間で循環させる
#include <stdio.h>
int main(void) {
int n = 12345;
printf("末尾の桁: %d\n", n % 10);
printf("偶数か: %s\n", n % 2 == 0 ? "はい" : "いいえ");
return 0;
}
末尾の桁: 5
偶数か: いいえ
インクリメント・デクリメント演算子
インクリメント演算子 ++ は変数に 1 を加え、-- は 1 を引きます。それぞれ前置と後置の 2 つの形式があり、式が返す値が異なります。
前置と後置
| 形式 | 名称 | 効果 | 式の値 |
|---|---|---|---|
++i |
前置インクリメント | i が 1 増える | 新しい(増えた)値 |
i++ |
後置インクリメント | i が 1 増える | 古い(元の)値 |
--i |
前置デクリメント | i が 1 減る | 新しい(減った)値 |
i-- |
後置デクリメント | i が 1 減る | 古い(元の)値 |
#include <stdio.h>
int main(void) {
int a = 5;
int b = ++a;
printf("前置: a=%d, b=%d\n", a, b);
int c = 5;
int d = c++;
printf("後置: c=%d, d=%d\n", c, d);
return 0;
}
前置: a=6, b=6
後置: c=6, d=5
a = ++a + a++ のような書き方は未定義動作で、コンパイラによって結果が異なります。
関係演算子
関係演算子は 2 つの値を比較し、「真」(1)または「偽」(0)を返します。
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
== |
等しい | 5 == 5 |
1 |
!= |
等しくない | 5 != 3 |
1 |
< |
より小さい | 3 < 5 |
1 |
> |
より大きい | 3 > 5 |
0 |
<= |
以下 | 5 <= 5 |
1 |
>= |
以上 | 3 >= 5 |
0 |
#include <stdio.h>
int main(void) {
int a = 10;
int b = 20;
printf("a == b: %d\n", a == b);
printf("a != b: %d\n", a != b);
printf("a < b: %d\n", a < b);
return 0;
}
a == b: 0
a != b: 1
a < b: 1
== は比較、= は代入です。書き間違えると比較が代入になり、エラーも出ません。良い習慣として定数を左側に置きましょう:5 == a と書けば、うっかり 5 = a と書いてもコンパイラが検出してくれます。
論理演算子
論理演算子は複数の条件を組み合わせ、やはり 1(真)または 0(偽)を返します。
| 演算子 | 意味 | 例 | 結果 |
|---|---|---|---|
&& |
論理積(AND) | 1 && 0 |
0 |
| ` | ` | 論理和(OR) | |
! |
論理否定(NOT) | !0 |
1 |
真理値表
| A | B | A && B | A || B | !A | |---|---|--------|--------|----| | 0 | 0 | 0 | 0 | 1 | | 0 | 1 | 0 | 1 | 1 | | 1 | 0 | 0 | 1 | 0 | | 1 | 1 | 1 | 1 | 0 |
短絡評価
&& では左側が偽なら右側は評価されません。|| では左側が真なら右側はスキップされます。この機能を利用して不正な操作を防げます:
#include <stdio.h>
int main(void) {
int divisor = 0;
int value = 10;
if (divisor != 0 && value / divisor > 5) {
printf("条件を満たしました\n");
} else {
printf("条件を満たしません。ゼロ除算も発生していません\n");
}
return 0;
}
条件を満たしません。ゼロ除算も発生していません
-5 は論理的には「真」です。
代入演算子
基本の代入演算子 = は右辺の値を左辺の変数に格納します。C言語には演算と代入を組み合わせた複合代入演算子もあります。
| 複合 | 同等の式 |
|---|---|
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 |
#include <stdio.h>
int main(void) {
int score = 80;
score += 10;
printf("ボーナス後: %d\n", score);
score -= 25;
printf("ペナルティ後: %d\n", score);
score *= 2;
printf("倍増後: %d\n", score);
return 0;
}
ボーナス後: 90
ペナルティ後: 65
倍増後: 130
条件演算子(三項演算子)
条件演算子 ?: は C言語唯一の三項演算子です。構文は次の通り:
条件 ? 式1 : 式2
条件が真なら式1が評価され、偽なら式2が評価されます。if-else の短縮形です。
#include <stdio.h>
int main(void) {
int age = 20;
char *status = age >= 18 ? "成人" : "未成年";
printf("年齢 %d、%s\n", age, status);
int a = 15, b = 28;
int max = a > b ? a : b;
printf("大きい値: %d\n", max);
return 0;
}
年齢 20、成人
大きい値: 28
カンマ演算子
カンマ演算子 , は各式を左から右へ評価し、カンマ式全体の値は最後の式の値になります。
#include <stdio.h>
int main(void) {
int a, b, c;
c = (a = 1, b = 2, a + b);
printf("a=%d, b=%d, c=%d\n", a, b, c);
return 0;
}
a=1, b=2, c=3
sizeof演算子
sizeof はデータ型や変数がメモリ上で占めるバイト数を返します。コンパイル時に評価され、実行時ではありません。
#include <stdio.h>
int main(void) {
printf("char: %zu bytes\n", sizeof(char));
printf("int: %zu bytes\n", sizeof(int));
printf("float: %zu bytes\n", sizeof(float));
printf("double: %zu bytes\n", sizeof(double));
int arr[5] = {1, 2, 3, 4, 5};
printf("配列の合計サイズ: %zu bytes\n", sizeof(arr));
printf("配列の要素数: %zu\n", sizeof(arr) / sizeof(arr[0]));
return 0;
}
char: 1 bytes
int: 4 bytes
float: 4 bytes
double: 8 bytes
配列の合計サイズ: 20 bytes
配列の要素数: 5
sizeof(int))ですが、変数には不要(sizeof a)です。ただし一貫性のため、常に括弧を使うのが良いでしょう。
演算子の優先順位
式に複数の演算子が含まれる場合、優先順位が高いものが先に評価されます。下の表は優先順位が高い順に並べています:
| 優先順位 | 演算子 | 結合性 |
|---|---|---|
| 1(最高) | () [] -> . |
左から右 |
| 2 | ! ~ ++ -- +(単項) -(単項) *(間接参照) &(アドレス取得) sizeof |
右から左 |
| 3 | * / % |
左から右 |
| 4 | + - |
左から右 |
| 5 | << >> |
左から右 |
| 6 | < <= > >= |
左から右 |
| 7 | == != |
左から右 |
| 8 | & |
左から右 |
| 9 | ^ |
左から右 |
| 10 | ` | ` |
| 11 | && |
左から右 |
| 12 | ` | |
| 13 | ?: |
右から左 |
| 14 | = += -= *= /= %= など |
右から左 |
| 15(最低) | , |
左から右 |
例
各種演算子を組み合わせて 3 桁の数値の各桁の合計を計算します:
#include <stdio.h>
int main(void) {
int num = 952;
int hundreds = num / 100;
int tens = (num / 10) % 10;
int ones = num % 10;
int sum = hundreds + tens + ones;
printf("数値: %d\n", num);
printf("百の位: %d、十の位: %d、一の位: %d\n", hundreds, tens, ones);
printf("各桁の合計: %d\n", sum);
return 0;
}
数値: 952
百の位: 9、十の位: 5、一の位: 2
各桁の合計: 16
例
論理演算子と関係演算子を使って閏年かどうかを判定します:
#include <stdio.h>
int main(void) {
int year = 2024;
int is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
printf("%d 年は閏年%s\n", year, is_leap ? "です" : "ではありません");
return 0;
}
2024 年は閏年です
型変換
暗黙の変換
異なる型が混在する式では、コンパイラが自動的に精度の低い型を精度の高い型に変換します:
#include <stdio.h>
int main(void) {
int a = 5;
double b = 2.0;
double c = a / b;
printf("5 / 2.0 = %f\n", c);
char ch = 'A';
int code = ch + 1;
printf("'A' + 1 = %c(ASCII %d)\n", code, code);
return 0;
}
5 / 2.0 = 2.500000
'A' + 1 = B(ASCII 66)
変換の方向:char → int → long → double、int → unsigned → long → double。
明示的キャスト
(型名) を使って値を強制的に特定の型に変換します:
#include <stdio.h>
int main(void) {
int a = 7, b = 2;
double result = (double)a / b;
printf("キャスト付き: %f\n", result);
return 0;
}
キャスト付き: 3.500000
❓ よくある質問
a++ と ++a に違いはありますか?= と == をどう区別すればいいですか?= は代入(「になる」)、== は比較(「等しいか?」)です。if (a = 0) と書き間違えてもエラーになりませんが、ロジックは完全に変わります。良い習慣:定数を左側に置く——if (0 == a) と書けば、if (0 = a) とタイプミスしてもコンパイラが検出してくれます。% 演算子は浮動小数点数にも使えますか?% は整数型にしか使えません。浮動小数点の剰余には #include <math.h> の fmod() 関数を使ってください。📖 まとめ
- 算術演算では整数除算が小数部分を切り捨てます。剰余演算子は整数にしか使えません
++/--の前置は新しい値を返し、後置は古い値を返します。同一変数に 1 つの式で複数回使うのは避けてください- 関係演算子は 0 または 1 を返します。
=と==の混同に注意 - 論理演算子
&&と||は短絡評価を行い、右辺の式を保護できます - 優先順位は暗記しなくて大丈夫——迷ったら括弧を追加しましょう
📝 練習問題
- 秒数(例:3661)を入力とし、
/と%を使って対応する時間・分・秒を計算して出力するプログラムを書いてください - 2 つの整数を入力とし、三項演算子を使って大きい値と小さい値を見つけて出力するプログラムを書いてください
- 自分のパソコンで
short、int、long、long longのサイズをsizeofで出力し、結果を観察するプログラムを書いてください



