C言語基礎|6章のまとめ

6章、おつかれさま!ここまで来たあなたはもう「Cの関数を“呼べる”」だけじゃなくて、関数を“設計できる”入口に立ってます。
この章で学んだのは、関数そのものの作り方だけじゃなくて、

  • どうすれば再利用しやすい部品になるか
  • 配列や多次元配列をどう安全に渡すか
  • 変数の見える範囲(有効範囲)と寿命(記憶域期間)をどう把握するか

みたいな、ちょっと大きめのプログラムを書くための土台でした。
このまとめでは、6章の重要ポイントを「見返しやすい形」に整理しつつ、最後に“章全体を一気に復習できる別プログラム例”も用意します。

6章で身につけたことを一枚に整理

6章の重要キーワード早見表

テーマひとことで代表キーワード
関数手続きを部品化する返却値型、仮引数、呼出し
値渡し引数はコピーで渡る実引数、仮引数、値渡し
void関数値を返さず処理だけするvoid、return;
関数原型宣言先に仕様を伝えるprototype、セミコロン
ヘッダとインクルードライブラリの仕様を取り込む#include、stdio.h
配列の受渡し配列名+要素数で渡すv[]、const、n
線形探索・番兵法探して見つける/高速化FAILED、sentinel
有効範囲名前が見える範囲ブロック、ファイル、隠蔽
記憶域期間変数の寿命auto、static

(この表は「どの話がどこにつながるか」を俯瞰するための地図です。以降、各項目を短く確実に復習します。)

関数はプログラムの部品

関数は「ひとまとまりの処理」を切り出して部品化したもの。部品化のメリットはこれです。

  • 同じ処理を何度も書かなくていい(再利用)
  • main が短くなって読みやすい(見通し)
  • 仕様が決まれば中身を入れ替えやすい(保守)

関数を特徴づける3要素

要素意味
返却値型int / double / void関数が返す値の型
関数名ave2 / search何をする関数か
仮引数型並び(int a, int b)受け取る値の型と個数

関数呼出しとプログラムの流れ

関数呼出しは「関数名(実引数...)」の形。呼ぶと流れが関数へ移動し、終わると戻ってきます。

関数呼出しの基本書式

ポイント
引数なしhello()丸括弧は必要
引数ありave2(n1, n2)実引数はコンマ区切り
返り値を使うx = ave2(3, 5)式として扱える

引数の受渡しは値渡し

Cの引数は基本的に 値渡し(コピー渡し)
だから「仮引数を書き換えても、実引数は変わらない」でしたね。

値渡しのイメージ(コピー)

この図が意味すること

  • 受け取った側の x を変更しても、呼び出し側の a はそのまま
  • “安心して呼べる”のが値渡しの強み

void関数は「処理だけする部品」

値を返さない関数は返却値型を void にします。

return と void の関係

関数の返却値型return の役割
int / double などreturn 値; で値を返す
voidreturn; で早期終了できる(省略もOK)

関数原型宣言と関数定義

「まだ定義されていない関数を先に呼びたい」なら、先に仕様だけ書いておく必要があります。これが関数原型宣言。

宣言と定義の違い

種類実体を作る?
関数原型宣言int top(void);作らない(仕様だけ)
関数定義int top(void){...}作る(中身を持つ)

ヘッダとインクルード

printf や scanf の仕様(関数原型宣言など)はヘッダにあります。だから #include で取り込みます。

#include の書式

書式意味
システムヘッダ#include <stdio.h>標準ライブラリ等
自作ヘッダ#include "my.h"自分のヘッダ等

インクルードのイメージ

#include <stdio.h>
↓(取り込み)
stdio.h の中身がここに入ったように扱われる

配列の受渡しと const

配列は「配列名」を渡すと、受け取る側では“同じ配列”を扱う形になります。
だから書き換えられる可能性がある。読み取り専用なら const を付けるのが礼儀です。

配列引数の基本ルール

目的仮引数の宣言意味
読むだけconst int v[]関数内で代入禁止にする
書き換えるint v[]要素変更が可能

多次元配列引数の宣言規則(要点)

多次元配列は「一番外側(行数など)は可変にできる」が、「内側(列数など)は固定が必要」でした。

多次元配列引数の典型

次元可変にできるのは?
1次元int v[], int n要素数 n
2次元int v[][3], int n行数 n(列数3は固定)
3次元int v[][2][3], int n最外の要素数 n(内側2,3は固定)

有効範囲と記憶域期間(混同しやすい所)

同じ「変数」でも、

  • 名前がどこで見えるか(有効範囲)
  • いつ生まれていつ消えるか(記憶域期間)
    は別物です。

表:最後にここだけは押さえる

用語何の話?
ブロック有効範囲そのブロック内で名前が通用forの中の変数
ファイル有効範囲ソース末尾まで名前が通用グローバル変数
自動記憶域期間ブロックを抜けたら消える関数内の普通の変数
静的記憶域期間終了まで生き続けるstatic 変数、グローバル

サンプルプログラムで6章を一気に復習

元の「二つの整数の平均」ではなく、配列の平均+警報+staticで呼び出し回数表示に変えます。
表示メッセージも別の日本語に置き換えています。

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

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

// 6章まとめ復習:配列、const、void、static、関数原型宣言

#include <stdio.h>

double ave_array(const int a[], int n);  // 関数原型宣言
void beep_n(int n);                      // void関数
void show_calls(void);                   // staticを使う

double ave_array(const int a[], int n)
{
    double sum = 0;

    for (int i = 0; i < n; i++)
        sum += a[i];

    return sum / n;
}

void beep_n(int n)
{
    for (int i = 0; i < n; i++)
        putchar('\a');
}

void show_calls(void)
{
    static int count = 0;
    count++;
    printf("show_calls:%d回目の呼び出しです。\n", count);
}

int main(void)
{
    int scores[5];

    puts("5つの値を入力してください。");
    for (int i = 0; i < 5; i++) {
        printf("scores[%d]:", i);
        scanf("%d", &scores[i]);
    }

    show_calls();

    printf("平均は%.2fです。\n", ave_array(scores, 5));

    puts("合図としてビープ音を2回鳴らします。");
    beep_n(2);

    return 0;
}

このプログラムで復習できる対応関係

scores[] を渡す → 配列の受渡し
const int a[]    → 読み取り専用の配列引数
double ave_array → 返り値のある関数
void beep_n      → 値を返さない関数
show_calls static→ 静的記憶域期間
関数原型宣言     → mainより前に仕様を書く

登場する命令の書式(まとめ用)

この章で頻出の“書き方”

命令・要素書式何をする?
関数原型宣言返却値型 関数名(引数);仕様を先に伝える
関数定義返却値型 関数名(引数){…}実体(中身)を作る
#include#include <stdio.h>ヘッダを取り込む
配列引数const int v[], int n配列+要素数で受け取る
void関数void f(void)値を返さない
static変数static int x;値を保持し続ける