Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
計算機言語 第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;
}
関数の例
関数のプロトタイプ宣言
既に定義されている関数
仮引数
実引数
関数の型
メイン文
関数の本体
関数の宣言の仕方
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が入力されるまでの数字を加算するプログラムを作成し、出力を確認せよ。
(横道)max関数は,stdlib.hファイル内にて定義されている.
関数の再起呼び出し
関数は自分自身を呼び出すことができ,このことを再起呼び出しという.
再起関数内で注意する事は次の二点
①関数内で使う変数の記憶クラスは自動変数にする. 自動変数 (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);
}
abcSLen
SLen SLen abc
SLen SLen abcSLen
SLen SLenSLen SLen abc
SLen SLenSLen 0
SLen 1SLen 0
SLen 11 0
1 11 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丁目 3丁目4丁目 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によって入れ替えた値を表示するプログラムを作成せよ.また,入力に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;
}
配列の受け渡し関数には配列を渡す事ができる.配列を渡す時には,アドレスによる呼び出しを用いてデータを渡します.
メモリ
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個の整数(途中で止めれるようにしても良い)を入力して,その関数によって平均値(少数)を求めて出力するプログラムを作成せよ.また,入力に1から10まで順番に入力して,その出力を確認せよ.
まとめ関数を作成するときには,引数の型と数を一致させなければならない.
関数はプロトタイプ宣言をしなくてはならない.
関数には,値渡しと,ポインタ渡しと外部変数による渡しがある.
関数のような働きをするものに引数付置換マクロがある.