
C言語基礎|8章のまとめ
「マクロ・ソート・列挙体・再帰・入出力――“道具箱”が一気に増える、第8章総復習!」
第8章は“C言語で作れること”が急に広がる章
第8章は、いろいろなミニプログラムを題材にしながら、C言語の実戦力をぐっと上げる章でした。
- コードを短く強くする:関数形式マクロ、コンマ演算子
- データを扱う力:ソート、列挙体
- 考え方の幅:再帰
- 入出力の基礎体力:getchar、EOF、文字コード、エスケープシーケンス
ここでは「何を学んだか」を表で整理しつつ、章末のサンプルも 別のシンプルな例に差し替え、表示メッセージも 別の日本語にしてまとめ直しますね。

第8章で学んだこと一覧(全体の見取り図)
第8章のトピックと要点
| テーマ | ひとことで | できるようになること |
|---|---|---|
| 関数形式マクロ | 引数つきで展開されるマクロ | 型をまたいだ短い記述、処理の共通化 |
| マクロの副作用 | 引数が複数回評価される危険 | a++ などを安全に扱う意識がつく |
| コンマ演算子 | a と b を順に評価し、値は b | 複数処理を「1つの式」として書ける |
| ソート(バブルソート) | 隣同士を比べて入れ替える | 配列の並べ替えの基本が分かる |
| 列挙体 | 限られた値に名前を付ける | 選択肢を安全・読みやすく表現できる |
| 名前空間 | enumタグと変数名は別枠 | 同じ綴りでも区別できる理由が分かる |
| 再帰 | 同じ関数を自分の中から呼ぶ | 分割統治や木構造の入口を理解できる |
| 文字入出力 | getchar と EOF | 1文字ずつ処理するループが書ける |
| 文字コード | 文字は整数 | '0' と 0 の違いが腹落ちする |
| エスケープ | 見えない文字を表す | \n や " を正しく扱える |
表の説明
章全体は「小技」ではなく、実装の幅を増やすための“道具セット”です。どれも後の章や実務で何度も登場します。
関数形式マクロ:置換ではなく展開で“式”を作る
オブジェクト形式マクロは単純置換、関数形式マクロは 引数つきで展開されます。
マクロの種類の違い
| 種類 | 書き方の例 | 何が起きる? |
|---|---|---|
| オブジェクト形式マクロ | define PI 3.14159 | PI が 3.14159 に置換される |
| 関数形式マクロ | define max2(a,b) ... | max2(式,式) が定義通りに展開される |
| 引数なし関数形式マクロ | define alert() ... | alert() が展開される(呼び出し風) |
表の説明
関数形式マクロは「呼び出しっぽく書けるけど関数ではない」のがポイントです。コンパイル前の段階で展開されます。
命令の書式:define
- 書式(オブジェクト形式)
#define マクロ名 置換テキスト - 書式(関数形式)
#define マクロ名(仮引数...) 置換テキスト
何をする命令?
define はプリプロセッサへの指示で、ソースコードを翻訳(コンパイル)する前に、指定した規則で置換・展開します。
副作用:マクロは“引数が何回評価されるか”に注意
関数形式マクロの落とし穴は、引数が展開後に 複数回出てくると、そのぶん評価されることです。
副作用が起きる典型例(イメージ)
定義:sqr(x) は (x) * (x)
呼出:sqr(a++)
展開: (a++) * (a++)
結果:a が2回増える
図の説明
関数なら引数は一度だけ評価して仮引数に渡しますが、マクロは展開された式として評価されるため、同じ引数が複数回出るとそのまま複数回動きます。
コンマ演算子:複数の処理を“1つの式”としてまとめる
コンマ演算子 a, b は a を評価して捨て、b の値を結果にする演算子です。
コンマ演算子のルール
| 形 | 評価順 | 式全体の値 |
|---|---|---|
| a, b | a → b | b の評価結果 |
表の説明
if の本体などで「式1個」を求められる場所に、複数の処理を置きたいときに役立ちます。マクロと相性がいいです。
ソート:バブルソートは“比較と交換”の繰り返し
ソートは、データを昇順・降順に並べ替えること。バブルソートは隣同士を比べて入れ替える素朴な方法です。
バブルソートの1パスのイメージ(昇順)
後ろから見ていき、逆なら交換
…を繰り返すと、小さい値が前へ寄っていく
図の説明
本文の例では「末尾から先頭へ走査」して、最小値が先頭に寄っていく説明でした。走査方向は実装により変えられますが、考え方は同じです。
列挙体:限られた値に“名前”を付ける
列挙体は「選択肢の集合」を作るのが得意です。数値そのものではなく 名前で表現できて読みやすくなります。
列挙体の基本要素
| 用語 | 例 | 意味 |
|---|---|---|
| 列挙体タグ | enum RGB | 列挙型の識別のためのタグ |
| 列挙定数 | Red, Green, Blue | 個々の値(中身は整数) |
| 型名 | enum RGB | これが型名(RGB だけでは型名にならない) |
表の説明
列挙体タグ RGB は「タグ」、型として使うときは enum RGB と書きます。ここが最初の注意点です。
名前空間:enumタグ名と変数名は“別枠”
C言語では、識別子は用途ごとに別の名前空間に所属します。
そのため、列挙体タグと変数名が同じ綴りでも区別される場合があります。
名前空間のイメージ
enum のタグ名 と 変数名 は別の箱に入っている
同じ綴りでも衝突しないことがある
図の説明
現実のコードでは混乱しやすいので、同名にしないのが無難ですが、「区別される理由」を知っておくと読み解きが楽になります。
再帰:同じ関数を呼び出して問題を小さくする
再帰は「自分と同じ関数を呼ぶ」ことで、問題を小さく分けながら解きます。
ただし、終了条件がないと無限に呼び続けるので、必ず 止まる条件が必要です。
再帰のチェックポイント
| 観点 | 何を見る? |
|---|---|
| 終了条件 | どこで止まる? |
| 分割 | 1回の呼び出しで問題が小さくなる? |
| 戻り | 戻りながら答えを組み立てられる? |
表の説明
階乗は再帰の入門にちょうどよい例ですが、実務では木構造・探索・分割統治で本領を発揮します。
文字入出力:getchar と EOF、そして文字コード
getchar は1文字読み込み、読み込めないと EOF を返します。
さらに C言語では、文字は整数(文字コード)として扱われます。
getchar と EOF の要点
| 項目 | 内容 |
|---|---|
| getchar の戻り値 | int(EOF を扱うため) |
| EOF | 入力終了やエラーを表す特別な値(多くは負) |
| 典型ループ | while ((ch = getchar()) != EOF) |
表の説明
char ではなく int で受けるのは、EOF と区別するためです。ここは超重要です。
数字文字の性質:'0' からの差で 0〜9 にできる
数字文字 '0'〜'9' は 1ずつ増える関係が保証されるので、ch - '0' で 0〜9 に変換できます。
変換のイメージ
'0' - '0' = 0
'5' - '0' = 5
'9' - '0' = 9
図の説明
文字コードの値そのもの(例:48)を直接使わずに済むので、環境が変わっても動きやすい書き方になります。
エスケープシーケンス:引用符や改行を安全に書く
単一引用符や二重引用符は、文字列や文字定数の中でルールが変わります。
引用符とエスケープの要点
| 目的 | 使う表記 |
|---|---|
| 文字列の中で " を書く | " |
| 文字定数の中で ' を書く | ' |
| 改行 | \n |
| 逆斜線そのもの | \ |
表の説明
一番よくやるミスは「文字列の中の " をそのまま書く」ことです。" を習慣にすると安心です。
サンプルプログラム
まとめ例1:列挙体で「メニュー選択」を表示する
#include <stdio.h>
enum Menu { Coffee, Tea, Water };
int main(void)
{
int sel;
printf("0~2を入力してください:");
scanf("%d", &sel);
printf("選んだ飲み物は ");
switch (sel) {
case Coffee: printf("コーヒー"); break;
case Tea: printf("お茶"); break;
case Water: printf("水"); break;
default: printf("未対応"); break;
}
printf(" です。\n");
return 0;
}この例で確認できること
- enum Menu の列挙定数は 0,1,2 になる
- switch の case ラベルに列挙定数を使うと読みやすい
- default を入れると不正入力にも対応しやすい
登場する命令の役割
- enum:列挙型を宣言するためのキーワード
- switch / case / break:値に応じて分岐する構文
- printf / scanf:入出力(標準出力・標準入力)
まとめ例2:マクロ+コンマ演算子+getchar+EOF+数字処理を一気に使う
数字の合計を出しつつ、改行が来たら区切り線を出すプログラムです。
プロジェクト名:chap8-15-2 ソースファイル名:chap8-15-2.c
#include <stdio.h>
// 区切り線を出す(引数なし関数形式マクロ)
#define separator() (puts("-----"))
// 文字cを表示して改行(コンマ演算子で1つの式にする)
#define putchar_ln(c) (putchar(c), putchar('\n'))
int main(void)
{
int ch;
int sum = 0; // 入力中の数字の合計
puts("文字を入力してください(終了は Ctrl+D または Ctrl+Z)。");
while ((ch = getchar()) != EOF) {
if (ch >= '0' && ch <= '9')
sum += ch - '0';
if (ch == '\n') {
separator();
} else {
putchar_ln(ch);
}
}
printf("入力された数字の合計は%dです。\n", sum);
return 0;
}まとめ例2で使った要素
| 要素 | どこで使った? | 何がうれしい? |
|---|---|---|
| 引数なし関数形式マクロ | separator() | 呼び出しっぽく書けて読みやすい |
| コンマ演算子 | putchar_ln(c) | 複数処理を1つの式にまとめられる |
| getchar と EOF | while ループ | 1文字ずつ読み、終端で止まれる |
| 数字文字判定 | ch >= '0' && ch <= '9' | 文字→数値変換の前に安全確認 |
| ch - '0' | sum += ... | 可搬性を保った変換 |
表の説明
この1本で「第8章の要点が何度も出てくる」構成になっています。短いのに学びが濃いです。
