C言語では変数を1増やす書き方が複数ありますが、i++
と++i
は同じようでいて式として使ったときの値が変わります。
この記事では、初心者の方でも混乱しやすい両者の違いを、動作の原理から実行例、避けるべき書き方まで丁寧に解説します。
単独の文では差は出ない一方で、式の一部に組み込むと結果が変わる点が最重要ポイントです。
i++ と ++i の基本
どちらも変数の値を1増やす
まず共通点から確認します。
i++
も++i
も、変数i
の値を1だけ増やす単項演算子です。
インクリメント演算子と呼ばれ、変数自体の中身を1つ増やす副作用を持ちます。
この「1増やす」という副作用は同じですが、その式自体がとる値(式の結果)が異なります。
これが実用上の違いのすべてと言ってよいでしょう。
前置インクリメント(++i)の意味
++i
は増やしてから値を使う演算です。
式を評価するとき、まずi
が1増え、その後で式の値として「増えた後のi
」が使われます。
- 例:
i
が3のとき++i
は4になり、i
も4になります。
後置インクリメント(i++)の意味
i++
は値を使ってから増やす演算です。
式を評価するとき、まず式の値として「増やす前のi
」が使われ、その後でi
が1増えます。
- 例:
i
が3のときi++
は3になり、式の評価が終わったあとi
は4になります。
次の表に両者の違いを簡潔にまとめます。
書き方 | 増えるタイミング | 式の値(評価結果) |
---|---|---|
++i | 最初に増える | 増えた後の値 |
i++ | 後で増える | 増える前の値 |
両者とも最終的に変数は1増えますが、「式の値」が違うことを意識してください。
i++ と ++i の違い
++iは増やした後の値が式の値
++i
は式の値が増えた後になります。
そのため、右辺の式の値をそのまま使いたいときに向いています。
#include <stdio.h>
int main(void) {
int i = 3;
int x = ++i; // ここでiはまず4になる
printf("x=%d, i=%d\n", x, i); // x=4, i=4
return 0;
}
x=4, i=4
i++は増やす前の値が式の値
i++
は式の値が増える前になります。
もとの値を使いたいが、ついでに変数も後で1増やしておきたいときに使います。
#include <stdio.h>
int main(void) {
int i = 3;
int x = i++; // xにはまず3が入る。その後でiが4になる
printf("x=%d, i=%d\n", x, i); // x=3, i=4
return 0;
}
x=3, i=4
単独の文では違いは出ない(i++; ++i;)
文として単独で使う場合(例: i++;
や++i;
)、どちらも「iを1増やす」だけなので結果は同じです。
式の値をどこにも使っていないため違いが現れません。
#include <stdio.h>
int main(void) {
int a = 10;
a++; // aは11になる
printf("a=%d\n", a); // a=11
int b = 10;
++b; // bも11になる
printf("b=%d\n", b); // b=11
return 0;
}
a=11
b=11
i++ と ++iの実例
代入の違い(j = i++; と j = ++i;)
代入に混ぜると、右辺の式の値の違いがそのまま結果に反映されます。
#include <stdio.h>
int main(void) {
int i, j;
i = 5;
j = i++; // 後置: jに5が入り、その後iが6になる
printf("case1: i=5; j=i++ -> j=%d, i=%d\n", j, i);
i = 5;
j = ++i; // 前置: iが6になってから、jに6が入る
printf("case2: i=5; j=++i -> j=%d, i=%d\n", j, i);
return 0;
}
case1: i=5; j=i++ -> j=5, i=6
case2: i=5; j=++i -> j=6, i=6
出力の違い(printfでi++/++iを使う)
printf
の引数に直接入れると、前置と後置で表示される値が異なります。
以下は安全な例です。
同じ呼び出しで同じ変数を複数回使わないことがポイントです。
#include <stdio.h>
int main(void) {
int i;
i = 10;
printf("printfでi++ : %d\n", i++); // 10が表示され、表示後にiは11
printf("表示後のi : %d\n", i); // 11
i = 10;
printf("printfで++i : %d\n", ++i); // 11が表示され、そのままiは11
printf("表示後のi : %d\n", i); // 11
return 0;
}
printfでi++ : 10
表示後のi : 11
printfで++i : 11
表示後のi : 11
同じprintf
呼び出しの中で同じ変数を「読み」と「インクリメント」で同時に使うのは避けてください。
Cでは関数引数の評価順序が規定されておらず、printf("%d %d\n", i, i++);
のような式は未定義動作になります。
ループのカウンタ(for文)ではどちらでもOK
ループでカウンタを1ずつ進める用途では、どちらを使っても挙動は同じです。
整数カウンタに限って言えば性能差も通常はありません。
#include <stdio.h>
int main(void) {
printf("i++ のforループ: ");
for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
printf("\n");
printf("++i のforループ: ");
for (int j = 0; j < 5; ++j) {
printf("%d ", j);
}
printf("\n");
return 0;
}
i++ のforループ: 0 1 2 3 4
++i のforループ: 0 1 2 3 4
使い分けと注意点
読みやすさ重視: 単独ならi++が一般的
単独の文として使うならi++;
が広く使われます。
読みやすさと慣習の観点で、Cでは整数のカウンタやインデックスにはi++
を選ぶのが無難です。
もちろん++i;
でも意味は同じなので、プロジェクトのコーディング規約に従って統一してください。
式で値が必要なら++iとi++を使い分ける
右辺の式の値が必要な場面では、次のように目的で選びます。
- 増やした後の値を使いたいなら
++i
を使う - 増やす前の値を使いたいなら
i++
を使う
例として、配列アクセスでは意図が明確な書き方を心がけます。
たとえば「今の位置を使ってから次へ進む」ならa[i++]
、「次へ進んでから使う」ならa[++i]
です。
いずれも読み手に意図が伝わることが大切です。
同じ式で同じ変数を何度も++しない
最重要の注意として、同じ式の中で同じ変数を複数回インクリメントしたり、読みと書きを同時に行わないでください。
これはCでは未定義動作になり、コンパイラや最適化の違いで結果が変わったり、予測不能な挙動になります。
以下はすべて避けるべき「悪い例」です。
// 悪い例: 未定義動作になる可能性がある書き方
int i = 1;
// 1) 読みとインクリメントを同じ式で混在 (関数引数の評価順は未規定)
printf("%d %d\n", i, i++); // 未定義動作
// 2) 同じ変数を同じ式で2回インクリメント
int x = i++ + ++i; // 未定義動作
// 3) 自分自身へ代入とインクリメントの組み合わせ
i = i++; // 未定義動作
i = ++i; // 未定義動作
このような場面では、式を分解して順序を明確にしましょう。
// 良い例: ステップを分けて安全かつ明快にする
int i = 1;
int a = i; // まず読む
i = i + 1; // 次に増やす
// あるいは順序が明確になるよう一文ずつ書く
int b = i++;
int c = i;
複雑な式に混ぜない(代入や関数引数に多用しない)
インクリメントを複雑な式に埋め込むほど、評価順序や副作用の理解が必要になりバグの温床になります。
特に以下に注意します。
- 関数の複数の引数で同じ変数を同時に使わない。Cでは引数の評価順序が規定されないため、
f(i, i++)
のような書き方は危険です。 - 代入の右辺での多用を避け、必要なら一旦一時変数や複数行に分ける。
- マクロの引数に
i++
を渡すのも要注意です。マクロ定義によっては複数回評価され、思わぬ回数インクリメントされる可能性があります。
安全で読みやすいコードは、副作用の位置と回数が一目で分かるように書かれています。
まとめ
++iとi++は「式の値」が違うという一点を押さえれば、使い分けは難しくありません。
増やした後の値が必要なら++i
、増やす前の値が必要ならi++
を選びます。
単独の文やforループのカウンタではどちらでも同じですが、同じ式で同じ変数を読み書き・多重インクリメントするのは避けるのが鉄則です。
評価順序に依存せず、式を分解して明確に書くことで、予期せぬ未定義動作を防ぎ、読みやすく堅牢なCコードを書けます。