C言語基礎|数字文字の出現回数

「0〜9を数えるだけで、文字処理と配列の基本が一気につながる!」

数字文字の出現回数を数えると、入出力の“実戦力”が身につく

文字を1つずつ読み込みながら、必要な情報だけを取り出して集計する――これはテキスト処理の王道パターンです。
今回のテーマは、その中でも分かりやすい 数字文字 0〜9 の出現回数カウント

ポイントは次の3つです。

  • getchar で1文字ずつ読み込む(EOF で終了)
  • 数字文字かどうかを判定する。
  • 配列 cnt[10] を「0〜9の箱」として使い、該当する箱を増やす。

サンプルプログラム

例:入力に含まれる数字文字の回数を数える

文字 '0' を引いて添字にする 方式のシンプルなプログラム例です。

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

#include <stdio.h>

int main(void)
{
    int ch;
    int cnt[10] = {0};

    puts("文字列を入力してください(終了は Ctrl+D または Ctrl+Z)。");

    while ((ch = getchar()) != EOF) {
        if ('0' <= ch && ch <= '9') {
            cnt[ch - '0']++;
        }
    }

    puts("数字文字の集計結果");
    for (int i = 0; i < 10; i++) {
        printf("%d : %d回\n", i, cnt[i]);
    }

    return 0;
}

実行例(イメージ)

文字列を入力してください(終了は Ctrl+D または Ctrl+Z)。
A1B20-9Z9
数字文字の集計結果
0 : 1回
1 : 1回
2 : 1回
3 : 0回
4 : 0回
5 : 0回
6 : 0回
7 : 0回
8 : 0回
9 : 2回

全体の流れ:読む→判定→数える→表示

処理の流れ(イメージ)

入力 → getcharで1文字読む → 数字なら cnt を増やす → EOFで終了 → 集計を表示

説明
このパターンは、英字カウント、単語数カウント、行数カウントなどにもそのまま応用できます。

配列 cnt[10] が意味するもの

cnt は「数字ごとの回数」を入れる10個の箱です。

cnt 配列の対応

数字文字添字意味
'0'00 の出現回数
'1'11 の出現回数
.........
'9'99 の出現回数

表の説明
数字の種類は10個なので、配列も10要素にするとピッタリ収まります。

なぜ cnt[10] = {0}; で全部0になるの?

int cnt[10] = {0};

これは「先頭要素を0で初期化」と書いているように見えますが、C言語では配列初期化のルールにより 残りの要素もすべて0 になります。

配列の0初期化のポイント

書き方結果
int cnt[10] = {0};cnt[0]〜cnt[9] が全部0
int cnt[10];中身は不定(ゴミ値の可能性)

表の説明
カウント処理は「最初は0」が大前提なので、ここはしっかり初期化するのが大切です。

switch を並べなくていい理由:文字と添字を対応させる

元の版だと、'0' なら cnt[0]++、'1' なら cnt[1]++ … と10個並びます。
でも、数字文字は並びが連続しているので、こうできます。

cnt[ch - '0']++;

ch - '0' の意味(イメージ)

ch が '0' → '0' - '0' = 0  → cnt[0]++
ch が '5' → '5' - '0' = 5  → cnt[5]++
ch が '9' → '9' - '0' = 9  → cnt[9]++

図の説明
文字は内部的には整数(文字コード)として扱われます。
数字文字は連続しているので、'0' を基準にずらすと 0〜9 が作れます。

数字かどうかの判定が必要な理由

もし数字以外でも cnt[ch - '0'] をやってしまうと、添字が変な値になって配列の外を触る危険があります。
だから必ずこの判定を入れます。

if ('0' <= ch && ch <= '9')

判定の役割

判定目的
'0' <= ch && ch <= '9'数字文字のときだけ配列を更新して安全にする。

getchar と EOF:いつまで読み続ける?

この while 条件式が、入力処理の定番です。

while ((ch = getchar()) != EOF)

Fig.3 条件式の読み方(分解)

(1) ch = getchar() で1文字読む
(2) それが EOF か調べる
(3) EOF でなければ繰り返す

図の説明
EOF は「入力がもうない」または「エラー」の合図です。
これが来るまで読み続けるので、ファイル読み込みにも同じ形が使えます。

登場する命令・構文の書式と役割

getchar の書式

int getchar(void);

何をする?
標準入力から次の1文字を読み込み、読めた文字を返します。読めないときは EOF を返します。

puts の書式

int puts(const char *s);

何をする?
文字列を表示し、最後に改行も出します。今回は案内メッセージ表示に使っています。

printf の書式

int printf(const char *format, ...);

何をする?
書式に従って表示します。今回は集計結果を見やすく出すために使っています。

while の書式

while (条件) {
    文;
}

何をする?
条件が真の間、繰り返します。EOF が来るまで読み続けるのに便利です。

if の書式

if (条件) {
    文;
}

何をする?
数字文字のときだけカウントする、という“安全装置”になります。

このプログラムの学びどころ

学べるポイント一覧

学びどこで出る?
文字を1つずつ読むgetchar と EOF
条件で選別するif ('0' <= ch && ch <= '9')
配列で集計するcnt[10] と cnt[...]++
文字→添字の変換ch - '0'
結果の表示for と printf

演習問題

演習8-9:標準入力に現れた行数をカウントせよ

標準入力から文字を読み込み、改行文字の数を数えて行数を表示するプログラムを作成せよ。
(入力終了は EOF)

解答例

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

#include <stdio.h>

int main(void)
{
    int ch;
    int lines = 0;

    puts("文章を入力してください(終了は Ctrl+D または Ctrl+Z)。");

    while ((ch = getchar()) != EOF) {
        if (ch == '\n')
            lines++;
    }

    printf("行数は%dです。\n", lines);
    return 0;
}

解説

  • 行の区切りは改行文字 \n
  • 1文字ずつ読んで、\n を見つけた回数を増やすだけ
  • 「読む→条件で数える→EOFで終了」は数字カウントと同じ型です