閉じる

【C言語】++iとi++は何が違う?同じに見えて挙動が変わる理由

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式の値が増えた後になります。

そのため、右辺の式の値をそのまま使いたいときに向いています。

C言語
#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増やしておきたいときに使います。

C言語
#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増やす」だけなので結果は同じです。

式の値をどこにも使っていないため違いが現れません。

C言語
#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;)

代入に混ぜると、右辺の式の値の違いがそのまま結果に反映されます。

C言語
#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の引数に直接入れると、前置と後置で表示される値が異なります。

以下は安全な例です。

同じ呼び出しで同じ変数を複数回使わないことがポイントです。

C言語
#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ずつ進める用途では、どちらを使っても挙動は同じです。

整数カウンタに限って言えば性能差も通常はありません。

C言語
#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では未定義動作になり、コンパイラや最適化の違いで結果が変わったり、予測不能な挙動になります。

以下はすべて避けるべき「悪い例」です。

C言語
// 悪い例: 未定義動作になる可能性がある書き方
int i = 1;

// 1) 読みとインクリメントを同じ式で混在 (関数引数の評価順は未規定)
printf("%d %d\n", i, i++);   // 未定義動作

// 2) 同じ変数を同じ式で2回インクリメント
int x = i++ + ++i;           // 未定義動作

// 3) 自分自身へ代入とインクリメントの組み合わせ
i = i++;                     // 未定義動作
i = ++i;                     // 未定義動作

このような場面では、式を分解して順序を明確にしましょう。

C言語
// 良い例: ステップを分けて安全かつ明快にする
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コードを書けます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!