【C言語/C++】関数の宣言・定義まとめ

公開日: : 最終更新日:2014/08/14 C/C++

スポンサーリンク

関数プロトタイプ宣言・定義

関数は値を入力したら何か帰ってくるブラックボックスみたいなものです。入力は引数と呼ばれ任意の型を複数指定することができ、一方、出力は戻り値とよばれintやdoubleや構造体などを一つだけ指定できます。

戻り値なしの場合はvoid(空)を指定することも可能です。

プロトタイプ宣言

プロトタイプは訳すと「原型」という意味で、プロトタイプ宣言は関数の仕様を示す宣言文のことです。例えば引数が2つあるものは以下のように書きます。

戻り値型 関数名(引数型1 仮引数名1,引数型2 仮引数名2);

引数の数はいくつでも構いませんが引数がいらない場合はvoidを指定します。

戻り値型 関数名(void);

定義

関数は宣言だけでは中身がないので何をするか定義してあげる必要があります。

/*関数プロトタイプ宣言*/
戻り値型 関数名(引数型1 仮引数名1,引数型2 仮引数名2);
/*関数定義*/
戻り値型 関数名(引数型1 仮引数名1,引数型2 仮引数名2)
{
	戻り値型 dst;
	/*何らかの処理(省略)*/
	return dst;
}

returnは関数の戻り値を返す文の一つです。戻り値がない場合(void)はreturn文は不要となります。このように宣言と定義をわけることで複数関数を作る場合でも初めの宣言リストだけ見ればどういう関数があるかわかりやすいということになります。

例)

/*関数プロトタイプ宣言*/
/*足し算*/
int add(int a,int b);
/*引き算*/
int sub(int a,int b);
/*掛け算*/
int mult(int a,int b);
/*割り算*/
double div(int a,int b);
int main(void)
{
	int tmp1,tmp2;
	int dst;
	double dst2;
	tmp1 = 12;
	tmp2 = 30;
	dst = add(tmp1,tmp2);
	printf("足し算:%d\n",dst);
	dst = sub(tmp1,tmp2);
	printf("引き算:%d\n",dst);
	dst = mult(tmp1,tmp2);
	printf("掛け算:%d\n",dst);
	dst2 = div(tmp1,tmp2);
	printf("割り算:%f\n",dst2);
}
/*足し算*/
int add(int a,int b)
{
	return (a+b);
}
/*引き算*/
int sub(int a,int b)
{
	return (a-b);
}
/*掛け算*/
int mult(int a,int b)
{
	return (a*b);
}
/*割り算*/
double div(int a,int b)
{
	return ((double)a/b);
}
足し算:42
引き算:-18
掛け算:360
割り算:0.400000

ここまで宣言と定義を別々に書きましたがまとめて書いてしまっても問題ありません。つまり宣言なしで定義しても大丈夫です。ただし、その定義がmain文などの関数を使う前に記述されている必要がありますので注意してください。

/*足し算*/
int add(int a,int b)
{
	return (a+b);
}
int main(void)
{
	int tmp1,tmp2;
	int dst;
	tmp1 = 12;
	tmp2 = 30;
	dst = add(tmp1,tmp2);
	printf("足し算:%d\n",dst);
}

ファイルを分ける

短いソースコードなら問題ないのですが量が増えるにつれて関数の管理が大変なことになるのですが、そこで便利なのがファイル分割です。役割ごとに別々のファイルにして作業することができます。

sub.h

/*関数プロトタイプ宣言*/
/*足し算*/
int add(int a,int b);
/*引き算*/
int sub(int a,int b);
/*掛け算*/
int mult(int a,int b);
/*割り算*/
double div(int a,int b);

sub.c(sub.cpp)

#include"sub.h"
/*足し算*/
int add(int a,int b)
{
	return (a+b);
}
/*引き算*/
int sub(int a,int b)
{
	return (a-b);
}
/*掛け算*/
int mult(int a,int b)
{
	return (a*b);
}
/*割り算*/
double div(int a,int b)
{
	return ((double)a/b);
}

main.c(main.cpp)

#include"sub.h"
int main(void)
{
	int tmp1,tmp2;
	int dst;
	double dst2;
	tmp1 = 12;
	tmp2 = 30;
	dst = add(tmp1,tmp2);
	printf("足し算:%d\n",dst);
	dst = sub(tmp1,tmp2);
	printf("引き算:%d\n",dst);
	dst = mult(tmp1,tmp2);
	printf("掛け算:%d\n",dst);
	dst2 = div(tmp1,tmp2);
	printf("割り算:%f\n",dst2);
}

結果は先ほどと同じになります。sub.hに関数のプロトタイプ宣言、sub.c(sub.cpp)に関数の定義を書くことで役割分担できるだけでなくこのヘッダとCファイルをそのまま別のところで再利用できるというメリットもあります。

この再利用ですが世の中にはCGのOpenGLやDirectX、画像処理のOpenCVなどのライブラリという便利な関数やクラス群(C++)をひとまとめにして配布しているものがあるので参考にしてみるのも良いのではないかと思います。

関数のオーバーロード

C++のみの機能です。引数の数や型を変えれば同じ名前の関数を定義することができます。

//例)
int add(int a,int b);
int add(int a,double b);
int add(int a,int b,int c);
double add(int a,int b,int c,int d);

戻り値も変更することができますが、引数が同じ場合は定義できないので注意してください。

引数の形式

関数の引数の形式はいくつかあります。いままで普通に書いてきたのは「値渡し」といいいますが、他に「参照渡し」があります。

値渡し

引数として渡した値は関数内に入るとコピーされて使われます。なので関数内で引数の値をいくら変更しても変わることはありません。

例)

void test(int a)
{
	a = 100;
	printf("a=%d\n",a);
}
int main(void)
{
	int x = 1;
	test(x);
	printf("x=%d\n",x);
}
a=100
x=1

関数に引数を渡すたびに値がコピーされるので規模のでかい構造体を引数とする場合に時間がかかってしまうことや、引数の値を変えたいときちょっと困るといった問題があります。

ポインタ渡し

参照渡しとも言いますが、C++のものと区別するためにポインタ渡しとしました。ポインタ渡しでは引数でその変数のアドレスが格納されているので、関数内で値を変えると値が変わります。書き方は(*)マークを引数の前に記述させ、引数に渡すときは&を使います。

例)

void test(int *a)//(int* a)でもいい
{
	a = 100;
	printf("a=%d\n",a);
}
int main(void)
{
	int x = 1;
	test(&x);
	printf("x=%d\n",x);
}
a=100
x=100

参照渡し

C++のみの文法となります。参照渡しとは参照を引数にしてます。ここでの参照とは「別名」の意味を表しており、仮引数(宣言・定義部分の引数)と実引数(実際に代入した引数)は実際には同じものとなっているので、関数内で値を変えるとちゃんと値が変わります。書き方は引数に&を付けるだけです。

例)

void test(int &a)//(int& a)でもいい
{
	a = 100;
	printf("a=%d\n",a);
}
int main(void)
{
	int x = 1;
	test(x);
	printf("x=%d\n",x);
}
a=100
x=100

可変引数

可変引数とは文字通り引数の数が決まってなく、いくつでも引数に代入できる引数です。実はprintfで使われています。

OpenCVやOpenGLなどのライブラリで文字を描画するような関数を作りたいといった場合に利用すると便利だと思います。

『C言語Tips集 – 可変長引数を持つ関数を作成する』
http://www.c-tipsref.com/tips/function/va_arg.html

デフォルト引数

C++のみ。引数にあらかじめ値を入れておける機能です。その引数には値を代入しても構わないですし、もちろん何も書かなくても大丈夫になります。

int sum(int a,int b,int c=0)
{
	return (a+b+c);
}
int main(void)
{
	int test = sum(10,4);
	int test2 = sum(10,4,5);
	printf("test=%d , test2=%d\n",test,test2);
}
test=14 , test2=19

上の例では宣言は書きませんでしたが、宣言と定義を別々にする場合は宣言の方だけデフォルトの引数を記述してください。(両方書くとエラーになる)

int sum(int a,int b,int c=0);
int main(void)
{
	int test = sum(10,4);
	int test2 = sum(10,4,5);
	printf("test=%d , test2=%d\n",test,test2);
}
int sum(int a,int b,int c)
{
	return (a+b+c);
}

なお、一つの引数だけではなく複数の引数で可能ですが、その引数の右側は全てデフォルト引数が入っている形でないとエラーが出ます。あと、通常の関数と区別のつかないオーバーロードもダメです。

良い例)

int sum1(int a,int b=0,int c=0);
int sum2(int a=0,int b=0,int c=0);
int sum3(int a,int b);
int sum3(int a,int b,int c,int d=0);

エラーが出る例)

int sum1(int a,int b=0,int c);
int sum2(int a=0,int b,int c=0);
int sum3(int a,int b);
int sum3(int a,int b,int c=0);//sum3は区別のつかない場合があるのでエラー
『関数プロトタイプ』
http://www.cc.kyoto-su.ac.jp/~hxm/cstext/prog03.html

『プロトタイプ e-Words』
http://e-words.jp/w/E38397E383ADE38388E382BFE382A4E38397.html

『ソースファイルの分割と外部参照の解消』
http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide84.html

『関数オーバーロード』
http://msdn.microsoft.com/ja-jp/library/vstudio/5dhe1hce.aspx

『値渡しと参照渡し(WikiBooks)』
http://ja.wikibooks.org/wiki/C%E8%A8%80%E8%AA%9E/%E9%96%A2%E6%95%B0#.E5.80.A4.E6.B8.A1.E3.81.97.E3.81.A8.E5.8F.82.E7.85.A7.E6.B8.A1.E3.81.97

『C++編(言語解説) 第15章 参照』
http://www.geocities.jp/ky_webid/cpp/language/015.html

『C言語Tips集 – 可変長引数を持つ関数を作成する』
http://www.c-tipsref.com/tips/function/va_arg.html

『関数のデフォルト引数 』
http://homepage1.nifty.com/MADIA/vc/C__/2_1.htm

『言語別のデフォルト引数』
http://d.hatena.ne.jp/tako222/20100327/1269681087

『【C++全般】デフォルト引数に注意せよ』
http://blog.livedoor.jp/dormolin/archives/52020664.html

スポンサーリンク
Amazon
  • このエントリーをはてなブックマークに追加

関連記事

【C言語/C++】配列をシャッフルしてランダムに入れ替える

C言語・C++で配列をシャッフルする方法 Fisher–Yatesシャッフルアルゴルズムにより配列

記事を読む

no image

【C++】既に main.obj で定義されています

error LNK2005: 既に main.obj で定義されています。 fatal error

記事を読む

【C言語/C++】関数ポインタと関数オブジェクトを使ってみる

関数ポインタを使う 関数ポインタはポインタの一種で文字通り関数のポインタの事で、関数を遠隔操作でき

記事を読む

【C言語】printfのような関数を作る

C言語でよくつかわれるprintfでは例えば int a,b,c; … printf(

記事を読む

【C言語/C++】配列のまとめ

C/C++を使っていると必ず配列を使う場面が出てくると思いますが、その配列についてまとめました。C言

記事を読む

【C言語/C++】コンソールでAAアニメーション

コンソール上でAA(アスキーアート)のアニメーションをさせます。 手順としては

記事を読む

【C言語/C++】はてなの演算子の三項演算子について

C言語などのサンプルにたまに出てくるはてな(?)の演算子は 『?』と『:』の2つで1つの演算子であ

記事を読む

【C言語/C++】ファイルをCSV形式でfprintfを使って保存・書き込みする

数値計算などをC言語でプログラミングするとき、その演算結果をファイルとして保存する必要性がでてくるこ

記事を読む

【C言語/C++】フォルダ作成を行う

C言語、C++でフォルダを作成するには『direct.h』にある『_mkdir』関数を使うことで実現

記事を読む

【C言語/C++】int整数などの数値をchar配列の文字列に変換する

C++であればstringが使えて非常に便利ですが、C言語で文字列というと基本的にはcharの配列を

記事を読む

NVIDIA DIGITSをSupervisorを使って自動起動する

はじめに 先日Ubuntu14.04にDIGITS 5をGPUなしP

【2017年度】GeForce 1080 Ti搭載BTOパソコン比較

はじめに 最近ディープラーニング用にGPUのないPCにDIGITSを

Windows用のシンプルなストップウォッチソフト紹介

Windows(10)でも使える使いやすいKAZAMITimerという

MNISTをDIGITS 5のCPUのみで試す(GPUなし)

はじめに DIGITSを使えばGUI操作で簡単にディープラーニングが

Windowsユーザが初めてMacBookを購入したときの注意点や感想

最近12インチのMacBookを購入しました。今までWindowsしか

Redmine3.2をUbuntu14.04にインストールして躓いた所についてメモ

はじめに Ubuntu14.04 ServerにRedmine3.2

UWSCを使ったソフト自動立ち上げ【SoftEther VPN Server】

やりたいこと 最近SoftEtherという筑波大学発のベンチャー企業

→もっと見る

  • Author : ががんぼ
    プログラミングやWeb関係で気付いたことについてメモしていく予定。だいたいが備忘録ですが、自分でサンプルを作って動かしてみたりしています。
PAGE TOP ↑