Skip to content

6. 문자열(String)


1. 키워드

  • 문자열(String)
  • string 클래스
  • length()size() 메서드
  • append() 메서드
  • find() 메서드
  • compare() 메서드
  • replace() 메서드
  • capacity()max_size() 메서드


2. C 스타일의 문자열

1) C++ 문자열


  • 문자열이란 메모리에 저장된 일련의 연속된 문자(Character)들의 집합을 의미한다.
  • C++에서는 이러한 문자열을 다음과 같은 두 가지 방법으로 생성할 수 있다.


1] C 스타일의 문자열

2] string 클래스를 이용한 문자열


2) C 스타일의 문자열

  • C++에서는 ""(큰따옴표)를 사용해 표현되는 문자열을 문자열 상수(String Constant)라고 한다.
  • 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, 문자열의 내용 또한 변경할 수 없기 때문이다.
  • C++에서 char 타입 배열을 선언하면 이 배열이 곧 문자 배열이 된다.
  • C++에서는 문자열의 길이에 제한을 두지 않는다.


3) 널(NULL) 문자

  • C++에서 char 타입 배열로 선언된 문자 배열은 문자열의 끝을 프로그램에 따로 알려주어야 한다.
  • 그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레깃값을 구분할 수 있다.
  • 따라서 문자열에 속한 데이터가 끝나면, 문자열의 끝을 의미하는 문자를 하나 더 삽입해 준다.
  • 이러한 문자를 널 문자라고 하며, '\0'으로 표시하고 아스키코드값은 0이다.
  • 널 문자의 유무로 char 타입 데이터 배열과 실제 문자열을 서로 구분할 수 있다.
  • 그러므로 문자열을 저장하기 위한 char 타입 배열을 선언할 때에는 반드시 널 문자까지 포함해서 생각해야 한다.


4) 문자열 입력

  • C++에서 문자열을 입력 받기 위해서는 문자열이 저장될 char 타입 배열을 미리 생성해놔야 한다.


#include <iostream>
using namespace std;

int main() {
    const int SIZE = 20;
    char address[SIZE];
    char name[SIZE];

    cout << "자신의 이름을 적어주세요: ";
    cin >> name;

    cout << "자신이 살고 있는 도시를 적어주세요: ";
    cin >> address;

    cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;

    return 0;
}

// 자신의 이름을 적어주세요: 홍길동 (입력)
// 자신이 살고 있는 도시를 적어주세요: 서울 (입력)
// 서울에 살고 있는 홍길동님~ 감사합니다!


  • 위의 코드는 사용자의 이름과 살고 있는 도시명을 입력 받는 것이다.
  • 하지만 이 코드는 다음과 같은 두 가지 문제점을 안고 있다.


1] 이름에 띄어쓰기가 들어가면 도시명을 입력할 수 없다.

2] 20바이트 이상의 이름이나 도시명을 입력하면 프로그램이 강제 종료된다.


  • C++에서 cin 객체는 띄어쓰기를 포함한 '\t'(탭 문자), '\n'(캐리지 리턴 문자) 등을 모두 문자열의 끝으로 인식한다.
  • 따라서 띄어쓰기를 포함한 문자열을 전부 입력받으려면 cin 객체의 get() 메서드를 사용하여 다음처럼 수정해야 한다.


#include <iostream>
using namespace std;

int main() {
    const int SIZE = 20;
    char address[SIZE];
    char name[SIZE];

    cout << "자신의 이름을 적어주세요: ";
    cin.get(name, SIZE).get();

    cout << "자신이 살고 있는 도시를 적어주세요: ";
    cin.get(address, SIZE).get();

    cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;

    return 0;
}

// 자신의 이름을 적어주세요: 홍 길동 (입력)
// 자신이 살고 있는 도시를 적어주세요: 한국의 서울 (입력)
// 한국의 서울에 살고 있는 홍 길동님~ 감사합니다!


  • 위의 코드는 띄어쓰기를 포함한 이름이나 도시명을 정확히 입력할 수 있게 되었다.
  • 하지만 아직도 20바이트 이상의 이름을 입력할 경우, 도시명을 입력 받지 못하는 문제점을 안고 있다.
  • 이 문제는 cin 객체의 ignore() 메서드를 사용하여 다음처럼 수정할 수 있다.


#include <iostream>
using namespace std;

int main() {
    const int SIZE = 20;
    char address[SIZE];
    char name[SIZE];

    cout << "자신의 이름을 적어주세요: ";
    cin.get(name, SIZE).ignore(SIZE, '\n');

    cout << "자신이 살고 있는 도시를 적어주세요: ";
    cin.get(address, SIZE).ignore(SIZE, '\n');

    cout << address << "에 살고 있는 " << name << "님~ 감사합니다!" << endl;

    return 0;
}

// 자신의 이름을 적어주세요: abcdefghijklmnopqrstuvwxyz (입력)
// 자신이 살고 있는 도시를 적어주세요: ABCDEFGHIJKLMNOPQRSTUVWXYZ (입력)
// ABCDEFGHIJKLMNOPQRS에 살고 있는 abcdefghijklmnopqrs님~ 감사합니다!


  • 위의 코드의 실행결과를 살펴보면, 20바이트 이상의 이름이나 도시명을 입력해도 정확히 20바이트까지만 입력 받고 있는 것을 확인할 수 있다.


  • 위의 코드와 같이 C 스타일의 문자열 입력에서는 입력할 문자열의 길이를 미리 알고 있어야만 한다.
  • 하지만 C++에서 제공하는 string 클래스를 이용하면 다음처럼 아주 간단하게 그 문제를 해결할 수 있다.


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

int main() {
    string address, name;

    cout << "자신의 이름을 적어주세요: ";
    getline(cin, name);

    cout << "자신이 살고 있는 도시를 적어주세요: ";
    getline(cin, address);

    cout << address << "에 살고 있는 " << name << "님~ 감사합니다!";

    return 0;
}

// 자신의 이름을 적어주세요: 가나다라마바사아자차카타파하 (입력)
// 자신이 살고 있는 도시를 적어주세요: ABCDEFGHIJKLMNOPQRSTUVWXYZ (입력)
// ABCDEFGHIJKLMNOPQRSTUVWXYZ에 살고 있는 가나다라마바사아자차카타파하님~ 감사합니다!


  • 위의 코드는 앞서 살펴본 문자열의 띄어쓰기 문제나 문자열의 길이와 상관없이 모든 문자열을 정확히 입력 받을 수 있다.


5) C 문자열 처리 함수

  • C++에서 C 스타일의 문자열을 처리하기 위해 C 라이브러리의 문자열 처리 함수를 사용할 수 있다.
  • 이러한 C의 문자열 라이브러리를 사용하기 위해서는 우선 cstring 헤더 파일을 포함해야 한다.


3. string 클래스

  • C++은 문자열을 예전의 C 스타일뿐만 아니라, 새롭게 추가된 string 클래스를 이용하여 처리할 수 있도록 해준다.
  • string 클래스는 char 타입 배열보다 사용하기 편리하며, 문자열을 하나의 타입처럼 표현할 수 있게 해준다.
  • C++에서 string 클래스를 사용하기 위해서는 우선 string 헤더 파일을 포함해야 한다.
  • 또한, string 클래스는 std 네임스페이스에 속해 있으므로, using 지시자를 사용하거나 해당 네임스페이스를 참조해야 한다.


1) 문자열 선언 및 초기화

  • C++에서 string 객체를 사용한 문자열 선언 방식은 다음과 같다.


string str1;               // 문자열의 선언
str1 = "C++ Programming";  // 문자열의 초기화
string str2 = "C++";       // 문자열의 선언과 동시에 초기화


  • string 객체는 위와 같의 문자열을 배열 형태가 아닌 단순한 변수로 선언한다.
  • 따라서 사용자가 길이를 명시하지 않아도 되며, 문자열 길이에 대한 문제는 C++ 프로그램이 자동으로 처리해 준다.
  • 위의 코드에서 문자열 str1은 선언 시 길이가 0string 객체를 생성한다.
  • 그 후 문자열을 초기화하면 C++ 프로그램이 문자열 str1의 길이를 자동으로 조절해 준다.
  • 따라서 string 객체를 사용하면 char 타입 배열을 사용하는 것보다 훨씬 더 편리하고 안전하게 문자열을 처리할 수 있다.


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

int main() {
    string dog;
    cout << "현재 dog 변수의 길이는 " << dog.length() << "입니다." << endl;

    dog = "Navi";
    cout << dog << "! 정말 예쁜 이름이네요!" << endl;

    cout << "현재 dog 변수의 길이는 " << dog.length() << "입니다." << endl;
    cout << "강아지 이름의 첫 글자는 바로 " << dog[0] << "입니다." << endl;

    return 0;
}

// 현재 dog 변수의 길이는 0입니다.
// Navi! 정말 예쁜 이름이네요!
// 현재 dog 변수의 길이는 4입니다.
// 강아지 이름의 첫 글자는 바로 N입니다.


  • 위의 코드에서 보면 string 객체로 만든 문자열도 배열처럼 인덱스를 통해 다룰 수 있다는 것을 알 수 있다.
  • 또한, 길이가 0string 객체가 입력된 문자열에 따라 자동으로 길이가 조절됨을 알 수 있다.


한글

  • 컴퓨터에서 한글은 2바이트로 취급된다.
  • 따라서 위의 예제에서 한글을 입력하면 이름의 첫 글자로 이상한 문자가 출력될 것이다.


  • 참고로 string 클래스의 length()size() 메서드를 사용하면 string 객체의 현재 길이를 알 수 있다.


2) 문자열 처리

  • C++에서 string 객체를 이용한 문자열의 처리는 char 타입 배열을 이용하는 방식보다 훨씬 더 간단하다.
  • C에서 char 타입 배열 사이의 대입 작업은 strcpy()strncpy() 함수를 사용했다.
  • 하지만 string 객체를 이용한 문자열에서는 =(대입 연산자)만을 사용하여 간단히 대입 작업을 할 수 있다.


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

int main() {
    string str1 = "C++ is Cool!";
    string str2;

    str2 = str1;  // 문자열 대입 연산
    cout << str2 << endl;

    return 0;
}

// C++ is Cool!


  • 또한, char 타입 배열 사이의 추가나 결합 작업은 strcat()이나 strncat()함수를 사용했다.
  • 하지만 string 객체를 이용하면 +=(복합 대입 연산자)나 append() 메서드를 이용하여 손쉽게 추가나 결합을 할 수 있다.


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

int main() {
    string str1 = "C++ is ";
    string str2 = "Cool! and funny!";
    string str3;

    str3 = str1 + str2;  // 문자열 결합 연산
    cout << str3 << endl;

    str1 += str2;  // 문자열 추가 연산
    cout << str1 << endl;

    return 0;
}

// C++ is Cool! and funny!
// C++ is Cool! and funny!


3) 문자열 입출력

  • string 객체를 이용한 문자열의 입력에는 cin 객체를, 출력에는 cout 객체를 사용할 수 있다.
  • 하지만 cin 객체를 이용한 문자열의 입력은 한 단어 단위로 수행된다.
  • 따라서 문자열을 한 행(Line)씩 읽고 싶을 때는 getline() 함수를 사용해야 한다.


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

int main() {
    string name, subject;

    cout << "자신의 이름을 적어주세요: ";
    getline(cin, name);

    cout << "가장 자신있는 과목을 적어주세요: ";
    getline(cin, subject);

    cout << name << "님이 가장 자신있어 하는 과목은 바로 "
         << subject << "입니다!" << endl;

    return 0;
}

// 자신의 이름을 적어주세요: 홍길동 (입력)
// 가장 자신있는 과목을 적어주세요: 국어 (입력)
// 홍길동님이 가장 자신있어 하는 과목은 바로 국어입니다!


  • getline() 함수는 첫 번째 매개변수로 cin 객체를, 두 번째 매개변수로 문자열을 저장할 string 객체 변수를 전달 받는다.


4. string 메서드

  • string 메서드는 string 클래스에 정의된 문자열과 관련된 작업을 할 때 사용하는 메서드이다.
  • string 클래스에서 제공하는 대표적인 문자열 처리 함수는 다음과 같다.


1] length()size()

2] append()

3] find()

4] compare()

5] replace()

6] capacity()max_size()


1) length()size() 메서드

  • length() 메서드는 문자열의 길이를 반환하는 메서드이다.
  • size() 메서드도 length() 메서드와 언제나 같은 값을 반환하지만, 그 의미는 약간 다르다.


  • 다음과 같이 length() 메서드는 문자열의 길이를 나타내지만, size() 메서드는 해당 string 객체가 메모리에서 실제 사용하고 있는 크기를 나타낸다.


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

int main() {
    string str1;
    string str2 = "C++ Programming";

    cout << "문자열 str1의 길이는 " << str1.length() << "입니다." << endl;
    cout << "문자열 str2의 길이는 " << str2.size() << "입니다." << endl;

    return 0;
}

// 문자열 str1의 길이는 0입니다.
// 문자열 str2의 길이는 15입니다.


2) append() 메서드

  • append() 메서드는 하나의 문자열의 끝에 다른 문자열을 추가하는 메서드이다.


  • append() 메서드를 위한 원형은 다음과 같다.


1. 문자열.append(추가할문자열);               // 추가할 문자열을 맨 끝에 추가함
2. 문자열.append(추가할문자열, 시작위치, 개수);  // 추가할 문자열의 시작 위치부터 개수만큼만 맨 끝에 추가함
3. 문자열.append(개수, 추가할문자);           // 추가할 문자를 개수만큼 맨 끝에 추가함
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str1, str2, str3;

    str1.append("C++ Programming");
    str2.append("C++ Programming", 4, 7);
    str3.append(4, 'X');

    cout << str1 << endl;
    cout << str2 << endl;
    cout << str3 << endl;

    return 0;
}

// C++ Programming
// Program
// XXXX


3) find() 메서드

  • find() 메서드는 특정 문자열을 찾아, 그 시작 위치를 반환하는 메서드이다.


  • find() 메서드를 위한 원형은 다음과 같다.


1. 문자열.find(찾을문자열);          // 인덱스 0부터 찾을 문자열을 찾아, 그 시작 위치를 반환함
2. 문자열.find(찾을문자);           // 인덱스 0부터 찾을 문자를 찾아, 그 시작 위치를 반환함
3. 문자열.find(찾을문자열, 시작위치);  // 시작 위치부터 찾을 문자열을 찾아, 그 시작 위치를 반환함


  • find() 메서드는 해당 문자열에서 찾을 문자열을 찾지 못하면, string::size_typestring::npos라는 상수를 반환한다.


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

int main() {
    string str = "C++ Programming";

    cout << str.find("Pro") << endl;
    cout << str.find('r') << endl;

    if (str.find("Pro", 5) != string::npos) {
        cout << "해당 문자열을 찾았습니다." << endl;
    } else {
        cout << "해당 문자열을 찾지 못했습니다." << endl;
    }

    return 0;
}

// 4
// 5
// 해당 문자열을 찾지 못했습니다.


  • 정적 상수인 string::nposstring 클래스에 static const size_type = -1로 명시되어 있다.


4) compare() 메서드

  • compare() 메서드는 두 문자열 간의 내용을 비교하는 메서드이다.


  • compare() 메서드의 반환값이 참(true)이 되는 경우는 다음과 같다.


1. str1.compare(str_02) == 0  // str1과 str2이 같을 경우
2. str1.compare(str_02) < 0   // str1이 str2보다 사전 편찬순으로 앞에 있을 경우
3. str1.compare(str_02) > 0   // str1이 str2보다 사전 편찬순으로 뒤에 있을 경우
#include <iostream>
#include <string>
using namespace std;

int main() {
    string str1 = "ABC";
    string str2 = "ABD";

    if (str1.compare(str2) == 0) {
        cout << str1 << "이 " << str2 << "와 같습니다." << endl;
    } else if (str1.compare(str2) < 0) {
        cout << str1 << "이 " << str2 << "보다 사전 편찬 순으로 앞에 있습니다." << endl;
    } else {
        cout << str1 << "이 " << str2 << "보다 사전 편찬 순으로 뒤에 있습니다." << endl;
    }

    return 0;
}

// ABC이 ABD보다 사전 편찬 순으로 앞에 있습니다.


5) replace() 메서드

  • replace() 메서드는 특정 문자열을 찾아, 그 문자열을 다른 문자열로 대체하는 메서드이다.


  • replace() 메서드를 위한 원형은 다음과 같다.


문자열.replace(대체할문자열의시작위치, 대체할문자열의길이, 새로운문자열);
// 전달된 시작 위치부터 문자열의 길이만큼을 제거한 후에, 새로운 문자열을 삽입함


  • 다음의 코드는 문자열에서 "nice"라는 문자열을 찾아, "awesome"으로 바꾸는 것이다.


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

int main() {
    string str1 = "C++ is very nice!";
    string str2 = "nice";
    string str3 = "awesome";

    string::size_type index = str1.find(str2);
    if (index != string::npos) {
        str1.replace(index, str2.length(), str3);
    }

    cout << str1 << endl;

    return 0;
}

// C++ is very awesome!


  • 위의 코드처럼 replace() 메서드를 사용하기 전에 우선 find() 메서드를 사용하여 해당 문자열이 존재하는지를 파악하는 것이 좋다.


6) capacity()max_size() 메서드

  • capacity() 메서드는 해당 문자열이 재대입(Reallocation) 받지 않고 저장할 수 있는 최대 문자열의 길이를 반환한다.
  • max_size() 메서드는 해당 문자열이 최대한 대입 받으면 가질 수 있는 최대 문자열의 길이를 반환한다.


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

int main() {
    string str = "C++ Programming";

    cout << "문자열 str의 length는 " << str.length() << "입니다." << endl;
    cout << "문자열 str의 capacity는 " << str.capacity() << "입니다." << endl;
    cout << "문자열 str의 max_size는 " << str.max_size() << "입니다." << endl;

    return 0;
}

// 문자열 str의 length는 15입니다.
// 문자열 str의 capacity는 22입니다.
// 문자열 str의 max_size는 18446744073709551599입니다.

References