소년코딩

05.03 - 문자열, std::string

처음으로 작성한 C++ 프로그램은 다음과 같다.

#include <iostream>

int main()
{
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

"Hello, world!"는 정확히 뭘까? "Hello, world!"는 문자열(string)이라고 불리는 연속적인 문자들의 모음이다. C++ 에서 문자열을 이용해 이름, 주소, 단어, 문장과 같은 텍스트를 출력한다. 문자열 리터럴(Ex. "Hello, world!")은 큰따옴표("") 사이에 배치되어 문자열로 식별된다.

문자열은 프로그램에서 흔히 사용되므로 대부분의 현대 프로그래밍 언어에는 문자열 자료형이 내장되어 있다. C++은 언어의 코어가 아닌 표준 라이브러리의 일부로 문자열(string)이 포함되어 있다.


std::string

C++의 문자열을 사용하려면 먼저 std::string에 대한 선언을 가져오기 위해 <string> 헤더 파일을 #include해야 한다. 이 작업이 완료되면 std::string 타입의 변수를 정의할 수 있다.

#include <string>

std::string myName;

일반 변수와 마찬가지로, 다음과 같이 값을 초기화하거나 문자열 값을 할당할 수 있다.

std::string myName("Alex"); // initialize myName with string literal "Alex"
myName = "John";            // assign variable myName the string literal "John"

문자열에는 숫자도 포함할 수 있다.

std::string myID("45"); // "45" is not the same as integer 45!

문자열 형식에서 숫자는 숫자가 아닌 텍스트로 처리되므로 숫자처럼 조작할 수 없다. (Ex. 곱하기, 더하기 등) C++는 문자열 숫자를 정수 또는 부동 소수 점 값으로 자동 변환하지 않는다.


문자열 입력 및 출력 (String input and output)

std::cout을 사용하여 문자열을 예상대로 출력할 수 있다.

#include <string>
#include <iostream>

int main()
{
    std::string myName("Alex");
    std::cout << "My name is: " << myName;

    return 0;
}

// My name is: Alex

그러나 std:cin과 함께 문자열을 사용하면 놀랄 일이 발생할 수 있다!

#include <string>
#include <iostream>

int main()
{
    std::cout << "Enter your full name: ";
    std::string name;
    std::cin >> name; // this won't work as expected since std::cin breaks on whitespace

    std::cout << "Enter your age: ";
    std::string age;
    std::cin >> age;

    std::cout << "Your name is " << name << " and your age is " << age;
}
Enter your full name: Boy Coding
Enter your age: 27
Your name is Boy and your age is Coding

무슨 일일까? 연산자 >>를 사용하여 cin에서 문자열을 추출할 때, >>는 첫 번째 공백까지만 반환한다. 다른 모든 문자는 cin 내부에 남겨져 다음 추출을 기달린다.

따라서 연산자 >>를 사용하여 문자열을 변수 name으로 추출할 때 "Boy"만 추출되어 std::cin 내에 "Coding"가 남겨져 다음 추출을 기다린다. >> 연산자를 다시 사용하여 변수 age에 문자열을 추출하면 "27" 대신 "Coding"가 나타난다. 세 번째 추출을 수했한다면 "27"을 얻게 될 것이다.


std::getline()을 사용한 텍스트 입력 (Use std::getline() to input text)

문자열 전체를 읽으려면 std::getline() 함수를 사용하는 것이 좋다. std::getline()은 두 개의 매개 변수가 있다. 첫 번째 매개 변수는 std::cin이고, 두 번째 매개 변수는 std::string 변수다.

#include <string>
#include <iostream>

int main()
{
    std::cout << "Enter your full name: ";
    std::string name;
    std::getline(std::cin, name); // read a full line of text into name

    std::cout << "Enter your age: ";
    std::string age;
    std::getline(std::cin, age); // read a full line of text into age

    std::cout << "Your name is " << name << " and your age is " << age;
}
Enter your full name: Boy Coding
Enter your age: 27
Your name is Boy Coding and your age is 27

Mixing std::cin and std::getline()

std::cin과 std::getline을 모두 사용하여 입력을 받으면 예기치 않은 동작이 발생할 수 있다.

#include <string>
#include <iostream>

int main()
{
    std::cout << "Pick 1 or 2: ";
    int choice { 0 };
    std::cin >> choice;

    std::cout << "Now enter your name: ";
    std::string name;
    std::getline(std::cin, name);

    std::cout << "Hello, " << name << ", you picked " << choice << '\n';

    return 0;
}

// pick 1 or 2: 2
// Now enter your name: Hello, , you picked 2

위 프로그램은 먼저 1이나 2를 입력하도록 요청하고 입력할 때까지 기다린다. 그러면 입력을 하고 난 뒤 이름을 입력해야 한다. 하지만 실제로는 이름을 입력할 때까지 기다리지 않는다! 대신 "Hello" 라인을 출력한 다음 종료한다. 무슨 일일까?

cin을 사용하여 숫자 값을 입력하면 cin은 숫자 값만 캡처할 뿐만 아니라 "\n"도 캡처한다. 그럼 cin은 실제로 "2\n" 문자열을 얻는다. 그런 다음 숫자 값 2를 추출해서 choice 변수에 할당한다. 그러면 getline() 함수가 이름을 읽으러 갈 때 스트림에 "\n"이 남아있는 걸 보고 빈 문자열을 입력받았다고 생각하여 name 변수에 빈 문자열을 할당한다. 의도했던 결과가 아니다!

std:cin으로 숫자 값을 읽은 후 스트림에서 "\n"을 제거하는 것이 좋다.

std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed

choice 변수를 읽은 직후에 위 코드를 삽입하면, 관련 없는 개행이 스트림에서 제거되고 프로그램이 예상대로 작동한다!

int main()
{
    std::cout << "Pick 1 or 2: ";
    int choice { 0 };
    std::cin >> choice;

    std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed

    std::cout << "Now enter your name: ";
    std::string name;
    std::getline(std::cin, name);

    std::cout << "Hello, " << name << ", you picked " << choice << '\n';

    return 0;
}
// pick 1 or 2: 2
// Now enter your name: Boy Coding
// Hello, Boycoding, you picked 2

std:cin이 포함된 숫자 값을 읽는 경우, std:cin.ignore()를 사용하여 관련 없는 새 라인을 제거하는 것이 좋다.

매직 넘버 32767은 무엇을 의미할까?

32767은 cin::ignore() 함수가 무시할 문자 수다. 이 숫자는 모든 플랫폼에서 2-byte 정수의 가장 큰 값이다.

기술적으로 무제한 입력을 무시하는 올바른 방법은 다음과 같다.

#include <limits>

// ...

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore unlimited characters until a \n is removed

그러나 위 코드는 길뿐만 아니라 헤더 파일까지 포함해야 한다. 대부분은 버퍼링 된 입력을 두 줄 이상 무시할 필요가 없으므로 32767을 사용하는 게 실용적이다.


문자열 추가 (Appending strings)

연산자 +을 사용해서 두 문자열을 연결하거나 연산자 +=를 사용해서 한 문자열을 다른 문자열에 추가할 수 있다.

#include <string>
#include <iostream>

int main()
{
    std::string a("45");
    std::string b("11");

    std::cout << a + b << "\n"; // a and b will be appended, not added
    a += " volts";
    std::cout << a;

    return 0;
}

// 4511
// 45 volts

연산자 +는 문자열 "45"와 "11"을 "4511"로 연결한다. 숫자처럼 더하지 않는다.


문자열 길이 (String length)

문자열의 길이를 알고 싶으면 length() 멤버 함수를 통해 문자열의 길이를 요청할 수 있다.

#include <string>
#include <iostream>
int main()

{
    std::string myName("Alex");
    std::cout << myName << " has " << myName.length() << " characters\n";
    return 0;
}

// Alex has 4 characters

문자열 길이를 알려면 length(myName) 대신 myName.length()를 사용한다.

length() 함수는 지금까지 사용한 것처럼 일반적인 함수가 아니며, 멤버 함수라는 std::string에 속하는 특별한 유형의 함수다. 나중에 멤버 함수에 대해 자세히 설명할 예정이다.


cpp 번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/4-4b-an-introduction-to-stdstring/ 입니다.

댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기