수색…


소개

배열은 인접한 메모리 위치에있는 동일한 유형의 요소입니다. 요소는 색인이 추가 된 고유 식별자로 개별적으로 참조 할 수 있습니다.

이를 통해 특정 유형의 여러 변수 값을 선언하고 각 값에 대한 변수를 선언 할 필요없이 개별적으로 액세스 할 수 있습니다.

배열 크기 : 컴파일시 안전합니다.

#include <stddef.h>     // size_t, ptrdiff_t

//----------------------------------- Machinery:

using Size = ptrdiff_t;

template< class Item, size_t n >
constexpr auto n_items( Item (&)[n] ) noexcept
    -> Size
{ return n; }


//----------------------------------- Usage:

#include <iostream>
using namespace std;
auto main()
    -> int
{
    int const   a[]     = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
    Size const  n       = n_items( a );
    int         b[n]    = {};       // An array of the same size as a.
    
    (void) b;
    cout << "Size = " << n << "\n";
}

배열 크기의 sizeof(a)/sizeof(a[0]) 대한 C idiom은 포인터를 인수로 받아들이고 일반적으로 잘못된 결과를 산출합니다.

C ++ 11

C ++ 11을 사용하면 다음을 수행 할 수 있습니다.

std::extent<decltype(MyArray)>::value;

예:

char MyArray[] = { 'X','o','c','e' };
const auto n = std::extent<decltype(MyArray)>::value;
std::cout << n << "\n"; // Prints 4

C ++ 17까지 (앞으로 작성 될 예정) C ++에는 내장 언어 나 표준 라이브러리 유틸리티가 없기 때문에 배열의 크기를 얻을 수 있지만, 함수 템플리트를 참조 하여 배열 전달하면 구현할 수 있습니다. 위에 표시된. 미세하지만 중요한 점 : 템플릿 크기 매개 변수는 size_t 이며 서명 된 Size 함수 결과 유형과 다소 일치하지 size_t 때때로 템플리트 일치를 위해 size_t 를 고집하는 g ++ 컴파일러를 수용해야합니다.

C ++ 17 이상에서는 대신 배열을 전문으로하는 std::size 를 사용할 수 있습니다.

동적 크기의 원시 배열

// Example of raw dynamic size array. It's generally better to use std::vector.
#include <algorithm>            // std::sort
#include <iostream>
using namespace std;

auto int_from( istream& in ) -> int { int x; in >> x; return x; }

auto main()
    -> int
{
    cout << "Sorting n integers provided by you.\n";
    cout << "n? ";
    int const   n   = int_from( cin );
    int*        a   = new int[n];       // ← Allocation of array of n items.
    
    for( int i = 1; i <= n; ++i )
    {
        cout << "The #" << i << " number, please: ";
        a[i-1] = int_from( cin );
    }

    sort( a, a + n );
    for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; }
    cout << '\n';
    
    delete[] a;
}

배열 T a[n]; 을 선언하는 프로그램 T a[n]; n 은 런타임으로 결정되며 C99 가변 길이 배열 (VLA)을 언어 확장으로 지원하는 특정 컴파일러로 컴파일 할 수 있습니다. 그러나 VLA는 표준 C ++에서 지원되지 않습니다. 이 예제는 new[] -expression을 통해 동적 크기 배열을 수동으로 할당하는 방법을 보여줍니다.

int*        a   = new int[n];       // ← Allocation of array of n items.

... 그런 다음 그것을 사용하고 마지막으로 delete[] -expression을 통해 할당을 해제합니다.

delete[] a;

여기에 할당 된 배열에는 불확실한 값이 있지만 new int[n]() 과 같이 빈 괄호 () 추가하면 제로화 될 수 있습니다. 보다 일반적으로 임의 항목 유형의 경우이 작업은 값 초기화를 수행합니다.

호출 계층 구조에서 함수의 일부로이 코드는 예외 안전이 아닙니다. delete[] 표현식 이전의 예외 (및 new[] 다음의 예외)가 메모리 누수를 일으킬 수 있기 때문입니다. 이 문제를 해결하는 한 가지 방법은 예를 들어 std::unique_ptr 스마트 포인터를 통해 정리를 자동화하는 것입니다. 하지만 일반적으로 더 나은 방법은 std::vector 사용하는 것입니다. std::vector 가 그 것이다.

std :: vector를 사용하여 동적 크기 배열 확장

// Example of std::vector as an expanding dynamic size array.
#include <algorithm>            // std::sort
#include <iostream>
#include <vector>               // std::vector
using namespace std;

int int_from( std::istream& in ) { int x = 0; in >> x; return x; }

int main()
{
    cout << "Sorting integers provided by you.\n";
    cout << "You can indicate EOF via F6 in Windows or Ctrl+D in Unix-land.\n";
    vector<int> a;      // ← Zero size by default.

    while( cin )
    {
        cout << "One number, please, or indicate EOF: ";
        int const x = int_from( cin );
        if( !cin.fail() ) { a.push_back( x ); }  // Expands as necessary.
    }

    sort( a.begin(), a.end() );
    int const n = a.size();
    for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; }
    cout << '\n';
}

std::vector 는 가변 크기 배열의 개념을 제공하는 표준 라이브러리 클래스 템플릿입니다. 그것은 모든 메모리 관리를 담당하고 버퍼는 연속적이므로 버퍼에 대한 포인터 (예 : &v[0] 또는 v.data() )는 원시 배열이 필요한 API 함수로 전달 될 수 있습니다. vector 는 런타임에 예를 들어 항목을 추가하는 push_back 멤버 함수를 통해 확장 될 수도 있습니다.

벡터 확장에 포함 된 복사 또는 이동을 포함하여 n 개의 push_back 연산 시퀀스의 복잡성은 상각 된 O ( n )입니다. "상각 된": 평균.

내부적으로 이것은 일반적으로 더 큰 버퍼가 필요할 때 버퍼 크기, 용량을 두 배로 증가 시키는 벡터에 의해 달성됩니다. 예를 들어, 크기 1로 시작하고 n = 17 push_back 호출에 대해 필요에 따라 반복적으로 두 배로되는 버퍼의 경우이 값은 1 + 2 + 4 + 8 + 16 = 31 복사 작업을 포함하며 2 × n = 34 미만입니다. 보다 일반적으로이 시퀀스의 합은 2 × n을 초과 할 수 없습니다.

동적 크기의 원시 배열 예제와 비교할 때,이 vector 기반 코드는 사용자가 앞에있는 항목의 수를 제공 (및 알고 있어야 함) 할 필요가 없습니다. 대신 벡터는 사용자가 지정한 새 항목 값마다 필요한만큼 확장됩니다.

고정 크기의 원시 배열 행렬 (즉, 2D 원시 배열)입니다.

// A fixed size raw array matrix (that is, a 2D raw array).
#include <iostream>
#include <iomanip>
using namespace std;

auto main() -> int
{
    int const   n_rows  = 3;
    int const   n_cols  = 7;
    int const   m[n_rows][n_cols] =             // A raw array matrix.
    {
        {  1,  2,  3,  4,  5,  6,  7 },
        {  8,  9, 10, 11, 12, 13, 14 },
        { 15, 16, 17, 18, 19, 20, 21 }
    };
    
    for( int y = 0; y < n_rows; ++y )
    {
        for( int x = 0; x < n_cols; ++x )
        {
            cout << setw( 4 ) << m[y][x];       // Note: do NOT use m[y,x]!
        }
        cout << '\n';
    }
}

산출:

   1   2   3   4   5   6   7
   8   9  10  11  12  13  14
  15  16  17  18  19  20  21

C ++에서는 다차원 배열 색인 작성을위한 특수 구문을 지원하지 않습니다. 대신 이러한 배열은 배열의 배열 (배열 등)로 표시되며 일반 단일 색인 표기법 [ i ] 이 각 수준에 사용됩니다. 위의 예에서 m[y]my 를 참조합니다. 여기서 y 는 0부터 시작하는 인덱스입니다. 그런 다음이 행을 차례로 인덱싱 할 수 있습니다 (예 : 행 yx 번째 항목 또는 열 -을 나타내는 m[y][x] ).

즉, 마지막 인덱스가 가장 빠르며, 선언에서이 인덱스의 범위는 행 당 열 수입니다. 마지막으로 "가장 안쪽"크기입니다.

C ++은 동적 할당 이외의 동적 크기 배열을 기본적으로 지원하지 않기 때문에 동적 크기 매트릭스는 종종 클래스로 구현됩니다. 그런 다음 로우 배열 매트릭스 표기법 m[y][x] 는 구현을 노출함으로써 (예 : 전치 행렬의 뷰가 실제로 불가능 해 지도록) 또는 반환을 통해 완료 될 때 약간의 오버 헤드와 약간의 불편 함을 추가하여 비용이 발생합니다 operator[] 의 프록시 객체. 그리고 그러한 추상화를위한 색인 표기법은 일반적으로 look-and-feel과 색인 순서 m(x,y) 예 : m(x,y) 또는 m.at(x,y) 또는 m.item(x,y) 이다.

저장을 위해 std :: vector를 사용하는 동적 크기 행렬입니다.

불행히도 C ++ 14에서는 C ++ 표준 라이브러리에 동적 크기 행렬 클래스가 없습니다. 동적 크기를 지원 매트릭스 클래스는 부스트 매트릭스 라이브러리 (부스트 라이브러리 내의 하위 라이브러리)을 포함하여 제 3 파티 라이브러리의 숫자에서 그러나 사용할 수 있습니다.

Boost 또는 다른 라이브러리에 의존하지 않으려면 C ++의 한 가난한 사람의 동적 크기 행렬이 다음과 같습니다.

vector<vector<int>> m( 3, vector<int>( 7 ) );

... vectorstd::vector . 여기서 n 은 행 수, 여기서는 3 인 행 벡터를 n 번 복사하여 만들어집니다. 고정 크기의 원시 배열 행렬과 동일한 m[y][x] 색인 표기법을 제공하는 장점이 있지만 각 행에 대해 동적 할당이 필요하기 때문에 다소 비효율적입니다. 실수로 행의 크기를 조정할 수 있기 때문에 조금 안전하지 않습니다.

보다 안전하고 효율적인 접근 방법은 단일 벡터를 행렬의 저장소 로 사용하고 클라이언트 코드 ( x , y )를 해당 벡터의 해당 색인에 매핑하는 것입니다.

// A dynamic size matrix using std::vector for storage.

//--------------------------------------------- Machinery:
#include <algorithm>        // std::copy
#include <assert.h>         // assert
#include <initializer_list> // std::initializer_list
#include <vector>           // std::vector
#include <stddef.h>         // ptrdiff_t

namespace my {
    using Size = ptrdiff_t;
    using std::initializer_list;
    using std::vector;

    template< class Item >
    class Matrix
    {
    private:
        vector<Item>    items_;
        Size            n_cols_;
        
        auto index_for( Size const x, Size const y ) const
            -> Size
        { return y*n_cols_ + x; }

    public:
        auto n_rows() const -> Size { return items_.size()/n_cols_; }
        auto n_cols() const -> Size { return n_cols_; }

        auto item( Size const x, Size const y )
            -> Item&
        { return items_[index_for(x, y)]; }
        
        auto item( Size const x, Size const y ) const
            -> Item const&
        { return items_[index_for(x, y)]; }

        Matrix(): n_cols_( 0 ) {}

        Matrix( Size const n_cols, Size const n_rows )
            : items_( n_cols*n_rows )
            , n_cols_( n_cols )
        {}
        
        Matrix( initializer_list< initializer_list<Item> > const& values )
            : items_()
            , n_cols_( values.size() == 0? 0 : values.begin()->size() )
        {
            for( auto const& row : values )
            {
                assert( Size( row.size() ) == n_cols_ );
                items_.insert( items_.end(), row.begin(), row.end() );
            }
        }
    };
}  // namespace my

//--------------------------------------------- Usage:
using my::Matrix;

auto some_matrix()
    -> Matrix<int>
{
    return
    {
        {  1,  2,  3,  4,  5,  6,  7 },
        {  8,  9, 10, 11, 12, 13, 14 },
        { 15, 16, 17, 18, 19, 20, 21 }
    };
}

#include <iostream>
#include <iomanip>
using namespace std;
auto main() -> int
{
    Matrix<int> const m = some_matrix();
    assert( m.n_cols() == 7 );
    assert( m.n_rows() == 3 );
    for( int y = 0, y_end = m.n_rows(); y < y_end; ++y )
    {
        for( int x = 0, x_end = m.n_cols(); x < x_end; ++x )
        {
            cout << setw( 4 ) << m.item( x, y );        // ← Note: not `m[y][x]`!
        }
        cout << '\n';
    }
}

산출:

   1   2   3   4   5   6   7
   8   9  10  11  12  13  14
  15  16  17  18  19  20  21

위의 코드는 산업용 등급이 아니며 기본 원칙을 보여주고 C ++를 배우는 학생들의 요구에 부응하도록 고안되었습니다.

예를 들어, 인덱싱 표기법을 단순화하기 위해 operator() 오버로드를 정의 할 수 있습니다.

배열 초기화

배열은 특정 유형의 변수에 대한 순차적 메모리 위치 블록 일뿐입니다. 배열은 일반 변수와 같은 방식으로 할당되지만 배열 메모리에 맞는 요소의 수를 포함하는 이름 [] 대괄호가 추가됩니다.

다음의 배열의 예는, typ int , 변수 명 arrayOfInts , 및 배열의 ​​스페이스를 가지는 요소 [5] 를 사용합니다.

int arrayOfInts[5];

배열은 다음과 같이 동시에 선언하고 초기화 할 수 있습니다.

int arrayOfInts[5] = {10, 20, 30, 40, 50};

모든 멤버를 나열하여 배열을 초기화 할 때 대괄호 안에 요소의 수를 포함 할 필요는 없습니다. 컴파일러에 의해 자동으로 계산됩니다. 다음 예제에서는 5입니다.

int arrayOfInts[] = {10, 20, 30, 40, 50};

또한 더 많은 공간을 할당하면서 첫 번째 요소 만 초기화 할 수도 있습니다. 이 경우 대괄호로 길이를 정의하는 것은 필수입니다. 다음은 길이가 5 인 배열을 부분 초기화와 함께 할당합니다. 컴파일러는 나머지 모든 요소를 ​​요소 유형의 표준 값으로 초기화합니다.이 경우 0입니다.

int arrayOfInts[5] = {10,20}; // means 10, 20, 0, 0, 0

다른 기본 데이터 유형의 배열은 같은 방식으로 초기화 될 수 있습니다.

char arrayOfChars[5]; // declare the array and allocate the memory, don't initialize

char arrayOfChars[5] = { 'a', 'b', 'c', 'd', 'e' } ; //declare and initialize

double arrayOfDoubles[5] = {1.14159, 2.14159, 3.14159, 4.14159, 5.14159};

string arrayOfStrings[5] = { "C++", "is", "super", "duper", "great!"};

또한 배열 요소에 액세스 할 때 배열의 요소 인덱스 (또는 위치)가 0부터 시작한다는 점에 유의해야합니다.

int array[5] = { 10/*Element no.0*/, 20/*Element no.1*/, 30, 40, 50/*Element no.4*/};
std::cout << array[4]; //outputs 50
std::cout << array[0]; //outputs 10


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow