이전글로 C++의 커스텀 정렬에 대해 글을 작성했었다 (링크)
하지만, C언어 또는 Java에서는 사용하는 비교방법과는 일부 다르다는 점과,
실제로 알고리즘 문제 풀이를 하다 실수를 했던 부분이 있어서 글을 작성해보게 되었다.
C언어에서 처음 문자열을 공부하면, strcmp()라는 함수를 접해보게 된다.
이 함수는, strcmp(s1,s2)의 인자로 s1,s2를 비교해서 -1또는 0또는 1을 리턴한다.
반환 값에 "같다"의 경우가 포함되어있다.
하지만, 링크글에서 보듯이 C++의 비교함수는 int가 아닌 bool타입 리턴이다.
즉, C어는 compare(a,b)를 하면 -1,0,1로 리턴하기 때문에
"작다","같다","크다"를 표현하지만,
C++은 "작다" 또는 "크다"만 표현한다.
(참고로 예전에 Java Compare 방법에 대해서도 작성한 글이 있는데, 자바 역시 작다,같다,크다로 분류한다 (참고 : 링크)
사실 그렇다고 해서 C++에서 같다를 표현할 수 없는 것은 아니다.
compare(a,b)가 true고 compare(b,a)가 true이거나
또는 compare(a,b)가 false고 compare(b,a)도 false인 경우는 같다고 볼 수 있다.
실제 C++의 binary_search()등에서 "같다"를 표현하기 위해서는 이와같은 방식을 사용한다.
따라서 C언어를 사용하다가 C++로 비교함수를 정의할 때는 이점을 주의해야한다.
또한, int로 리턴해도 bool타입으로 자동형변환이 된다는점을 이용해서
Java,C언어에서 비교함수 리턴하듯 음수,0,양수 리턴시에는 비교가 제대로 동작하지 않는다.
왜냐면, 0은 false지만 음수는 true이기 때문이다.
즉, a<b를 원할 때 a-b가 음수인경우에는 a<b를 만족하지만,
a>b일 때 a-b도 양수로 true이므로 비교가 잘못된다.
아래 예시를 통해 확인해보자
#include <string>
#include <iostream>
using namespace std;
int cmp_str(const void *a, const void *b)
{
const char *sa = *(const char * const *)a;
const char *sb = *(const char * const *)b;
return strcmp(sa, sb); /* OK: 규약 준수 */
}
int main()
{
const char *arr[] = {"delta", "alpha", "charlie", "bravo"};
size_t n = sizeof arr / sizeof arr[0];
qsort(arr, n, sizeof arr[0], cmp_str);
cout << "== C++: 정렬 결과 ==\n";
for (auto& s : arr) cout << s << '\n';
cout <<"\n\n";
// alpha
// bravo
// charlie
// delta
vector<string> v = {"delta", "alpha", "charlie", "bravo"};
sort(v.begin(),v.end(), [](auto a, auto b) {
return a.compare(b); // a<b : 음수 → true
});
cout << "== C++: 잘못된 정렬 결과 ==\n";
for (auto& s : v) cout << s << '\n';
// bravo
// charlie
// alpha
// delta
}
특히 나는 bool을 리턴해야하는걸 알고 있었음에도 실수로 정수를 리턴하게 함수를 만들었었는데,
c++ 컴파일러가 bool타입 리턴 함수에서 int타입을 리턴하더라도 컴파일 오류없이 컴파일이 되다보니 이 상태에서 내가 알고리즘 문제를 제출했다가 예제 케이스는 맞지만 실제 제출시 계속 오답 판정이 되어 코드에서 잘못된 점을 찾다가 크게 고생했던 경험이 있어서 이렇게 글을 적어보게 되었다.