[C++] 동적 스트링 Part 1
🌈 프로그래밍/C++

[C++] 동적 스트링 Part 1

반응형

 

 

안녕하세요? 수구리입니다!

 

 

지난 포스팅에서는 Chapter 1장을 마무리하고

 

 

간단한 콘솔 프로그램인 직원 관리 프로그램을 만들어 보았습니다!

 

 

책에 있는 예제 코드가 따로따로 적혀있어서 직접 한눈에 보려고 파일을 한 번에 포스팅해두었습니다.

 

 

2021.08.23 - [C++] - [C++] 직원 관리 프로그램 만들기

 

[C++] 직원 관리 프로그램 만들기

안녕하세요? 수구리입니다. 지난 포스팅에서는 C++의 유니폼 초기화에 대해서 알아보았었죠? 2021.08.20 - [C++] - [C++] 유니폼 초기화란? [C++] 유니폼 초기화란? 안녕하세요? 수구리입니다. 저번 포스

tasddc.tistory.com

 

그럼 이번 포스팅에서는 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을 제공하는지에 대해서 자세하게 알아보도록 하겠습니다!

 

 

감사합니다!

반응형