# 関数

## 関数の定義

C/C++ では、関数を定義するときに引数とその型、さらに戻り値の型を指定する必要があります。例えば、整数 `a` と整数 `b` の和を計算して返す関数 `add` を定義し、`main` 関数から呼び出す例は次の通りです。`main` 関数から `add` を呼び出すため、`add` 関数の定義を `main` の前に置いています。

```cpp
#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` の前に宣言する必要があります。

```cpp
#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;
}
```

## 関数のオーバーロード

C/C++ では、関数は引数の型まで含めて識別されます。例えば `int add(int x, int y)` に小数を渡すと、小数は整数に変換されてから計算されます。異なる型に対応した関数を同じ名前で定義できる機能を関数のオーバーロードと呼びます。

```cpp
#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++ のテンプレート機能を使うとより便利です。

## 値渡し・ポインタ渡し・参照渡し

関数に引数を渡す方法には次の種類があります。

- 値渡し：引数のコピーが渡されるため、関数内で値を変更しても呼び出し元には影響がありません。
- ポインタ渡し：変数のアドレスが渡されるため、関数内で値を変更すると呼び出し元に反映されます。
- 参照渡し：C++ で追加された機能で、関数内で変更すると呼び出し元にも反映されます。

### 値渡し

```cpp
#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;
}
```

### ポインタ渡し

```cpp
#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;
}
```

### 参照渡し

```cpp
#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;
}
```

## 関数の引数と戻り値に配列を指定する方法

### 配列を引数に渡す

C/C++ では関数に配列そのものを渡すことはできません。その代わり、配列の先頭要素のアドレス、つまりポインタを渡します。配列名は先頭要素へのポインタとして扱われます。

```cpp
#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;
}
```

関数の引数として配列を指定する場合、次のように書くこともできます。

```cpp
int sum(int arr[], int arr_size) { ... }
```

配列の内容を変更して反映させたい場合は、戻り値を持たず、ポインタ経由で配列を操作します。

```cpp
#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;
}
```


### 配列を戻り値として返す

関数の戻り値として配列を直接返すことはできません。その代わり、配列のポインタを返します。関数内部で `static` 修飾子を使うと、関数終了後もメモリが有効なままになります。

```cpp
#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;
}
```
