計算機言語第 7 回 長宗高樹
目的 関数について理解する. 入力 X 関数 f 出力 Y Y=f(X)
関数の例 関数の型 #include <stdio.h> int tasu(int a, int b); main(void) int x1, x2, y; x1 = 2; x2 = 3; y = tasu(x1,x2); 実引数 printf( %d + %d = %d, x1, x2, y); int tasu(int a, int b) int c; c = a + b; return c; 仮引数 関数のプロトタイプ宣言メイン文既に定義されている関数関数の本体
関数の宣言の仕方 記憶クラスデータ型関数名 ( 仮引数の型と変数宣言の並び関数の型 ) 内部変数の宣言 ; 実行文 ; return 文 ;( プロトタイプの宣言で返り値がvoidの場合は省略 ) 例 1) 例 2) 関数の型 仮引数 int tasu(int a, int b) int c; c = a + b; return c; 返り値 void disp(int a) printf( a = %d,a);
関数のルール 1. 関数にはデータ型を宣言しなければならない. 例外として int 型の場合は, 省略可能. 2. 実引数と仮引数の型と数, 順序は一致していなければならない. 3. 引数がなくても, 引数をくくる括弧 () は必要である. 4. 関数の結果として値を返すには,return 文を用いる. 5. 関数の型は, 呼び出し側でも宣言しなければならない. これをプロトタイプ宣言と呼ぶ. 6. 分割コンパイルしたほかのソースファイル上の関数を使う場合は, 呼び出し側で外部の関数であることを宣言 (extern) しなければならない. #include <stdio.h> int tasu(int a, int b) int c; c = a + b; return c; main(void) int x1, x2, y; x1 = 2; x2 = 3; y = tasu(x1,x2); printf( %d + %d = %d, x1, x2, y);
コンパイラ 高水準言語コンパイラ機械語 (C 言語など ) プログラムが大きくなってくると, 一つのファイルだけで作成すると, 全体が見難くなり, バグが発生しやすく, 修正も困難. また, 同じ関数を使用するときに, 毎回, 同じ定義を宣言する事も賢い選択とは言えない. そこで, いくつかの機能毎にソースファイルを分割して作成し, メインのプログラムは他のファイルで定義されている関数を使用する. 呼び出し側メインのソースファイル数値演算関数ファイル表示用関数ファイル入力用関数ファイル コンパイラ 機械語
分割コンパイルの一例
演習 1 二つの引数を比較し, 大きい方を出力する関数 max を定義し, 標準入力から二つの整数値を入力し, 大きい方の値を出力するプログラムを作成せよ. また, 入力に 3 と 8 を代入してその出力を確認せよ.
演習 1( 回答例 ) 標準入力から整数値を入力し 0 が入力されるまでの数字を加算するプログラムを作成し 出力を確認せよ ( 横道 )max 関数は,stdlib.h ファイル内にて定義されている.
関数の再起呼び出し 関数は自分自身を呼び出すことができ, このことを再起呼び出しという. 再起関数内で注意する事は次の二点 1 関数内で使う変数の記憶クラスは自動変数にする. 自動変数 (auto) 静的変数 (static) 2 無限ループにならないように終了条件を必ずいれる.
再起関数の例 #include <stdio.h> int SLeng(char *s); main(void) char str[50]; int SLeng(char *); while(1) scanf( %s,str); printf( [%s] --> %d n n, str, SLeng(str)); int SLeng(char *s) if(!*s) return 0; return(sleng(++s)+1); SLen abc SLen SLen abc SLen SLen SLen abc SLen SLen SLen SLen SLen abc SLen SLen 0 SLen SLen 1 0 SLen 1 1 0 1 1 1 0
演習 2 引数に n が入力された時に,1 から始まる奇数の数列の n 番目の値を出力する再起関数を作成し, 標準入力から n を代入し,n 番目の奇数を表示するプログラムを作成せよ. また,6 を代入し, その出力を確認せよ. 奇数の数列 1,3,5,7,9,11,13,15
置換マクロ プリプロセッサの #define は, 見かけ上は関数の働きをする. この関数のような働きをするマクロを引数付置換マクロという. 高水準言語コンパイラ機械語 (C 言語など ) 高水準言語プリプロセッサ展開された高水準言語コンパイラ機械語 1 ファイルの読み込み (#include) 2 マクロの展開 (#define) 3 定数の数値への置き換え ( FILE, LINE ) 4 コンパイル条件によるソースコードの部分的選択 (-lm)
置換マクロの例 普通の置換マクロ引数付置換マクロ引数 #include <stdio.h> #include <stdring.h> #define MAX_LEN 10 #define MESSAGE hello, world!! main(void) int ilen; char str[20]; ilen = MAX_LEN; strcpy(str,message); printf( ilen = %d n,ilen); printf( %s n,str); #include <stdio.h> #define PrintMac(x) printf( %s n, x) void PrintfFnc(char *); main(void) PrintMac( C Program!! in #define ); PrintFnc( C Program!! in function ); void PrintFnc(char *str) printf( %s m,str);
関数間のデータの受け渡し 関数を実際に記述する際には, どのようにしてデータを渡すか? が重要になってくる. 1 値による呼び出し (Call by value) 一般的 2 アドレスによる呼び出し 例外外部変数による受け渡し 複数個の値を変化させる場合特に配列のデータを渡す場合上記二例で都合が悪い場合そのような場合はほとんどない.
アドレスによる呼び出し (1/2) 値渡し #include <stdio.h> int hiku(int x)return x-5; main(void) int a, b; a = 21; b = hiku(a); printf( ans = %d n, b); ポインタ渡し #include <stdio.h> void hiku(int *x)return *x = *x-5; main(void) int a, b; a = 21; hiku(&a); printf( ans = %d n, a); main 文 21 16 21 16 21? main 文 3 丁目 4 丁目 3 丁目 4 丁目 3 丁目 void 関数 F 関数 F 見えない!! 見える!!
アドレスによる呼び出し (2/2) #include <stdio.h> void hiku(int *x) return *x = *x-5; ポインタアドレスの参照ポインタによる代入 int n; int *p; p = &n; *p = 10; 数値が入るアドレスが入るアドレスの代入 main(void) int a, b; a = 21; hiku(&a); printf( ans = %d n, a); メモリ??? アドレス 1 丁目 2 丁目 3 丁目 メモリ?? n? 4 丁目? p(3 丁目 ) 5 丁目?? 6 丁目?
演習 3 二つの整数のアドレスが与えられた時に, アドレス内の二つの値を入れ替える関数 swap を作成し, 標準入力から与えられた二つの整数値を表示し, 関数 swap によって入れ替えた値を表示するプログラムを作成せよ. また, 入力に 3 と 5 を入力して, その出力を確認せよ.
外部変数による受け渡し #include <stdio.h> int sio1, sio2; void add(); main(void) int a=15, b=25; sio1 = a; sio2 = b; add(); printf( add (%d,%d) --> %d n, a, b, sio1); void add() sio1 = sio1+sio2;
配列の受け渡し 関数には配列を渡す事ができる. 配列を渡す時には, アドレスによる呼び出しを用いてデータを渡します. int dt[5]; アドレスメモリ 1 丁目 dt[0] 2 丁目 dt[1] 3 丁目 dt[2] 4 丁目 dt[3] 5 丁目 dt[4] 6 丁目? アドレス &dt[0] &dt[1] &dt[2] &dt[3] &dt[4] &dt[5] dt? どうやって, 関数は配列の終わりを知るか? #include <stdio.h> void wa(int dt[], int len, int *ans); main(void) int dt[3]; int ans; dt[0] = 2007, dt[1] = 11, dt[2]=14; wa(dt, 3, &ans); printf( ans = %d n,ans); void wa(int dt[], int len, int *ans) *ans = 0; for(int i=0;i<len;i++) *ans += dt[i];
演習 4 受け渡された 10 個の要素の配列の平均値を求める関数を作成し, 標準入力から 10 個の整数 ( 途中で止めれるようにしても良い ) を入力して, その関数によって平均値 ( 少数 ) を求めて出力するプログラムを作成せよ. また, 入力に 1 から 10 まで順番に入力して, その出力を確認せよ.
まとめ 関数を作成するときには, 引数の型と数を一致させなければならない. 関数はプロトタイプ宣言をしなくてはならない. 関数のような働きをするものに引数付置換マクロがある. 関数には, 値渡しと, ポインタ渡しと外部変数による渡しがある.