String 문자열

우리가 c언어나 c++언어에서 문자열을 처리할 때 문제가 되었던 것이 있는데,

char line[LINE_LENGTH];
cin.getline(line, LINE_LENGTH);

이와 같은 상황에서 애러가 발생하는 케이스가 있다.

  1. 아무것도 읽지 못했을 때
  2. 한줄에 문자가 256자 이상일 때 (즉, 버퍼크기가 충분하지 않을 때)

여기서 대안으로 나온것이

std::string 클래스 이다

그리고 이 string 클래스는 이후 등장하는 언어에 기본적인 원시 타입이 된다.

우리가 알고있는 그 string 타입이 첫시작은 C++ 클래스.

#include<iostream>
#include<string>
using namespace std;

int main()
{
    string str1 = "Hellow";
    string str2 = "World";

    cout << str1 << str2 << endl;
}

과 같이 사용가능.

string 클래스

string 클래스를 이용한 문자열은 앞서 나온 char[] (char array)와 달리 길이가 증가할 수 있다. 이를 이용해 대입(Assignment)과 덧붙이기(Appending)이 가능하다.

  • c언어
char firstName[20] = "Ha-Young";
char fullName[20];
strcpy(fullName, firstName); // 대입. 불완전
strcat(fullName, " CHOI"); // 덧붙이기. 불완전

c언어를 보면 다음과 같이 문자열을 처리 할 수 있는데, 고정된 크기이기 때문에 너무나도 불완전하다. (공간이 남거나 넘어버리거나)

  • c++언어
string firstName="Ha-Young";
string fullName;

fullName = firstName;
fullName += " CHOI";

c++언어의 string을 이용하면 위 char array로 표현하던 문자열과 달리 문자열 처리가 훨씬 간편해 진다.

  • c언어
snprintf(fullName, 40, "%s %s", firstName, lastName);
  • c++ string
fullName = firstName + " " + lastName;

여기에 더해 string 클래스는 비교연산도 가능하다.

==, !=, >, <, <=, >= 와 같은.

String 클래스 메서드

C++의 String은 Class이기 때문에 메서드도 있다.

  • size(), length() - 문자열 길이 반환
  • c_str() - 해당 string이 가지고 있는 문자배열의 시작주소를 가리키는 포인터를 반환

    string line;
    cin >> line;
    const char* cLine = line.c_str();
  • 그 외 함수는 여기를 참조.

string 속에 문자 접근?

string 속에 문자접근이 가능할까?

c와 같다. (배열 index로 접근) -> 말고도 at()도 있다.

firstName[2] = '-';

함수(연산자오버로딩) 반환값인데 대입이 가능한 이유는 뭘까?

그것은 [] 연산자 오버로딩함수가 참조형으로 반환했기 때문에 가능하다.

한 줄 읽기

string mailheader;
getline(cin, mailheader, '@'); // @문자까지 읽기

string과 stream

string과 stream을 이용하여 아래와 같은 조건을 만족할 때까지 스트림에서 문자들을 꺼내 string에 저장 할 수 있다.

  • end-of-file 만날 때 (eofbit 값이 true가 됨)
  • 구분문자(delimiter)를 만날 때 까지 (구분문자는 버려짐)

  • std:istringstream

    • cin과 비슷. 키보드 대신 string으로 읽어온다.
    • sscanf()와 비슷
  • std:ostringstream

    • cout과 비슷. 콘솔 대신 string에 출력.
    • sprintf()와 비슷
  • 자주 쓰이지 않는다.

근데, C의 헤더를 가져다 써도 되나요?

C++에서는 C의 함수들이 많이사용되고 있는데,

그이유는 성능상의 이유. C언어의 함수들이 더 빠르게 동작한다.

C C++
<string.h> <cstring>
<stdio.h> <cstdio>
<ctype.h> <cctype>

등등

그럼 String 클래스는 어떻게 동작?

그래서 결국 String 클래스는 문자배열길이에 관해 고민 할 필요가 없다.

근데 어떻게 동작하는가?

string 클래스는 내부적으로 char* array가 존재하고

포인터 변수, 크기변수 등을 제외하고 char array는 heap영역에 저장한다. (memory allocation)

플랫폼마다 다르지만, 보통 처음 16바이트로 설정하고 그 후에 크기가 모자라면 재할당(기존 힙영역 free)

32바이트, 64바이트 … 와 같은 식으로 늘려간다.

String 단점은?

하지만, String이라고 만능은 아닌것이

  • 힙(Heap) 메모리 할당은 느리다.
  • 메모리 단편화(memory fragmentation)문제
  • 내부 버퍼의 증가는 멀티 쓰레드 환경에서 안전하지 않을 수 있다.
  • 여전히 C++을 쓰는 업계가 어디인지 생각해보자.

    • 그래서 여전히 sprintf와 char[]을 매우 많이 사용한다. (성능상의 이유)

Stack 메모리 <-> Heap 메모리

  • Stack 메모리 : exe가 컴파일 될 때 가지는 메모리. 빠르다.
  • Heap 메모리 : os가 가지고 있는 모든 메모리. 느리다. 메모리 단편화 문제 야기(조각조각 나서 연속된 메모리 X - 잦은 길이변화가 있다면)

막간상식 - pointer의 위치마다 달라지는 변화

  • const char* -> pointer to const char -> const char를 가리키는 포인터
  • char* const -> const pointer to char -> const pointer가 가르키는 char
  • const char* const -> const pointer to const char