プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

Slides:



Advertisements
Similar presentations
プログラミング 関数編 情報科学科. プログラミングにあたって C 言語では、 main 内に処理を記述 1000 行になるような大きなプログラムでは、 プログラム全体が何をしているのかを把握 することが困難になる 他人が見ると非常に理解しにくい 作成者であっても時が経てば内容を忘れて、他 人が見た時と同じ状況になる.
Advertisements

オブジェクト指向言語・ オブジェクト指向言語演習 中間試験回答例. Jan. 12, 2005 情報処理技術基礎演習 II 2 オブジェクト指向言語 中間試験解説 1  (1) 円柱の体積(円柱の体積 = 底面の円の面積 x 高さ) を求めるプログラムを作成しなさい。ただし、出力結果は、入 力した底面の円の半径.
A B x y z 復習 構造体変数 普通の変数 x y z 構造体変数 x y z 箱のイメージ 引き出しのイメージ
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
データ構造とアルゴリズム 第10回 mallocとfree
画像ファイル(ppm)の読み書き 画像データ用のメモリ確保・解放
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
第2回ネットワークプログラミング 中村 修.
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
プログラミング演習II 2004年10月19日(第1回) 理学部数学科・木村巌.
記憶クラス 変数をどのような記憶領域に割り当てるかを指定するのが記憶クラス 記憶クラスには、自動変数、静的変数、外部変数などがある。
構造体.
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
画像ファイル(ppm)の読み書き 画像データ用のメモリ確保・解放
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
プログラミング論 関数ポインタ と 応用(qsort)
ちょっとした練習問題① 配列iroを['R', 'W', 'R', 'R', 'W' , 'W' , 'W']を宣言して、「W」のときの配列の番号をprintfで表示するようなプログラムを記述しなさい。
プログラミング2 関数
プログラミング論 ファイル入出力
関数の定義.
第10回関数 Ⅱ (ローカル変数とスコープ).
プログラミング 4 記憶の割り付け.
プログラミング演習I 2003年5月7日(第4回) 木村巌.
プログラミング入門2 第2回 型と演算 条件分岐 篠埜 功.
知能情報工学演習I 第12回(後半第6回) 課題の回答
プログラミング入門2 第11回 情報工学科 篠埜 功.
第9回関数Ⅰ (簡単な関数の定義と利用) 戻り値.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
地域情報学 C言語プログラミング 第5回 ポインタ、関数、ファイル入出力 2017年11月17日
プログラミング論 ファイル入出力
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
B演習(言語処理系演習)第2回 田浦.
C言語 はじめに 2016年 吉田研究室.
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
11.1 標準ライブラリ関数 11.2 関数呼び出しのオーバーヘッド 11.3 大域変数 11.4 プロトタイプ宣言 11.5 関数引数
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
C プログラミング入門 基幹7 (水5) 14: 発展事項
モジュール分割.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
関数と再帰 教科書13章 電子1(木曜クラス) 2005/06/22(Thu.).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
第10回 関数と再帰.
オブジェクト指向言語論 第三回 知能情報学部 新田直也.
情報処理Ⅱ 第9回:2003年12月16日(火).
14: 発展事項 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習II 2003年11月19日(第6回) 木村巌.
情報処理Ⅱ 小テスト 2005年2月1日(火).
プログラミング入門2 第3回 条件分岐(2) 繰り返し文 篠埜 功.
計算技術研究会 第5回 C言語勉強会 関数(function)を使う
プログラミング演習I 補講用課題
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
C プログラミング入門 総機1 (月1) 14: 発展事項
プログラミング 2 静的変数.
Presentation transcript:

プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) C言語入門 第8週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

関数定義と関数呼び出し

関数の宣言・定義・利用 書式: 教科書 pp.149-160. 関数の宣言 戻り値の型 関数名(引数の宣言, ...); .h ファイルへ書き出す 関数の定義 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 } .c ファイルへ書き出す 関数の利用 変数名 = 関数名(引数, ...); 適宜呼び出す

関数(サブルーチン) 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 関数

(ユーザー定義)関数 関数は自分で作ることが出来る 関数の定義の書式: 機能、分量等、ある程度まとまった処理は 関数にまとめる 教科書 pp.149-160. (ユーザー定義)関数 関数は自分で作ることが出来る 機能、分量等、ある程度まとまった処理は 関数にまとめる 可読性が向上する 再利用が容易になる 関数の定義の書式: C言語の関数は 0個以上の引数と 0または1個の戻り値を持つ。 引数や戻り値が不要な場合は void を宣言するよう 推奨されている。 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 }

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

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 訂正2015-06-26 誤: double = sub(); 正: double x = sub(); $ gcc return_ex2.c && ./a 1.000000

関数のプロトタイプ宣言 関数は使う前に宣言されている必要がある 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();

関数のプロトタイプ宣言 関数は使う前に宣言されている必要がある 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 1.230000

(ユーザー定義)関数の例 閏年の判定を関数にまとめてみる 教科書 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; 関数の定義 自分で作成した関数を サブルーチンとして呼ぶ

(ユーザー定義)関数の例 関数を使う前にはパラメータの型と数が 分かっている必要がある(コンパイラの都合) 教科書 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.86-89.

関数のプロトタイプ宣言 関数は使う前にプロトタイプ宣言する 教科書 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; } 関数のプロトタイプ宣言 戻り値の型、引数の数と型を宣言する 関数のプロトタイプ宣言さえしておけば 関数の定義はどこにあっても良い。 例えば外部のファイルにあっても良い。

関数をファイルに分離する 再利用性が高まる(コピペしなくて良くなる) 教科書 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; } 関数本体の定義

ファイルに分離した関数の利用 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 外部ファイルで定義した 関数を呼び出し

分割コンパイル コンパイルする複数の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 文により 自動的に取り込まれる

プリプロセッサ 条件付きコンパイル 条件に合った箇所のみを コンパイラに渡す構文 定数式の結果は0と非0の真偽値 定数式なら 演算も可能 #if 定数式 #elif 定数式 #else #endif #if 0 // ここはコンパイルされない #if defined(__BORLANDC__) // __BORLANDC__ という名前のマクロが // 定義されていた場合のみコンパイルされる #if defined(__BORLANDC__) && 0x0551 <= __BORLANDC__ // ... 条件に合った箇所のみを コンパイラに渡す構文 定数式の結果は0と非0の真偽値 定数式なら 演算も可能

プリプロセッサ 条件付きコンパイル #if defined( ) の短縮表記 #if !defined( ) の短縮表記 #ifdef __BORLANDC__ // ... #endif #ifndef __BORLANDC__ #if defined( ) の短縮表記 #if !defined( ) の短縮表記

プリプロセッサ 定義済みマクロ __LINE__ 現在の行番号 __FILE__ 現在のファイル名 __func__ 現在の関数名(C99) __FUNC__ 現在の関数名(Borland C++) #ifdef __BORLANDC__ #define __func__ __FUNC__ #endif Borland C++ で C99互換の定義済みマクロが 使えるようにする 条件付きコンパイル

関数をファイルに分離する 作業用変数を用いる場合 教科書 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 そのまま 結果を戻り値として返す

関数の差し替え 関数のプロトタイプ宣言が同じなら関数は差し替えて使える。 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

変数のスコープ(有効範囲) 大域(グローバル)変数 局所(ローカル)変数 プログラム全体からアクセス可能 ブロック内からのみアクセス可能 教科書 pp.161-169. 変数のスコープ(有効範囲) 大域(グローバル)変数 プログラム全体からアクセス可能 局所(ローカル)変数 ブロック内からのみアクセス可能 C言語では { } で 囲まれた部分がブロック

変数のスコープ(有効範囲) ローカル変数は{}の中のみで有効 教科書 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; 関数の引数はローカル変数 ブロックを作成するとローカル変数の有効範囲を制限出来る

変数のスコープ(有効範囲) ローカル変数は{}の外側に影響していない $ gcc scopetest.c && ./a 教科書 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; 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

教科書 pp.203-206. 関数の演習 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 と一緒にコンパイルしてみて動作を確認してみましょう。

参考文献 [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)