2.12.8. 関数#
2.12.8.1. 関数の定義#
C/C++ では、関数を定義するときに引数とその型、さらに戻り値の型を指定する必要があります。例えば、整数 a と整数 b の和を計算して返す関数 add を定義し、main 関数から呼び出す例は次の通りです。main 関数から add を呼び出すため、add 関数の定義を main の前に置いています。
#include <stdio.h>
int add(int x, int y) {
int s = x + y;
return s;
}
int main() {
int a = 10;
int b = 20;
int s = add(a, b);
printf("%d", s);
return 0;
}
add 関数を main 関数の後に記述する場合は、関数プロトタイプを main の前に宣言する必要があります。
#include <stdio.h>
int add(int, int);
int main() {
int a = 10;
int b = 20;
int s = add(a, b);
printf("%d", s);
return 0;
}
int add(int x, int y) {
int s = x + y;
return s;
}
2.12.8.2. 関数のオーバーロード#
C/C++ では、関数は引数の型まで含めて識別されます。例えば int add(int x, int y) に小数を渡すと、小数は整数に変換されてから計算されます。異なる型に対応した関数を同じ名前で定義できる機能を関数のオーバーロードと呼びます。
#include <stdio.h>
float add(int, int);
float add(float, float);
float add(int, float);
float add(float, int);
int main() {
float a = 1.1;
int b = 2;
float s = add(a, b);
printf("%f", s);
return 0;
}
float add(int x, int y) {
float s = (float)x + y;
return s;
}
float add(float x, float y) {
float s = x + y;
return s;
}
float add(int x, float y) {
float s = x + y;
return s;
}
float add(float x, int y) {
float s = x + y;
return s;
}
このように同じ機能の関数を複数定義する場合、C++ のテンプレート機能を使うとより便利です。
2.12.8.3. 値渡し・ポインタ渡し・参照渡し#
関数に引数を渡す方法には次の種類があります。
値渡し:引数のコピーが渡されるため、関数内で値を変更しても呼び出し元には影響がありません。
ポインタ渡し:変数のアドレスが渡されるため、関数内で値を変更すると呼び出し元に反映されます。
参照渡し:C++ で追加された機能で、関数内で変更すると呼び出し元にも反映されます。
2.12.8.3.1. 値渡し#
#include <stdio.h>
void f(int x) {
x += 1;
}
int main(void) {
int x = 10;
printf("%d\n", x); // 10
f(x);
printf("%d\n", x); // 10
return 0;
}
2.12.8.3.2. ポインタ渡し#
#include <stdio.h>
void g(int* x) {
*x += 1;
}
int main(void) {
int x = 10;
printf("%d\n", x); // 10
g(&x);
printf("%d\n", x); // 11
return 0;
}
2.12.8.3.3. 参照渡し#
#include <stdio.h>
void h(int& x) {
x += 1;
}
int main(void) {
int x = 10;
printf("%d\n", x); // 10
h(x);
printf("%d\n", x); // 11
return 0;
}
2.12.8.4. 関数の引数と戻り値に配列を指定する方法#
2.12.8.4.1. 配列を引数に渡す#
C/C++ では関数に配列そのものを渡すことはできません。その代わり、配列の先頭要素のアドレス、つまりポインタを渡します。配列名は先頭要素へのポインタとして扱われます。
#include <stdio.h>
int sum(int* arr, int arr_size) {
int sum = 0;
for (int i = 0; i < arr_size; i++) {
sum += arr[i];
}
return sum;
}
int main(void) {
int arr[] = {1, 2, 3, 4, 5};
int s = sum(arr, sizeof(arr)/sizeof(arr[0]));
printf("%d\n", s);
return 0;
}
関数の引数として配列を指定する場合、次のように書くこともできます。
int sum(int arr[], int arr_size) { ... }
配列の内容を変更して反映させたい場合は、戻り値を持たず、ポインタ経由で配列を操作します。
#include <stdio.h>
void times1000(int* arr, int arr_size) {
for (int i = 0; i < arr_size; i++) {
arr[i] *= 1000;
}
}
int main(void) {
int arr[] = {1, 2, 3, 4, 5};
times1000(arr, sizeof(arr)/sizeof(arr[0]));
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
printf("%d\n", arr[i]);
}
return 0;
}
2.12.8.4.2. 配列を戻り値として返す#
関数の戻り値として配列を直接返すことはできません。その代わり、配列のポインタを返します。関数内部で static 修飾子を使うと、関数終了後もメモリが有効なままになります。
#include <stdio.h>
int* calc(int x, int y) {
static int arr[6];
arr[0] = sizeof(arr)/sizeof(arr[0]);
arr[1] = x + y;
arr[2] = x - y;
arr[3] = x * y;
arr[4] = x / y;
arr[5] = x % y;
return arr;
}
int main(void) {
int* arr = calc(10, 20);
for (int i = 1; i < arr[0]; i++) {
printf("%d\n", arr[i]);
}
return 0;
}