C言語のきほん|インクリメント演算子とデクリメント演算子

++ と -- は「1だけ更新」の特急券!前置・後置の違いまで分かると、ループも表示も迷わなくなるよ。

C言語では、数を 1 だけ増やす・1 だけ減らす処理がびっくりするほどよく出てきます。たとえばループのカウンタ、配列の添字、試行回数、残り回数、ページ番号…などなど。

そんな「+1」「-1」を毎回 n = n + 1 と書くのもいいんですが、もっとスッキリ書ける仕組みが用意されています。それが インクリメント演算子 ++デクリメント演算子 -- です。

しかも ++ と -- は、ただ短いだけじゃなくて「前に付けるか」「後ろに付けるか」で挙動が変わります。ここを理解しておくと、printf の結果が思ったのと違う…みたいな混乱が減って、コードがずっと読みやすくなりますよ。

1だけ加算・減算する演算子

まずは3つの書き方を対応させる

変数 n を 1 増やす処理は、次の3通りで書けます。

書き方意味
n = n + 1;n を 1 増やして保存
n += 1;n を 1 増やして保存(複合代入)
n++; または ++n;n を 1 増やす(インクリメント)

減らす場合も同じです。

書き方意味
n = n - 1;n を 1 減らして保存
n -= 1;n を 1 減らして保存(複合代入)
n--; または --n;n を 1 減らす(デクリメント)

単独で使うなら、n++ と ++n は「最終的に n が 1 増える」という点では同じです。
でも、式の中で使うと違いが出ます。

前置と後置の違い(ここが一番大事)

ルールをひとことで

  • 前置(++n / --n):先に更新してから、その値を使う
  • 後置(n++ / n--):その値を使ってから、あとで更新する

図っぽく書くとこんな感じです。

表で確認(n が 5 のとき)

「式として使ったときに何が返るか」を見ると差がはっきりします。

書き方その場で使われる値実行後の n
++n66
n++56
--n44
n--54

シンプルなプログラム例(前置・後置の違いを確認)

ファイル名:6_6_1.c

#include <stdio.h>

int main(void)
{
    int tickets = 5;   /* 残りチケット枚数 */
    int shown;

    /* 前置:先に減らしてから、その値を使う */
    shown = --tickets;
    printf("前置デクリメント: 表示=%d, 残り=%d\n", shown, tickets);

    tickets = 5;  /* 元に戻す */

    /* 後置:先に使ってから、あとで減らす */
    shown = tickets--;
    printf("後置デクリメント: 表示=%d, 残り=%d\n", shown, tickets);

    printf("メッセージ: 表示される値と更新後の値がズレるのがポイントです。\n");

    return 0;
}

この例だと、前置では「表示も残りも同じ値」、後置では「表示は古い値、残りは新しい値」になります。

printf は値を変えない(でも ++ と組み合わせると変化が見える)

文書の補足にある大事な考え方を、ここでも押さえておきます。

  • printf は「値を表示するだけ」で、変数そのものは変えません
  • ただし、printf の引数に ++n や n++ を書くと、その演算子の効果で変数が変わります

つまり「printf が変えた」んじゃなくて「++ が変えた」んですね。

実践問題

次の実行結果になるように、プログラムの空欄 ① と ② を埋めてください。
前置と後置の違いが出るように書いてね。

#include <stdio.h>

int main(void)
{
    int a, x1 = 2, x2 = 2;

    a = ➀ ;

    printf("x1: %d\ta: %d\n", x1, a);

    a = ➁ ;

    printf("x2: %d\ta: %d\n", x2, a);

    return 0;
}

実行結果

x1: 3 a: 3
x2: 3 a: 2

ヒント:\t はタブです。表示をそろえるための記号だよ。

解答

① は ++x1
② は x2++

(どちらも「x を 1 増やす」けど、a に入る値が変わります)

完成形

ファイル名:6_6_2.c

#include <stdio.h>

int main(void)
{
    int a, x1 = 2, x2 = 2;

    a = ++x1;   /* 先にx1を増やしてから、その値をaへ */

    printf("x1: %d\ta: %d\n", x1, a);

    a = x2++;   /* まずx2の値をaへ、そのあとx2を増やす */

    printf("x2: %d\ta: %d\n", x2, a);

    return 0;
}

解説(どうしてこの結果になるの?)

最初は x1 も x2 も 2 です。

  • a = ++x1 は「先に x1 を 3 にして、その 3 を a に入れる」
    だから x1: 3、a: 3
  • a = x2++ は「まず 2 を a に入れてから、x2 を 3 にする」
    だから x2: 3、a: 2

この“表示のズレ”が、前置・後置の理解ポイントです。

代入と演算による変数の値の変化(確認用の小さな例)

ファイル名:6_6_3.c

#include <stdio.h>

int main(void)
{
    int a = 3, b = 4, sum;

    /* 計算結果を表示するだけ(aやbは変わらない) */
    printf("表示だけ: a+b=%d\n", a + b);

    /* 計算結果を代入して保存する */
    sum = a + b;
    printf("保存したsum=%d\n", sum);

    /* aを1増やす(代入の形) */
    a = a + 1;
    printf("aを更新後: a=%d\n", a);

    /* bを1増やす(複合代入) */
    b += 1;
    printf("bを更新後: b=%d\n", b);

    /* sumを1増やす(インクリメント) */
    sum++;
    printf("sumを更新後: sum=%d\n", sum);

    printf("メッセージ: 表示と更新は別物。更新したいなら代入や++が必要だよ。\n");

    return 0;
}

使いどころのコツ(読みやすさ優先で)

  • ループのカウンタ更新は i++ が定番で読みやすい
  • 式の中で ++i と i++ を混ぜると混乱しやすいので、慣れないうちは「単独行で更新」も全然アリです

たとえば、

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

みたいに分けると、意図がまっすぐ伝わります。