C言語基礎|後置演算子を使ったカウントダウンとカウントアップ

はじめに:後置演算子は「表示してから更新」が得意技

前の節で学んだ i++ や no-- は、カウンタを1ずつ増やしたり減らしたりする“超定番”でしたね。
そして今回のテーマは、その後置演算子の特性―

  • 式の値は更新前
  • 変数の更新は後

をうまく使って、カウントダウン / カウントアップを短く気持ちよく書くことです。

「表示した直後に増える(減る)」という動きが、コードの見た目そのままに表現できるので、慣れるとかなり便利ですよ。

サンプル:残り秒数をカウントダウン → 経過秒数をカウントアップ

タイマーっぽく「残り秒数を表示しながら減らす」「経過秒数を表示しながら増やす」プログラムを例に解説します。

プロジェクト名:chap4-7-1 ソースファイル名:chap4-7-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

// 後置演算子で、残り秒数のカウントダウンと経過秒数のカウントアップを表示する
#include <stdio.h>

int main(void)
{
    int sec;

    printf("秒数を入力してください:");
    scanf("%d", &sec);

    // カウントダウン:表示してから減らす
    while (sec > 0)
        printf("残り %d 秒\n", sec--);

    // カウントアップ:0から、入力値まで表示してから増やす
    int elapsed = 0;
    while (elapsed <= sec)  // ここは sec が 0 になっているので、0 だけ表示される
        printf("経過 %d 秒\n", elapsed++);

    return 0;
}

…このままだと、カウントダウン後の sec が 0 になっているので、カウントアップが 0 だけになってしまいます。
なので、実用的には 元の入力値を保存しておくのが自然です。次が完成形です。

プロジェクト名:chap4-7-2 ソースファイル名:chap4-7-2.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

// 後置演算子で、残り秒数のカウントダウンと経過秒数のカウントアップを表示する(完成版)
#include <stdio.h>

int main(void)
{
    int sec;
    int total;

    printf("秒数を入力してください:");
    scanf("%d", &sec);

    total = sec;   // 入力値を保存

    // カウントダウン:表示してから減らす
    while (sec > 0)
        printf("残り %d 秒\n", sec--);

    printf("カウントダウン終了!\n");

    // カウントアップ:0から total まで、表示してから増やす
    int elapsed = 0;
    while (elapsed <= total)
        printf("経過 %d 秒\n", elapsed++);

    printf("完了です。\n");
    return 0;
}

実行例

秒数を入力してください:3
残り 3 秒
残り 2 秒
残り 1 秒
カウントダウン終了!
経過 0 秒
経過 1 秒
経過 2 秒
経過 3 秒
完了です。

後置増分・後置減分の復習(今回の土台)

後置演算子はこのルールでした。

後置演算子の特徴

演算子変数はどうなる?式全体の値は?
a++a が 1 増える増える前の a
a--a が 1 減る減る前の a

つまり printf("%d", a++); のように式の中で使うと、

  1. まず増える前の値が使われる(表示される)
  2. その直後に a が更新される

という順番になります。

printf の中で no-- が起こす2ステップ

たとえば sec-- の部分を分解すると、こういう動きです。

printf("残り %d 秒\n", sec--); の中身

(1) sec の値を取り出して表示する
(2) 表示が終わった直後に sec を 1 減らす

だから「表示した直後に減る」という挙動が、1行で自然に書けるわけです。

while文と後置演算子の相性が良い理由

while文は「条件を先にチェック」してからループ本体を実行します。

図:while の基本フロー

制御式を評価する
      ↓
真(値は非0)なら
  ループ本体を実行する
      ↓
  制御式の評価へ戻る
偽(値は0)なら
  ループを終了する

この「ループ本体を実行したら、次の判定へ戻る」流れの中で、
後置演算子で値を1つ更新しておくと、次の判定が自然につながります。

今回のカウントダウンなら、

  • 条件:sec > 0
  • 本体:表示して sec を 1 減らす(sec--)

これで sec が 0 になった瞬間に while が止まる、というスッキリした設計になります。

カウントダウンとカウントアップの形を並べて比較

同じ “表示してから更新” を、増える版・減る版で比べると理解が早いです。

後置演算子で作る定番ループ

種類条件本体の表示更新
カウントダウンx > 0x を表示x--
カウントアップi <= limiti を表示i++

今回の完成版はこの2つをそのまま使っています。

ここで登場した命令の書式まとめ

while文(繰り返し制御)

書式何をする?
while (式) 文式が真の間、文を繰り返す
while (式) { ... }式が真の間、ブロックを繰り返す

後置増分 / 後置減分

書式何をする?
変数++変数を 1 増やす(式の値は更新前)
変数--変数を 1 減らす(式の値は更新前)

値の変化を表で追う(入力が3のとき)

完成版のカウントダウン部分を追ってみます。

カウントダウンの変化(sec--)

繰り返しループ開始時 sec表示される値更新後 sec
1332
2221
3110
40--(条件が偽で終了)

「表示は 3→2→1、更新後は 2→1→0」になってるのがポイントです。

演習問題

演習4-4:1までカウントダウン、0以下なら何も表示しない

整数 n を読み込み、n から 1 までを 1 ずつ減らしながら表示せよ。
ただし、n が 0 以下のときは 何も表示しない

解答例

プロジェクト名:chap4-7-3 ソースファイル名:chap4-7-3.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

int main(void)
{
    int n;

    printf("整数を入力してください:");
    scanf("%d", &n);

    while (n > 0)
        printf("%d ", n--);

    return 0;
}

演習4-5:入力値以下の正の奇数を順に表示する

正の整数 n を読み込み、n 以下の 正の奇数(1, 3, 5, ...)を順に表示せよ。
(例:n が 10 なら 1 3 5 7 9)

解答例

プロジェクト名:chap4-7-4 ソースファイル名:chap4-7-4.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

int main(void)
{
    int n;
    int i = 1;

    printf("正の整数を入力してください:");
    scanf("%d", &n);

    while (i <= n) {
        printf("%d ", i);
        i += 2;
    }

    return 0;
}

(ここは後置演算子にこだわらず、2ずつ増やすので i += 2 が素直です)

演習4-6:入力値以下の3のべき乗を順に表示する

正の整数 n を読み込み、n 以下の 3のべき乗(3, 9, 27, ...)を順に表示せよ。
(例:n が 30 なら 3 9 27)

解答例

プロジェクト名:chap4-7-5 ソースファイル名:chap4-7-5.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

int main(void)
{
    int n;
    int p = 3;

    printf("正の整数を入力してください:");
    scanf("%d", &n);

    while (p <= n) {
        printf("%d ", p);
        p *= 3;
    }

    return 0;
}

まとめ:後置演算子は「表示→更新」を1行で自然に書ける

  • no-- は「今の値を使った後に減る」
  • i++ は「今の値を使った後に増える」
  • while文と組み合わせると、カウントダウン/アップが短く書ける
  • 表示は更新前、変数の最終値は更新後、ここは意識しておくと安心