C 스타일 스트링
C 언어는 스트링 문자 배열로 표현했다.
스트링의 마지막에 널 문자(\0)를 붙여서 스트링이 끝났음을 표현했다.
이러한 널 문자에 대한 공식 기호는 NUL이다.
L이 두 개가 아니라 하나며 NULL 포인터와는 다른 값이다.
아직도 C 스타일 스트링을 쓰는 C++ 프로그램이 많기 때문에 C 언어 스타일 스트링을 알아둘 필요가 있다.
C 스트링을 다룰 때 \0 문자를 담을 공간을 깜박하고 할당하지 않는 실수를 저지르기 쉽다.
예를 들어 'hello'란 스트링을 구성하는 문자는 다섯 개이지만,
메모리에 저장할 때는 문자 여섯 개만큼의 공간이 필요하다.
myString | 'h' | 'e' | 'l' | 'l' | 'o' | '\0' |
C++은 C 언어에서 사용하던 스트링 연산에 대한 함수도 제공한다.
이러한 함수는 <cstring> 헤더 파일에 정의돼 있다.
예를 들어 strcpy() 함수는 스트링 타입 매개변수를 두 개 받아서 두 번째 스트링을 첫 번째 스트링에 복사한다.
다음 코드는 주어진 스트링에 딱 맞게 메모리를 할당한 결과를 리턴하는 함수를
strcpy()에 대한 래퍼 함수 형태로 구현한 예를 보여주고 있다.
여기서 스트링의 길이는 strlen() 함수로 구한다.
char* copyString(const char* str)
{
char* result = new char[strlen(str)]; // 버그! 한 칸 부족하다.
strcpy(result, str);
return result;
}
위 copyString() 함수 코드에 오류가 하나 있다.
strlen() 함수에서 리턴하는 값은 스트링을 저장하는 데 사용된 메모리 크기가 아니라 스트링 길이를 리턴한다.
따라서 strlen()은 'hello'란 스트링에 대해 6이 아닌 5를 리턴한다.
따라서 스트링을 저장하는 데 필요한 메모리를 제대로 할당하려면 문자 수에 1을 더한 크기로 지정해야 한다.
char* copyString(const char* str)
{
char* result = new char[strlen(str) + 1]; // 버그! 한 칸 부족하다.
strcpy(result, str);
return result;
}
스트링 세 개를 하나로 합쳐서 리턴하는 함수를 생각해보면 스트링에 딱 맞게 공간을 할당하려면 세 스트링의 길이를
strlen() 함수로 구해서 모두 더한 값에 마지막 '\0' 문자에 대한 공간 하나를 추가해야 한다.
만약 strlen() 함수가 '\0'을 포함한 길이를 리턴하도록 구현됐다면 메모리 공간에 딱 맞게 계산하기가 번거롭다.
다음 코드는 방금 설명한 작업을 strcpy()와 strcat() 함수로 처리하는 예이다.
char* appendStrings(const char* str1, const char* str2, const char* str3)
{
char* result = new char[strlen(str1) + strlen(str2) + strlen(str3) + 1];
strcpy(result, str1);
strcat(result, str2);
strcat(result, str3);
return result;
}
C와 C++에서 제공하는 sizeof() 연산자는 데이터 타입이나 변수의 크기를 구하는 데 사용된다.
예를 들어 sizeof(char)은 1을 리턴하는데, char의 크기가 1바이트이기 때문이다.
C 스타일 스트링에 적용할 때는 sizeof()와 strlen()의 결과가 전혀 다르다.
따라서 스트링의 길이를 구할 때는 절대로 sizeof()를 사용하면 안 된다.
sizeof()의 리턴 값은 C 스타일 스트링이 저장된 방식에 따라 다르기 때문이다.
스트링을 char[]로 저장하면 sizeof()는 '\0'을 포함하여 그 스트링에 대해 실제로 할당된 메모리 크기를 리턴한다.
char text1[] = "abcdef";
size_t s1 = sizeof(text1); // 7
size_t s2 = strlen(text1); // 6
반면 C 스타일 스트링을 char*로 저장했다면 sizeof()는 포인터의 크기를 리턴한다.
const char* text2 = "abcdef";
size_t s3 = sizeof(text2); // 플랫폼마다 다르다
size_t s4 = strlen(text2); // 6
이 코드를 32비트 모드에서 컴파일하면 s3의 값은 4고, 64비트 모드에서 컴파일하면 8이다.
sizeof()가 포인터 타입인 const char*의 크기를 리턴하기 때문이다.
C 스타일 스트링 연산에 관련된 함수는 모두 <cstring> 헤더 파일에 정의돼 있다.
strcpy()나 strcat은 컴파일러에서 보완 관련 경고나 에러 메시지가 출력될 수 있다.
경고가 나오지 않게 하려면 strcpy_s()나 strcat_s()와 같은 C 표준 라이브러리 함수를 사용하면 된다.
또한 프로텍트- 속성-C/C++-전처리기-전처리기 정의 칸에 _CRT_SECURE_NO_WARNINGS를 입력하면
strcpy를 써도 오류가 생기지 않는다.
'💻프로그래밍 내용 정리 > C++17' 카테고리의 다른 글
[C++ 2.1.3-1] C++std::string 클래스, 표준 사용저 정의 리터럴's' (0) | 2022.08.20 |
---|---|
[C++ 2.1.2] 스트링 리터럴(리터럴 폴링, 로 스트링 리터럴, 확장 로스트링 리터럴) (0) | 2022.08.19 |
[C++ 1.6.4] 사용자 인터페이스 (0) | 2022.08.19 |
[C++ 1.6.3] Database 클래스 (0) | 2022.08.18 |
[C++ 1.6.2] Employee 클래스 (0) | 2022.08.18 |