計算機言語 第7回
目的
関数について理解する.
入力X 関数f 出力Y
#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; }
関数の例
関数のプロトタイプ宣言 既に定義されている関数 仮引数 実引数 関数の型 メイン文 関数の本体関数の宣言の仕方
int tasu(int a, int b) { int c; c = a + b; return c; } 記憶クラス データ型 関数名(仮引数の型と変数宣言の並び) { 内部変数の宣言; 実行文; return文;(プロトタイプの宣言で返り値がvoidの場合は省略) } void disp(int a) { printf(“a = %d”,a); } 例1) 例2) 仮引数 関数の型 関数の型 返り値
関数のルール
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が入力されるまでの数字を加算するプログラムを 作成し、出力を確認せよ。
関数の再起呼び出し
関数は自分自身を呼び出すことができ,このことを再起呼び出しという. 再起関数内で注意する事は次の二点 ①関数内で使う変数の記憶クラスは自動変数にする. 自動変数 (auto) 静的変数 (static) ②無限ループにならないように終了条件を必ずいれる.再起関数の例
#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); } abc SLen SLen SLen abcSLen SLen SLen abc
SLen SLen SLen SLen abc SLen 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言語など) 高水準言語 プリプロセッサ 展開された高水準言語 コンパイラ 機械語 ① ファイルの読み込み(#include) ② マクロの展開(#define) ③ 定数の数値への置き換え(__FILE__, __LINE__) ④ コンパイル条件によるソースコードの部分的選択(-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); } 普通の置換マクロ 引数付置換マクロ 引数
関数間のデータの受け渡し
関数を実際に記述する際には,どのようにしてデータを渡すか?が重要になってくる. ① 値による呼び出し(Call by value) ② アドレスによる呼び出し 例外 外部変数による受け渡し 一般的 複数個の値を変化させる場合 上記二例で都合が悪い場合 そのような場合はほとんどない. 特に配列のデータを渡す場合アドレスによる呼び出し(
1/2)
関数F main文 21 16 21 16 関数F main文 3丁目 void 21 ? 3丁目 4丁目 3丁目 4丁目 値渡し ポインタ渡し #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); }
アドレスによる呼び出し(2
/2)
#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); } int n; int *p; p = &n; *p = 10; 数値が入る アドレスが入る アドレスの代入 ポインタ アドレスの参照 メモリ ? ? n ? ? ? 1丁目 2丁目 3丁目 4丁目 5丁目 6丁目 アドレス メモリ ? ? ? ? p(3丁目) ? ポインタによる代入
演習3
二つの整数のアドレスが与えられた時に,アドレス内の二つの値を入れ替える関数 swapを作成し,標準入力から与えられた二つの整数値を表示し,関数swapによって入 れ替えた値を表示するプログラムを作成せよ.
外部変数による受け渡し
#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; }
配列の受け渡し
関数には配列を渡す事ができる. 配列を渡す時には,アドレスによる呼び出しを用いてデータを渡します. メモリ dt[0] dt[1] dt[2] dt[3] dt[4] ? 1丁目 2丁目 3丁目 4丁目 5丁目 6丁目 アドレス int dt[5]; &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個の 整数(途中で止めれるようにしても良い)を入力して,その関数によって平均値(少数)を 求めて出力するプログラムを作成せよ.