[코테/C++] 코테에서 자주 사용되는 C++ 메서드 정리
코딩 테스트 준비를 위해 C++에 입문한 지 얼마되지 않아,
아직은 기본적인 사용법도 헷갈리는 상태다.
여태까지 문제를 풀며
초보적인 수준에서
가장 자주 사용했던 자료 구조와 메서드 등을 정리 해본다.
입력과 출력
프로그래머스 같은 경우 보통 직접 값을 입력받고 출력하지 않아도 되지만,
백준 같은 경우, 직접 값을 입력 받고 출력 하는 코드도 작성해야 한다.
프로그래머스를 사용한 시험에서도 값을 입력받아야 했던 적도 있다. (그 때 매우 당황했다.)
일반적인 경우, 입력과 출력은 cin/cout을 사용하여 간단히 처리할 수 있다.
int n, m;
cin >> n >> m;
cout << n << ' ' << m << '\n';
int a[n];
for(int i = 0; i < n; i++){
cin >> a[i];
}
for(int e : a){
cout << e << '\n';
}
보통 변수를 미리 선언하여 cin으로 받은 값을 바로 그 변수에 할당한다.
여러 값이 띄어쓰기나 줄 바꿈으로 들어오는 경우, cin 한 번에 하나의 값이 들어오니
당황하지 않고 for문 등을 사용해 값을 받으면 된다.
출력은 훨씬 더 간단하다.
원하는 값을 cout으로 출력하면 된다. '\n'은 줄바꿈이다.
그러나 cin으로는 값을 입력받기 어려운 경우가 있는데,
숫자 값 등을 띄어쓰기나 줄바꿈 없이 한번에 여러 값을 한 줄에 이어 입력시키는 경우이다.
이 때는 cin으로 입력받기에는 매우 복잡하므로,
scanf를 사용하는 것이 좋다.
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
scanf("%1d", &a[i][j])
}
}
위 코드와 같이 작성하면
01010111111000 과 같이 띄어쓰기가 없는 경우에도
a라는 2차원 배열에 숫자를 하나씩 입력받아 집어넣을 수 있다.
그러나 이런 문제는 되도록이면 만나지 않기를 바라며, 웬만한 경우에는 cin을 사용한다고 한다.
String
자바스크립트에서는 char와 string을 구분하지 않기에 특히 자주 실수하는 부분 중 하나다.
C++에서는 char(하나의 문자) 타입과 string(문자열)을 꽤나 엄격히 구분한다.
char c = 'c';
string = b = "big";
string = d = "D";
위와 같이 char타입은 작은 따옴표(''), string은 큰 따옴표("")를 사용해야 하며,
이는 반드시 지켜져야 한다.
지키지 않고 컴파일 오류를 맞이할 때가 자주 있다.
string으로 정의했다면 한 글자라도 큰 따옴표를 사용해야 한다.
string은 char의 묶음, 일종의 배열이라
여러가지 string에만 적용되는 유용한 메서드들이 많다.
하나하나 많이 쓰이는 주옥 같은 메서드들이니, 모두 외우도록 하자.
+=
C++에서도 문자열끼리 더하기 연산자로 이어붙이는 것이 가능하다.
C++같은 엄격한 언어에서 가능하다는 것에 놀랐다.
string a = "walwal";
a = a + " dev blog";
cout << a << '\n';
//walwal dev blog
코테에서는 주로 ret += "어떤 값"; 과 같이 return 값에 값을 이어붙이는 방식으로 많이 사용한다.
begin(), end(), size()
세가지 모두 매우 자주 사용되는 요소 불러오기 메서드로
스트링 변수 뒤에 .으로 붙여주기만 하면 된다.
begin()은 문자열의 첫번째 자리 이터레이터 호출,
end()는 마지막 요소 하나 뒤 자리 이터레이터를 호출한다.
size()는 해당 문자열의 크기를 호출하며, 문자열의 길이라고 생각하면 된다.
string s = "start";
s.begin();
s.end();
s.size();
셋 다 다른 메서드와 결합되어 자주 사용된다.
세 요소는 vector에도 동일하게 적용되기 때문에, 사용법이 그리 헷갈리지는 않는 편이다.
아래 메서드들은 string 한정으로 사용되며,
사용법이 헷갈리고,
매우 중요한 메서드들이다.
메서드 앞에 s.이 붙은 경우는 적용할 문자열에 .으로 사용해야하는 메서드임을 표시한 것이다.
문자열 언급 없이 바로 사용할 수 있는 메서드들과 구분하기 위함이다.
s.insert(삽입할 위치 인덱스, 삽입할 문자열)
s.erase(삭제가 시작되는 인덱스, 삭제할 글자 수)
삽입과 삭제 메서드들이다.
적용할 문자열을 앞에 붙이고 사용한다.
첫 인자로 넣는 위치는 pointer/이터레이터가 아닌 index이다.
첫 글자 자리는 0, 마지막 자리는 s.size() - 1 을 입력하면 된다.
insert에서는 삽입할 문자열을 넣어주면 되는데, 직접 "이렇게" 넣어줘도 되고,
변수로 지정해서 넣어도 된다.
erase에서는 삭제할 문자열이 아닌
삭제할 글자 수를 넣어줘야 한다.
s.pop_back()
맨 뒤 글자 하나만 삭제한다.
s.find(찾을 문자열)
찾을 문자열을 인자로 입력하면, 값이 있는 경우
위치 인덱스 0, 1, 2, 3, ... 등을 반환한다.
역시나 pointer/이터레이터를 반환하지 않음 주의.
찾는 문자열이 없는 경우, 포함되어 있지 않는 경우 반환하는 값이 특이하다.
string :: npos라는 값을 반환한다.
if문에 사용할 일이 분명 있을테니 반드시 외워두자.
s.substr(추출을 시작할 위치 인덱스, 글자 수)
문자열의 일부를 추출할 때 사용한다.
해당 메서드를 사용한다고 해서 그 부분이 erase되는 것이 아님 주의!!!
사실 내가 항상 헷갈려 하는 부분이다.
그저 문자열의 일부를 참조하여 사용할 수 있는 메서드다.
reverse(s.begin(), s.end())
문자열 개체에 종속되지 않고 그냥 사용하는 메서드로,
문자열을 뒤집으며,
원본이 변경된다.
인자로 문자열의 시작 위치 이터레이터와 end 이터레이터를 입력한다.
일부만 reverse할 수도 있다.
atoi(s.c_str())
문자열로 입력된 숫자를 int로 변경할 수 있는 유용한 메서드다.
문자열로 입력된 숫자인 경우 그 숫자를,
문자열인 경우 0을 반환한다.
문자열로 0이 입력되어 있는 경우에도 0을 반환하기 때문에
이 부분은 별도로 처리하는 로직이 필요하다.
문자열 뒤에 붙여 사용하는 메서드는 아니지만,
atoi 인자로 문자열에 .c_str()을 붙이 값을 넣어야 한다.
또한 이 메서드는 char타입에는 작동하지 않는다.
char타입에 작동하지 않을 거라 생각하지 못해서 당황했었다.
문자열 s가 "1D2T" 식으로 적혀 있을 때
1과 2를 int로 변환하고 싶으면
atoi(s[0].c_str())로 사용할 수 없고,
atoi(s.substr(0, 1).c_str()) 등으로 string 상태를 유지하며 사용해야 한다.
아래는 사용 예시 코드이다.
#include <bits/stdc++.h>
using namespace std;
int main(){
string s = "walwalddd";
cout << s.find("ddd") <<"\n"; //6
s.insert(6, "haha");
cout << s <<"\n"; //walwalhahaddd
s.erase(6, 2);
cout << s <<"\n"; //walwalhaddd
s.pop_back();
cout << s <<"\n"; //walwalhadd
cout << s.find("wal") <<"\n"; //0
cout << s.find("dev") << "\n"; //string::npos
//18446744073709551615
string sub = s.substr(0, 3);
cout << sub << "\n"; //wal
reverse(s.begin(), s.end());
cout << s <<"\n"; //ddahlawlaw
string num = "1234";
cout << atoi(num.c_str()) << '\n'; //1234
cout << atoi(s.c_str()) << '\n'; //0
return 0;
}
함수
초기화 함수
배열을 만들고 배열 내 모든 값을 동일한 값으로 초기화하고 싶을 때가 있다.
그때 사용할 수 있는 메서드들이다.
fill()은 어떤 값으로든 초기화할 수 있으나, memset()은 -1, 0 둘 중 하나로만 초기화가 가능하다.
둘 다 배열 뒤에 .으로 붙이지 않고 단독으로 사용한다.
fill(시작 이터레이터, end 이터레이터, 초기화 값)
int a[10][10];
int b[8][8];
fill(&a[0][0], &a[0][0] + 10 * 10, 2);
fill(&b[0][0], &b[7][8], 100);
memset(배열 이름, 0 또는-1, 배열 사이즈)
int a[10];
int a2[10][10];
memset(a, -1, sizeof(a));
memset(a2, 0, sizeof(a2));
sort(v.begin(), v.end())
특정 영역을 정렬하는 메서드로,
시작 이터레이터와 끝 이터레이터만 입력하면 해당 영역을 오름차순으로 정렬한다.
내림차순으로 정렬하려면 아래와 같이 세 번재 인자를 추가해주면 된다.
sort(v.beign(), v.end(), greater<int>())
원본 배열을 변경하는 메서드이다.
int a[5] = { 3, 2, 1, 4, 5 };
vector<int> b = { 6, 8, 9, 10, 7 };
sort(a, a + 5);
for(int i : a) cout << i << ' '; //1 2 3 4 5
sort(a, a + 5, greater<int>());
for(int i : a) cout << i << ' '; //5 4 3 2 1
sort(b.begin(), b.end());
for(int i : b) cout << i << ' '; //6 7 8 9 10
accumulate(v.begin(), v.end(), 0)
특정 배열의 값들의 합을 구하는 메서드이다.
단독으로 사용하며, 인자로 첫번째 이터레이터, 끝 이터레이터, 시작값을 넣는다.
당연히 0부터 더해야 한다고 생각해 시작값을 까먹데 될 때가 많은데,
인자 3개를 넣지 않으면 동작하지 않기 때문에 시작값을 반드시 넣어줘야 한다.
int a[5] = { 3, 2, 1, 4, 5 };
vector<int> b = { 6, 8, 9, 10, 7 };
int sum = accumulate(a, a + 5, 0);
cout << sum << '\n'; //15
cout << accumulate(b.begin(), b.end(), 0) << '\n'; //40
max(값1, 값2) / min(값1, 값2)
더 큰 값과 더 작은 값을 가려내는 메서드이다.
인자는 2개만 넣을 수 있어, 보통은 for문으로 max/min 값을 찾는다.
실수하게 되는 부분 중 하나는,
변수 이름으로 max, min을 사용하지 않아야 한다.
mx, mn로 통일시켜버리자.
cout << max(100, 20) <<'\n'; //100
cout << min(100, 20) <<'\n'; //20
그 외
typedef 타입 별칭
타입에 별칭을 붙여 사용할 수 있는 명령어로
long long과 같이 타입 이름이 긴 경우에 주로 사용하게 된다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll a = 1234;
return 0;
}
참고로 long long은 int보다 큰 정수를 나타내는 타입이다.
#define 변수명 값
상수, 매크로 등을 정의할 수 있는 명령어로,
import한 header에서 내가 원하는 변수명을 이미 사용하고 있을 때 주로 사용한다.
예를 들어, y1이라는 변수명으로 사용하고 싶을 때
아래와 같이 y1에 임의의 값을 define하고 다시 내가 원하는 대로 사용하는 것이다.
#include <bits/stdc++.h>
using namespace std;
#define y1 aaaa
int y1;
int main() {
y1 = 12234;
cout << y1 << '\n'; //12234
return 0;
}