この記事の要点
- 算術演算子では代入は行われないが、インクリメント(デクリメント)では代入まで行われる
- インクリメント(デクリメント)演算子は、前置きと後置きで処理順が変わる
- 比較演算子や論理演算子は、主にif文などの条件判定で使われる
以前、C言語とはどんな言語か、またどんな業務で利用されるのかなど、基本を解説していました。
C言語の中でも初心者の方にとってハードルが高いのが、演算子です。
C言語の演算子の種類はたくさんあり、初心者が全て覚えるのは困難です。
そこで当記事では、C言語の演算子の使い方をサンプルコード付きで丁寧に解説しています。
1記事でほとんどの演算子をカバーしているため、網羅的に演算子を学習することができます。
目次
算術演算子とインクリメント・デクリメント演算子
「算術演算子」は、足し算や引き算などの計算を行うための演算子です。
「インクリメント演算子」「デクリメント演算子」は、足し算、引き算と代入を一度に行える演算子です。
それぞれ具体的に見ていきましょう。
算術演算子
演算子 | 使用例 | 説明 |
---|---|---|
+ | a + b | a に b を加えた結果を返す |
- | a - b | a から b を引いた結果を返す |
* | a * b | a に b をかけた結果を返す |
/ | a / b | a を b で割った結果を返す |
% | a % b | a を b で割った余りを返す |
以下はサンプルコードです。
int a = 5; int b = 2; printf("%d\n", a + b); // 7 printf("%d\n", a - b); // 3 printf("%d\n", a * b); // 10 printf("%d\n", a / b); // 2 printf("%d\n", a % b); // 1 printf("a : %d b : %d\n", a, b); // a : 5 b : 2
気を付けていただきたいのは、算術演算子を使っただけでは、aやbの値が変わっていないことです。
これは、算術演算子では、代入処理が行われていないからです。
インクリメント演算子、デクリメント演算子
演算子 | 使用例 | 説明 |
---|---|---|
++ | a++, ++a | a に 1 を加えた値を a に代入する(インクリメント) |
-- | a--, --a | a から 1 を引いた値を a に代入する(デクリメント) |
サンプルコードは次のようになります。
int a = 5; a++; printf("%d\n", a); // 6 a--; printf("%d\n", a); // 5
算術演算子と違うのは、計算結果の代入まで行われる点です。
インクリメントやデクリメントは、特にfor文内で使われることが多くあります。
for(int i = 0; i < 10; i++){ }
前置きと後置き
「++」や「--」を変数の前につける(前置き)か、後につける(後置き)かで、処理の順序が変わります。
使用例 | 説明 | |
---|---|---|
前置き | ++a, --a | 他の処理より前にインクリメント(デクリメント)を行う |
後置き | a++, a-- | 他の処理より後にインクリメント(デクリメント)を行う |
説明だけだと理解しづらいと思うので、具体例を見ていきましょう。
// 前置き int a1 = 5; int b1 = ++a1; printf("a1 : %d b1 : %d\n", a1, b1); // a1 : 6 b1 : 6
// 後置き int a2 = 5; int b2 = a2++; printf("a2 : %d b2 : %d\n", a2, b2); // a2 : 6 b2 : 5
前置きの場合、b1への代入処理より前に、a1のインクリメントが行われるため、b1には加算後の「6」が代入されます。
一方、後置きの場合、b2への代入処理の後に、a2のインクリメントが行われます。
つまり、b2への代入処理の時点では加算されていないので、b2に「5」が代入されます。
代入演算子
「代入演算子」は、変数に値を代入するための演算子です。
算術演算子とセットになった、「複合代入演算子」も合わせてご紹介します。
演算子 | 使用例 | 説明 |
---|---|---|
= | a = b | a に b を代入する |
+= | 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 の計算結果を代入する |
以下はサンプルコードです。
int a = 5; int b = 2; a += b; printf("%d\n", a); // 7 a -= b; printf("%d\n", a); // 5 a *= b; printf("%d\n", a); // 10 a /= b; printf("%d\n", a); // 5 a %= b; printf("%d\n", a); // 1
複合代入演算子を使う度に、aの値が変化していることがおわかりいただけると思います。
比較演算子
「比較演算子」は、ある値どうしを比較したい場合に使います。
演算子 | 使用例 | 説明 |
---|---|---|
< | a < b | a が b より小さければtrue、それ以外false |
> | a > b | a が b より大きければtrue、それ以外false |
<= | a <= b | a が b 以下ならtrue、それ以外false |
>= | a >= b | a が b 以上ならtrue、それ以外false |
== | a == b | a が b と等しいならtrue、それ以外false |
!= | a != b | a が b と等しくないならtrue、それ以外false |
以下はサンプルコードです。
int a = 0; int b = 5; while(true){ if(a == b){ break; } if(a < b){ a++; } } printf("%d", a); // 5
aがbより小さい間、aをインクリメントし続け、aとbが等しくなったらループを脱出します。
このように、比較演算子はif文などの条件判定に使うことがほとんどです。
論理演算子
「論理演算子」は、論理値(true, false)の計算に使います。
演算子 | 使用例 | 説明 |
---|---|---|
! | !a | aを否定する(aがtrueならfalse、falseならtrue) |
&& | a && b | a、bの論理積(a、bが共にtrueならtrue、それ以外false) |
|| | a || b | a、bの論理和(a、bが共にfalseならfalse、それ以外true) |
それぞれ、trueとfalseの組合せで次のような結果になります。
a | b | !a | a && b | a || b |
---|---|---|---|---|
true | true | false | true | true |
true | false | false | false | true |
false | true | true | false | true |
false | false | true | false | false |
こちらも多くの場合、比較演算子と同様にif文などの条件分岐判定に使われます。
ビット演算子とシフト演算子
「ビット演算子」は、ビット単位での計算を行いたい場合に利用します。
「シフト演算子」は、ビットの桁移動を行いたい場合に利用します。
どちらも、メモリリソースが制限される、組み込み系プログラミングなどで利用されます。
しかし、かなりややこしい上に使う場面は限定的なので、初心者の方は必要になったときに勉強すれば十分です。
前項の論理演算子でも登場した記号(&、|)が使われていますが、全く別の演算なので混同しないよう注意してください。
演算子 | 使用例 | 説明 |
---|---|---|
& | a & b | a と b のビット単位の論理積 |
| | a | b | a と b のビット単位の論理和 |
^ | a ^ b | a と b の排他的論理和 |
~ | ~a | a のビットパターンを反転 |
<< | a << b | a を b桁左シフト |
>> | a >> b | a を b桁右シフト |
以下はビット演算のコードサンプルです。
2進数の演算の知識が必要なため詳細な説明は割愛しますが、「|」を使うことで、flagという1つの変数に、flag1とflag3という2つのフラグを持たせています。
また、フラグがたっているかの判定に「&」を使っています。
short int flag1 = 0b0001; short int flag2 = 0b0010; short int flag3 = 0b0100; short int flag4 = 0b1000; short int flag = flag1 | flag3; // 0101 if((flag & flag1) != 0){ puts("flag1"); } if((flag & flag2) != 0){ puts("flag2"); } if((flag & flag3) != 0){ puts("flag3"); } if((flag & flag4) != 0){ puts("flag4"); }
以下はシフト演算のサンプルです。
こちらも2進数の桁移動に関する理解が必要になりますが、「<>」を使って2のn乗分の1の計算を行っています。
算術演算子を使う場合より、高速に計算できます。
int num = 30; num = num << 2; // 30 * 2の2乗 printf("%d\n", num); // 120 num = num >> 3; // 120 / 2の3乗 printf("%d", num); // 15
その他よく使う演算子
こちらでは、その他のよく使う演算子をご紹介します。
sizeof演算子
「sizeof演算子」は、型の大きさを調べるために使います。
演算子 | 使用例 | 説明 |
---|---|---|
sizeof | sizeof(a) | a の型の大きさを返す |
例えば、
sizeof(int)
と記述すると、多くの処理系では4が返って来ます。
これは、int型の変数には、メモリが4Byte割り当てられていることを意味します。
キャスト演算子
「キャスト演算子」は、明示的に型変換したい場合に利用します。
演算子 | 使用例 | 説明 |
---|---|---|
(型名) | (double)a | a の型をdoubleに変換する |
例えば、以下のサンプルをご覧ください。
int num1 = 5; int num2 = 3; double result = num1 / num2;
このようにすると、intどうしの割り算となり小数点以下が切り捨てられます。
結果、resultには、1.000…が入ります。
そこで、以下のようにキャストを使います。
double result = (double)num1 / num2;
こうすると、doubleとintの割り算になるため、小数点以下も有効となります。
resultには1.6666…が入ります。
演算子の優先順位
演算子には優先順位があります。
優先順位が高いものほど、先に評価されます。
例えば、
int num = 1 + 2 * 3;
とすると、「+」より「*」のほうが優先順位が高いため先に計算され、numには7が入ります。
当記事でご紹介した演算子の優先順位一覧は以下の通りです。
優先度 | 演算子 | 説明 | 結合の向き |
---|---|---|---|
1 | ++ | 後置インクリメント | 左から右 |
-- | 後置デクリメント | ||
2 | ! | 論理否定 | 右から左 |
~ | ビット否定 | ||
++ | 前置インクリメント | ||
-- | 前置デクリメント | ||
sizeof | 型の大きさを取得 | ||
3 | (型名) | キャスト | 右から左 |
4 | * | 掛け算 | 左から右 |
/ | 割り算 | ||
% | 剰余 | ||
5 | + | 足し算 | 左から右 |
- | 引き算 | ||
6 | << | 左シフト | 左から右 |
>> | 右シフト | ||
7 | < | 左の方が小さい | 左から右 |
<= | 左は右以下 | ||
> | 左の方が大きい | ||
>= | 左は右以上 | ||
8 | == | 等しい | 左から右 |
!= | 等しくない | ||
9 | & | ビット単位の論理積 | 左から右 |
10 | ^ | ビット単位の排他的論理和 | 左から右 |
11 | | | ビット単位の論理和 | 左から右 |
12 | && | 論理積 | 左から右 |
13 | || | 論理和 | 左から右 |
14 | = | 代入 | 右から左 |
+= | 足し算 + 代入 | ||
-= | 引き算 + 代入 | ||
*= | 掛け算 + 代入 | ||
/= | 割り算 + 代入 | ||
%= | 剰余 + 代入 |
まとめ
C言語は演算子の数が多く、最初は覚えきれないと感じるかもしれません。
特に、「=」と「==」、「&」「|」と「&&」「||」を混同してしまうのは初心者あるあるなので、注意してください。
使っているうちに自然と身についていくので、焦らずじっくり取り組みましょう。
もし忘れてしまったら、その都度当記事を参照して、復習してみてください。
また、演算子と同じく初心者がC言語でつまずきやすいのが「ポインタ」です。
ポインタが難しいと感じている方や、ポインタの使い方やメリットがわからないという方に向けて、ポインタを効果的に習得する方法をご紹介しています。
「ポインタ」と混同されやすい「配列」についても解説していますので、こちらも参考にしてください。