string에 대해서 이해하기 위해서는 옛날 방식이 왜 안좋은지 부터 알아야 한다.
C스타일 문자열 방식
const char* name = "Rokiss";
끝에 null로 끝난거 확인하고 시작위치에 포인터를 가지고 있어 인지하는 방식이다.
우리가 문자열을 들고만 있을 것이라면 상관이 없을 수 있다.
하지만 우리는 보통 문자열을 이용하여 여러가지 작업을 하게될 것이다. (비교, 추가, 자르기..등)이러한 부분에서 한계가 좀 있다.
만약
const char* name = "Rookiss";
const char* name2 = "Rookiss";
if (name = name2)
{
cout << "같음" << endl;
}
else
{
cout << "다름" << endl;
}
이런 코드가 있을 때 과연 같음이 뜰까? 다름이 뜰까?
같음이 뜬다.
우리가 사용하는 문자열 그 자체는 데이터영역에 박혀서 변수에 연결해서 사용하는 것이기 때문에 같다고 뜰 것이다. (컴파일러마다 다를 수 있음)
그럼 일반적인 방식으로 문자자체를 배열?느낌으로 만들어보자
char name[] = "Rookiss";
char name2[] = "Rookiss";
if (name = name2)
{
cout << "같음" << endl;
}
else
{
cout << "다름" << endl;
}
이러면 이제 스택영역에다가 문자 배열을 만들어서 그 값을 넣어주는 것이기에 느낌이 달라질 수 있다.
그래서 실행을 해본다면 다르다고 나온다는 것을 알 수 있다.
왜냐하면 실제로 가지고 있는 문자열은 같지만 가지고 있는 주소값이 다르기에 다르다고 뜨는 것이다.
우리가 원하던 비교는 문자열을 비교하는 것이였지만 주소값을 비교하고 있기에 원하는 비교가 안된 것이다. (배열의 이름은 배열의 시작 주소값)
그래서 옛날에는 strcmp(name, name2);
(비교), strcat(name, name2);
(뒤에 추가)이런식으로 사용을 했어야 했다. 즉 불편하다..
그래서 C스타일의 문자열 방식은 굉장히 직관적이지 않고, 사용하기에도 불편하고, 다른 다방면에서 불편하다는 것을 알 수 있다.
그래서 C++이나 다른 언어에서는 string을 지원해서 문자열을 좀 더 편리하게 사용할 수 있게 해준다.
std::string str = "Rookiss";
std::string str2 = "Rookiss";
생성을 할 때 C스타일 방식처럼 생성을 해줄 수 있다.
그래서 직관적으로 사용할 수 있다는 점이 큰 장점이라고 볼 수 있다.
애도 뭐 별다른게 아니라 vector와 마찬가지로 클래스이다.
vector와 유사하게 capacity()도 들고있고 다양한 정보를 가지고 있다.
그래서 내부적으로 문자열을 잘 관리하고 있기에 우리는 string클래스를 사용하는데 집중을 하면 된다.
그럼 우리는 무엇을 알아보고 공부해야 할까?
//str.compare(str2) 같으면 0 다르면 -1
// operator 오버로딩이 되어있다.
if(str == str2)
{
}
이런식으로 사용하게 될 것이다.
그리고 이런것들을 공부할 때마다 우리는 이러한 것들을 게임에서 어떻게 사용할 수 있을까를 고민해보아야 한다. (ID/PW 비교 등..)
만약
string str3;
str3 = str;
이런식으로 코드를 작성하였을 때,
원본에도 영향을 줄까?
우리는 복사를 하였기때문에 원본에는 영향을 주지 않는다.
만약 우리가 문자열 뒤에 추가를 하고 싶다면,
//str.append("12313"); // 다른 언어처럼 append도 사용가능
str += "123455";
이런식으로 추가를 해줄 수 있다.
우리가 만약 게임에서 캐릭터삭제같은 작업을 하게 되었을 때,
캐릭터를 진짜로 삭제하는 것이 아니라 그 캐릭터의 아이디명 뒤에 어떠한 수식어
예) _DELETE 등을 사용해서 표시만 해둔다.
이러한 상황에서 추가를 사용할 수 있다. (다른 상황도 많다)
어떤 문자가 들어가 있는지 찾고 싶다면 find()를 사용하면 된다.
auto c = str.find("Roo");
if(c == std::string::npos) // std::string::npos는 vector.end()과 같은 역활을 한다.
{
cout << "못 찾음" << endl;
}
find()를 사용하면 몇 번째 인덱스에 존재하는지 반환을 해준다.
string을 사용할 때 기능이 많이 필요할 수 있지만 이러한 것들을 자주 사용하면 외워지지만 생각보다 자주 사용할 일이 없기 때문에 모르겠으면 구글링을 해보자.
만약 게임채팅에서 비속어를 사용하게 된다면 ***나오는 것처럼
string chatStr = "SHIT !!!";
string findStr = "SHIT";
string replaceStr = "****";
chatStr.replace(charStr.find(findStr), findStr.length(), replaceStr);
이런식으로 사용할 수 있다.
이러한 것도 못 외우겠으면 나중에 필요할 때 찾으면 사용법도 나와있기 때문에 찾아서 사용하면 된다.
그리고 종종 사용하는 것들은
string str4 = str.substr(0, 3);
문자열 자르기
const char* name = str.c_str();
옛날 방식으로 되돌리기 (옛날함수를 사용할 때 쓸 수도 있음)
이런 여러가지 기능이 있다는 것을 기억하고 다른 것들은 하나씩 사용해보거나 찾아보면서 익숙해 지면 된다.
그리고 잡설이지만 욕설 교체(필터링)하는 것을 온라인 게임에서 서버가 할까? 클라가 할까? 이건 당연히 클라에서 하는게 맞다.
강사님이 겪은 일인데, 퍼블리셔쪽에서 신입직원들이 뭔가 아느척을 하고 싶어서 그런지 클라에서 필터링을 하게 되면 누군가가 해킹을 하여서 무력화 시키면 욕설이 보이지 않냐?라고 말을 하였다고 한다.
가끔가다가 퍼블리셔가 그러한 요청도 한다라고 한다.
그래서 이러한 것들은 대부분 클라쪽에서 한다고 생각하면 된다.
그래서 실질적으로 문자열을 다루게 되면 string같은 만들어진 클래스를 사용하는 것이 합리적이라고 보지만, 프로젝트마다 다르기 때문에 시니어가 되기 전까지는 의견을 따라야 한다.
string도 vector와 같은 class이기 때문에 함수나 다른곳에 넘겨줄 때 복사 비용을 줄이고 싶다면 참조값을 넘겨주는 걸 신경써주자.
하지만 다른 내용에서 좀 헷갈려 질 수 있다.
바로 멀티바이트와 유니코드이다. 이쪽이 혼돈의 도가니라고 할 수 있다.
그래서 다음시간에는 멀티바이트와 유니코드에 대해서 알아볼 것이다.