2장 - C에서의 스트링, 스트링 리터럴

1) C에서의 string

C에서는 string을 부가적인 기능으로 취급했으며, 문자 배열의 마지막에 널(NULL이 아니다! NUL) 문자 \0을 붙여서 스트링이 끝나는 것을 표현했다. 이런 방식으로 hello를 표현하려면, h, e, l, l, o, \0 이렇게 여섯 개 만큼의 공간이 필요하다.

C에서 제공하던 스트링 연산에 대한 함수는 C++에서 헤더로 제공된다. 함수 목록은 [링크](https://docs.microsoft.com/ko-kr/cpp/standard-library/cstring?view=msvc-170)에서 확인하자

  • strcpy()

    스트링 타입 매개변수를 두 개 받아서, 두 번째 스트링을 첫 번째 스트링에 복사하는 함수이다. 두 스트링의 길이 비교를 하지 않는다는 특징이 있다.

  • strlen()

    스트링의 길이를 구한다. 여기서 얻은 길이를 통해 동적으로 스트링을 할당할 수 있는데, strlen()은 \0을 포함하지 않은 길이를 반환하므로, 할당시 +1된 크기를 할당해야 한다. 여러 스트링을 합칠 때, 길이를 strlen(str1) + strlen(str2) + strlen(str3) +1 처럼 나타낼 수 있다.

  • strcat()

    스트링을 합친다. 
    

참고로 길이를 구할 때, strlen()말고 sizeof()를 쓸 수도 있지만 결과가 다르다. sizeof는 실제로 할당된 메모리 크기를 반환하기에 \0을 포함하여 계산한다. 아래의 코드를 보자.

int main() {
	char myString2[] = "ThankYou";
	cout << sizeof(myString2) << endl;  // 9
	cout << strlen(myString2) << endl;  // 8
}

앞으로 스트링을 쓸 일이 있으면, 우선 C++의 string을 쓰자. 그 다음에 cstring에서 개량형인 strcpy_s(), strcat_s()등을 사용할 것. 접미사로 _s가 붙은 차이는 링크과 같다.


2) 스트링 리터럴

변수에 담지 않고 “Hello”처럼 바로 값으로 표현한 스트링을 스트링 리터럴이라고 한다. 스트링 리터럴은 메모리의 읽기 전용 영역에 저장되어, 레퍼런스 형태로 재사용된다. 실제 할당 공간은 하나인 것이다(= 리터럴 풀링).

읽기 전용 영역에 있으므로, 스트링 리터럴은 const char가 N개인 배열이다. 아래 이미지를 보면 const char*은 정상적으로 대입 되는 모습이다.

Untitled

상수 배열이기에 myString[3] = 'A'이렇게 값을 변경할 수 없다. 안전성이 높다는 말이다. 그런데 포인터 배열이 아니라 그냥 문자 배열(myString1)은 어떨까?

Untitled

컴파일러는 문자 배열을 읽기 전용 메모리에 넣지도, 재사용 하지도 않는다. 그렇기에 마음것 값을 변경할 수 있다. 초기값을 설정할 때는 스트링 리터럴을 사용하여 큰 배열을 생성한 뒤 실제 값을 넣는 방식을 사용한다.

raw string literal

여러 줄에 걸쳐 작성한 스트링 리터럴. 이스케이프 시퀀스를 따로 표시할 필요가 없다. 예를들어 "를 일반적인 스트링 리터럴 중간에 사용하면 에러가 발생한다. "Hello " World"같이 말이다. 그래서 이스케이프 시퀸스를 사용하여 \"와 같이 표현해야 문자로 인식된다. 로우 스트링 리터럴은 이럴 필요가 없다. R"( ~ )"의 형태로 사용한다.

const char* str1 = "Hello \"World\"!";
	cout << str1 << endl;
	
const char* str2 = R"(Hello "World"!)";
	cout << str2 << endl;

//==========================
>> Hello "World"!
>> Hello "World"!

참고 자료