int main(void)

第7章
関数の作りかた
リスト 2数の平均値を求めるプログラム
#include <stdio.h>
double ave(double x, double y);
ー関数プロトタイプ
int main(void)
{
double a, b, avdt;
a = 11.11;
b = 33.33;
avdt = ave(a, b);
ー関数ave()を使って平均を求める
printf(“a=%df b=%f 平均=%f\n”, a, b, avdt);
return 0;
}
double ave(doub le x, double y) ー関数ave()の本体
{
double wk;
ー関数ave()の中だけで一時的に使用する変数
wk = (x + y) / 2.0;
return wk;
}
ー渡された2数x,yの平均を求めwkに代入する
ーwkの値を戻り値にする
実行結果
a=11.110000 b=33.330000 平均=22.220000
図7-1 関数呼び出しの関係図
main()側
ave()側
a,b
avdt=ave(a,b);
答え
avdt = ave(a, b);
2数の平均
a,bの値をx,yに渡す
double ave(double x, double y)
{
double wk;
wk = (x + y) / 2.0;
その和を計算する
return wk;
}
答えを返す
リスト 複数rerurn文と処理打ち切りreturn文の例
#include <stdio.h>
#include <math.h> /* for sqrt() */
double maxdt(double a, double b);
void disp_sqrt(double n);
関数プロトタイプ
int main(void)
{
double mx;
mx = maxdt(11.22, 33.44);
printf(“mx=%f\n”, mx);
disp_sqrt(2.0);
disp_sqrt(-5.0);
return 0;
}
ー最大値を求める
ー平方根を表示
ー負値の引数で呼ぶ
/* 大きい値を返す */
double maxdt(double a, double b)ー戻りの値の型はdouble
{
if (a > b)
どれかのreturn文に出会うと
return a;
値を返し処理を終了する
else
return b;
}
/* nが正の値なら平方根を表示する */
void disp_sqrt(double n)
ー戻りの値がないのでvoid型に
する
{
if (n <= 0.0) return;
ー処理打ち切りのreturn文
printf(“%f の平方根=%f\n”, n, sqrt(n));
}
実行結果
mx=33.440000
2.000000 の平方根=1.414214
←disp_sqrt(-5.0)の対応表示はない
リスト void型関数の記述例
#include <stdio.h>
void putd(int a);
{
putd(123);
ー関数プロトタイプ
return 0;
}
void putd(int a)
ー数値を出力するだけで戻り値のない関数
{
printf(“%d\n”, a);
}
ーreturn文による値戻しがない
リスト void型引数の記述例
#include <stdio.h>
void opening(void); ー関数プロトタイプ
int main(void)
{
opening();
ー関数呼出側ではvoidを記述する必要はない
return 0;
}
void opening(void) ー引数のない関数を定義
{
printf(“program start\n”);
}
関数プロトタイプの簡単記述方法
#include <stdio.h>
double maxdt(double a, double b);
ここに持ってくる
int main(void)
{
・・・
}
double maxdt(double a, double b)
{
・・・
}
自作関数の先頭行に’;’を付けて
◎プロトタイプ宣言を省略する方法
#include <stdio.h>
double maxdt(double a, double b);ーこのプロトタイプでmaxdt()
の仕様が判明しているので
int main(void)
{
double mx;
mx = maxdt(11.22, 33.44);
-この呼び出しは正しく処理
される
・・・
}
double maxdt(double a, double b) -maxdt()関数の本体
{
・・・
}
#include <stdio.h>
double maxdt(double a, double b);ー関数定義の先頭行でmaxdt()
の仕様が判明するので
・・・
}
int main(void)
{
double mx;
mx = maxdt(11.22, 33.44);ーこの呼び出しは正しく処理さ
・・・
れる
}
関数プロトタイプを
書くスタイルが正当
7.3関数にデータを渡す方法
◎数値を渡す
値による呼び出し(Call by value)
リスト 関数呼び出し側
a = 11.11,
b = 33.33,
avdt = ave(a, b);
リスト 関数定義側
double ave(double x, double y)
{
double wk;
wk = (x + y) / 2.0;
return wk;
}
代入
呼び出し側の変数aの値
関数側の変数x
代入
呼び出し側の変数bの値
関数側の変数y
a = 100;
avdt = ave(a, 200);
図7-2 値による呼び出し処理
呼び出し側
関数側
avdt=ave(a, 200);
a 100
200
double ave(double x, double y)
aの値(100)をxに代入
数値200をyに代入
wkの値(150)を
avdtに代入
avdt 150
x 100
y 200
wk=(x+y) /2.0
を計算
wk 150
◎配列を渡す
アドレスによる呼び出し
リスト 配列を関数に渡す1
#include <stdio.h>
void disp_ary(int nn[]);
int main(void)
{
int dt[5] = {100, 200, 300, 400, 500};
disp_ary(dt);
ー配列の先頭アドレスを渡す
return 0;
}
void disp_ary(int nn[])
ー配列を仮引数にする
{
printf(“nn[0]=%d\n”, nn[0]);ー配列内容を表示する
printf(“nn[4]=%d\n”, nn[4]);
}
図7-3 アドレスによる配列私のメカニズム
main関数側
disp_ary()関数側
disp_ary(dt);でdtの内容(アドレス)である10000をnnに代入す
る
dt
10000
dt[0]
100
dt[1]
dt[2]
200
10000番地
10004番地
300
10008番地
dt[3]
400
10012番地
dt[4]
500
10016番地
nn
10000
メモリ内の同じ配列を指
す
リスト 配列を関数に渡す2
#include <stdio.h>
void disp_ary1(int nn[], int len);
void disp_ary2(int nn[]);
int main(void)
{
int aa[5] = {100, 200, 300, 400, 500};
int bb[6] = {111, 222, 333, 444, 555, -1};-終了マークー1
をにする
disp_ary1(aa, 5); -配列の先頭アドレスと配列長を渡す
disp_ary2(bb);
ー配列の先頭アドレスを渡す
return 0;
}
void disp_ary1(int nn[], int len) -lenは配列長情報
{
int i;
for (i=0; i<len; i++) {
printf(“%d ”, nn[i]);ーnn[0]~nn[len-1]を表示
}
printf(“\n”);
ー最後に改行
}
void disp_ary2(int nn[])
{
int i = 0;
ー終了マーク方式
while (nn[i] != -1) {
ー-1でない間ループする
printf(“%d ”, nn[i]); ー値を表示
++i;
}
printf(“\n”);
ー最後に改行
}
◎文字列を渡す
‘A’
‘B’
‘C’
‘D’
‘E’
0
これが目印
になる
リスト 文字列を関数に渡す
#include <stdio.h>
void strout(char ss[]);
int main(void)
{
char st[] = “ABCDEF”;
strout(st);
strout”ABab12”);
return 0;
}
ー文字配列を渡す
ー直接文字列を渡す
void strout(char ss[])
{
int i;
ー引数をchar[]にする
printf(“ss=%s\n”, ss);
ー文字列をそのまま出力する
i = 0;
while (ss[i]) {
ーss[i]が’\0’でない間ループする
printf(“%X ”, ss[i]);ーss[i]を16進数出力
++i
}
printf(“\n”);
ー最後に改行する
}
表7-1 ローカル変数とグローバル変数
ローカル変数
関数内で宣言され、その関数内でのみ参照できる
グローバル変数
関数外で宣言され、どの関数からでも参照できる
リスト 文字列を関数に渡す
#include <stdio.h>
void func(void);
int glb;
int main(void)
{
int a;
ー関数の外側でグローバル変数gldを宣言
ーmain()関数内で使用できるローカル変数aを
宣言
a = 10;
ー自分のローカル変数に値設定
gld = 20;
ーグローバル変数に値設定
printf(“main a=%d glb=%d\n”, a, glb);ー両方の値を表示
func();
ー関数を呼ぶ
return 0;
}
void func(void)
{
int b; ーfunc()関数内で使用できるローカル変数bを宣言
b = 99; ー自分のローカル変数に値設定
printf(“func b=%d gld=%d\n”, b, gld);ー両方の値を表示
}
gldはmain()関数で設定した値
変数の通用範囲
int glb;
int main(void)
{
int a;
・・・
変数aの通用範囲
}
変数glbの通用範囲
void func(void)
{
int b;
・・・
}
変数bの通用範囲
◎ローカル変数は衝突しない
リスト ローカル変数の機能を見る
#include <stdio.h>
void func(void);
int main(void)
{
int a;
ー変数aを宣言する
a = 100;
printf(“main a=%d\n”, a);ー変数aの値を表示する
func();
ー1度関数func()を呼んで
printf(“main a=%d\n”, a);ー再び変数aの値を表示する
return 0;
}
void func(void)
{
int a;
ーこちらでも変数aを宣言する
a = 22222;
ー独自に値を設定する
printf(“func a=%d\n”, a); ー変数aの値を表示する
}
◎ローカル変数が優先される
リスト グローバル変数よりローカル変数が優先される例
#include <stdio.h>
void func(void);
int gg = 1234;
ー初期設定ありグローバル変数
int main(void)
{
printf(“main gg=%d\n”, gg);ーグローバル変数の値を表示
func();
-関数を呼ぶ
printf(“main gg=%d\n”, gg);ーグローバル変数をもう1度表示
return 0;
}
void func(void)
{
int gg;
ー同名のローカル変数を用意するとグローバル
変数ggは操作できなくなる
gg = 9999; ー自分の変数ggに値設定
printf(“func gg=%d\n”, gg);ー自分の変数ggの値を表示
}
◎グローバル変数と外部変数
(1)staticの付かないグローバル変数(外部結合グローバル変数)
(2)staticの付いたグローバル変数(内部結合グローバル変数)
auto記憶クラス指定子
プログラム実行中にメモリ上に確保されたり消去されたりす
る一時的な変数で、関数の中だけで使用できる。
extern記憶クラス指定子
プログラム実行中に常にメモリ上の同じ場所に存在する恒
久的な変数で、どの関数からも使用できる。externがあると、
よそで設定されたグローバル変数を参照しろという指定にな
る。
static記憶クラス指定子
プログラム実行中に常にメモリ上の同じ場所に存在する恒
久的な変数で、関数の中で使用する方法と、関数の外で使
用する方法がある。
変数の通用範囲
#include <stdio.h>
void func(void);
int gg = 1234;
グローバル変数を記述
int main(void)
{
printf(“main gg=%d\n”, gg);
func();
グローバル変数ggを使用
myprg2.cにある関数を呼ぶ
return 0;
}
myprg2.cの内容
#include <stdio.h>
extern int gg;
void func(void)
{
printf(“func gg=%d\n”, gg);
}
よそで宣言されている
グローバル変数ggを利用
可能にする、という宣言
myprg1.cのグローバル
変数ggを使用できるよう
になる
◎static記憶クラス指定子
リスト
static変数の使用例
#include <stdio.h>
void max_auto(int n);
void max_static(int n);
int main(void)
{
max_auto( 40);
max_auto(100);
max_auto( 80);
max_static( 40);
max_static(100);
max_static( 80);
3つの値でmax_auto()を呼ぶ
3つの値でmax_static()を呼ぶ
return 0;
}
void max_auto(int n)
{
int max = 0;
ー変数maxは自動変数
if (n > max) max = n;
ー最大値を記憶
printf(“max_auto max=%d\n”, max); ーその値を出力
}
void max_static(int n)
{
static int max = 0;
ー変数maxは静的変数
if (n > max) max = n;
ー最大値を記憶
printf(“max_static max=%d\n”, max); ーその値を出力
}
記憶クラスの使い分け法
(1)通常は
→自動変数を使う。ただし”auto”は省略する
(2)値を保持したいときは →静的変数を使う(staticを付ける)
(3)共通に使用したいときは→グローバル変数を使う
リスト
外部変数を使ったデータやりとりの例
#include <stdio.h>
void wasa(void);
int n1, n2, wa, sa; ーグローバル変数の宣言
int main(void)
{
n1 = 300;
n2 = 100;
wasa();
ー引数なしで関数コールする
printf(“n1=%d n2=%d 和=%d 差=%d\n”, n1, n2, wa, sa);
return 0;
}
void wasa(void)
{
wa = n1 + n2;
wa = n1 - n2;
}
ーグローバル変数を使うので引数不要
ー戻り値もグローバル変数に入れる