このスライドの使い方

  • 画面下の「▶」で再生開始、「⏸」で一時停止

  • 画面右下の「>」で次頁へ、「<」で前頁へ

  • 青字下線の部分は、まとめプリントの穴埋め

  • 作業」のところでは、ファイルをダウンロードしてコンパイル・実行

第 6 章
「関数」

教科書 pp.141–179

§ 6-1「関数とは」
(教 pp.142–151)

main 関数とライブラリ関数
(教 p.142)

関数とは(教 p.142)

繰返し使うプログラムの一部の命令列を部品として、再利用できるようにしたもの
(他の言語ではサブルーチン・手続き・副プログラムなどと呼ばれる)

関数定義(教 p.143)

分類 一般形
関数定義 関数名 ( 変数名1 ,, 変数名n ) 複合文

  • 関数定義には型が必要である
  • かっこの中の変数(変数名1〜変数名n)は仮引数 (parameter) と呼ばれる

関数定義(つづき)

  • C の関数定義は必ずプログラムのトップレベルに書く
    • 関数定義の中に関数定義は書けない。
    • 他のブレース「{」〜「}」の中に入らない
  • 後述のプロトタイプ宣言をしているときを除き、使うよりも先(上)に書く

関数呼出し式(教 p.144)

分類 一般形
関数呼出し式 関数名 ( 1 ,, n )
  • 関数呼出しには型は不要である
  • かっこの中の式1〜式n実引数 (argument) と呼ばれる

これで文法上、式 (expression) になる

注: ここのコンマはコンマ演算子ではない。

作業: List 6-1 を実行する

関数呼出し式 (つづき)

関数を呼出すと、

  • プログラムの実行は呼び出された関数の定義の先頭に移り、
  • 実引数の値が仮引数の変数の初期値になる

return 文(教 p.145)

分類 一般形 補足説明
return 文 return ;
return ;
値を返す場合
値を返さない場合

関数の呼出し元に値を返す

  • プログラムの実行が関数の呼出し元に戻り、
  • return 文の式の値が、関数呼出し式の値になる

関数本体の最後の閉じブレース「}」にたどり着いたときも、プログラムの実行は関数の呼出し元に戻る

return 文を一個にする必要はない

3 値の最大値を求める関数
(教 p.147)

作業: List 6-2 を実行する

関数の返却値を引数として関数に渡す
〜自作の関数を呼び出す関数
(教 pp.148–149)

作業: List 6-3 を実行する

作業: List 6-4 を実行する

値渡し(pass by value)(教 p.150)

引数は基本的に値がやりとりされる

  • 関数呼出しのたびに仮引数のための新しいメモリ領域(“箱”)が用意される
  • 仮引数の変数に値の代入を行なっても、呼出し元の実引数は影響を受けない
    作業: List 6-6 を実行する

§ 6-2「関数の設計」
(教 pp.152–171)

値を返さない関数(教 p.152)

関数の定義の返却値型を書くところに void と書く

作業: List 6-7 を実行する(幾通りかの入力を試す)

関数の汎用性(教 p.152)

教科書を読んでおく

引数のない関数(教 p.154)

関数の定義の仮引数のならびを書くところにvoidと書く

  • 関数の定義の仮引数のならびを空にすると、古い C 言語の規格で書かれていると見なされてしまい、意味が変る

関数を呼出すときは () のなかは空にする

作業: List 6-9 を実行する

rev_int 関数(教 p.154)

こう書くべき


int rev_int(int num) {
    int tmp = 0;
    while (num > 0) {
        tmp = tmp * 10 + num % 10;
        num /= 10; 
    }
    return tmp;
}

ブロック有効範囲 (スコープ、scope)
(教 p.155)

変数には有効範囲がある

  • 同じ変数名でも有効範囲が異なれば別の変数
  • ブロック(教 p.60)の中で宣言された変数(局所変数、ブロック有効範 囲を持つ変数)は、宣言された場所から、ブロックの最後までが 有効範囲

  • 関数の仮引数は、その関数本体が有効範囲

ファイル有効範囲(教 p.156)

  • 関数の外で宣言された変数(大域変数・グローバル変数、ファイル有効 範囲を持つ変数)は、宣言された場所からファイルの終端までが 有効範囲
    (どうしても必要でない限り使わないこと)

宣言と定義(教 p.156)

教科書を読んでおいてください

関数プロトタイプ宣言
(function prototype declaration)(教 p.157)

関数を定義より前に(あるいは定義されているのと別のファイルで)使用する場合は、 関数プロトタイプ宣言が必要

分類 一般形
関数プロトタイプ宣言 関数名 ( 変数名 ,, 変数名 ) ;

変数名は省略可能

関数プロトタイプ宣言(つづき)

関数定義がその呼出しよりも前にある場合は、定義が宣言を兼ねるのでプロト タイプ宣言は不要

  • いずれにしても、実行は常に mainから開始される

ヘッダーとインクルード(教 p.158)


#include <stdio.h>

の stdio.h は、printf, putchar などの関数 のプロトタイプ宣言が集められたもの(通常はファイル)

このようにプロトタイプ宣言やマクロの定義が集められたものヘッダーと呼ぶ

ヘッダーとインクルード(続き)

  • #include はヘッダーの内容を、そっくりそのままその場所に読み込む (インクルードする)指令である
  • 標準のヘッダーがおかれる場所は処理系により異なる
  • ライブラリー関数(前もって用意された関数)を利用するときは、ほとんどの 場合、適切なヘッダーをインクルードする必要がある
    • 例えば sin, cos, sqrt などの数学関数を 利用するときは math.h をインクルードする

関数の汎用性(教 p.159)

できるだけ大域変数を使わないようにする

配列の受渡し(教 p.160)

関数の引数として配列を渡すこともできる
仮引数の宣言は、

型 引数名[]

としておき、 実引数としては配列の名前だけ書く

作業: List 6-11 を実行する

配列の受渡し(つづき)

  • 関数に配列を引数として渡す場合、コピーではなく、配列そのもの (正確にいうと、配列の先頭要素のアドレス)が渡される(重要)

    • 関数の中で、配列の要素の値を変更すると、 呼出し側の配列に反映される
    • 一方、int, double 型などの配列でない普通の型の引数の場合は、 値がコピーされて渡される(プログラム例の cbv.c 参照)
    • int, double 型などの普通の型の引数の場合は、呼出し側には反映されない
  • 引数として渡された配列の要素数を関数の中で知る方法はないので、 通常は要素数も引数として渡す必要がある

const型修飾子(教 p.162)

作業: List 6-12 を実行する

関数の引数の配列が書換えられないことを保証するためには const という型修飾子を仮引数の宣言につける

  • const をつけているのに、その変数を書き換えようとする とコンパイル時にエラーになる

作業: List 6-12x を実行する

値呼びの確認 (cbv.c)
(まとめのプリント・章末)

作業: cbv.c を実行する

線形探索(逐次探索)(教 p.164)

教科書を読んでおく

番兵法 (sentinel)(教 p.166)

探索の対象となっているデータ(番兵 (sentinel))をデータの最後 に付け加えること

  • 探索範囲の終わりのチェックをする必要がなくなるので、少し効率が良くなる

多次元配列の受渡し(教 p.170)

教科書を読んでおく

作業: List 6-16 を実行する

§ 6-3「有効範囲と記憶域期間」(教 pp.172–177)

有効範囲と識別子の可視性
(教 p.172)

同名の変数の有効範囲が重なるとき、 より内側のブロックで宣言されているものが優先する

作業: List 6-17 を実行する

記憶域期間(教 p.174)

C 言語の変数の寿命(記憶クラス, storage class)には 2 種類のものがある

自動変数 (automatic variable)
— 自動記憶域期間を持つ変数

  • 関数の中で定義された変数で static という修飾 子がついていないもの

  • プログラムの流れが宣言を通過するときに、変数のための領域(箱)が確保され、 初期化される。有効範囲を抜ける時に箱が回収される

  • 初期化子が与えられていない場合、その値は不定値となる

静的変数 (static variable)
— 静的記憶域期間を持つ変数

  • 関数の外で定義・宣言された変数、または関数の中で宣言された変数で、 staticという修飾子がついているもの

  • プログラムの開始時に変数のための領域(箱)が生成され、 初期化される。プログラムの終了時まで回収されない

  • 初期化子が与えられていない場合、0 に初期化される

静的変数は、過去の呼出しによって結果が変わるような関数の場合には必要となる
(逆に言うと、必要なければ使うべきではない

作業: List 6-18 を実行する

第 6 章・終