Transcript 7_revised

第7週
関数(1)
プログラミング言語 2014
立命館大学情報理工学部
関数の種類
P.114
• main関数
– C言語のプログラムでただ1つ存在.
– 必ず main関数から実行される.
• ライブラリ関数
– あらかじめ提供されている関数
– ソースコード内でヘッダファイルを#includeし,
コンパイル時にライブラリをリンクして使う(後述)
• 自分で作る関数
– ソースコード内でmain関数とは別の関数を定義
– 次からのスライドで記述方法を説明
– main関数の前に置く場合,後に置く場合で書き方に違い
• 最初は,前に置く場合を説明
List6-1 P.115 関数の定義と呼出し
(必須知識)
/* 2つの整数の大きい方の値を返す関数 */
#include <stdio.h>
int maxof(int x, int y)
{
xに83,yに45を代入
if( x > y )
return x;
else
return y;
}
int main(void)
{
int na, nb;
puts(“2つの整数を入力 “);
printf(“整数1 : “);
scanf(“%d”, &na);
printf(“整数2 : “);
scanf(“%d”, &nb);
実行してみよう
Fig.6-4 (P.116) も参考に
main関数から開始
maxof(83,45)を
関数呼び出し
2つの整数を入力
整数1 : 83
naの値は83
整数2 : 45
nbの値は45
大きい方の値は83です.
printf(“大きい方の値は%dです.\n”, maxof(na, nb) );
return 0;
}
main関数に戻った時の
maxof(83,45)の値はreturn された値,
つまり,83
関数定義
P.114, p.116, p.117 (必須知識)
呼び出される側の書き方
関数頭部 : 型 関数名(型 仮引数1, 型 仮引数2, …)
この関数が返す返却値の型
int maxof( int x, int y)
{
if(x > y)
return x;
else
return y;
}
関数本体 = {
仮引数の型
return 式;
で示された式の
評価値が
この関数が返す
返却値(戻り値)
} で囲まれた複合文
関数呼び出し P.115
(必須知識)
呼び出す側の書き方
• 関数呼び出し式: 関数名(実引数1,実引数2, …)
int main(void)
{
int na, nb;
naに83, nbに45を入力する
printf(“大きい方の値は%dです.\n”, maxof(na, nb) );
return 0;
}
• 関数呼び出し式を評価すると,returnで返却される値
– 返却値の型は,前スライドにあった「関数が返す返却値の型」
List6-3 P.119 関数は複数あってもよい
/* 2整数の2乗の差 */
#include <stdio.h>
int main(void)
{
int p, q, p2, q2;
int sqr(int x)
{
return x * x;
}
左からの続き
puts("2つの整数を入力してください\n");
printf("整数p : "); scanf("%d", &p);
printf("整数q : "); scanf("%d", &q);
int diff(int x, int y)
{
return x>y ? x-y: y-x;
}
p2 = sqr(p);
q2 = sqr(q);
printf(“pの2乗とqの2乗の差は%d\n",diff(p2, q2));
return 0;
}
右へ続く
printf(“pの2乗とqの2乗の差は%d\n", diff( sqr(p), sqr(q) );
と書いてもよい.
List6-4 P.120
ループを持つ関数
関数本体はmain関数と同じような構造
局所変数: 関数内で定義される変数(後述)
/* べき乗 */
#include <stdio.h>
double power(double dx, int no)
{
int i;
double tmp = 1.0;
for( i = 1; i <= no; i++)
tmp *= dx;
return tmp;
}
int main(void)
{
int n;
double x;
左からの続き
printf(“実数は?:"); scanf("%lf",&x);
printf(“整数は?:"); scanf("%d",&n);
printf("%.2fの%d乗は%.2fです.\n",
x, n, power(x, n));
return 0;
}
右へ続く
[注] scanf(“%lf”,&x):
変数 x が,float型ならf,double 型なら lf
値渡し
P.120 必須知識
• 呼出されると,関数内の
変数用のメモリ出現
• 呼出し側の値が,呼ばれ
る側の変数に複製
• 呼ばれる側の変数を変更
しても,呼出し側の変数に
影響なし
• 返却値を返す
• 関数の局所変数はreturn
後, 消滅
List 6-4 の power() が
main()から呼ばれるとき
呼ばれる側 power()
関数内の局所変数 tmp
関数内の局所変数 i
関数の仮引数 n
関数の仮引数 x
関数の返却値(関数値)
呼び出し側 main()
呼出し側の変数
(
= power
実引数 x
,
実引数 n
)
仮引数の変更
List6-5 P.121
値渡しを活かしてコンパクト化
/* 局所変数をループ変数に利用 */
double power(double dx, int no)
{
double tmp = 1.0;
while( no-- > 0)
tmp *= dx;
return tmp;
}
double power(double dx, int no)
{
int i;
double tmp = 1.0;
power() を
変更
for( i = 1; i <= no; i++)
tmp *= dx;
return tmp;
}
呼ばれる側の変数を
変更しても,呼出し側
の変数に影響なし
この例では,仮引数をループ変数に
使って,コンパクト化
List6-6 P.121
関数を呼び出す関数
int maxof(int x, int y)
{
if( x > y )
return x;
else
return y;
}
int max4(int w, int x, int y, int z)
{
return maxof(maxof(w,x), maxof(y,z));
}
int main(void)
{
ここでmax4()の値が求められる
:
max4(a, b, c, d);
:
}
関数呼び出しとメモリ
y
x
maxof
y
x
maxof
返却値
y
x
maxof
返却値
返却値
maxof( maxof( w, x ), maxof( y, z ) )
max4()
z
y
x
w
max4の返却値
関数実行終了後,そのためのメモリは消滅
max4(
main()
a
,
b
,
c
,
d
)
11
List6-7 P.122 値を返さない関数
/* 直角三角形 */
#include <stdio.h>
関数の型が void
void put_starts(int no)
{
while( no-- > 0)
putchar('*');
}
i 行目に i 個の*
int main(void)
{
int i, ln;
実行してみよう
% ./triangle
何段ですか: 6
*
**
***
****
*****
******
%
printf("何段ですか: ");
scanf("%d", &ln);
}
for(i = 1; i <= ln; i++) {
put_stars(i);
putchar('\n');
}
return 0;
i個の印字をひと塊の機能とみなす
今回押さえるべきプログラム
List 6-8 P.123
汎用性P.129
/* 左に空白がある直角三角形 */
#include <stdio.h>
印字する文字を引数に
void put_nchar(int ch, int no)
{
while( no-- > 0)
putchar(ch);
ln-i 個の空白
}
int main(void)
{
int i, ln;
printf("何段ですか: ");
scanf("%d", &ln);
何段ですか: 6
* i 個の*
**
***
****
*****
******
for(i = 1; i <= ln; i++) {
put_nchar(' ', ln -i);
put_nchar('*', i);
putchar('\n');
}
return 0; これを1からlnまでループ
}
この関数は2つの機能に使え,汎用性が高い
List6-9 P.124 仮引数を受け取らない関数
仮引数が void
実引数は空
int rev_int(int num)
{
int tmp = 0;
#include <stdio.h>
int scan_unit(void)
{
int tmp;
do {
printf("非負の整数: ");
scanf("%d", &tmp);
if(tmp < 0)
puts(“\a間違い");
} while( tmp < 0 );
}
}
int main(void)
{
int nx = scan_unit();
return tmp;
右へ続く
}
\a は「警告音を鳴らせ」
if(num > 0) {
do {
tmp = tmp*10+num%10;
num /= 10;
} while(num > 0);
}
return tmp;
printf("反転した値は%d\n",
rev_int(nx));
return 0;
関数の返却値で
初期化
ブロック有効範囲(block scope)
P.125
必須知識
{ }内で定義された変数は{ }の内側で有効
int scan_unit(void)
{
int tmp;
printf("非負の整数: ");
scanf("%d", &tmp);
return tmp;
}
– ブロック(block): { と } で囲まれた部分
– 変数の有効範囲をスコープという
– ブロックで定義された変数のスコープは,
ブロック内
このtmp
これらは
scan_unit()
tmp
rev_int()
tmp
int rev_int(int num)
このtmp
{
返却値
返却値
int tmp = 0;
これらは
do {
main()
tmp = tmp*10+num%10;
num /= 10;
関数内の局所変数を格納したメモリは
} while(num > 0);
return tmp;
関数実行終了後,消滅するので,
}
当たり前といえば当たり前
ファイル有効範囲(file scope) P.126
• どのブロックにも定義が含まれない変数のス
コープは,その定義からファイルの最後まで
• ファイル・スコープを持つ変数は,使いにくい
ので,薦められない.
宣言と定義
P.127
• 定義:変数や関数がメモリ上に割付けられる
• 宣言:変数や関数の型など使い方(仕様)を示す
プロトタイプ
関数の原型宣言(P.127)
#include <stdio.h>
void put_starts(int number);
int main(void)
{
int i, ln;
printf("何段ですか: ");
scanf("%d", &ln);
}
for(i = 1; i <= ln; i++) {
put_stars(i);
putchar('\n');
}
return 0;
void put_starts(int no)
{
while( no-- > 0)
putchar('*');
}
(必須知識)
List6-7 を修正
• main()のあとで,
関数を定義する場合
• main()が,関数の
– 返却値の型
– 引数の数
– 引数の型
を知る手段が必要
プロトタイプ宣言を前に
(最後に ; を忘れずに)
ヘッダファイルと #include
P.128
(必須知識)
• プロトタイプ宣言は,関数の仕様を示す.
– これが最初にあると,いろいろな関数を使える.
– printf(), scanf()などを使うためのプロトタイプ宣言
はヘッダファイル stdio.h に入っている.
• #include
– その1行が,ファイルの内容と入れ替わる
[例] #include <stdio.h>
C言語であらかじめ用意されている,関数をそのファイル
で使用できるようになる
クイズ:
プログラムを実行した結果を求めよ
#include <stdio.h>
#define MAX_NUMBER (4)
int M(int left, int right)
{
return left > right ? left : right;
}
int m(int left, int right)
{
return left > right ? right : left;
}
int main(void)
{
int d[MAX_NUMBER] = {1, 9, 3, 8};
printf("答えは%d\n", m( M(d[0], d[1]), M(d[2], d[3])));
}
return 0;
正解
• M()は2つの整数のうち,大きいほうを返す
• m()は2つの整数のうち,小さい方を返す.
• 最初にM(1,9)の値は9
• ついでM(3,8)の値は8
• 最後にm(9,8)の値は8
• よって,正解は8