はじめに
本投稿は、C++入門 名前空間・for文・配列の続きです。今回は、関数について解説をします。
関数の書き方
関数は、特定の作業をまとめておくものです。
下記のように記述をします。
#include <iostream>
void helloworld(){
std::cout << "Hello World!" << std::endl;
}
int main(){
helloworld();
}
// 出力
// Hello World!
細かく分けて解説をします。
void helloworld(){
std::cout << "Hello World!" << std::endl;
}
まず、ここで関数の宣言・定義をします。定義の仕方は、
返り値の型 関数名(引数の型){ 関数の処理 }
の形で記述します。ここで、返り値とは関数で処理をした結果として返す値、引数とは関数に与える値のことを言います。上記の例では、Hello World!
と出力させる処理だけであるため、返り値・引数はありません。返り値が無い場合はvoid
として定義します。
int main(){
helloworld();
}
関数を呼び出すには、メイン関数内で関数名を呼び出せば良いです。
プロトタイプ宣言
プログラムは一番上の行から順に実行するのが基本のため、関数の宣言はメイン関数より上で定義する必要があります。しかし、使用する関数が多くなったり複雑になるほど、メイン関数の記述はどんどん下の行になってしまいます。そこで、以下のようにプロトタイプ宣言という、コンパイラに関数の存在を知らせる記述をすることで、関数を記述する位置をメイン関数よりも後ろにすることができます。
#include <iostream>
void helloworld();
int main(){
helloworld();
}
void helloworld(){
std::cout << "Hello World!" << std::endl;
}
// 出力
// Hello World!
値渡し
返り値と引数が存在する場合には、下記のように定義します。
#include <iostream>
int twice(int a){
return a * 2;
}
int main(){
int x = 10;
int y = twice(x);
std::cout << "y = " << y << std::endl;
}
// 出力
// 20
上記の場合、定義したメイン関数でtwice関数を呼び出した際、x(=10)がtwice関数のaにコピーされます。そして、twice関数でa*aを計算し、返り値としてyに格納されます。このような引数の渡し方を値渡しと呼びます。
ただし、この方法では、引数として渡す型のサイズが小さければ問題ありませんが、サイズが大きくなると処理時間が長くなってしまうというデメリットがあります。
ポインタ渡し
ポインタ渡しとは、変数のメモリ上のアドレスを参照する方法です。int x = 10;
で変数を定義した際に、メモリ上には領域が確保されます。&(変数)
の記述により、指定した変数のメモリ上のアドレスを参照することができます。&はアドレス参照演算子と呼びます。
#include <iostream>
int twice(int* a){
std::cout << "*a = " << *a << std::endl;
return *a * 2;
}
int main(){
int x = 10;
std::cout << "x = " << x << std::endl;
std::cout << "&x = " << &x << std::endl; //&xでアドレスを取得
int y = twice(&x);
std::cout << "y = " << y << std::endl;
}
// 出力
// x = 10
// &x = 0x7ffdbf4d23a4
// *a = 10
// y = 20
この例では、twice関数の引数にアドレスが渡されるように定義しています。ポインタint* a
における*
は間接参照演算子と呼ばれ、xのアドレスを代入しています。これにより、関数の呼び出し元の変数を書き換えることができ、値渡しのようにコピーすることは無くなります。まとめると、下記のような関係となります。
- &(変数):変数のメモリ上のアドレスを示す(参照)
- 型名* 変数:変数のアドレスを代入する
参照渡し
ポインタ渡しで使用した参照機能を関数に適用することで、呼び出し元の変数にアクセスすることができます。
#include <iostream>
void twice(int& a){
std::cout << "a = " << a << std::endl;
std::cout << "&a = " << &a << std::endl;
a = a * 2;
}
int main(){
int x = 10;
int & ref_x = x; //参照変数の定義
std::cout << "&x = " << &x << std::endl;
std::cout << "&ref_x = " << &ref_x << std::endl;
twice(x);
std::cout << "x = " << x << std::endl;
}
//出力
//0x7ffde77b1544
//0x7ffde77b1544
//20
この例では、変数 x
のアドレスに対して、参照変数 ref_x
というラベルを貼り付けており、xと ref_x はメモリ上において同一のアドレスに存在しています。この参照機能を使用することで、変数 x
とtwice関数の参照変数 a は同一のアドレスを示し、参照変数 a
の値を2倍すると、メイン関数の変数 x
の値を書き換えることが可能です。
ポインタ渡しでは、&(アドレス参照演算子)や *(間接参照演算子)を駆使する必要がありますが、参照渡しではそれに比べて簡素な記述で同様の出力を得ることができるようになっています。