출처: https://blog.encrypted.gg/923?category=773649
포인터가 아닌 일반 타입을 함수 인자로 보내면 복사돼서 넘어가기에 함수 외부의 값은 바뀌지 않는다.
배열을 인자로 주면, 배열의 주소를 넘기는 것이니, 함수 내부에서 배열 요소 값을 바꿀 수 있다.
참조자
void swap1(int a, int b) {
int tmp = a;
a = b;
b = tmp;
} // X
void swap2(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
} // O
void swap3(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
} // O
C언어와 같이 변수를 복사해서는 값을 바꿀 수 없고 swap2
처럼 포인터를 보내서 값을 바꿀 수 있다.
C++에서는 해결법이 하나 더 있는데, 참조자를 사용하는 것이다.
swap3
에서 매개변수 앞에 &
가 붙어있는 것을 볼 수 있는데, 이를 사용하면 a와 b가 참조자가 된다.
저렇게 a와 b를 참조자로 만들면 함수 내의 코드에서는 그냥 대입하는 것 처럼 보이지만,
원본의 주소를 받아와 원본을 바꾸는 행위가 된다.
vector
은 일종의 가변배열로 크기를 마음대로 늘렸다 줄였다 할 수 있다.
vector
는 vector
헤더에 선언되어있다.
STL
을 함수 인자로 넘길 때
void func1(vector<int> v) {
v[10] = 7; // vector을 쌩으로 함수 인자로 넣으면 복사해서 보낸다.
}
int main() {
vector<int> v(100); // int형이고 0으로 초기화된 100칸짜리 가변배열 v 선언
func1(v); // v가 복사되어서 들어가기 때문에 func1 외부 값은 변경되지 않는다.
}
bool cmp1(vector<int> v1, vector<int> v2, int idx) {
return v1[idx] > v2[idx];
}
// 위 함수는 v1과 v2를 모두 복사해야 하기 때문에, 의도한 바와 달리 O(N)의 시간복잡도를 가진다.
bool cmp2(vector<int> &v1, vector<int> &v2, int idx) {
return v1[idx] > v2[idx];
}
// 참조자를 사용하면, 참조 대상의 주소 정보만 넘어오기 때문에,
// 시간복잡도는 의도한 대로 O(1)이 된다.
C에서는 scanf / printf
로 입출력을 처리하고, C++에서는 cin / cout
을 사용하는데,
기능에 별 차이가 없으니 어느 것을 사용해도 상관이 없다.
getline
을 이용한다.(다른 방법이 있지만, 이게 제일 깔끔)입출력으로 인한 시간초과를 막기 위해 ios::sync_with_stdio(0)
, cin.tie(0)
이라는 두 명령을 실행시켜야 한다.
(이를 하지 않으면 입/출력 양이 많을 때, 시간초과가 날 수 있다.)
(아래 내용을 이해하지 않고 사용해도 상관은 없다.)
ios::sync_with_stdio(0)
scanf / printf
에서 쓰는 C 스트림과 cin / cout
이 쓰는 C++ 스트림은 분리되어 있는데,
기본적으로 프로그램은 두 스트림 모두 동기화 하고 있다.
하지만, 내가 C++ 스트림만 사용한다면 두 스트림 모두 동기화할 필요가 없기 때문에
위 명령어로 동기화를 끊는다.
(동기화를 끊으면 printf / scanf
를 사용하면 안된다.)
ios::sync_with_stdio(false) == ios::sync_with_stdio(0)
cin.tie(0)
입출력 시 버퍼를 사용하는데, 출력을 예시로 할 때,
출력이 바로 콘솔로 나오는 것이 아닌, 버퍼에 넣었다가 나오게 되는데,
문제 해결 시, 입력과 출력이 번갈아 나오고 그게 한 화면에서 보여지는 경우 버퍼의 존재로 인해 순서가 꼬일 수 있다.
이러한 현상을 막기 위해 기본적으로 cin
명령 수행 전 cout
버퍼를 비우는데,
코딩테스트에서는 입력과 출력 글자 사이에 순서가 꼬인다고 해도 채점에 영향을 주지 않는다.
그렇기에 굳이 cin
을 수행하기 전에 cout
을 비우지 않아도 되기 때문에 더 빠르게 실행할 수 있다.
cin.tie(nullptr) == cin.tie(0)
endl
쓰지마세요.
절대절대절대절대 쓰지말자.
endl
은 개행문자 출력 후 출력 버퍼를 비우라는 명령이지만, 코테는 버퍼를 비울 필요가 없다.
그러니 endl
대신 개행문자(\n
)를 사용하자.
실제 개발을 오래했던 사람은 코드를 아주 정교하게 짜는 경우가 더러 있다.
하지만, 코딩테스트는 내가 헷갈리지 않는 범위 안에서 어떻게든 타이핑을 아끼는 게 최고다.
💡 코딩테스트의 목표는 남이 알아볼 수 있는 클린코드를 작성하는 게 아니다.
어떻게든 제한된 시간 안에 정답을 받아야 한다.
그렇기 때문에, 깔끔하게 만들기 위해 노력하기 보다는 좀 더럽더라도
내가 빠르게 짤 수 있는 방식으로 빠르게 구현하는 것이 중요하다.
있어도, 없어도 정답 처리가 되기 때문에 별도로 예외처리 할 필요가 없다.
답이 올바르게 나오지 않을 때, 디버거를 사용하는 경우가 있는데,
코딩테스트의 코드는 길어야 100줄 전후의 길이일 것이다.
문제가 있을 때, 디버거를 켜서 더 늪에 빠지는 느낌을 받을 수 있기 때문에
차라리 중간 변수를 보고 싶으면 중간에서 출력을 확인하고 디버거는 사용하지 않는 것을 권장한다.
저도 코딩테스트를 C++로 준비하려고 하는데, 좋은 팁들 얻어갑니다! 😄