String 문자열
우리가 c언어나 c++언어에서 문자열을 처리할 때 문제가 되었던 것이 있는데,
char line[LINE_LENGTH];
cin.getline(line, LINE_LENGTH);
이와 같은 상황에서 애러가 발생하는 케이스가 있다.
- 아무것도 읽지 못했을 때
- 한줄에 문자가 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