Language/C, C++

[C++] STL Vector 사용법

개발자 김모씨 2020. 11. 16. 21:37
반응형

<C++ Vector>

 

안녕하세요.
개발자 김모씨입니다.

오늘은, C++의 시작과 끝이라 할 수 있는
Vector에 대해 알아보겠습니다.

 

우리가 C언어를 사용할 때 가장 스트레스 받는 일은 무엇이었나요?
뭐...여러가지가 있겠지만...(지옥의 C언어)

아무래도 동적배열 부분이 아닐까 싶습니다.
int형 동적 배열을 생성한다고 하면,

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int main()
{
    int size;

    scanf("%d", &size);

    int *numPtr = malloc(sizeof(int) * size);   
    // (int 크기 * 입력받은 크기)만큼 동적 메모리 할당
	
    free(numPtr); // 동적으로 할당한 메모리 해제
}

 

이런 식으로, malloc과 free를 사용하여야 했죠.
동적배열을 free 해주지 않고 종료하면 발생했던 memory leak 때문에 힘들었던 시절이 떠오르는군요.....

2차원 동적 배열은 또 어땠습니까!!!

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int main()
{
    int **m = malloc(sizeof(int *) * 3);   
    // 이중 포인터에 (int 포인터 크기 * 세로 크기)만큼 동적 메모리 할당

    for (int i = 0; i < 3; i++)
    {
        m[i] = malloc(sizeof(int) * 4);    
        // (int 크기 * 가로 크기)만큼 동적 메모리 할당.                               
    }

    for (int i = 0; i < 3; i++)
    {
        free(m[i]);                
        // 2차원 배열의 가로 공간 메모리 해제
    }

    free(m);    // 2차원 배열의 세로 공간 메모리 해제

    return 0;
}

어휴...토가 나올 것 같습니다.

코딩테스트 보러 가서 C언어를 썼는데
malloc의 저 복잡한 구조가 생각나지 않아서 멘붕이 왔던 기억도 납니다......

총체적 난국이었죠 정말!

Vector는 이런 문제를 단번에 해결해 준, 구세주 같은 존재입니다!!!

 


Vector 란?

Vector는 C++의 STL(Standard Template Library)에 속해 있는 컨테이너 중 하나입니다.

STL 중, 시퀀스 컨테이너(Sequence container)에 속합니다.
시퀀스 컨테이너란, 말 그대로 배열처럼 객체들을 순차적으로 보관하는 컨테이너 입니다.

벡터를 쉽게 표현하자면,
원소들을 메모리 상에서 순차적으로 저장하는, '가변길이 배열'이라고 생각하시면 됩니다.

 

https://www.mycplus.com/tutorials/cplusplus-programming-tutorials/c-vectors-stdvector-containers-library/

데이터를 할당된 크기(Capacity)를 초과해 추가하면,
자동으로 크기가 늘어나는 거죠!(이것은 마법인가요?)

여기서 주의해야 할 것은 size와 capacity 입니다.
size는 우리가 흔히 알고 있는 컨테이너의 길이 이고(컨테이너에 들어있는 변수의 갯수),
capacity는 vector의 용량입니다.

size가 capacity를 넘어서게 되면, vector가 자동으로 확장되는 거죠.

시퀀스 컨테이너 + 가변길이 라고 하면 어떤 장점을 가질까요?
바로, 크기를 크게 신경쓰지 않고 데이터를 맘대로 넣어도 되고,
이를 빠르게 순회하며 접근할 수 있다. 는 점이죠.

 


Vector 사용법

그럼 vector의 사용법에 대해 알아봅시다.

먼저 가장 중요한 헤더파일입니다. (외웁시다)

#include <vector>

 

편의를 위해서 이것도 항상 작성해줍시다.

using namespace std;

//작성하지 않으면 항상
//std::vector<int> 등으로 std:: 를 붙여주어야 합니다!

 

  • Vector 초기화

벡터의 초기화에는 크게 여섯가지 방법이 있습니다.
여기서 자료형이란
일반적인 자료형인 int, string, float 등은 물론이고
사용자가 정의한 구조체도 가능합니다.

format Description
vector<자료형> 변수명 vector 변수 생성
vector<자료형> 변수명(숫자) vector 변수 생성 및 숫자만큼 size, 초기값 0
vector<자료형> 변수명 = {x, y, z, ... } vector 생성 후, 오른쪽 변수 x, y, z 등의 값으로 초기화
vector<vector<자료형>> 변수명 2차원 벡터 생성(열과 행 모두 가변길이)
vector.assign(범위, 초기값) 범위만큼 초기값으로 초기화

 

//EX
##include <vector>
using namespace std;

int main() {
  vector<int> v; //int형 백터 생성


  vector<int>v(3); //int형 백터 생성 후 크기를 3으로 할당 및 0으로 초기화 : {0, 0, 0}


  vector<int>v = {1, 2, 3}; //int형 백터 생성 후 1, 2, 3 으로 초기화


  vector<vector<int>> v; //2차원 백터 생성(행과 열 모두 가변)


  vector<int> v = {1, 2, 3, 4, 5}; //크기가 5인 벡터 생성
  v.assign(5, 10);    //크기 5만큼 10으로 초기화 : {10, 10, 10, 10, 10}
}

 

  • Vector 요소 접근

그럼, 생성된 vector에 접근해서 element를 가져와야겠죠?

format Description
vector.front() vector의 첫번째 요소 접근
vector.back() vector의 마지막 요소 접근(size-1)
vector.at(i) vector의 i 번째 요소 접근 (0 부터 시작)
vector[i] vector의 i 번째 요소 접근 (0부터 시작)

 

//EX
#include <vector>
using namespace std;

int main() {
  vector<int> v = { 1, 2, 3, 4};

  cout << v.front() << endl; //1
  cout << v.back() << endl; //output : 4
  cout << v.at(1) << endl; //output : 2
  cout << v[2] << endl; //output : 3
}

이처럼, vector는 front()와 back() 외에도,
at()과 [ ] 연산자를 사용하여 배열처럼 접근할 수 있습니다.
물론 요소의 index는 0, 1, 2, 3, ... 순이니, 주의하여 사용하여야 합니다.

 

  • Vector 요소 삽입, 제거
format Description
vector.push_back(A) 벡터 마지막에 요소 A 추가
vector.pop_back() 벡터의 마지막 요소 제거
vector.insert(삽입할 주소, A) 원하는 위치에 요소 A 삽입
vector.erase(삭제할 주소)
vector.erase(삭제 시작 주소, 삭제 끝 주소)
원하는 위치의 요소 제거
vector.clear() 벡터의 모든 요소 제거(size = 0)
vector.resize(X) 벡터의 size를 X로 변경
기존 size 초과 시 자동으로 0으로 초기화

 

//EX
#include <vector>
using namespace std;

int main(){
  vector<int> v;

  v.push_back(10);
  v.push_back(20); //v = { 10, 20 }

  v.insert(v.begin() + 1, 100); // v = { 10, 100, 20 }

  v.pop_back(); // v = { 10, 100 }

  v.erase(v.begin() + 1); // v = { 1 }
  
  v.resize(6);    // v = { 1, 0, 0, 0, 0, 0 }
  v.clear();    // v : empty()     
}

 

  • Vector iterator

위에서 begin() 이라는 함수가 나왔죠.
이는 vector의 요소에 접근하여, 순회를 빠르게 하기 위한 반복자 입니다.
역시 STL에 정의되어 있죠.

format Description
vector.begin() vector의 시작점 주소값 반환
vector.end() vector의 끝점 + 1 주소 반환 (끝 요소 주소 아님 주의!)
vector.rbegin() vector의 끝점을 반환
vector.rend() vector의 (시작-1) 점을 반환 (시작 요소 주소 아님 주의!)

 

https://modoocode.com/223

 

#include <iostream>
#include <vector>

int main() {
  std::vector<int> vec;
  vec.push_back(10);
  vec.push_back(20);
  vec.push_back(30);
  vec.push_back(40);

  // 전체 벡터를 출력하기
  for (std::vector<int>::iterator itr = vec.begin(); itr != vec.end(); ++itr) {
    std::cout << *itr << std::endl;
  } // 10 20 30 40

  std::vector<int>::iterator itr = vec.begin() + 2;
  std::cout << "3 번째 원소 :: " << *itr << std::endl;
  // 30
  
  // 역순으로 출력하기
  std::vector<int>::reverse_iterator r_iter = vec.rbegin();
  for (; r_iter != vec.rend(); r_iter++) {
    std::cout << *r_iter << std::endl;
  } // 40 30 20 10
}

 

iterator 변수 itr은 주소값이기 때문에, *itr을 사용하여 itr의 값을 가져온다는 점에 주의하세요!!!

 

  • Vector size, capacity
format Description
vector.empty() 벡터가 비어있으면 true, 아니면 false 반환
vector.size() 벡터 size 반환
vector.capacity() 현재 heap에 할당된 벡터 capacity 반환
vector.reserve(X) 벡터 size를 X로 예약
vector.shrink_to_fit() 벡터의 capacity를 size에 맞춤

 

#include <vector>
using namespace std;

int main() {
	vector<int> v = {1, 2, 3, 4, 5}
    
    cout << v.size() << endl; //5
    cout << v.capacity() << endl; //10 (OS 및 컴파일 환경에 따라 다름)
    
    v.reserve(20);
    cout << v.capacity() << endl; //20
    
    v.shrink_to_fit();
    cout << v.capacity() << endl; //5
    
    cout << v.empty() << endl; //false
    v.clear();
    cout << v.empty() << endl; //true
}

 

 


자 오늘은 이렇게,
C++의 vector에 대해 알아보았습니다.

 

가장 기본적인 컨테이너인 만큼,
vector 만큼은 자유자재로 쓰는
코린이가 됩시다!!

구독과 댓글은 개발자 김모씨에게 큰 힘이 됩니다.

 

감사합니당당당

반응형