【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
  • このエントリーをはてなブックマークに追加

関連記事

PAK15_notepenhikkiyougu20140312500-thumb-500xauto-4327

【C言語/C++】fgetsを使ってファイルを読み込む

fgetsで単純にファイルを読み取る C言語、C++でfgetsを使ってファイルを読み込む方法です

記事を読む

PAK86_codeing20140517500-thumb-500xauto-4601

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

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

記事を読む

Window Command Line

コンソールアプリケーションでC++/CLIの関数を使う

今時(?)なかなか使っている人がいるかどうかわかりませんが、VisualStudio(2008)で「

記事を読む

blog-372771_640

【C言語】文字列に指定の文字列が含まれるか調べる

ある文字列に指定の文字列が含まれるかどうかを調べるにはstring.hにあるstrstr関数を使いま

記事を読む

CSS85_keywosousasruop20131019500-thumb-500xauto-4249

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

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

記事を読む

PAK86_codeing20140517500-thumb-500xauto-4601

【C言語/C++】余りを求める剰余演算子(%)を使う

基本的なことかもしれませんが、C言語やC++などであまりを出すには剰余演算子である『%』を使います。

記事を読む

CSSS85_MBAwonozokujyosei20131019500-thumb-500xauto-4044

【C++】vectorの解放

C++STLにあるvectorは配列の要素数がわからない場合などに非常に便利ですがメモリ関係で面倒だ

記事を読む

no image

【C++】文字列のcontainsメソッドによる比較

C++/CLIなどではStringのContainsメソッドが便利ですが、純粋なC++のstring

記事を読む

question

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

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

記事を読む

PAK23_husentomemo20140313500-thumb-500xauto-4376

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

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

記事を読む

encodingtype
【PHP】headerでContent-Typeを指定したのに効かない場合の対処法

PHPでサイトマップを作ろうと思い、XML形式のファイルを出力しようと

_rtm0919_tp_v
スマホ向け幅固定サイトの回転時の幅対応方法

幅固定サイトでのスマホ回転時Webサイトの横幅を合わせる方法のメモ。

rssimage
【PHP】特定のURLからそのAtomやRSSのフィードを抽出する方法

特定のURLからRSSやATOMのフィードを抽出する方法をメモ。 流

rssimage
フィード抽出ツール(RSS1.0、RSS2.0、atom)

任意URL サイト名 サイトURL RSS1.0

computer_server
格安プラン限定レンタルサーバー機能比較表(2016年)

はじめに  最近新しい共用サーバーをレンタルしようと思い調査およびそ

school_toshokan_hondana
kindle unlimitedが便利だったのでお勧めの使い方など感想メモ

 kindle unlimitedというサービスが8/3からAmazo

TAKEBE055122558_TP_V
寝る前にスマホを見ると斜視になる可能性とその対策

はじめに  寝る前などスマホを横になりながら見続けると斜視になる可能

→もっと見る

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