[C++] 配列を関数の引数として渡す方法

C++では、配列を関数の引数として渡す際に、配列のポインタを使用することが一般的です。

関数のパラメータとして配列を受け取る場合、配列の要素数を指定することはできませんが、ポインタを使って配列の先頭アドレスを渡すことができます。

この方法により、関数内で配列の要素にアクセスすることが可能です。

また、配列のサイズを関数内で使用する場合は、別途サイズを引数として渡す必要があります。

この記事でわかること
  • 配列を関数に渡す際のポインタと参照の使い方
  • std::arrayとstd::vectorを用いた配列の渡し方と返し方
  • 多次元配列や部分配列を関数に渡す方法
  • 配列を使ったソートや探索アルゴリズムの実装例

目次から探す

配列を関数に渡す方法

C++では、配列を関数に渡す方法がいくつかあります。

それぞれの方法には利点と注意点があり、用途に応じて使い分けることが重要です。

以下では、配列を関数に渡す方法について詳しく解説します。

配列のポインタを渡す

ポインタを使った配列の渡し方

配列を関数に渡す最も一般的な方法は、配列の先頭要素のポインタを渡すことです。

以下にその例を示します。

#include <iostream>
// 配列をポインタで受け取る関数
void printArray(int* array, int size) {
    for (int i = 0; i < size; ++i) {
        std::cout << array[i] << " ";
    }
    std::cout << std::endl;
}
int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    printArray(numbers, size); // 配列の先頭アドレスを渡す
    return 0;
}
1 2 3 4 5

この方法では、配列の先頭アドレスを渡すことで、関数内で配列の要素にアクセスできます。

ポインタを使う際の注意点

  • 配列のサイズ情報は別途渡す必要があります。

ポインタだけでは配列のサイズを知ることができません。

  • 配列の要素数が固定されていない場合、誤ったサイズを渡すとバッファオーバーランの原因になります。

配列の参照を渡す

参照を使った配列の渡し方

C++11以降では、配列を参照として渡すことも可能です。

これにより、配列のサイズをコンパイル時に固定することができます。

#include <iostream>
// 配列を参照で受け取る関数
template <size_t N>
void printArray(const int (&array)[N]) {
    for (size_t i = 0; i < N; ++i) {
        std::cout << array[i] << " ";
    }
    std::cout << std::endl;
}
int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    printArray(numbers); // 配列を参照で渡す
    return 0;
}
1 2 3 4 5

この方法では、配列のサイズがテンプレート引数として渡されるため、サイズ情報を別途渡す必要がありません。

参照を使う際の注意点

  • 配列のサイズが固定されるため、異なるサイズの配列を同じ関数に渡すことはできません。
  • テンプレートを使用するため、コンパイル時にコードが展開され、バイナリサイズが増加する可能性があります。

std::arrayを使った方法

std::arrayの基本

std::arrayは、C++11で導入された固定サイズの配列を扱うためのコンテナです。

std::arrayは、配列のサイズをテンプレート引数として指定します。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> numbers = {1, 2, 3, 4, 5};
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
1 2 3 4 5

std::arrayは、配列のサイズをコンパイル時に固定し、要素数を超えるアクセスを防ぎます。

std::arrayを関数に渡す方法

std::arrayを関数に渡す際は、通常のオブジェクトと同様に参照を使うことが一般的です。

#include <iostream>
#include <array>
// std::arrayを参照で受け取る関数
void printArray(const std::array<int, 5>& array) {
    for (int num : array) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}
int main() {
    std::array<int, 5> numbers = {1, 2, 3, 4, 5};
    printArray(numbers); // std::arrayを参照で渡す
    return 0;
}
1 2 3 4 5

この方法では、std::arrayのサイズが固定されているため、サイズ情報を別途渡す必要がありません。

std::vectorを使った方法

std::vectorの基本

std::vectorは、可変長の配列を扱うためのコンテナです。

要素の追加や削除が容易で、動的にサイズを変更できます。

#include <iostream>
#include <vector>
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    numbers.push_back(6); // 要素を追加
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
1 2 3 4 5 6

std::vectorは、動的にサイズを変更できるため、柔軟な配列操作が可能です。

std::vectorを関数に渡す方法

std::vectorを関数に渡す際は、通常のオブジェクトと同様に参照を使うことが一般的です。

#include <iostream>
#include <vector>
// std::vectorを参照で受け取る関数
void printVector(const std::vector<int>& vec) {
    for (int num : vec) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}
int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    printVector(numbers); // std::vectorを参照で渡す
    return 0;
}
1 2 3 4 5

この方法では、std::vectorのサイズを動的に変更できるため、柔軟な配列操作が可能です。

配列を関数から返す方法

C++では、関数から配列を返す方法がいくつかあります。

配列のポインタを返す方法や、std::arraystd::vectorを使った方法があります。

それぞれの方法について詳しく解説します。

配列のポインタを返す

配列のポインタを関数から返す方法は、動的にメモリを確保する必要があります。

以下にその例を示します。

#include <iostream>
// 配列のポインタを返す関数
int* createArray(int size) {
    int* array = new int[size]; // 動的にメモリを確保
    for (int i = 0; i < size; ++i) {
        array[i] = i + 1; // 配列に値を設定
    }
    return array;
}
int main() {
    int size = 5;
    int* numbers = createArray(size);
    for (int i = 0; i < size; ++i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << std::endl;
    delete[] numbers; // メモリを解放
    return 0;
}
1 2 3 4 5

この方法では、動的にメモリを確保するため、使用後に必ずdelete[]でメモリを解放する必要があります。

std::arrayを返す

std::arrayを関数から返す方法は、配列のサイズが固定されている場合に適しています。

#include <iostream>
#include <array>
// std::arrayを返す関数
std::array<int, 5> createArray() {
    std::array<int, 5> array = {1, 2, 3, 4, 5};
    return array;
}
int main() {
    std::array<int, 5> numbers = createArray();
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
1 2 3 4 5

この方法では、std::arrayのサイズが固定されているため、サイズ情報を別途管理する必要がありません。

std::vectorを返す

std::vectorを関数から返す方法は、可変長の配列を扱う場合に適しています。

#include <iostream>
#include <vector>
// std::vectorを返す関数
std::vector<int> createVector(int size) {
    std::vector<int> vec(size);
    for (int i = 0; i < size; ++i) {
        vec[i] = i + 1; // ベクターに値を設定
    }
    return vec;
}
int main() {
    int size = 5;
    std::vector<int> numbers = createVector(size);
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
1 2 3 4 5

この方法では、std::vectorのサイズを動的に変更できるため、柔軟な配列操作が可能です。

また、std::vectorは自動的にメモリ管理を行うため、メモリリークの心配がありません。

応用例

配列を関数に渡す基本的な方法を理解したら、次は応用的な使い方を学びましょう。

ここでは、多次元配列や部分配列の渡し方、配列を使ったアルゴリズムの実装例を紹介します。

多次元配列を関数に渡す

多次元配列の定義と渡し方

多次元配列を関数に渡す場合、配列の次元数と各次元のサイズを指定する必要があります。

以下にその例を示します。

#include <iostream>
// 多次元配列を受け取る関数
void printMatrix(int matrix[2][3]) {
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }
}
int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    printMatrix(matrix); // 多次元配列を渡す
    return 0;
}
1 2 3
4 5 6

この方法では、配列の次元数と各次元のサイズを関数の引数で指定します。

多次元配列のポインタを使う方法

多次元配列をポインタで渡す場合、ポインタの配列を使うことができます。

#include <iostream>
// 多次元配列をポインタで受け取る関数
void printMatrix(int* matrix, int rows, int cols) {
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            std::cout << *(matrix + i * cols + j) << " ";
        }
        std::cout << std::endl;
    }
}
int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    printMatrix(&matrix[0][0], 2, 3); // ポインタで渡す
    return 0;
}
1 2 3
4 5 6

この方法では、配列の要素をポインタ演算でアクセスします。

配列の一部を関数に渡す

部分配列の渡し方

配列の一部を関数に渡す場合、配列の開始位置と長さを指定します。

#include <iostream>
// 部分配列を受け取る関数
void printSubArray(int* array, int start, int length) {
    for (int i = 0; i < length; ++i) {
        std::cout << array[start + i] << " ";
    }
    std::cout << std::endl;
}
int main() {
    int numbers[] = {1, 2, 3, 4, 5, 6};
    printSubArray(numbers, 2, 3); // 部分配列を渡す
    return 0;
}
3 4 5

この方法では、配列の開始位置と長さを指定して部分配列を渡します。

範囲を指定する方法

C++20以降では、std::spanを使って範囲を指定することができます。

#include <iostream>
#include <span>
// std::spanを使って部分配列を受け取る関数
void printSpan(std::span<int> sp) {
    for (int num : sp) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}
int main() {
    int numbers[] = {1, 2, 3, 4, 5, 6};
    printSpan(std::span<int>(numbers).subspan(2, 3)); // 範囲を指定して渡す
    return 0;
}
3 4 5

std::spanを使うことで、配列の一部を簡潔に渡すことができます。

配列を使ったアルゴリズムの実装

ソートアルゴリズムの実装例

配列を使ったソートアルゴリズムの例として、バブルソートを実装します。

#include <iostream>
// バブルソートを実装する関数
void bubbleSort(int* array, int size) {
    for (int i = 0; i < size - 1; ++i) {
        for (int j = 0; j < size - i - 1; ++j) {
            if (array[j] > array[j + 1]) {
                std::swap(array[j], array[j + 1]);
            }
        }
    }
}
int main() {
    int numbers[] = {5, 3, 2, 4, 1};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    bubbleSort(numbers, size);
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
1 2 3 4 5

バブルソートは、隣接する要素を比較して並べ替えるシンプルなソートアルゴリズムです。

探索アルゴリズムの実装例

配列を使った探索アルゴリズムの例として、線形探索を実装します。

#include <iostream>
// 線形探索を実装する関数
int linearSearch(int* array, int size, int target) {
    for (int i = 0; i < size; ++i) {
        if (array[i] == target) {
            return i; // 見つかった場合のインデックスを返す
        }
    }
    return -1; // 見つからなかった場合
}
int main() {
    int numbers[] = {5, 3, 2, 4, 1};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    int target = 4;
    int index = linearSearch(numbers, size, target);
    if (index != -1) {
        std::cout << "Found at index: " << index << std::endl;
    } else {
        std::cout << "Not found" << std::endl;
    }
    return 0;
}
Found at index: 3

線形探索は、配列の要素を順番にチェックして目的の要素を探すシンプルな探索アルゴリズムです。

よくある質問

配列を関数に渡すときにコピーは発生しますか?

配列を関数に渡す際、通常は配列の先頭要素のポインタが渡されるため、配列全体のコピーは発生しません。

これは、配列のポインタを渡す方法や参照を使う方法でも同様です。

したがって、配列の要素数が多い場合でも、効率的に関数に渡すことができます。

ただし、std::arraystd::vectorを値渡しする場合は、コピーが発生するため、参照渡しを使用することが推奨されます。

配列のサイズを関数内で取得する方法はありますか?

配列のサイズを関数内で取得するためには、配列のサイズを別途引数として渡す必要があります。

C++の配列はポインタとして渡されるため、関数内で配列のサイズを直接取得することはできません。

例:void function(int* array, int size)のように、サイズを引数として渡すことで、関数内で配列のサイズを利用できます。

std::arraystd::vectorを使用する場合は、size()メソッドを使ってサイズを取得できます。

std::vectorと配列のどちらを使うべきですか?

std::vectorと配列のどちらを使うべきかは、用途によって異なります。

std::vectorは、動的にサイズを変更できるため、要素の追加や削除が頻繁に行われる場合に適しています。

また、std::vectorは自動的にメモリ管理を行うため、メモリリークの心配が少なくなります。

一方、配列は固定サイズでメモリ効率が良いため、サイズが決まっている場合やパフォーマンスが重要な場合に適しています。

用途に応じて、適切なデータ構造を選択することが重要です。

まとめ

この記事では、C++における配列を関数に渡す方法や返す方法、さらに応用的な使い方について詳しく解説しました。

配列のポインタや参照、std::arraystd::vectorを用いたさまざまな手法を理解することで、効率的なプログラム設計が可能になります。

これらの知識を活用し、実際のプログラムで配列を効果的に扱ってみてください。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • URLをコピーしました!
目次から探す