C++ 핵심 개념 정리: 포인터, STL 컨테이너 및 활용법

C++ 학습 시 자주 사용되는 핵심 개념들을 코드 예제와 함께 정리합니다.

기본 입출력 및 배열 초기화

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N = 110;
int d[N]; // 전역 변수

int main() {
    int n;
    cin >> n;
    cout << n * 2 << endl;

    // memset을 사용한 배열 초기화
    memset(d, -1, sizeof(d)); // d 배열의 모든 요소를 -1로 설정

    // 데이터가 100만 개 이상이면 scanf 사용 고려
    // scanf("%d", &n);
    return 0;
}

팁: memset은 바이트 단위 초기화이므로 0이나 -1 이외의 값에는 사용에 주의해야 합니다. 대규모 입력 처리 시 scanf/printfcin/cout보다 빠릅니다.

포인터 심층 분석

기본

포인터 변수는 메모리 주소를 저장합니다. 타입과 관계없이 포인터 변수 자체의 크기는 동일합니다(예: 64비트 시스템에서는 8바이트).

int a = 10;
int* p = &a; // p는 a의 주소를 저장

const와 포인터 1: 가리키는 값을 수정하지 못하게 하기

const double pi = 3.14;
double* ptr = &pi;          // 오류: const 변수의 주소를 비const 포인터에 할당 불가
const double* cptr = &pi;   // 정상

double f = 3.14;
const double* cp = &f;      // 정상: 비const 객체의 주소를 const 포인터에 할당 가능
// *cp = 1.68;              // 오류: const 포인터를 통해 값 수정 불가
f = 1.68;                   // 정상: f 자체는 const가 아니므로 직접 수정 가능

// 함수 매개변수로 활용
void process(const int* p) {
    // *p = 10; // 오류: 수정 불가
    cout << *p << endl;
}

요약: const T* 형태는 "포인터가 가리키는 대상"을 상수 취급하여 간접 수정을 막습니다.

const와 포인터 2: 포인터 자체를 상수화하기

int a = 10, b = 20;
int* const pc = &a; // pc는 상수 포인터 (주소 변경 불가)
// pc = &b;         // 오류: pc가 가리키는 주소는 읽기 전용
// pc++;            // 오류
*pc = 100;          // 정상: pc가 가리키는 대상(a)은 수정 가능

문자열 처리 (string)

<string><cctype>을 포함하여 사용합니다.

#include <string>
#include <cctype>
#include <algorithm>

using namespace std;

int main() {
    string s1 = "Hello";
    string s2 = "World";
    s1 += " ";          // "Hello "
    s1.append(s2);      // "Hello World"

    // 서브스트링 & 검색
    string sub = s1.substr(6, 5);   // "World"
    size_t pos = s1.find("World");  // 6

    // 삽입 & 삭제
    s1.insert(5, ",");              // "Hello, World"
    s1.erase(5, 1);                 // "Hello World" (쉼표 제거)

    // 비교
    if (s1 == "Hello World") { }
    int cmp = s1.compare("Apple");  // 양수 반환

    // 대소문자 판별 & 변환
    char c = 'g';
    if (isalpha(c)) {
        char upper = toupper(c);   // 'G'
        char lower = tolower(c);   // 'g'
    }

    // 정렬
    string s = "cdefba";
    sort(s.begin(), s.end());      // "abcdef"
    return 0;
}

STL 컨테이너

vector

#include <vector>
#include <algorithm>

// 1차원
std::vector<int> v1(5);          // {0,0,0,0,0}
std::vector<int> v2(5, 10);      // {10,10,10,10,10}
v1.push_back(7);                 // 끝에 추가
v1.pop_back();                   // 마지막 요소 제거
sort(v1.begin(), v1.end());      // 정렬
reverse(v1.begin(), v1.end());   // 뒤집기

// 2차원
int rows = 3, cols = 4;
vector<vector<int>> mat(rows, vector<int>(cols, 0));
int m = mat.size();              // 행 개수
int n = mat[0].size();           // 열 개수

map & set

#include <map>
#include <set>

// set 기본
set<int> s;
s.insert(10);
s.erase(10);
if (s.find(10) != s.end()) { }

// map 기본
map<string, int> m;
m["apple"] = 5;
m.insert({"banana", 10});

auto it = m.find("apple");
if (it != m.end()) {
    string key = it->first;    // "apple"
    int val = it->second;      // 5 (수정 가능)
    it->second = 3;            // 값 변경 가능
}

// set: 중복 제거, 존재 여부 확인
// map: 빈도수 계산, 키-값 매핑
// unordered_map: O(1) 평균 조회 (해시 테이블)

pair

#include <utility>  // 대부분의 STL 헤더가 간접 포함

pair<int, string> p1(21, "hello");
vector<pair<int, string>> vec;
vec.push_back(make_pair(42, "world"));

stack & queue

#include <stack>
#include <queue>

// stack
stack<int> st;
st.push(1);
int top = st.top();   // 1
st.pop();             // 제거 (반환값 없음)

// queue
queue<int> q;
q.push(1);
int front = q.front();
int back = q.back();
q.pop();

구조체 (struct)

생성자와 초기화

// 생성자 없음 - 중괄호 초기화
struct Point {
    int x, y;
};
Point p1 = {1, 2};

// 생성자 있음 - 괄호 초기화
struct Data {
    int id;
    double val;
    Data(int i, double v) : id(i), val(v) {}
};
Data d1(10, 3.14);
Data* pd = new Data(20, 2.71);

// 구조체 배열
struct Range {
    int l, r;
    Range(int left, int right) : l(left), r(right) {}
    bool operator<(const Range& other) const {
        return r < other.r;  // 끝점 기준 정렬
    }
};

Range arr[3] = {
    Range(1, 5),
    Range(2, 3),
    Range(4, 6)
};
sort(arr, arr + 3);  // operator< 사용

sort를 위한 비교 함수

// 외부 비교 함수
bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
    if (a.first != b.first) return a.first < b.first;
    return a.second > b.second;
}
vector<pair<int, int>> vec;
sort(vec.begin(), vec.end(), cmp);

// 구조체 내부 연산자 오버로딩
struct Item {
    int first, second;
    bool operator<(const Item& o) const {
        if (first != o.first) return first < o.first;
        return second > o.second;
    }
};
vector<Item> items;
sort(items.begin(), items.end());

priority_queue

#include <queue>

// 기본: 최대 힙 (max-heap)
priority_queue<int> maxHeap;

// 최소 힙 (min-heap)
priority_queue<int, vector<int>, greater<int>> minHeap;

// 기본 연산
minHeap.push(10);
minHeap.push(5);
minHeap.push(20);
cout << minHeap.top();  // 5 (최소값)
minHeap.pop();           // 5 제거
cout << minHeap.top();  // 10

이터레이터 (Iterator)

#include <vector>
#include <iostream>

vector<int> v = {1, 2, 3, 4, 5};

// 순방향
for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it << " ";  // 1 2 3 4 5
}

// 역방향 (rbegin: 마지막 요소, rend: 첫 요소 이전)
for (auto rit = v.rbegin(); rit != v.rend(); ++rit) {
    cout << *rit << " ";  // 5 4 3 2 1
}

이터레이터 vs. 포인터 vs. 참조

  • 포인터: 메모리 주소를 저장, *로 역참조, 산술 연산 가능.
  • 참조: 별명(alias), 선언 시 반드시 초기화, 재할당 불가, 널(null) 불가.
  • 이터레이터: 컨테이너 요소 접근을 위한 추상화; 포인터와 유사한 문법(*it, ++it) 지원.

태그: pointer STL vector map set

6월 9일 01:15에 게시됨