前回に引き続き関数を取り上げます.
・長方形の二辺の長さを渡すと,面積を戻す関数を作成してみよう.
/* 長方形の二辺の長さを渡すと,面積を戻す関数 */ #include <stdio.h> int area(int a, int b) { return a * b; } void main() { int a, b; printf("たて="); scanf("%d", &a); printf("よこ="); scanf("%d", &b); printf("面積=%d", area(a,b)); }
・円の半径を渡すと,面積を戻す関数を作成してみよう. 面積は,実数であることに注意.
/* 円の半径を渡すと,面積を戻す関数 */ #include <stdio.h> float carea(int r) { return r * r * 3.14; } void main() { int r; printf("半径="); scanf("%d", &r); printf("面積=%f", carea(r)); }
ある数 n の階乗 n! を求めるプログラムを,関数を用いて作成せよ
ただし,0! = 1 であることに注意.
/* ある数 n の階乗 n! を求めるプログラム */ #include <stdio.h> float fact(int n) { int i; float f = 1.0; for(i=0; i<n; i++){ f *= (i + 1); } return f; } void main() { int n; printf("n="); scanf("%d", &n); printf("n!=%.f", fact(n)); }
ここで, n! = n * (n-1)! であることを利用してプログラムを書くと,どうなるか?考えてみよう.
C言語では,関数の中から自分自身を呼び出すことができます.(これを再帰といいます)
どうなっているのか,わかるかな?
/* ある数 n の階乗 n! を求めるプログラム */ /* 再帰関数バージョン*/ #include <stdio.h> float fact(float n) { if(n == 0){ return 1.0; }else{ return n * fact(n-1); } } void main() { int n; printf("n="); scanf("%d", &n); printf("n!=%.f", fact(n)); }
変数は,宣言する場所によって,その有効範囲が異なります.同じ変数名なのに,関数によって値が違ってくるのは,このためです.
ある関数の中で宣言した変数のことをローカル変数といいます.ローカル変数を利用できる範囲は,変数を宣言した関数の中に限られます.この変数の有効範囲のことを変数のスコープと呼びます.
int funca() { int y; ..... return y; |
変数yの有効範囲
変数yは,関数funcaの中のみ有効 |
void main() { int x; x = 3; y = 4; ×エラー!! } |
main関数では,変数yは使えません |
関数の外で宣言した変数のことをグローバル変数といいます.グローバル変数は,どの関数からも参照できます.
int y; int funca() { .... return y; |
変数yの有効範囲
変数yは,main関数の中でも使える |
void main() { int x; x = 3; y = 4; ◎ } |
簡単なプログラムで確認してみましょう.
#include <stdio.h> int test(int a) { a += 10; return a; } void main() { int a, b; printf("aの値を入力してください:"); scanf("%d", &a); b = test(a); printf("aの値は%d\nbの値は%d\n", a, b); }
aに2を入力すると,結果はどのように表示されるだろう.
これまでは,一つの値しか関数から戻すことができなかった.また,同じ変数名を使っていても,関数の方で値を変えても,mainでは変化しなかった.これは,関数には変数の中身が伝えられているためです.
ここで,関数から複数の値を戻したい場合や,文字列や配列データを渡したい場合を考えよう.この場合,関数に変数のしまってある場所を伝え,その場所のデータを関数で使うようにすれば,よいと考えられる.
ポインタを用いて,変数の場所を関数に渡したプログラムの例です.
#include <stdio.h> int test2(int *a) /* 変数aのアドレスを受け取る(ポインタ変数) */ { *a += 10; /*aの指すアドレスの中身に1を加えるから,main関数でも変化する */ return *a; } void main() { int a, b; printf("aの値を入力してください:"); scanf("%d", &a); printf("関数へ渡す前のaの値は,%dです\n", a); b = test2(&a); /* 変数aのアドレスを関数に渡す */ printf("関数から戻ると...\naの値は%d\nbの値は%d\n", a, b); }
aに2を入力すると,どのように関数にわたり,
ポインタを用いて,アドレスを関数に渡せることがわかりました.
では,関数に配列データを渡してみましょう.
まずは,入力された文字の長さを返す関数を作ってみましょう.
配列を受け渡している例を見てください.
#include <stdio.h> void dim_init(int *ary, int no, int val) { int i; for(i = 0; i < no; i++){ ary[i] = val; } } void main() { int i; int ary[] = {1,2,3,4,5}; dim_init(ary, 5, 0); for(i =0; i < 5; i++){ printf("ary[%d] = %d\n", i, ary[i]); } }
このプログラムは,配列aryの先頭からno番目までの要素の値をvalに設定する関数です.関数の初期化などの際に用います.関数には,配列の先頭のアドレス(ary)が渡されるので,関数側ではポインタ(int *ary)で受け取っています.関数で変更の加えられたデータは,特に戻り値を指定していませんが,main関数では,その変更が反映されます.
文字列は,配列として扱うことを思い出してください.関数に文字列を受け渡すには,上記の配列の場合と同様,ポインタを用います.
ここで,文字の長さを数えるプログラムを関数を用いて書き換えてみよう.
#include <stdio.h> void main() { char str[128]; int i; printf("文字列を入力してください:"); scanf("%s", str); for(i = 0; str[i] != 0x00; i++); printf("入力された文字列は,%sです.", str); printf("文字数は,%dです.",i); }
ここで,青い色の部分を関数にしてみよう.
#include <stdio.h> int moji_nagasa(char *str) { int i; for(i = 0; str[i] != 0x00; i++); return(i); } void main() { char str[128]; int i; printf("文字列を入力してください:"); scanf("%s", str); printf("入力された文字列は,%sです.", str); printf("文字数は,%dです.", moji_nagasa(str)); }
(2) 配列の要素の和を求める関数を作成せよ.
(3) ある文字列を入力したとき,文字数を数える関数を利用して,文字を逆に並べる関数を作成せよ.