본문 바로가기

별걸다하는 IT/프로그래밍언어

[C/C++]cstring vs string.h vs string 스트링클래스 차이(C-strings vs std::string)

[C언어, C++언어, JAVA언어 라이브러리 및 함수 메서드 링크 ]

[C/C++]

 

string은 문자열을 담는 클래스잖아요?

하지만 헤더를 '#include<cstring>'이나 '#include<string.h>'로 놓고 문자열을 출력해보면 빨간 줄!! 불가능하다고 뜨는 걸 본적이 있어요.

그런데 이 헤더선언문을 #include<string>으로 바꿔주면 빨간 줄이 뜨고 컴파일이 잘 됩니다. 도대체 무슨 차이가 있는 걸까요~?

 

 

cstring vs string.h

 

 

The 'cstring' header provides functions for dealing with C-style strings - null-terminated arrays of characters. This includes functions like 'strlen' and 'strcpy'. it's the C++ version of the classic 'string.h' header from C.

 

C는 입출력함수로 #inlcude<stdio.h>를 놓고, C++은 #include<iostream>을 놓고 시작하죠?

이렇듯 C에는 '.h'로 끝나는 라이브러리가 대부분이예요. 똑같은 클래스를 C++형태로 바꿀 때, 암묵적으로 보통 뒤의 '.h'를 지우고 대신 앞에 'c'를 붙여줍니다.

 

← 그래서 라이브러리를 확인해보면 cstring외에도 앞에 c가 붙는 c++라이브러리가 많다는 것을 알 수 있어요. 간단하게는 cstring = string.h라고 생각하셔도 무방합니다.

문자열 길이를 리턴해주는 'strlen'함수나 문자열 복사해주는 'strcpy' 등의 함수를 사용할 수 있습니다.

 

그럼, cstring과 string 클래스 라이브러리의 차이는 뭘까요?

1. 원리 - 문자열을 어떻게 저장하는가?

C에서 문자열 저장할 때, 우리는 배열을 쓰는걸 알고 있어요.

#include <iostream>
using namespace std;
int main()
{
    char string_Arr[] = "hello in array";
    const char* stringPt = "hello with pointer";
    cout << string_Arr << "\n";
    cout << stringPt;
    return 0;
}

C에서는 이렇게 문자열을 출력하죠!

즉 C에서는 문자열을 배열에 저장하고, 지막에 문자열 끝이라는 신호를 주기 위해 '\0' 널문자가 삽입되기 때문에 배열 사이즈가 실제 문자열 사이즈보다 1커요. 이건 다 배웠던 거니깜~~ 간략히만 짚고 넘어왔어요. 이 게 C스타~일, 널로 종료되는 배열 기반의 문자열을 가지고 유용한 함수를 구현한게 cstring 라이브러리입니다. 

 

2. cstring의 문제

근데 이게 사용하다보니까 불편한게 너무 많은 거예요. 일단 C배열은 자신의 크기를 알 수 없어요. 문자열 쓸때마다 사이즈를 알려면 매번 strlen함수를 사용해줘야합니다. 뭔가 어딘가에 할당해주려면 문자열 하나마다 매~~~번 strlen하고 strcpy하고 C를 조금 해보신 사람들은 많이 겪어봤을 거예요. (잘 모르는 사람이면 앞으로 주구장창 겪을 ..)

class NameCard
{
    char* name;
    char* Comp;
    char* phone;
    int position;
public:
    NameCard(char* initname, char* initComp, char* initphone, int initpostion)
    {
        int leng = strlen(initname) + 1;
        name = new char[leng];
        strcpy(name, leng, initname);

        leng = strlen(initComp) + 1;
        Comp = new char[leng];
        strcpy(Comp, leng, initComp);

        leng = strlen(initphone) + 1;
        phone = new char[leng];
        strcpy(phone, leng, initphone);

        position = initpostion;
    }
    ~NameCard()
    {
        delete[] name;
        delete[] Comp;
        delete[] phone;
    }
}

 

하나의 예시를 가져왔어요. '명함'을 정의한건데 명함에는 이름(name), 회사(comp), 전번(phone), position(직급)등이 적혀있어요.

그런데 저 안에 보시면 문자열 저장할 이런 변수들 어떤 처리 때문에 strlen함수와 strcpy가 게속 쓰이는 걸 볼 수 있죠? (코드 해석을 못하더라도 아 좀 번거롭구나 정도 이해하면 됩니다) 

 

또 cstring은 직관성이 떨어진다는 문제를 갖습니다. 문자를 비교할 때, strcmp라는 함수를 호출해서 쓰고, 문자열을 붙일 때 strcat이라는 함수를 호출해서 쓰죠? 즉 우리는 매번 함수이름을 정확히 알고 있어야하고, 매개변수로 뭘 전달해줄지 문법을 알고 있어야해요. "hello" + "my name" 이런식으로 직관적으로 쓸 수 있음 얼마나 좋겠어요~ 이것들을 정리해준게 std::string 즉 string라이브러리입니다.

 

맨날 널 생각해서 한 사이즈 크게 만드는것도 (코드 보면 strlen()다음에 +1이 있는 것은 널때문이예요) 

이 배열크기가 실제로 달라(boundary condition) 반복문이든, 계산할 때 신경써줘야하는거에서 사람들이 실수를 종종 하는데 이처럼 하나 차이 때문에 나는 버그를 off-by-one bugs 라고 불러요.

코드 가독성도 떨어지고 계산할 때마다 그 놈의 배열 크기 때문에 신경써야 하는게 한두게도 아니고 그 외에 불편한 문제점들이 많아요. ~~! 

 

3. C++의 std::string과 발전된 특징

이런 cstring의 불편했던 점들을 개선하기 위해, 이런 밑단 문자열들을 관리하기 위해 새로 만든 포장박스!(class)가 std::string입니다. 좀 편하게 쓸 수 있게 문자열을 새로 정의해서 내부적으로 불편한 것들을 자동으로 처리해주는거죠.

The string header provides the std::string class and related functions and operators.

std::string을 사용하는 것이 string라이브러리입니다. 연산자(아까 위에서 예시로 들었던 +같은거)랑 메서드를 제공해줘요.

The headers have similar names, but they're not really related beyond that. They cover separate tasks.

헤더는 이름이 매우 비슷한데, 'cstring'이랑 'string'이니까 헷갈릴만하죠?ㅎㅎ 근데 커버하는 게 완전 달라요. 

 

달라진 몇가지 특징만 뽑아볼까요?

1. Flexible storage capacity,  

사이즈를 드디어 자유자래로 늘였다 줄였다 편하게 할 수 있어요. 매번 선언하고 크기 재할당 일일이 설정 안해줘도 된다는거죠.

2. No need to worry about manual memory management or resizing strings

이제는 메모리 매번 신경쓸 필요도 없고 문자열 재할당 할 필요도 없어요 

3. Boundary issues are handled for me, with or without a null character.

이말은 널때문에 발생했던 boundary issue가 이제 발생하지 않는다는 거 (알아서 해주니까)

4. Intuitive assignment using = operator rather than strcpy

strcpy함수 쓸 필요 없이 '='만으로 자동으로 복사해줍니다. 깊은 복사든 얕은 복사든 이제 신경 안써도 돼요. strcpy 매개변수로 뭐가 들거아야하는지 신경쓸 필요 없습니다!

5. Intuitive comparison using the ==operator rather than strcmp

마찬가지 문자열 비교할 때 strcmp함수를 썻어야 했잖아요?  간단하게 '=='가 해결해줍니다. 숫자비교할 때처럼 직관적으로 사용할 수 있어요. (문자열 붙이는데 +사용도 동일!)

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string st = "hello1!";
    string st2("hello2");
    string filledst(20, 'A');
    if (st < st2)
    {
        cout <<"st1 comes first lexicographically";
    }
    return 0;
}

string은 클래스이기 때문에 초기화를 name("~~")이런 형식으로 해줄 수 있습니다.

많은 기능들이 오버로딩되어 있어요 

 

즉 !! 이왕 문자열 쓸거면 string 라이브러리를 써서 편하게 사용하자! 더 많은 기능은 string 포스팅을 따로 빼서 알아볼게요~

  • 1 2020.07.09 13:27

    본문의 cstring과 MFC의 CString 클래스의 이름이 동일하여 혼동이 옵니다.

  • 온천장 2020.08.14 14:11

    MFC 개발을 하는데 있어 MFC의 CString 과 std::string 중 어느쪽을 사용하는걸 추천하시나요..?

  • 질문이요 2020.11.21 23:12

    C 에서 문자열을 출력하기 위해서 char 배열을 사용할땐 배열에 있는 문자의 갯수에 따라서 배열의 크기가 계속 바뀌는데 std::string 을 사용하면 문자가 얼마나 들어있던 24바이트로 고정되더라고요
    혹시 왜 그런지 아시나요?