반응형
안녕하세요? 수구리입니다!
지난 포스팅에서는 Chapter 1장을 마무리하고
간단한 콘솔 프로그램인 직원 관리 프로그램을 만들어 보았습니다!
책에 있는 예제 코드가 따로따로 적혀있어서 직접 한눈에 보려고 파일을 한 번에 포스팅해두었습니다.
2021.08.23 - [C++] - [C++] 직원 관리 프로그램 만들기
그럼 이번 포스팅에서는 Chapter 2장으로 넘어가서
스트링과 스트링 뷰에 관련된 내용을 포스팅해보려고 합니다.
C언어에서는 string이라는 타입이 있는데요~
C++에서는 string이 클래스로 정의되어 있습니다!
아무래도 타입이 아닌 클래스로 정의되어있으니깐 더 추가된 기능이 있겠죠???
그래서 간단하게 C에서의 string과 비교를 하면서 내용을 진행해보도록 하겠습니다.
2.1 동적 스트링
- 이번 장에서는 스트링에 대한 C언어와 C++의 차이에 대하여 알아보고
- C++의 std::string 클래스에 대하여 자세히 알아보며
- std:string_view의 용도와 그리고 로 스트링 리터럴에 대하여 알아보자.
- 프로그램을 작성하다 보면 스트링을 사용해야 하는 일이 굉장히 많다.
- C언어에서는 null을 사용하여 끝나는 문자 배열로 스트링을 표현함.
- 이는 버퍼 오버플로우 공격이라던지 다양한 보안 취약점이 있다.
- C++에서는 이러한 문제를 해결하기 위해 표준 라이브러리인 std::string 클래스를 제공한다.
- 즉, C에서는 스트링을 부가 기능처럼 취급한 반면 C++에서는 스트링을 핵심 데이터 타입으로 제공한다는 의미이다.
2.1.1 C 스타일 스트링
- 앞서 C언어에서는 '\0' 즉, NUL을 사용하여 스트링이 끝났음을 알렸다고 하였는데
- 이는 NULL 포인터와는 다르다는 것에 유의.
- C++의 헤더 파일에는 C에서 사용하던 스트링 연산에 대한 함수를 제공하고 있다.
- 대체로 메모리 할당 기능을 제공하지 않는다.
char* copyString(const char* str){
char* result = new char[strlen(str)]; // 한칸 부족!
strcpy(result, str);
return result;
}
- 위의 예제에서 strlen(str) 함수는 'hello'라는 문자열에 대하여 길이가 6이 아니라 5를 리턴한다.
- 따라서 지정된 크기로 할당을 위해서는 + 1을 해주어야 한다! C 스타일의 스트링을 다룰 때 주의해야 한다.
// 수정
char* copyString(const char* str){
char* result = new char[strlen(str) + 1];
strcpy(result, str);
return result;
}
- 그렇다면 왜 strlen 이란 함수는 실제 문자의 길이만 리턴할까? 다음 예제로 이해할 수 있다.
// 여러 스트링을 합쳐서 만든 스트링을 할당하는 경우
char* appendString(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;
}
- 만약 strlen() 함수가 '\0'까지 포함한 길이를 리턴했다면 메모리 공간에 맞게 계산하기가 어렵다!!
// sizeof()와 strlen()
char test1[] = "abcdef";
size_t s1 = sizeof(test1); // 7
size_t s2 = strlen(test1); // 6
- 위의 예제처럼 sizeof로 스트링의 길이를 가져온다면 '\0' 문자까지 포함한다.
- 따라서 C 스타일 스트링의 길이를 구할 때에는 sizeof()를 절대로 사용해서는 안 된다.
2.1.2 스트링 리터럴
- C++로 다시 돌아와서 스트링을 인용부호 (<<.. >>) 로 묶은 것을 보았을 것이다.
- 이는 스트링을 변수에 담지 않고 스트링 값을 바로 화면에 출력해준다.
- 내부적으로 메모리의 읽기 전용 영역에 저장.
- 읽기 전용이기 때문에 변수에 대입하게 된다면 여러 곳에서 공유하기 때문에 위험하다.
- 스트링 리터럴을 참조할 때는 const 문자에 대한 포인터를 사용하는 것이 안전하다.
리터럴 풀링
컴파일러가 같은 스트링 리터럴이 코드에 반복되어 나오면,
그중 한 스트링에 대한 레퍼런스를 재사용하는 방식으로 메모리를 절약한다.
즉, 코드에서 'hello'라는 스트링 리터럴을 500번 작성해도
컴파일러는 해당 스트링에 대한 메모리 공간을 딱 하나만 할당한다.
// 결과 예측 X
char* ptr = "hello"; // 변수에 스트링 리터럴 대입
ptr[1] = 'a'; // 결과 예측 X
// 읽기 전용 메모리에 쓰기 작업을 걸러줌.
const char* ptr = "hello";
ptr[1] = 'a'; // 에러 발생
로 스트링 리터럴
- 여러 줄에 걸쳐 작성한 스트링 리터럴
- 인용 부호를 이스케이프 시퀀스로 표현할 필요가 없고, '\t' 또는 'n' 같은 이스케이프 시퀀스를 일반 텍스트로 취급한다.
- 이스케이프 시퀀스를 무시하는 특징이 있다.
// 컴파일 에러
const char* str = "Hello "World"!"
// 정상
const char* str = "Hello \"World\"!";
// 로 스트링 리터럴 사용
const char* str = R"(Hello "World"!)"; // 인용 부호를 이스케이프 시퀀스로 표현 하지 않아도 OK
// 로 스트링 리터럴을 사용하여 여러줄 스트링 표현
const char* str = "Line 1\nLine 2";
// 위와 같은 결과
const char* str = R"(Line 1
Line 2)";
마무리하면서 이번 포스팅에서는 C에서 사용하는 string 스타일에 대해서 알아보았고
스트링 리터럴 풀링에 대해서 알아보았습니다!
다음 포스팅에서는 본격적으로 C++에서 어떤 식으로 string을 제공하는지에 대해서 자세하게 알아보도록 하겠습니다!
감사합니다!
반응형
'🌈 프로그래밍 > C++' 카테고리의 다른 글
[C++] 동적 스트링 Part 3 (4) | 2021.08.26 |
---|---|
[C++] 동적 스트링 Part 2 (0) | 2021.08.25 |
[C++] 직원 관리 프로그램 만들기 (2) | 2021.08.23 |
[C++] 유니폼 초기화란? (2) | 2021.08.20 |
[C++] 객체 지향 언어의 특성에 대하여 (0) | 2021.08.20 |