C言語 繰り返し(for文・while文)の練習問題

for文・while文を使う問題を、初級から上級まで13問そろえました。ブラウザでコードを書いて「採点する」を押すと、本物の gcc でいくつかの入力を試し、出力が正しいかを判定します。

この練習問題の使い方
  1. 問題文と実行例を読み、下の欄にコードを書く
  2. 「▶ 実行」で自分で入力を与えて動かしてみる
  3. 「✔ 採点する」で、用意したいくつかの入力に対して出力が正しいかを判定
  4. 行き詰まったら「ヒント」、解けたら「模範解答と解説」で確認
採点のルール
  • 出力は実行例と同じ形で表示する。「数を入力してください」のような入力を促すメッセージは表示しない
  • 行末の空白と、最後の空行の有無は区別しない
  • 書いたコードはこのブラウザに自動保存されます

※ 実行と採点では、コードを外部の無料コンパイルサービス Wandbox に送信して gcc で動かします。

全13問(初級 4・中級 5・上級 4)

for文・while文の練習問題(13問)

L01 初級

問1. 1からNまでの合計

整数 N(1 ≤ N ≤ 1000)を入力し、1 から N までの合計を表示せよ。
実行例(下線が入力)
10 合計: 55
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
合計を入れる変数 sum を 0 で初期化してから、for (i = 1; i <= n; i++) で sum += i; を繰り返します。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    int sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += i;
    }
    printf("合計: %d\n", sum);
    return 0;
}
解説:よくある間違いは2つです。sum を初期化し忘れると、中身が不定の値から足し始めてしまいます。条件を i < n にすると N が足されません(1 つ足りない「オフバイワン」)。
L02 初級

問2. 九九の表

九九の表(1の段〜9の段)を表示せよ。各段を1行とし、数値は %3d で幅3にそろえること。入力はない。
実行例
1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 (中略) 9 18 27 36 45 54 63 72 81
コードを書く
「実行」で入力を与えて動かす/「採点する」で 1 個のテストを自動で試します
for文を2重にします。外側のループが「段」(行)、内側のループが「かける数」(列)です。内側のループが終わったら printf("\n"); で改行します。
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            printf("%3d", i * j);
        }
        printf("\n");
    }
    return 0;
}
解説:2重ループでは、内側のループが1周し終わるごとに外側が1つ進みます。改行の printf("\n") を内側のループの中に書いてしまうと、1つ表示するたびに改行されます。
L03 初級

問3. N以下の偶数

整数 N(1 ≤ N ≤ 100)を入力し、2 以上 N 以下の偶数を小さい順に、空白区切りで1行に表示せよ。該当する数がないときは空の行を表示する。
実行例(下線が入力)
10 2 4 6 8 10
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
i を 2 から始めて i += 2 で増やせば、偶数だけを順に取り出せます。i % 2 == 0 で判定する方法でも解けます。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    for (int i = 2; i <= n; i += 2) {
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
解説:for文の3つ目(更新式)は i++ に限らず、i += 2 のように自由に書けます。この採点では行末の空白は無視するので、"%d " で末尾に空白が残っても正解になります。
L04 初級

問4. 階乗

整数 N(0 ≤ N ≤ 20)を入力し、N の階乗 N! を「N! = 値」の形で表示せよ。0! は 1 とする。
実行例(下線が入力)
5 5! = 120
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
掛け算を積み重ねる変数は 1 で初期化します。20! は int に入らない(約21億が上限)ので、long long 型と書式 %lld を使います。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    long long fact = 1;
    for (int i = 1; i <= n; i++) {
        fact *= i;
    }
    printf("%d! = %lld\n", n, fact);
    return 0;
}
解説:合計(足し算)の初期値は 0、積(掛け算)の初期値は 1 です。int のまま計算すると 13! 以降であふれて(オーバーフローして)おかしな値になります。N=20 のテストはこれを確かめています。
L05 中級

問5. 各桁の和

0 以上の整数 N(0 ≤ N ≤ 2000000000)を入力し、各桁の数字の和を表示せよ。
実行例(下線が入力)
12345 各桁の和: 15
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
n % 10 で一の位が取り出せ、n / 10 で一の位を捨てられます。これを n が 0 になるまで while文で繰り返します。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    int sum = 0;
    while (n > 0) {
        sum += n % 10;
        n /= 10;
    }
    printf("各桁の和: %d\n", sum);
    return 0;
}
解説:回数が前もって決まらない繰り返しは while文が向いています。「一の位を取り出す → 捨てる」は桁を扱う問題の定番の形なので、覚えておくと応用がききます。
L06 中級

問6. 0が入力されるまで合計

整数を次々に入力し、0 が入力されたら終了して、それまでに入力された数(0 は含まない)の個数・合計・平均を表示せよ。平均は小数第2位まで表示する。0 より前に1つも入力がなければ「データがありません」と表示する。
実行例(下線が入力)
3 5 7 0 個数: 3 合計: 15 平均: 5.00
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
while (1) で無限ループにして、読んだ値が 0 なら break で抜けます。平均は (double)sum / count のように片方を double にして割ります。
#include <stdio.h>

int main(void) {
    int x, count = 0, sum = 0;

    while (1) {
        scanf("%d", &x);
        if (x == 0) break;
        count++;
        sum += x;
    }

    if (count == 0) {
        printf("データがありません\n");
    } else {
        printf("個数: %d\n", count);
        printf("合計: %d\n", sum);
        printf("平均: %.2f\n", (double)sum / count);
    }
    return 0;
}
解説:sum / count と書くと整数どうしの割り算になり、小数部分が切り捨てられます。しかもその int の値を %.2f に渡すことになるので、表示はでたらめになります(未定義動作。0.00 と出る環境もあります)。コンパイラも警告を出すので、警告は必ず読みましょう。また count が 0 のまま割ると0除算になるので、先に分けて処理します。
L07 中級

問7. 約数の列挙

整数 N(1 ≤ N ≤ 10000)を入力し、N の約数を小さい順に空白区切りで1行に表示せよ。次の行に約数の個数を表示する。
実行例(下線が入力)
12 1 2 3 4 6 12 約数の個数: 6
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
1 から N までの i について、n % i == 0(割り切れる)なら約数です。表示と同時に個数も数えておきます。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    int count = 0;
    for (int i = 1; i <= n; i++) {
        if (n % i == 0) {
            printf("%d ", i);
            count++;
        }
    }
    printf("\n約数の個数: %d\n", count);
    return 0;
}
解説:ループの中に if文を入れて、条件に合うものだけ処理する形です。N 自身も約数なので、条件は i <= n にします。
L08 中級

問8. 直角三角形を描く

整数 N(1 ≤ N ≤ 20)を入力し、* で N 段の直角三角形を表示せよ。i 段目には * を i 個並べる。
実行例(下線が入力)
4 * ** *** ****
コードを書く
「実行」で入力を与えて動かす/「採点する」で 3 個のテストを自動で試します
外側のループで段 i を 1〜N と回し、内側のループで * を i 個表示します。内側の終了条件が外側の変数 i で決まるのがポイントです。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            printf("*");
        }
        printf("\n");
    }
    return 0;
}
解説:図形を描く問題は「i 段目に何を何個出すか」を式にするのがコツです。ここでは * が i 個なので、内側を j <= i にします。
L09 中級

問9. FizzBuzz

整数 N(1 ≤ N ≤ 100)を入力し、1 から N までを1行に1つずつ表示せよ。ただし 3 の倍数なら Fizz、5 の倍数なら Buzz、3 と 5 の両方の倍数なら FizzBuzz と表示する。
実行例(下線が入力)
15 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
判定の順番が大事です。最初に「15 の倍数か(3 と 5 の両方)」を調べ、次に 3、次に 5 の順に if〜else if で判定します。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        if (i % 15 == 0) {
            printf("FizzBuzz\n");
        } else if (i % 3 == 0) {
            printf("Fizz\n");
        } else if (i % 5 == 0) {
            printf("Buzz\n");
        } else {
            printf("%d\n", i);
        }
    }
    return 0;
}
解説:先に i % 3 == 0 を判定すると、15 のときも「Fizz」で止まってしまい、FizzBuzz が出ません。条件が重なるときは、より厳しい条件を先に書きます。
L10 上級

問10. N以下の素数を全部表示

整数 N(1 ≤ N ≤ 10000)を入力し、N 以下の素数を小さい順に空白区切りで1行に表示せよ。次の行に素数の個数を表示する(N が 1 のときは空の行と「素数の個数: 0」)。
実行例(下線が入力)
20 2 3 5 7 11 13 17 19 素数の個数: 8
コードを書く
「実行」で入力を与えて動かす/「採点する」で 5 個のテストを自動で試します
外側のループで候補 k を 2〜N と回し、内側のループで「2 から √k までのどれかで割り切れるか」を調べます。j * j <= k を条件にすると、√ を使わずに済みます。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    int count = 0;
    for (int k = 2; k <= n; k++) {
        int is_prime = 1;
        for (int j = 2; j * j <= k; j++) {
            if (k % j == 0) {
                is_prime = 0;
                break;
            }
        }
        if (is_prime) {
            printf("%d ", k);
            count++;
        }
    }
    printf("\n素数の個数: %d\n", count);
    return 0;
}
解説:「素数かどうか」を覚えておくフラグ変数(is_prime)を、候補ごとに 1 に戻すのを忘れないようにします。割り切れた時点で break すると無駄な計算を省けます。
L11 上級

問11. ピラミッドを描く

整数 N(1 ≤ N ≤ 20)を入力し、* で N 段のピラミッドを表示せよ。i 段目は、空白を N−i 個並べたあとに * を 2i−1 個並べる(行末に空白は付けない)。
実行例(下線が入力)
4 * *** ***** *******
コードを書く
「実行」で入力を与えて動かす/「採点する」で 3 個のテストを自動で試します
1つの段の中に内側のループを2つ並べます。1つ目で空白を n - i 個、2つ目で * を 2 * i - 1 個表示し、最後に改行します。
#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < n - i; j++) {
            printf(" ");
        }
        for (int j = 0; j < 2 * i - 1; j++) {
            printf("*");
        }
        printf("\n");
    }
    return 0;
}
解説:段ごとの個数を表にすると式が見えます(N=4 なら空白 3,2,1,0、星 1,3,5,7)。行頭の空白は採点で比べるので、数がずれると不正解になります。
L12 上級

問12. 最大公約数と最小公倍数

正の整数 a, b(1 ≤ a, b ≤ 100000)を空白区切りで入力し、最大公約数と最小公倍数を表示せよ。ユークリッドの互除法を使うこと。
実行例(下線が入力)
12 18 最大公約数: 6 最小公倍数: 36
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
互除法は「b が 0 になるまで、(a, b) を (b, a % b) に置き換える」だけです。そのときの a が最大公約数。最小公倍数は a / g * b(g は最大公約数)で求めます。結果は int に入らないことがあるので、(long long)a / g * b として %lld で表示します。
#include <stdio.h>

int main(void) {
    int a, b;
    scanf("%d %d", &a, &b);

    int x = a, y = b;
    while (y != 0) {
        int r = x % y;
        x = y;
        y = r;
    }
    int g = x;
    long long l = (long long)a / g * b;

    printf("最大公約数: %d\n", g);
    printf("最小公倍数: %lld\n", l);
    return 0;
}
解説:元の a, b は最小公倍数の計算で使うので、コピー(x, y)で互除法を回します。最小公倍数は約100億になることがあり int に入らないので long long で計算します。a * b / g の順だと掛け算の時点であふれやすいので、先に割ります。
L13 上級

問13. コラッツの問題

正の整数 N(1 ≤ N ≤ 100000)から始めて、「偶数なら 2 で割る、奇数なら 3 倍して 1 を足す」を N が 1 になるまで繰り返す。1 になるまでの操作の回数と、途中で現れた最大の値(N 自身を含む)を表示せよ。
実行例(下線が入力)
6 ステップ数: 8 最大値: 16
コードを書く
「実行」で入力を与えて動かす/「採点する」で 4 個のテストを自動で試します
while (n != 1) で回し、毎回 steps++ と最大値の更新をします。途中の値は N の数百倍になることもあるので、long long で扱うと安全です。
#include <stdio.h>

int main(void) {
    long long n;
    scanf("%lld", &n);

    int steps = 0;
    long long max = n;
    while (n != 1) {
        if (n % 2 == 0) {
            n /= 2;
        } else {
            n = 3 * n + 1;
        }
        steps++;
        if (n > max) max = n;
    }
    printf("ステップ数: %d\n", steps);
    printf("最大値: %lld\n", max);
    return 0;
}
解説:何回繰り返すか分からない典型的な while文の問題です。最大値の初期値を N 自身にしておかないと、N=1 のとき最大値が正しく出ません。途中の値は N よりはるかに大きくなります(N=77031 では約2193万、N をもっと大きくすると int の上限を超えます)。

復習する講座

← 練習問題の一覧へ