第 11 章 関数について 11.1 標準ライブラリ関数 11.2 関数呼び出しのオーバーヘッド 11.3 大域変数 11.4 プロトタイプ宣言 数学関数の自作.

Slides:



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

C 言語講座 第 7 回 ポインター. メモリとアドレス(ポインターの前 に) コンピュータのメモリには 1 バイトずつ 0 番地、 1 番地、 2 番地・・・というように 住所が割り当てられている この住所をアドレスという。 メモリはデータをしまうもので それを引き出すためには メモリに番号(アドレス)を振っておけばよいな.
配列の宣言 配列要素の初期値 配列の上限 メモリ領域 多次元配列 配列の応用
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
第13回構造体.
配列(2) 第10回[平成15年6月26日(木)]:PN03-10.ppt 今日の内容 1 素数を求める(教科書の例):復習
データ構造とアルゴリズム 第10回 mallocとfree
アルゴリズムとプログラミング (Algorithms and Programming)
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
プログラミング演習II 2004年10月19日(第1回) 理学部数学科・木村巌.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
プログラミング2 関数
プログラミング論 ファイル入出力
関数とポインタ 値呼び出しと参照呼び出し swapのいろいろ 関数引数 数値積分
関数と配列とポインタ 1次元配列 2次元配列 配列を使って結果を返す 演習問題
関数の定義.
第10回関数 Ⅱ (ローカル変数とスコープ).
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
地域情報学 C言語プログラミング 第5回 ポインタ、関数、ファイル入出力 2017年11月17日
プログラミング論 ファイル入出力
復習 2次元配列 4列 j = 0 j = 1 j = 2 j = 3 i = 0 i = 1 i = 2 3行
関数の再帰呼び出しとは ハノイの塔 リダイレクト レポート課題
関数への道.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
第14章 ファイル操作 14.1 ファイルへの書き込み 14.2 ファイルからの読み込み 14.3 ファイルへの追加書き込み
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
再帰的手続き.
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
メモリとメモリアドレス, ポインタ変数,関数へのポインタ渡し
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
第14章 ファイル操作 14.1 ファイルへの書き込み 14.2 ファイルからの読み込み 14.3 ファイルへの追加書き込み
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
復習 2次元配列 4列 j = 0 j = 1 j = 2 j = 3 i = 0 i = 1 i = 2 3行
プログラミング 3 2 次元配列.
ポインタとポインタを用いた関数定義.
11.1 標準ライブラリ関数 11.2 関数呼び出しのオーバーヘッド 11.3 大域変数 11.4 プロトタイプ宣言 11.5 関数引数
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
cp-3. 計算 (C プログラミング演習,Visual Studio 2019 対応)
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
関数と再帰 教科書13章 電子1(木曜クラス) 2005/06/22(Thu.).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
オブジェクト指向言語論 第三回 知能情報学部 新田直也.
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
プログラミング演習II 2003年11月19日(第6回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
第14章 ファイル操作 14.1 ファイルへの書き込み 14.2 ファイルからの読み込み 14.3 ファイルへの追加書き込み
計算技術研究会 第5回 C言語勉強会 関数(function)を使う
岩村雅一 知能情報工学演習I 第13回(後半第7回) 岩村雅一
プログラミング演習II 2003年10月29日(第2,3回) 木村巌.
プログラミング演習I 補講用課題
プログラミング 2 静的変数.
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
Presentation transcript:

第 11 章 関数について 11.1 標準ライブラリ関数 11.2 関数呼び出しのオーバーヘッド 11.3 大域変数 11.4 プロトタイプ宣言 数学関数の自作

11.1 標準ライブラリ関数 #include ← printf, scanf 等の入出力関数 #include ← sqrt, sin 等の数学関数 #include ← malloc, calloc, rand 等の関数 予め定義されており、ユーザが定義・作成し なくても使える関数 ヘッダ部に以下のマクロが必要

11.2 関数呼び出しのオーバーヘッド 関数の呼び出し回数が少なくて済むプログラムに 関数を呼び出す時、実際の計算以外のこと に使われるマシンへの余分な負荷をオー バーヘッドという 関数に渡すデータ(引数)などのコピー時 間や、そのためのメモリ消費など → 呼び出し回数が多いと無視できなくな る

プログラム例 改 #include #pragma comment(lib, "winmm.lib") #define N int main(void) { int i, t1, t2; static double a[N], b[N], c[N]; for (i = 0; i < N; i++) { a[i] = rand()/100.; b[i] = rand()/100.; } t1 = timeGetTime(); for (i = 0; i < N; i++) c[i] = a[i] + b[i]; t2 = timeGetTime(); printf("elapsed time = %d ms\n", t2-t1); printf("&i=%u, &t1=%u, &t2=%u\n", &i, &t1, &t2); printf("main=%u\n", main); printf("a=%10u, &a[N-1]=%10u\n", a, &a[N-1]); printf("b=%10u, &b[N-1]=%10u\n", b, &b[N-1]); printf("c=%10u, &c[N-1]=%10u\n", c, &c[N-1]); return 0; } 配列のたし算 ex11_2_1a.c 1000 万個の配列の足し算の 実行時間を計測

プログラム例 改 #include #pragma comment(lib, "winmm.lib") #define N double sum(double x, double y){return (x + y);} int main(void) { int i, t1, t2; static double a[N], b[N], c[N]; for (i = 0; i < N; i++) { a[i] = rand()/100.; b[i] = rand()/100.; } t1 = timeGetTime(); for (i = 0; i < N; i++) c[i] = sum(a[i], b[i]); t2 = timeGetTime(); printf("elapsed time = %d ms\n", t2-t1); printf("&i=%u, &t1=%u, &t2=%u\n", &i, &t1, &t2); printf("main=%u, sum=%u\n", main, sum); printf("a=%10u, &a[N-1]=%10u\n", a, &a[N-1]); printf("b=%10u, &b[N-1]=%10u\n", b, &b[N-1]); printf("c=%10u, &c[N-1]=%10u\n", c, &c[N-1]); return 0; } 配列のたし算 ex11_2_2a.c 1000 万個の配列の足し算の 実行時間を計測 プログラム例 改 にあえて関数を使ったら …

実行例 Z:\nyumon2>ex11_2_1a elapsed time = 250 ms &i= , &t1= , &t2= main= a= , &a[N-1]= b= , &b[N-1]= c= , &c[N-1]= Z:\nyumon2>ex11_2_2a elapsed time = 469 ms &i= , &t1= , &t2= main= , sum= a= , &a[N-1]= b= , &b[N-1]= c= , &c[N-1]= 関数 sum を 1000 万回呼び出しているため、 オーバーヘッドにより時間がかかっている プログラム領域 スタック領域 データ領域 プログラム領域 配列のたし算 10,000,000×8 バイト = 80,000,000 バイトずつ増加

プログラム例 改 #include #pragma comment(lib, "winmm.lib") #define N void sum(int n, double *x, double *y, double *z) {int i; for (i = 0; i < n; i++) z[i] = x[i] + y[i];} int main(void) { int i, t1, t2; static double a[N], b[N], c[N]; for (i = 0; i < N; i++) { a[i] = rand()/100.; b[i] = rand()/100.; } t1 = timeGetTime(); sum(N, a, b, c); t2 = timeGetTime(); printf("elapsed time = %d ms\n", t2-t1); printf("&i=%u, &t1=%u, &t2=%u\n", &i, &t1, &t2); printf("main=%u, sum=%u\n", main, sum); printf("a=%10u, &a[N-1]=%10u\n", a, &a[N-1]); printf("b=%10u, &b[N-1]=%10u\n", b, &b[N-1]); printf("c=%10u, &c[N-1]=%10u\n", c, &c[N-1]); return 0; } 配列のたし算 ex11_2_3a.c 関数 sum の呼び出しは1回 ポインタを使って結果を返す方 法 実行時間は ex11_2_1a.c と同程度

11.3 大域変数( global variable ) 全ての関数からアクセス可能な変数 10.4 で学習した 局所変数( local variable ) とは対立する概念 → 以下の3つのプログラム例を参照 グローバル変数、外部変数 (extern) 静的領域 に確保 スタック領 域に確保 自動変数 (auto)

10.4 関数と変数の可視範囲 より引用 関数内で宣言した変数は、その関数内でのみ可視 アクセス可能 ある関数の中でのみ通用する変数 = 局所変数 変数の可視範囲 = スコープ

int main(void) { int a = 10, b = 30; printf(" 関数呼び出し前 &a=%u:a=%d, &b=%u:b=%d¥n",&a,a,&b,b); scope_rule(); printf(" 関数呼び出し後 &a=%u:a=%d, &b=%u:b=%d¥n",&a,a,&b,b); return 0; } void scope_rule(void) { int a, b; a = 200; b = 400; printf(" 関数内部では &a=%u:a=%d, &b=%u:b=%d¥n",&a,a,&b,b); } この a,b のスコープは scope_rule のみ この a,b のスコープは main のみ main と scope_rule の両方で同じ変数 a,b を用いても良 い 同じ変数名 a,b でも、関数ごとに 別々にスコープが割り当てられる 局所変数の例 ― プログラム例 ―

#include void sum(void); void diff(void); double x, y; int main(void) { x = 12.5; y = 56.7; sum(); diff(); return 0; } void sum(void) { printf("&x=%u, &y=%u, 和は %f¥n", &x, &y, x + y); } void diff(void) { printf("&x=%u, &y=%u, 差は %f¥n", &x, &y, x - y); } 関数 sum や difference に引数は不要 この x,y のスコープは全ての関数 一見、便利! 大域変数の例 ― プログラム例 ― 関数 sum や difference で新たに変数宣言していないので、 x,y といえば、4行目で宣言された変数 x,y を指す

#include void scope_rule(void); int u, v; int main(void) { u = 10; v = 20; printf(" 関数の呼び出し前 &u=%u:u=%d, &v=%u:v=%d¥n", &u,u,&v,v); scope_rule(); printf(" 関数の呼び出し後 &u=%u:u=%d, &v=%u:v=%d¥n", &u,u,&v,v); return 0; } void scope_rule(void) { int u, v; u = 100; v = 200; printf(" 関数内では &u=%u:u=%d, &v=%u:v=%d¥n", &u,u,&v,v); } 関数内での局所変数名に大域変数名と同じ ものを用いても構わない。 この u,v のスコープは scope_rule のみ この u,v のスコープは全ての関数 大域変数を使わないプログラミングを心がけよう ! 混乱を招くので 乱用しない 混在する場合 ― プログラム例 ―

プログラム例 #include double sum(double x, double y); int main(void) { ・ return 0; } double sum(double x, double y) { double z; z = x + y; return z; } プロトタイプ宣言 1行でこれだけの意味を持つ プロトタイプ宣言とは ? (教科書 p.78 参照) sum という関数の定義部 11.4 プロトタイプ宣言 sum という関数を使う その詳細は後で定義 引数は double 型2個 戻り値は double 型

#include int foo(int, int, double); double bar(double, double); int main(void) {...; return 0; } int foo(int u, int v, double w) {...; } double bar(double m, double n) {...; } プロトタイプ宣言では、 関数の引数となる変数名は 省略できる 当然だが、関数定義では 仮引数は必要 プログラム例

プロトタイプ宣言の必要性 戻り値の型や引数の型のクロスチェック バグを減らすために有効 引数の変数名は省略可 呼び出す前に必要 先に関数が定義されていれば、なくてもよい 下請けの関数から順に書き、 main 関数を最後にす れば、必要なし 標準ライブラリはヘッダファイル内でプロトタイ プ宣言

指数関数の自作 ( 演習問題 10.5) 指数関数の級数展開と漸化式 n は 100 まででよい |a n /S n | < 10  16 で収束判定  10 < x < 10 で数学ライブラリ関数と比較

指数関数の自作 ( 演習問題 10.5) a ← 1 S ← 1 n = | a ← a  x / n S ← S  a Exp |a / S| < 10  16 n の出力 break S を返す main i =  | Exp(i), exp(i) の出力

#include double Exp(double x) { int n; double a=1, S=1; for (n=1; n<100; n++) { a *= x/n; S += a; if (fabs(a/S) < 1e-16) {printf("%d, ", n); break;} } return S; } int main(void) { int i; for (i=-10; i<=10; i++) printf("%f, %f\n", Exp(i), exp(i)); return 0; } exp.c 指数関数の自作 ( 演習問題 10.5) 収束確認用なので 完成後は削除する 自作 ライブラリ

三角関数の自作 ( 演習問題 10.5) 三角関数の級数展開と漸化式 n は 100 まででよい |a n /S n | < 10  16 で収束判定  10 < x < 10 で数学ライブラリ関数と比較 sin.c

本日のパズル 次のプログラムは何を出力するか #include #define PR(x) printf("%g\t",(double)x) #define NL putchar('\n') #define PRINT4(x1,x2,x3,x4) PR(x1);PR(x2);PR(x3);PR(x4);NL main() { double d; float f; long l; int i; i = l = f = d = 100/3; PRINT4(i,l,f,d); d = f = l = i = 100/3; PRINT4(i,l,f,d); i = l = f = d = 100/3.; PRINT4(i,l,f,d); d = f = l = i = (double)100/3; PRINT4(i,l,f,d); }