Part.7

関数と大域(グローバル)変数

内容

  • 関数の定義と利用
  • 大域変数について

目標

関数の定義の仕方と使い方を習得する.

関数の定義と利用

これまで、標準関数と呼ばれる関数をいくつか使いました(printf 関数と scanf 関数).C言語では、自分で関数を定義し利用することができます.まずは参考書のサンプルプログラムを見てみましょう.つぎのサンプルプログラムを Part7-1.c として打ち込んでください.(いつものとおり、説明の為の行番号は無視してください.)

 1: #include <stdio.h>
 2: 
 3: int beki(int a, int b);
 4:
 5: int main()
 6: {
 7:     int n;
 8:
 9:     n = beki(2, 3);
10:     printf("%d\n", n);
11:
12:     printf("%d\n", beki(3, 4));
13: }
14:
15: int beki(int a, int b)
16: {
17:     int i, ans;
18:
19:     ans = 1;
20:
21:     for (i = 1; i <= b; i++)
22:     {
23:         ans = ans*a;
24:     }
25:  
26:     return ans;
27: }

3行目および15~27行目が関数の定義に関わる部分で、9行目および12行目で、定義した関数を使用している部分です.まずは定義している部分から見ていきましょう.

3行目: 関数のプロトタイプ宣言と呼ばれる宣言です.後に定義する関数の戻り値の型と、引数の型を仕様として、プログラムの先頭部分(main 関数より前)にこのように書きます.関数を定義する場合には、このプロトタイプ宣言が必ず必要だと思っておいてください.(省略する方法もありますが、この演習では必ずプロトタイプ宣言をすることとします.)

5~13行目: main 関数の定義です.

15~27行目: beki 関数の定義です.

戻り値と引数

y = sin(x)

と書いたとき、sin が関数名で x が関数 sin の引数変数 y には sin(x) の戻り値が入ることになります.当然変数 x, y にはそれぞれ型があり、関数自体がもつ値(戻り値)にも型があります.

先のサンプルプログラムの3行目のプロトタイプ宣言や、15行目の関数定義の部分で、 int と整数型が宣言されているのはその為です.

beki 関数の定義

では、beki 関数の定義部分を詳しく見ましょう.15行目を見ると

int beki (int a, int b)

となっています.これは、先のプロトタイプ宣言と通常おなじ記述となります.はじめの int は、 beki 関数の戻り値の型が int であるという意味です.続いて関数名 beki があり、その後括弧に囲まれ、2つの変数が定義されています.これらは、引数として渡される値を格納する為の変数でそれらの名前をそれぞれ a, b とし、型はそれぞれ整数型としています.つまり、 beki(1,2) とこの関数が呼ばれた場合、 a には 1 が、 b には 2 が代入されることになります.

つづいて、中括弧に囲まれた、関数本体の処理内容が続きます.この中で、新たに(この関数の定義内でのみ有効な)変数 i と ans を用意しています.さらには、先の引数部分にあった、変数 a, b が参照されています.もちろん、 a, b には関数が呼ばれた時に引数として渡されている変数の内容である数値または直接数値として渡された場合にはその数値が代入されています.

最後の return 文により、 ans の内容が beki 関数の戻り値として返されます.

以上、関数を作る場合に必要なことをまとめると

  • 関数の名前は何にするか
  • 関数に渡すデータの型と名前は何であって、数はいくつか(引数の数)
  • 関数から戻るデータ(戻り値)の型は何か
  • 関数のプロトタイプ宣言の記述(プログラムの先頭部分.main 関数の定義より前)
  • 関数本体の処理方法の記述
  • 結果を戻すための記述(return 文)

他の例を見てみましょう.

例えば、実数値の絶対値を表示するプログラムを考えましょう.これまでの知識からプログラムは大体次のようなものになります.

#include <stdio.h>

int main()
{
    double a;

    printf("実数を入力してください:");
    scanf("%lf", &a);

    if (a < 0.0)
    {
        a = -a;
    }

    printf("入力された実数の絶対値は %lf です.\n", a);
}

このプログラムでは、 if 文を使って絶対値を求めていますが、絶対値を求める作業が多量にある場合、いちいち if 文を書くのは面倒です.絶対値を求める関数を作ってみましょう.

#include <stdio.h>

double myabs(double f);

int main()
{
   double a;

    printf("実数を入力してください:");
    scanf("%lf", &a);

    printf("入力された実数の絶対値は %lf です.\n", myabs(a));
}

double myabs(double f)
{
    if(f < 0.0)
    {
        f = -f;
    }

    return f;
}

以前にも述べたように、自分で関数を作る場合には自由な名前をつけることができます.しかし、標準関数として既にある関数の名前をつけることはできません(例えば、printf や scanf といった関数を新たにつくることはできません).実は絶対値を求める標準関数 abs がありますので、今回は myabs という名前にしています.また、関数の名前も変数の名前の規則同様使える文字と使えない文字があります.注意してください.数字から始まらない英数字を関数名としてください.

大域(グローバル)変数について

C言語では,大域変数を用いる事ができます.次の例を見てください.この例では,実数型変数 A が大域変数とよばれます.main 関数の外(プログラムの先頭付近)で定義されている事に注意してください.この位置で定義すると,そのプログラム中の他の関数定義の中でもその変数を用いる事ができます.下の例では,関数 main の中で A の値を設定し,関数 f の中で A を表示しています.対して,変数 B は局所変数とよばれます.両者の違いは以下のプログラムの動作をみれば分かると思います(一度に多くの事を説明する為の例なので少し分かりにくいかもしれません.実行結果とソースプログラムをよく見比べ,動作を確認してください).大域変数を用いた方がプログラムがすっきりする場合にはつかうと良いでしょう.大域変数とは,そのプログラム中で大域的に使えるという意味であり,局所変数は関数内のみで使えるという意味であると覚えればよいでしょう.

#include <stdio.h>
#include <math.h>
double f(double B);
double A;

int main()
{
    double B;
     A = 1.3;
     B = 1.5;
     printf("a: %lf\n", f(B));
     printf("b: %lf %f\n", A, B);
}

double f(double B)
{
     printf("c: %lf %lf\n", A, B);
     A = 2.0;
     B = 1.0;
     printf("d: %lf %lf\n", A, B);
     return (B);
}

このプログラムを実行すると以下のような出力が得られる.

c: 1.300000 1.500000

d: 2.000000 1.000000

a: 1.000000

b: 2.000000 1.500000

課題1

次の仕様を満たす関数を作成し、それを使うプログラムを作成せよ.

関数名: double mymax(double a, double b)

仕様: 実数型の2つの数 a, b を受け取り、それらのうち大きい方を戻り値として返す

課題2

正の整数を1つ入力すると、その数が素数かどうかを判定して表示するプログラムを作成せよ.

ヒント: いろいろな方法があると思うが、単純な方法としては、n > 2 の整数が素数である場合には、2 <= i <= n-1 の範囲内のすべての整数 i で n を割ったときの剰余がすべて 0 以外となる.ひとつでも剰余が 0 となるのであれば n は素数ではない.剰余は % 演算子を用いることで計算できる.

課題3

次の仕様を満たす関数を作成し、それを使うプログラムを作成せよ.

関数名: int sosu(int n)

仕様: 引数として整数 n を受け取り、それが素数であれば戻り値として 1 を返し、n が素数ではないまたは負である場合には -1 を返す

課題4

課題2のプログラム(素数判定プログラム)を課題3で作った関数を使うものに変更せよ.

Part.7で学んだ事

  • 関数を作成し、使うことができるようになりました