Skip to main content

8. 배열, 문자열, 그리고 여러 데이터를 다루는 법

배열, 문자열, 그리고 여러 데이터를 다루는 법

하나보다 여러 개가 더 현실적이다

지금까지는 숫자 하나, 문자 하나, 참/거짓 하나처럼 값 하나를 중심으로 배웠다. 하지만 실제 프로그램은 대개 여러 값을 한꺼번에 다룬다. 학생 30명의 점수, 한 줄 문장, 게임 캐릭터 이름 목록, 일주일 매출처럼 말이다. 그래서 이번 장의 핵심은 아주 단순하다. 값을 하나씩 따로 들고 있지 말고, 묶어서 다루는 법을 익히는 것이다.

C++에서 가장 먼저 만나게 되는 묶음 도구는 배열이고, 글자를 다룰 때는 std::string이 사실상 기본 선택지다. 배열은 같은 타입의 값을 여러 개 담는 상자 묶음이고, std::string은 문자열을 안전하고 편하게 다루도록 만든 C++ 표준 라이브러리의 타입이다.12

배열: 같은 종류의 값을 줄 세워 저장하기

배열은 같은 자료형의 값을 고정된 개수만큼 순서대로 저장하는 자료구조다. 원소는 0부터 시작하는 인덱스로 접근한다.1

#include <iostream>
using namespace std;

int main() {
    int scores[5] = {90, 85, 100, 76, 88};

    cout << scores[0] << 'n'; // 90
    cout << scores[3] << 'n'; // 76

    scores[1] = 95;
    cout << scores[1] << 'n'; // 95
}

scores[0]은 첫 번째 원소이고, scores[4]가 마지막 원소다. 원소가 5개라면 쓸 수 있는 인덱스는 0부터 4까지다. 초보자가 가장 자주 하는 실수는 scores[5]처럼 범위를 벗어나는 접근이다. 이런 코드는 겉으로는 멀쩡해 보여도 이상한 결과를 만들 수 있다.

배열의 중요한 특징은 크기가 처음부터 정해진다는 점이다. int scores[5];라고 적었다면, 이 배열은 원소를 5개 담는 구조로 끝이다. 나중에 6개, 10개로 저절로 커지지 않는다. 이 점은 불편해 보이지만, 구조가 단순해서 배우기 좋다. 나중에 더 유연한 vector를 배우면 이 답답함이 왜 생겼는지 자연스럽게 이해하게 된다.

배열을 순회한다는 뜻

배열을 배웠다면 곧바로 익혀야 할 감각이 하나 있다. 바로 순회다. 순회는 처음부터 끝까지 원소를 하나씩 방문하는 것을 말한다. 여러 데이터를 다루는 일의 대부분은 결국 순회다.

#include <iostream>
using namespace std;

int main() {
    const int COUNT = 5;
    int scores[COUNT] = {90, 85, 100, 76, 88};

    int sum = 0;

    for (int i = 0; i < COUNT; i++) {
        sum += scores[i];
    }

    double average = static_cast<double>(sum) / COUNT;

    cout << "총점: " << sum << 'n';
    cout << "평균: " << average << 'n';
}

배열을 순회할 수 있게 되면 할 수 있는 일이 확 늘어난다.

  • 모든 원소의 합 구하기

  • 가장 큰 값이나 가장 작은 값 찾기

  • 원하는 값이 있는지 검사하기

  • 각 원소를 바꾸거나 가공해서 출력하기

즉, 배열은 데이터를 모아 두는 도구이고, 반복문은 그 데이터를 움직이게 하는 엔진이라고 생각하면 된다.

2차원 배열: 표처럼 생각하면 쉽다

배열 안에 배열이 들어가면 2차원 배열이 된다. 말이 어려워 보여도, 사실 표나 좌석 배치표를 떠올리면 쉽다. 행과 열이 있는 구조다.1

#include <iostream>
using namespace std;

int main() {
    int seats[2][3] = {
        {1, 0, 1},
        {0, 1, 1}
    };

    for (int row = 0; row < 2; row++) {
        for (int col = 0; col < 3; col++) {
            cout << seats[row][col] << ' ';
        }
        cout << 'n';
    }
}

seats[0][2]는 0번째 행의 2번째 열을 뜻한다. 격자판 게임, 시간표, 작은 표 형태의 데이터는 이런 방식으로 표현할 수 있다. 처음에는 대괄호가 두 번 나온다는 사실에 익숙해지는 것만으로도 충분하다.

문자열은 문자들의 묶음이지만, 배열과는 다르다

문자 하나는 char로 저장한다. 그렇다면 글자 여러 개, 즉 문자열은 어떻게 저장할까? 여기서 두 길이 갈린다.

하나는 오래된 방식인 C 스타일 문자열이고, 다른 하나는 C++에서 기본처럼 쓰는 std::string이다. C 스타일 문자열은 char 배열을 바탕으로 하며 끝을 나타내는 특수 문자 '0'가 필요하다. 반면 std::string은 길이와 메모리를 스스로 관리해 더 안전하고 다루기 쉽다.23

구분C 스타일 문자열std::string
기본 형태char name[] = "Alice";std::string name = "Alice";
문자열 끝 표시'0' 필요내부적으로 관리
길이 다루기별도 방식 필요.size() 또는 .length() 사용
붙이기/비교함수 사용이 많음+, +=, == 등 사용 가능
보통 추천특별한 이유가 있을 때보통 이쪽이 기본

초보자라면 원칙 하나만 기억해도 충분하다. 특별한 이유가 없다면 문자열은 std::string부터 쓰면 된다.24

왜 std::string이 더 편한가

std::string은 그냥 문자 여러 개가 아니다. 문자열을 다루기 좋게 만들어진 클래스다. 그래서 길이를 쉽게 확인할 수 있고, 문자열끼리 이어 붙일 수 있고, 원하는 부분을 찾아낼 수도 있다.34

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

int main() {
    string first = "C++";
    string second = "학습";
    string title = first + " " + second;

    cout << title << 'n';
    cout << "길이: " << title.size() << 'n';
}

만약 오래된 C 라이브러리나 C 방식 API와 연결해야 한다면 std::string을 C 스타일 문자열 형태로 꺼낼 수도 있다. 그럴 때 쓰는 것이 .c_str()이다.34 다만 지금 단계에서는 필요할 때 연결도 가능하다는 정도만 알고 넘어가면 충분하다.

std::string 기본 조작 익히기

문자열은 통째로 다뤄도 좋지만, 문자 하나씩 살펴보거나 일부만 잘라 쓸 수도 있다.

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

int main() {
    string text = "banana";

    cout << text[0] << 'n';              // b
    text[0] = 'B';
    cout << text << 'n';                 // Banana

    cout << text.substr(0, 3) << 'n';    // Ban

    if (text.find("nan") != string::npos) {
        cout << "\"nan\"을 찾았습니다.n";
    }
}

여기서 자주 쓰는 기능을 짚어 보자.

  • text[index]는 특정 위치의 문자에 접근한다.

  • text.size()는 문자열 길이를 돌려준다.

  • text.substr(시작, 길이)는 부분 문자열을 만든다.

  • text.find(찾을내용)은 처음 발견된 위치를 찾고, 없으면 string::npos를 돌려준다.3

한 가지 더 중요한 점이 있다. operator[]는 편하지만 범위를 검사하지 않는다. 예를 들어 길이가 6인 문자열에서 text[100]에 접근하면 위험하다. 더 안전하게 접근하고 싶다면 text.at(index)를 쓸 수 있다. at()은 잘못된 위치에 접근할 때 예외를 던져 문제를 빨리 드러내 준다.35

공백이 있는 문자열 입력받기

문자열 입력에서도 한 번쯤 꼭 걸리는 함정이 있다. cin >> name;은 공백 전까지만 읽는다. 그래서 Hong Gil Dong을 입력하면 Hong까지만 들어간다. 문장 전체를 읽고 싶다면 getline()을 사용해야 한다.3

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

int main() {
    string sentence;

    cout << "좋아하는 문장을 입력하세요: ";
    getline(cin, sentence);

    cout << "입력한 문장: " << sentence << 'n';
    cout << "문장 길이: " << sentence.size() << 'n';
}

이 차이를 모르면 분명 입력했는데 뒤가 사라지는 일이 생긴다. 프로그램이 말을 안 듣는 게 아니라, 우리가 다른 입력 방식을 쓴 것이다.

문자열도 순회할 수 있다

문자열도 결국 문자의 모임이므로 배열처럼 하나씩 볼 수 있다.3

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

int main() {
    string word = "robot";

    for (int i = 0; i < word.size(); i++) {
        cout << i << "번 위치: " << word[i] << 'n';
    }
}

이 감각은 의외로 중요하다. 나중에 대소문자 바꾸기, 모음 개수 세기, 특정 문자 제거하기 같은 문자열 문제는 거의 모두 문자열 순회로 풀게 된다.

배열과 문자열을 함께 써 보는 작은 예제

이제 여러 문자열을 배열에 넣어 보자. 배열은 같은 타입의 값을 여러 개 저장하므로, std::string 여러 개도 담을 수 있다.

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

int main() {
    const int COUNT = 5;
    string words[COUNT] = {"cat", "banana", "sky", "computer", "book"};

    int longestIndex = 0;
    int totalLength = 0;

    for (int i = 0; i < COUNT; i++) {
        totalLength += words[i].size();

        if (words[i].size() > words[longestIndex].size()) {
            longestIndex = i;
        }
    }

    cout << "가장 긴 단어: " << words[longestIndex] << 'n';
    cout << "전체 글자 수: " << totalLength << 'n';
}

이 짧은 예제 안에 중요한 감각이 꽤 많이 들어 있다. string 배열로 여러 단어를 저장했고, 반복문으로 전체를 순회했고, 각 문자열의 길이를 구했고, 비교를 통해 가장 긴 단어를 찾아냈다. 실전 프로그램은 이런 작은 동작들을 여러 번 조합해서 만들어진다.

자주 하는 실수

처음 배열과 문자열을 배우면 비슷해 보여서 헷갈리기 쉽다. 특히 아래 실수는 정말 자주 나온다.

  • 배열 인덱스를 범위 밖까지 사용하기

  • 배열은 자동으로 크기가 늘어날 거라고 기대하기

  • char 배열과 std::string을 완전히 같은 것으로 생각하기

  • 공백이 있는 문자열에서 cin >>와 getline()의 차이를 놓치기

여기에 한 가지를 더 보태자면, 문자열도 결국 데이터 여러 개의 묶음이라는 사실을 자꾸 잊기 쉽다. 문자열 문제를 어려워하는 이유 중 하나는 문자열을 특별한 마법 상자로 보기 때문이다. 하지만 실제로는 문자 여러 개를 순서대로 저장한 구조다. 이 생각만 잡혀도 문자열이 훨씬 덜 낯설어진다.

이번 장에서 꼭 기억할 것

배열과 문자열은 앞으로 거의 모든 챕터에서 다시 만난다. 지금 단계에서는 아래 네 가지만 단단히 기억하면 충분하다.

  • 배열은 같은 자료형의 값을 여러 개 저장하는 고정 크기 구조다.

  • 배열 원소 접근은 0부터 시작하며, 범위를 벗어나면 위험하다.

  • 문자열은 초보자 기준으로 std::string을 기본으로 쓰는 것이 좋다.

  • 여러 데이터를 다루는 핵심 기술은 결국 반복문을 이용한 순회다.

값 하나를 다루는 법을 배웠다면, 이제부터는 값 여러 개를 자연스럽게 바라보는 눈을 길러야 한다. 그 눈이 생기면 문제를 푸는 방식도 달라진다. 변수 하나 더 만들까가 아니라, 이건 묶어서 저장해야겠네라고 생각하게 된다. 바로 그 순간부터 코드가 조금 더 프로그래머답게 변한다.

참고

1Chapter 6: Arrays and the C++ String Class

2Modern C++ : string vs std::string vs std::array<char, N>

3std::basic_string - cppreference.com

4basic_string 클래스 | Microsoft Learn

5C++ 문자열, 앗 실수! std::basic_string 사용 시 흔한 문제점과 해결책

책 목록

초보자를 위한 C++ 수업: 기초부터 현대 C++까지 한 권으로 끝내기

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기