수색…
소개
배열은 인접한 메모리 위치에있는 동일한 유형의 요소입니다. 요소는 색인이 추가 된 고유 식별자로 개별적으로 참조 할 수 있습니다.
이를 통해 특정 유형의 여러 변수 값을 선언하고 각 값에 대한 변수를 선언 할 필요없이 개별적으로 액세스 할 수 있습니다.
배열 크기 : 컴파일시 안전합니다.
#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]
는 m
행 y
를 참조합니다. 여기서 y
는 0부터 시작하는 인덱스입니다. 그런 다음이 행을 차례로 인덱싱 할 수 있습니다 (예 : 행 y
의 x
번째 항목 또는 열 -을 나타내는 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 ) );
... vector
가 std::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