[前へ]   [目次へ]   [次へ]

関数(1)(C/C++)


今回は、関数についてです。
これまで、関数というと printf とか puts とか fgets とかの言語標準関数が出てきました。
他に関数というと数学の y=2x とか y=3x+3 といった一次関数や f(x) といったものがあります。

これらは一見異なる「関数」ですが、C/C++の関数の扱いは実際は f(x) の記法とそっくりです。

ちなみに、 f(x) について知らない人に f(x) について簡単に説明すると、
例えば、
f(x)=2x
と最初に定義した後で、
y=f(x)
などとします。
この場合、 f(x) は 2x と定義されているので、
y=f(x)

y=2x
と同じ解釈になります。

f(x) は定義時に与える式により、一次関数だけでなく二次関数など他の関数にもなります。

↓具体値を求める場合は f(x) を f(2) などのように定数を与えます。
y=f(2)
この場合、上記の定義に加えて x=2 として計算します。
なので、 f(x)=2x の x の部分が2に置き換えられて
f(2)=2*2
となり、 y は4となります。


さて、これとほぼ同じことがC/C++での関数でもできます。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
#include <stdio.h>

int f(int x){//(1)
   
return 2*x;
}

int main(void){
   
int y;
   y=f(2);
//(2)
   
printf("%d\n",y);
   
//終了待ち
   
getchar();
   
return 0;
実行結果:
4

このソースは、先ほどの f(x) で行ったことと同じことを行います。
f(x)=2x
の部分が(1)3行目〜5行目に、
y=f(2)
の部分が(2)9行目にあたります。

なお、コンパイラは上から順に読んでいくので、
(1)の関数定義を(2)の呼び出しよりも下に書いてしまうと、
「関数 f は(まだ)定義されていません」とエラーになってしまいます。



遅れながら今回は「関数とは何か」についてが本題となります。
細かい記述部分は次回書きます。

上記のように、関数の定義部分はややこしくなってしまっていますが、
関数を使う時は数学のそれとそっくりなのがお分かりでしょうか。

もちろん、(2)9行目を
y=f(3);
とすれば結果は6となります。

さらに定数の代わりに変数を入れるとその変数の値で計算します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
#include <stdio.h>

int f(int x){
   
return 2*x;
}

int main(void){
   
int y,n=2;
   y=f(n);
//変数n(値2)を渡すと、f(2)と同じ扱い
   
printf("%d\n",y);
   
//終了待ち
   
getchar();
   
return 0;
実行結果:
4


さらにさらに式を入れると式の計算結果で計算します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
#include <stdio.h>

int f(int x){
   
return 2*x;
}

int main(void){
   
int y,n=5;
   y=f(n-3);
//式 n-3 の結果は2なので、f(2)と同じ扱い
   
printf("%d\n",y);
   
//終了待ち
   
getchar();
   
return 0;
実行結果:
4


と、このように関数に与える値を変えることで結果を変えることができ、
変数や式などを与えることでより変化を与えることができます。
↓ループと組み合わせれば数列を得ることだってできちゃいます。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
#include <stdio.h>

int f(int x){
   
return 2*x;
}

int main(void){
   
int y,i;
   
for(i=0;i<10;i++){
      y=f(i);
//ループするたびにiの値が増えるので・・・
      
printf("%d,",y);
   }
   
//終了待ち
   
getchar();
   
return 0;
実行結果:
0,2,4,6,8,10,12,14,16,18,


このように、C/C++の関数は数学の関数と同様にも使えます。
しかし、 printf や puts などの関数は数学の関数とは明らかに異なる使い方をしています。
すなわち、C/C++における関数の定義や使い方は何通りかのパターンがあります。
代表的なものは以下のようなものです。
●1.引数によって結果が確定する(数学における関数と同様、今回の関数 f もコレ)
●2.引数と他の何かによって結果が確定する
●3.他の何かによって結果が確定する
●4.引数によって結果以外にも何かが起こる
●5.引数と他の何かによって結果以外にも何かが起こる
●6.他の何かによって結果以外にも何かが起こる
ここで、「引数」は関数呼び出し時に与えた引数です。

「他の何か」は過去に呼び出した関数であったり、変数であったり、
プログラム管理情報であったり、システムの状態であったり、様々な引数以外の要因です。
「他の何か」が影響を与える場合は「何がどう影響するか」がドキュメントに記載されています。

「結果以外に起こる何か」はそれを実行することで上記「他の何か」に当たるものに影響を与えるものです。
printf や puts が実行中に「画面に文字を表示する」のもこれに当たります。
「影響を与える何か」がある場合は「何にどう影響するか」がドキュメントに記載されています。
また、この特性を持つものは「結果以外の作用をもたらす」ということで「副作用がある」とも呼びます。


ここで、1. 4. のパターンは呼び出し時の引数とその結果が対になることが保証されます。
つまり、引数を同じにすれば必ず同じ結果が得られるということです。
2. 3. 5. 6. のパターンは「他の何か」の変化可能性により、結果が対になることが保証されません。
これは引数が同じであっても結果が同じとは限らないことを意味します。

ちなみにこれまで出てきた関数がどれに該当するかというと、
関数名パターン
printf5.引数と他の何か(標準出力の状態)によって結果以外にも何か(標準出力の状態変化)が起こる
puts5.引数と他の何か(標準出力の状態)によって結果以外にも何か(標準出力の状態変化)が起こる
gets5.引数と他の何か(標準入力の状態)によって結果以外にも何か(標準入力の状態変化、変数の更新)が起こる
fgets5.引数と他の何か(標準入力の状態)によって結果以外にも何か(標準入力の状態変化、変数の更新)が起こる
scanf5.引数と他の何か(標準入力の状態)によって結果以外にも何か(標準入力の状態変化、変数の更新)が起こる
sscanf4.引数によって結果以外にも何か(変数の更新)が起こる
srand4.引数によって結果以外にも何か(乱数種の更新)が起こる
rand6.他の何か(乱数種の値)によって結果以外にも何か(乱数種の更新)が起こる
time5.引数と他の何か(システムの時計)によって結果以外にも何か(変数の更新)が起こる
注:引数にNULL以外を与えた場合。NULLを与えた場合は「3.他の何か(システムの時計)によって結果が確定する」の動作。
と、これまで出てきた関数はほとんど「他の何か」に影響を与えています。
1〜3のパターンと4〜6のパターンはかなり用法が異なってくるので、
完全な別物に見えますが同じ「関数」であり、文法は同じものを使います。


ちなみに、「1.引数によって結果が確定する」に該当する標準関数には
sin cos tan 三角関数など、数学関数群などがあります。

「2.引数と他の何かによって結果が確定する」に該当する標準関数には
文字判定関数群や文字変換関数群などがあります。これらは文字コードの設定により結果が変化します。

次回は関数定義についてです。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17