Cpp로 다시 하는 코테준비[~0x03]
취업하기 전에는 자바를 사용했지만 이왕 코테 공부 더 하는 거 앳코더같은 대회에도 나가보고 싶고, 평소에 사용해보고 싶었던 cpp를 선택했다.
백준 계정도 새로 만들었으니 제대로 해볼 것이다. 교보재는 바킹독님의 커리큘럼을 따라간다.
0x00~0x02
헤더
기본적으로 #include
를 쓴다. 강의에서는 bits/std++.h를 쓰는데, 나는 그냥 배움의 자세로 외워질 때까지 일일이 다 칠 예정이다.
stdio는 iostream으로, 자바의 ArrayList는 vector를 사용한다.
입출력
1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;
int main(){
cin.tie(0); ios::sync_with_stdio(0);
return 0;
}
입출력 버퍼를 개선해서 입력, 출력 순서가 꼬이지않도록 동기화를 해주는 코드다.
std를 namespace로 지정해주면 기존에 std::cout, std::cin같이 매번 넣어주던 걸 안해도 된다. 자바로 생각하면 wildcard import인데, 지금은 문제풀이에 집중하는 거지 좋은 프로젝트를 만드는 게 목적이 아니다.
그래서 그냥 쓴다. int를 long long으로 define 해두고 쓰는 경우도 많다고 한다.
참조연산자 &
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void swap(int& a, int& b){
// cpp 참조연산자 -> int reference
int tmp = a;
a = b;
b = tmp;
}
void vector_prac(){
vector<int> v(100);
// 자바의 Arraylist<Integer> k = new ArrayList(100);
v[20] = 100;
v[23] = -10;
cout << v[20] << "\n"; // 100
cout << v[23] << endl; // -10
}
bool cmp(vector<int>& v1, vector<int>& v2, int idx){ // 참조대상의 주소만 넘겨서 쓰기 때문에 의도한 대로 O(1)짜리 코드가 됨
return v1[idx] > v2[idx];
}
배열을 파라미터로 넣으면 주소값을 넘기기에 원본 값에 접근할 수 있지만, 원시타입이나 구조체, vector의 경우에는 복사본을 전달한다. 그래서 참조연산자를 써서 원본값에 접근하는 방식을 사용한다.
C언어를 공부했던 기억을 되살려서 포인터를 사용해보려고도 했는데, 일단 지금은 참조연산자를 주로 쓰면서 언어 숙련도를 높이려고한다.
endl은 개행문자를 추가하고 출력 버퍼를 비우는 작업인데, 연산에 막대한 손해를 입히기 때문에 사용을 지양해야한다.
구조체
지금은 어떻게 쓸지 잘 모르겠지만 일단 class 선언하는 거 보다는 편해보인다.
1
2
3
struct pt{
int x, y;
};
공백이 있는 입력 받기
cin은 화이스스페이스를 기준으로 끊긴다.
1
2
3
4
5
void getline_input(){
string s;
getline(cin, s);
cout << s;
}
그래서 중간에 공백이 있는 입력이 들어오면 자바의 StringTokenizer를 떠올리며 string으로 받아줘야한다. cpp라서 string을 자유롭게 쓸 수 있는데, c였으면 char*로 받아써야한다.
배열, vector
1
2
3
4
int a[21];
int b[10][10];
fill(a, a+21, 0); // algorithm 헤더에 위치
배열 초기화하는 방법에는 그냥 for문 돌리거나, fill을 사용하면 된다. a배열을 21번째 원소까지 0으로 채우는 함수다. ( ]
형태다.
배열을 기본적으로 알아야하지만, 자바하다고 온 입장에서 나는 벡터를 더 자주 쓸 것 같다. #include <vector>
로 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stdc++.h>
using namespace std;
int main(void) {
vector<int> v1(3, 5); // {5,5,5};
cout << v1.size() << '\n'; // 3
v1.push_back(7); // {5,5,5,7};
vector<int> v2(2); // {0,0};
v2.insert(v2.begin()+1, 3); // {0,3,0};
vector<int> v3 = {1,2,3,4}; // {1,2,3,4}
v3.erase(v3.begin()+2); // {1,2,4};
vector<int> v4; // {}
v4 = v3; // {1,2,4} -> deep copy라 원본을 참조하지않는다!
cout << v4[0] << v4[1] << v4[2] << '\n';
v4.pop_back(); // {1,2}
v4.clear(); // {}
}
스택으로 바로 쓸 수 있고, 값의 삽입 삭제가 쉽다. 근데 push_front, pop_front
는 O(1)이라 자바의 LinkedList처럼 쓸 수 없다. 연속된 공간이기 때문에 하나 빼서 앞으로 쭉 밀기 때문이다.
주의할 점은 vector의 size()
가 unsigned int라 0일때 -1해버리면 언더플로가 발생해버린다! 이거만 조심하면 된다.
추가로 for(int k: v)
에서 k는 복사본, for(int& k: v)
에서 k는 원본값 참조다.
for(auto c: input)
같은 사용법은 이제 부딪혀가며 익혀보겠다.