閉じる

C言語のインクリメント/デクリメント入門|for文から前置・後置の違いまで解説

C言語でループ処理を書くとき、インクリメントやデクリメントはほぼ必ず登場します。

特にfor文のカウンタ変数では、i++やi–、そして++iや–iの違いを正しく理解しているかどうかで、コードの読みやすさやバグの発生率が変わります。

この記事では、基本の使い方から前置・後置の評価タイミング、よくある落とし穴とベストプラクティスまで、図解とサンプルコードを交えながら丁寧に解説します。

C言語のインクリメント/デクリメントとは

インクリメント(i++)とは何か

インクリメントは「変数を1増やす」演算子です。

C言語では++という記号で表現し、もっともよく使われるのがi++の形です。

インクリメント演算子を使うと、例えばi = i + 1;と書くところをi++;と短く書けます。

どちらも意味としては同じで、「iに1を足して、その結果をもう一度iに代入する」という動作になります。

インクリメントの基本例

C言語
#include <stdio.h>

int main(void) {
    int i = 5;          // iに5を代入
    i++;                // iを1増やす (i = i + 1; と同じ)

    printf("i = %d\n", i);  // 結果を表示

    return 0;
}
実行結果
i = 6

このように、i++;「今の値に1を足す」ための非常にシンプルな書き方です。

デクリメント(i–)とは何か

デクリメントは「変数を1減らす」演算子です。

C言語では--という記号を使い、i--のように書きます。

意味としてはi = i - 1;と同じです。

デクリメントの基本例

C言語
#include <stdio.h>

int main(void) {
    int i = 5;          // iに5を代入
    i--;                // iを1減らす (i = i - 1; と同じ)

    printf("i = %d\n", i);  // 結果を表示

    return 0;
}
実行結果
i = 4

インクリメントとデクリメントは、ループのカウンタや配列のインデックス操作などで頻繁に使われます。

加算(+)との違いと使い分け

i++i = i + 1;は同じ意味だと説明しましたが、ではi = i + 2;などの場合はどう考えればよいでしょうか。

インクリメント/デクリメントは「1だけ増減」するときに使う専用の糖衣構文です。

それ以外の値を足したり引いたりする場合は、通常の加算・減算演算子を使います。

たとえば、次のように使い分けます。

C言語
#include <stdio.h>

int main(void) {
    int i = 10;

    i++;            // iは11になる (1だけ増やしたいとき)
    i = i + 2;      // iは13になる (2増やしたいので +2 を使う)
    i--;            // iは12になる (1だけ減らしたいとき)
    i = i - 5;      // iは7になる  (5減らしたいので -5 を使う)

    printf("i = %d\n", i);

    return 0;
}
実行結果
i = 7

インクリメント/デクリメントは「ループカウンタ」「配列の添字」「ポインタの移動」など、1ステップずつ進めたい処理で特に威力を発揮します。

それ以外の「任意の数だけ増減」したい場面では、普通に+-を使うほうが、かえって意図が伝わりやすくなります。

for文とインクリメント/デクリメント

for文の基本構造とカウンタ変数

for文は、「決まった回数だけ繰り返す処理」を書くのに最適な構文です。

C言語のfor文は、次の3つの部分から構成されます。

C言語
for (初期化; 条件; 更新) {
    // 繰り返したい処理
}

このうち「更新」の部分で、ほぼ必ずi++i--などのインクリメント/デクリメントが登場します。

ここに書かれた式は、ループの各反復の最後に実行されます。

for文でのi++とi–の書き方

もっとも典型的なfor文は、次のような「0からn-1まで繰り返す」形式です。

C言語
#include <stdio.h>

int main(void) {
    int i;

    // 0から4までの数字を順番に表示
    for (i = 0; i < 5; i++) {
        printf("i = %d\n", i);
    }

    return 0;
}
実行結果
i = 0
i = 1
i = 2
i = 3
i = 4

ここでは、i++の位置が「更新」にあります。

この位置に書かれたインクリメントは、ループ1回分の処理が終わるたびに1回だけ実行されます。

逆向きにカウントしたい場合はi--を使います。

C言語
#include <stdio.h>

int main(void) {
    int i;

    // 5から1へ向かってカウントダウン
    for (i = 5; i > 0; i--) {
        printf("i = %d\n", i);
    }

    return 0;
}
実行結果
i = 5
i = 4
i = 3
i = 2
i = 1

このように、増やすときはi++、減らすときはi–を「更新」の位置に書くのが基本です。

無限ループを避けるインクリメントの注意点

for文でよくあるバグのひとつが、インクリメントやデクリメントを書き忘れてしまうことです。

これにより、条件がいつまでも真のままになり、無限ループに陥ることがあります。

危険な例: 更新を書き忘れているfor文

C言語
#include <stdio.h>

int main(void) {
    int i;

    // NG例: 更新(i++)を書き忘れている
    for (i = 0; i < 5; /* ここにi++がない */) {
        printf("i = %d\n", i);
        // iの値が変わらないので、条件 i < 5 は永遠に真のまま
    }

    return 0;
}

このコードは、iがずっと0のままなのでi < 5が常に真となり、ループが終わりません。

実際には多くの開発環境でプログラムが止まらなくなり、強制終了が必要になります。

また、更新の方向と条件の関係にも注意が必要です。

例えば、次のようなコードはやはり無限ループになります。

C言語
#include <stdio.h>

int main(void) {
    int i;

    // NG例: 条件と更新の方向が合っていない
    for (i = 0; i < 5; i--) {  // iを減らしているのに「i < 5」としている
        printf("i = %d\n", i);
    }

    return 0;
}

この場合、iは0, -1, -2, …とどんどん小さくなっていきます。

するとi < 5は常に真となり、やはりループが終わりません。

「条件がいつか偽になるように、更新の方向と初期値を設計する」ことが、for文でインクリメント/デクリメントを使うときの重要なポイントです。

前置(++i)と後置(i++)の違い

ここからは、インクリメント/デクリメントの「前置」と「後置」の違いについて詳しく見ていきます。

C言語では、インクリメントを2通りの位置で書くことができます。

  • 前置インクリメント: ++i
  • 後置インクリメント: i++

どちらも「変数を1増やす」という点は同じですが、「その式がどんな値として評価されるか」が異なります。

前置インクリメント(++i)の評価タイミング

前置インクリメント(++i)は、値を「使う前に」変数を1増やします

つまり、++iという式の値は「1増やした後のiの値」になります。

前置インクリメントの例

C言語
#include <stdio.h>

int main(void) {
    int i = 5;
    int a;

    a = ++i;  // iを先に1増やしてから、その新しい値をaに代入

    printf("i = %d\n", i);
    printf("a = %d\n", a);

    return 0;
}
実行結果
i = 6
a = 6

この例では、++iによりiが5から6に増え、その増えた後の値aに代入されています。

後置インクリメント(i++)の評価タイミング

後置インクリメント(i++)は、値を「使った後で」変数を1増やします

つまり、i++という式の値は「増やす前のiの値」になります。

後置インクリメントの例

C言語
#include <stdio.h>

int main(void) {
    int i = 5;
    int a;

    a = i++;  // まずiの今の値(5)をaに代入し、その後でiを1増やす

    printf("i = %d\n", i);
    printf("a = %d\n", a);

    return 0;
}
実行結果
i = 6
a = 5

このように、++iとi++では、変数自体はどちらも1増えますが、「式の値として何が返るか」が逆になっていることがわかります。

代入式での前置・後置の具体例

前置と後置の違いは、代入式と組み合わせたときに特に重要になります。

次の表に簡単な比較をまとめます。

iの初期値評価結果(式の値)評価後のiの値説明
a = ++i;566先にiを6にしてから、その6をaに代入
a = i++;556先に5をaに代入し、その後iを6にする

この違いを実際のコードで確認してみましょう。

C言語
#include <stdio.h>

int main(void) {
    int i, a, b;

    i = 5;

    a = ++i;  // iを6にしてから、その6をaに代入
    printf("【前置】i = %d, a = %d\n", i, a);

    i = 5;    // iを再び5に戻す

    b = i++;  // 先に5をbに代入し、その後でiを6にする
    printf("【後置】i = %d, b = %d\n", i, b);

    return 0;
}
実行結果
【前置】i = 6, a = 6
【後置】i = 6, b = 5

「変数の値を使うタイミング」と「増やすタイミング」が前置と後置で入れ替わることが、インクリメントを理解するうえでの最重要ポイントです。

比較演算と前置・後置の挙動

インクリメントを比較演算と組み合わせると、条件判定のタイミングにも注意が必要です。

前置インクリメントとif文

C言語
#include <stdio.h>

int main(void) {
    int i = 3;

    if (++i < 5) {  // ここでiは4になってから比較される
        printf("++i < 5: 条件は真です (i = %d)\n", i);
    } else {
        printf("++i < 5: 条件は偽です (i = %d)\n", i);
    }

    return 0;
}
実行結果
++i < 5: 条件は真です (i = 4)

この場合、++iによりiは3から4に増え、その4が5と比較されます。

後置インクリメントとif文

C言語
#include <stdio.h>

int main(void) {
    int i = 3;

    if (i++ < 5) {  // まず3と5を比較し、その後でiが4になる
        printf("i++ < 5: 条件は真です (i = %d)\n", i);
    } else {
        printf("i++ < 5: 条件は偽です (i = %d)\n", i);
    }

    return 0;
}
実行結果
i++ < 5: 条件は真です (i = 4)

このように、比較の結果としては同じ「真」でも、評価の途中でどのタイミングでiが増えるのかが異なります。

実務では、if文の条件の中にインクリメント/デクリメントを書くとコードが読みにくくなるため、次のように分けて書くことが多いです。

C言語
#include <stdio.h>

int main(void) {
    int i = 3;

    i++;                    // 先に増やす
    if (i < 5) {            // その後で比較する
        printf("条件は真です (i = %d)\n", i);
    }

    return 0;
}

このように処理の順番をはっきり分けると、バグも防ぎやすくなります。

for文で前置++iを使うメリットと慣例

for文の更新部分では、i++++iのどちらも通常は同じ結果になります。

たとえば次の2つは、意味としてはほぼ同じです。

C言語
#include <stdio.h>

int main(void) {
    int i;

    // 後置インクリメント
    for (i = 0; i < 5; i++) {
        printf("i++ 版: i = %d\n", i);
    }

    printf("---\n");

    // 前置インクリメント
    for (i = 0; i < 5; ++i) {
        printf("++i 版: i = %d\n", i);
    }

    return 0;
}
実行結果
i++ 版: i = 0
i++ 版: i = 1
i++ 版: i = 2
i++ 版: i = 3
i++ 版: i = 4
---
++i 版: i = 0
++i 版: i = 1
++i 版: i = 2
++i 版: i = 3
++i 版: i = 4

for文の更新部分は「結果をどこにも使っていない」ため、前置/後置の評価結果の違いが表には出てきません。

そのため、動作としてはどちらでも問題ありません。

一部のスタイルガイドやC++界隈では、「++iのほうがわずかに効率的」とされ、++iを使うことを推奨する場合があります。

これは主にオブジェクト型のイテレータなどを扱う際に意味が出てくる話で、単なるint型のカウンタ変数であれば、i++でも++iでも性能差はほとんどありません

実務的には、次のように考えるとよいです。

  • Cの基礎学習の段階ではfor文では慣例的にi++を書くことが多い
  • C++や一部のコーディング規約では++iを推奨している場合もある
  • どちらにせよチームやプロジェクト内で統一することのほうが重要

いずれにしても、「前置と後置で評価タイミングが違う」という原則を理解しておくことが大切です。

注意したい書き方とベストプラクティス

複雑な式でのi++/++iは避ける

インクリメント/デクリメントを理解してくると、つい1行でいろいろなことをやりたくなってしまうことがあります。

しかし、複雑な式の中にこれらを埋め込むと、コードが非常に読みにくくなり、バグの温床になりやすいです。

読みにくい例

C言語
#include <stdio.h>

int main(void) {
    int i = 0;
    int sum = 0;

    // NG例: 何をしているかぱっと見でわかりにくい
    sum += i++;  // sumにiを足してからiを増やしているが、直感的でない場合が多い

    printf("i = %d, sum = %d\n", i, sum);

    return 0;
}
実行結果
i = 1, sum = 0

この行は「sum = sum + i;」「i++;」の2つの処理が1行に押し込まれており、処理順序を頭の中で展開しなければ理解できません

読みやすく書き直した例

C言語
#include <stdio.h>

int main(void) {
    int i = 0;
    int sum = 0;

    // OK例: 一つずつ順番に処理しているので分かりやすい
    sum = sum + i;  // 今のi(0)をsumに足す
    i = i + 1;      // その後でiを1増やす

    printf("i = %d, sum = %d\n", i, sum);

    return 0;
}
実行結果
i = 1, sum = 0

動作は同じですが、こちらのほうが「何をしているか」が明確です。

特にチーム開発や長期保守が前提のコードでは、読みやすさを最優先にした書き方を選ぶことが大切です。

未定義動作を招く危険なインクリメント例

C言語では、同じ変数を「1つの式の中」で複数回インクリメント/デクリメントしたり、値を読みながら変更したりすると、未定義動作になる場合があります。

未定義動作とは、コンパイラや環境によって結果が変わったり、クラッシュしたりしてもおかしくない状態のことです。

絶対に避けるべき例

C言語
#include <stdio.h>

int main(void) {
    int i = 5;

    i = i++;  // NG: 未定義動作の典型例

    printf("i = %d\n", i);

    return 0;
}

このコードがどう動くかは規格として決まっていません

コンパイラによっては5のままになることもあれば、6になることもあるかもしれません。

つまり、「たまたま動いているように見えても信用できない」コードです。

同様に、次のような書き方も危険です。

C言語
int i = 0;
array[i] = i++;  // NG: iを添字として使いながら同時に増やしている
C言語
int i = 0;
int x = i++ + ++i;  // NG: どちらが先に評価されるか決まっていない

このようなコードは、「どちらが先に評価されるか」が未定義であるため、結果が保証されません。

C言語では、+演算子の左右のオペランドの評価順序が規定されていないことが原因です。

ルール

「同じ変数を1つの式の中で、インクリメント/デクリメントしながら別の用途でも使う」ような書き方は絶対に避ける、という意識を持つことが重要です。

読みやすいインクリメント/デクリメントの書き方

実務でインクリメント/デクリメントを使いこなすには、「読みやすさ」と「バグを生みにくいこと」を基準に書き方を選ぶとよいです。

おすすめの基本パターン

C言語
#include <stdio.h>

int main(void) {
    int i;

    // 1. for文の更新欄でシンプルに使う
    for (i = 0; i < 10; i++) {   // または ++i でもよい
        printf("%d\n", i);
    }

    // 2. while文などでは、インクリメントはなるべく別行に書く
    i = 0;
    while (i < 10) {
        printf("%d\n", i);
        i++;  // ここで1ずつ増やす
    }

    // 3. 単独のステートメントとして使う
    i = 0;
    i++;  // iを1増やすだけの行として明確に表現

    return 0;
}

このように、「インクリメント/デクリメントは1行で1つのことだけをさせる」意識を持つと、読みやすさが大きく向上します。

さらに、前置/後置の違いを意識させない書き方をするのもコツです。

例えば、i++++iの式の値を他の演算で使わないようにすれば、「どちらで書いてもほぼ同じ意味」と割り切って使うことができます。

C言語でインクリメント/デクリメントを使いこなすコツ

最後に、C言語におけるインクリメント/デクリメントを上手に使うためのコツを整理しておきます。

1つ目のコツは、「1だけ増やす/減らすときにだけインクリメント/デクリメントを使う」という割り切り方です。

2以上増やしたい場合は素直にi = i + 2;と書くほうが、かえって意図が伝わりやすくなります。

2つ目のコツは、「for文の更新部分で素直にi++やi–を書く」ことです。

for文ではこのスタイルが一般的であり、ほかのCプログラマにとっても見慣れた形です。

3つ目は、「前置(++i)と後置(i++)では、式の評価タイミングが違う」ことをきちんと理解しておくことです。

代入式や比較式などで使ったときに、その差が結果に影響します。

4つ目は、「1つの式の中で複数のインクリメント/デクリメントを使わない」という安全策です。

これを守るだけで、未定義動作を避けることができ、バグのリスクを大幅に減らせます。

まとめ

C言語のインクリメント/デクリメントは、1だけ増減させるための専用演算子であり、特にfor文のカウンタや配列アクセスで頻繁に利用されます。

前置(++i)と後置(i++)は変数自体は同じように1増えますが、「式としてどの値が使われるか」という評価タイミングが異なる点が重要です。

また、同じ変数を1つの式の中で何度もインクリメントするような書き方は未定義動作を招くため、必ず避けるべきです。

基本的には、ループの更新欄などでシンプルにi++/i–を使い、複雑な式では処理を分けて書くという方針を守れば、安全で読みやすいCコードを書けるようになります。

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

URLをコピーしました!