Download presentation
Presentation is loading. Please wait.
1
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
C言語入門 第8週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
2
関数定義と関数呼び出し
3
関数の宣言・定義・利用 書式: 教科書 pp.149-160. 関数の宣言 戻り値の型 関数名(引数の宣言, ...);
.h ファイルへ書き出す 関数の定義 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 } .c ファイルへ書き出す 関数の利用 変数名 = 関数名(引数, ...); 適宜呼び出す
4
関数(サブルーチン) C 言語は処理を関数にしてまとめる main も関数 教科書 pp.149-160. コマンドライン引数の数
c_template.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { // Here is a main routine. return EXIT_SUCCESS; } コマンドライン引数を格納した 複数の文字列へのポインタ 関数名、引数、戻り値の定義 関数の本体 フルセットの main 関数
5
(ユーザー定義)関数 関数は自分で作ることが出来る 関数の定義の書式: 機能、分量等、ある程度まとまった処理は 関数にまとめる
教科書 pp (ユーザー定義)関数 関数は自分で作ることが出来る 機能、分量等、ある程度まとまった処理は 関数にまとめる 可読性が向上する 再利用が容易になる 関数の定義の書式: C言語の関数は 0個以上の引数と 0または1個の戻り値を持つ。 引数や戻り値が不要な場合は void を宣言するよう 推奨されている。 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 }
6
return 文 return 戻り値; 関数から抜けて呼び出し元へ戻り値を渡す return_ex1.c int sub() {
printf("hello\n"); } void main() int x = sub(); printf("%d\n", x); return文に与えた値が 関数の戻り値になり 演算に使用される return文を実行すると 呼び出し元に戻るので それ以降の文は 実行されない mintty + bash + GNU C $ gcc return_ex1.c && ./a 123
7
return 文 戻り値の型は必要に応じて適切な型を選ぶ return_ex2.c int sub() { return 1.23; }
void main() double x = sub(); printf("%f\n", x); 例えばもし 浮動小数点数の値を 戻したいなら 戻り値の型は doubleでないといけない この例では戻り値の型はintなので return文にdoubleを与えても 戻り値はint型にキャストされるので 整数になる mintty + bash + GNU C 訂正 誤: double = sub(); 正: double x = sub(); $ gcc return_ex2.c && ./a
8
関数のプロトタイプ宣言 関数は使う前に宣言されている必要がある prototype_ex1_err.c void main()
{ double x = sub(); printf("%f\n", x); } double sub() return 1.23; 未宣言の関数の引数や戻り値は int型を仮定して暗黙的に宣言される 異なる引数や戻り値で同名の関数は 関数名が競合するため利用出来ない mintty + bash + GNU C $ gcc prototype_ex1_err.c prototype_ex1_err.c:9:8: エラー: ‘sub’ と型が競合しています double sub() ^ prototype_ex1_err.c:5:14: 備考: 前の ‘sub’ の暗黙的な宣言はここです double x = sub();
9
関数のプロトタイプ宣言 関数は使う前に宣言されている必要がある prototype_ex1.c double sub();
void main() { double x = sub(); printf("%f\n", x); } double sub() return 1.23; int型以外の引数や戻り値を持つ関数は あらかじめプロトタイプ宣言されていなければならない mintty + bash + GNU C $ gcc prototype_ex1.c && ./a
10
(ユーザー定義)関数の例 閏年の判定を関数にまとめてみる 教科書 pp.149-160. leap_year_func_ex4_2.c
#include <stdio.h> #include <stdlib.h> int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } int main() { int year; fprintf(stderr, "year = ?\b"); scanf("%d", &year); printf("%d is%s leap year.\n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; 関数の定義 自分で作成した関数を サブルーチンとして呼ぶ
11
(ユーザー定義)関数の例 関数を使う前にはパラメータの型と数が 分かっている必要がある(コンパイラの都合) 教科書 pp.153-160.
#include <stdio.h> #include <stdlib.h> int main() { int year; fprintf(stderr, "year = ?\b"); scanf("%d", &year); printf("%d is%s leap year.\n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; } int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; 使う時点で不明な戻り値の型はintを仮定される。 引数については何も仮定しない。 もし、実際に定義されている関数の型が異なると 型が競合してエラーになる。 型が不明なので、このタイミングで int is_leap_year(int); が仮定される。 [1] pp
12
関数のプロトタイプ宣言 関数は使う前にプロトタイプ宣言する 教科書 pp.149-160. 関数のプロトタイプ宣言
#include <stdio.h> #include <stdlib.h> int is_leap_year(int year); int main() { int year; fprintf(stderr, "year = ?\b"); scanf("%d", &year); printf("%d is%s leap year.\n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; } 関数のプロトタイプ宣言 戻り値の型、引数の数と型を宣言する 関数のプロトタイプ宣言さえしておけば 関数の定義はどこにあっても良い。 例えば外部のファイルにあっても良い。
13
関数をファイルに分離する 再利用性が高まる(コピペしなくて良くなる) 教科書 pp.203-206. is_leap_year_func.h
ヘッダファイル #ifndef IS_LEAP_YEAR_FUNC_H #define IS_LEAP_YEAR_FUNC_H int is_leap_year(int year); #endif include ガード(二重includeを防ぐ) 関数の宣言 他所から使う際に、 関数名、引数、戻り値の 情報を得るために必要 is_leap_year_func_ex4_2.c 関数本体のソースファイル #include "is_leap_year_func.h" int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } 関数本体の定義
14
ファイルに分離した関数の利用 main 関数の部分 教科書 pp.203-206. is_leap_year_main.c
#include <stdio.h> #include <stdlib.h> #include "is_leap_year_func.h" int main() { int year; fprintf(stderr, "year = ?\b"); scanf("%d", &year); printf("%d is%s leap year.\n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; } ヘッダファイルの include 外部ファイルで定義した 関数を呼び出し
15
分割コンパイル コンパイルする複数のCのソースファイルを コンパイラに与えれば良い
mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex4_2.c コマンドプロンプト + Borland C++ >bcc32 is_leap_year_main.c is_leap_year_func_ex4_2.c 与えるのはCのソースファイルのみ ヘッダファイルは #include 文により 自動的に取り込まれる
16
プリプロセッサ 条件付きコンパイル 条件に合った箇所のみを コンパイラに渡す構文 定数式の結果は0と非0の真偽値 定数式なら 演算も可能
#if 定数式 #elif 定数式 #else #endif #if 0 // ここはコンパイルされない #if defined(__BORLANDC__) // __BORLANDC__ という名前のマクロが // 定義されていた場合のみコンパイルされる #if defined(__BORLANDC__) && 0x0551 <= __BORLANDC__ // ... 条件に合った箇所のみを コンパイラに渡す構文 定数式の結果は0と非0の真偽値 定数式なら 演算も可能
17
プリプロセッサ 条件付きコンパイル #if defined( ) の短縮表記 #if !defined( ) の短縮表記
#ifdef __BORLANDC__ // ... #endif #ifndef __BORLANDC__ #if defined( ) の短縮表記 #if !defined( ) の短縮表記
18
プリプロセッサ 定義済みマクロ __LINE__ 現在の行番号 __FILE__ 現在のファイル名 __func__ 現在の関数名(C99)
__FUNC__ 現在の関数名(Borland C++) #ifdef __BORLANDC__ #define __func__ __FUNC__ #endif Borland C++ で C99互換の定義済みマクロが 使えるようにする 条件付きコンパイル
19
関数をファイルに分離する 作業用変数を用いる場合 教科書 pp.203-206. ローカル変数 ブロック内の作業用。 ブロック外に
同じ名前の変数があっても 競合せず安全に使える。 is_leap_year_func_ex1_1.c #include "is_leap_year_func.h" int is_leap_year(int year) { int leap_year_flag; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } return leap_year_flag; ローカル変数の宣言 ブロック(複文) { } で囲まれた領域の事 ここは leap_year_practice_2.c そのまま 結果を戻り値として返す
20
関数の差し替え 関数のプロトタイプ宣言が同じなら関数は差し替えて使える。
mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex4_2.c 実装は異なるが プロトタイプ宣言が同じ関数を 定義したファイルで差し替え mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex1_1.c
21
変数のスコープ(有効範囲) 大域(グローバル)変数 局所(ローカル)変数 プログラム全体からアクセス可能 ブロック内からのみアクセス可能
教科書 pp 変数のスコープ(有効範囲) 大域(グローバル)変数 プログラム全体からアクセス可能 局所(ローカル)変数 ブロック内からのみアクセス可能 C言語では { } で 囲まれた部分がブロック
22
変数のスコープ(有効範囲) ローカル変数は{}の中のみで有効 教科書 pp.161-169. scopetest.c
関数外で宣言するとグローバル変数 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int gl = 100; void sub(int lo) { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d\n", __func__, __LINE__, ++gl, ++lo); } int main() int lo = 200; sub(300); return EXIT_SUCCESS; 関数の引数はローカル変数 ブロックを作成するとローカル変数の有効範囲を制限出来る
23
変数のスコープ(有効範囲) ローカル変数は{}の外側に影響していない $ gcc scopetest.c && ./a
教科書 pp 変数のスコープ(有効範囲) ローカル変数は{}の外側に影響していない scopetest.c 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int gl = 100; void sub(int lo) { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d\n", __func__, __LINE__, ++gl, ++lo); } int main() int lo = 200; sub(300); return EXIT_SUCCESS; mintty + bash + GNU C $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201
24
教科書 pp 関数の演習 is_leap_year_func_ex1_1.c、is_leap_year_func_ex4_2.c を参考に以下のファイルの処理を関数にしてファイルに分離してみましょう。 leap_year_ex1_2.c → is_leap_year_func_ex1_2.c leap_year_ex2_1.c → is_leap_year_func_ex2_1.c leap_year_ex2_2.c → is_leap_year_func_ex2_2.c leap_year_ex3_1.c → is_leap_year_func_ex3_1.c leap_year_ex3_2.c → is_leap_year_func_ex3_2.c leap_year_ex4_1.c → is_leap_year_func_ex4_1.c is_leap_year_main.c と一緒にコンパイルしてみて動作を確認してみましょう。
25
参考文献 [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.