문자열의 기초
요약
문자열의 기본 개념을 알아봅니다. C언어의 char 배열과 널 문자, Java의 String 비교(== vs equals)와 String Pool, Python의 슬라이싱과 인덱싱 등 정보처리기사 실기에 자주 출제되는 문자열 핵심 개념을 정리합니다.
문자열 핵심 정리
| 개념 | 설명 | 예시 |
|---|---|---|
| 문자열 | 문자(char)들의 배열 | char str[] = "HELLO"; |
널 문자 ('\0') | 문자열의 끝을 표시하는 특수 문자 | str[5] == '\0' |
| 문자열 길이 | 널 문자를 제외한 문자 개수 | "HELLO" → 길이 5 |
문자열이란?
C언어에서 문자열(String) 은 문자(char)들의 배열입니다. 문자열의 끝에는 항상 널 문자 '\0' 가 자동으로 추가됩니다.
위 코드는 다음과 같이 메모리에 저장됩니다.
| 인덱스 | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 값 | 'H' | 'E' | 'L' | 'L' | 'O' | '\0' |

널 문자 ('\0')
널 문자 '\0' 는 문자열의 끝을 표시하는 특수 문자입니다. ASCII 코드 값은 0입니다.
C언어의 문자열 함수들(printf, strlen 등)은 널 문자를 만날 때까지 문자를 처리합니다.
문자열 길이 계산
문자열의 길이를 직접 계산하려면, 널 문자를 만날 때까지 문자를 세면 됩니다.

동작 과정
"REPUBLICOFKOREA"의 경우:
| 인덱스 | 0 | 1 | 2 | ... | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|
| 값 | 'R' | 'E' | 'P' | ... | 'E' | 'A' | '\0' |
a = 0:str[0]='R'(널 문자 아님) →a = 1a = 1:str[1]='E'(널 문자 아님) →a = 2- ... 반복 ...
a = 14:str[14]='A'(널 문자 아님) →a = 15a = 15:str[15]='\0'(널 문자!) → 루프 종료
루프 종료 후 a = 15이므로, str[a - 2] = str[13] = 'E'
문자열 인덱싱
문자열도 배열이므로 인덱스로 개별 문자에 접근할 수 있습니다.
뒤에서부터 접근하기
문자열 길이를 알면 뒤에서부터 문자에 접근할 수 있습니다.
| 접근 방식 | 인덱스 | 문자 |
|---|---|---|
| 마지막 문자 | str[len - 1] | 'O' |
| 뒤에서 두 번째 | str[len - 2] | 'L' |
| 뒤에서 세 번째 | str[len - 3] | 'L' |
문자열 처리 알고리즘
문자열을 다루는 다양한 알고리즘이 시험에 출제됩니다. 포인터를 활용한 문자열 복사와 문자열 뒤집기가 대표적입니다.
String 비교 핵심 정리
| 개념 | 설명 | 예시 |
|---|---|---|
| String 리터럴 | String Pool에 저장, 같은 값이면 같은 객체 공유 | "gamja" |
| new String() | Heap에 새로운 객체 생성, 값이 같아도 다른 객체 | new String("gamja") |
| == 연산자 | 두 변수가 같은 객체를 가리키는지 비교 (주소 비교) | str1 == str2 |
| equals() 메서드 | 두 문자열의 내용(값) 이 같은지 비교 | str1.equals(str2) |
String Pool이란?
Java는 문자열 리터럴(따옴표로 직접 작성한 문자열)을 String Pool 이라는 특별한 메모리 공간에 저장합니다. 같은 값의 리터럴이 여러 번 사용되면, 새로 만들지 않고 기존 객체를 재사용합니다.
str1과 str2는 String Pool의 같은 "gamja" 객체를 가리키므로 str1 == str2는 true입니다.

String 리터럴 vs new String()
String 리터럴
따옴표로 직접 문자열을 작성하면 String Pool에 저장됩니다.
new String()
new 키워드를 사용하면 String Pool과 관계없이 Heap 메모리에 새로운 객체를 생성합니다.
값은 "gamja"로 같지만, str1과 str3는 서로 다른 객체입니다.
메모리 구조

| 변수 | 생성 방식 | 저장 위치 | 주소 |
|---|---|---|---|
str1 | 리터럴 "gamja" | String Pool | 0x100 |
str2 | 리터럴 "gamja" | String Pool (재사용) | 0x100 |
str3 | new String("gamja") | Heap | 0x200 |
== 연산자와 equals() 메서드
이제 문자열이 어떻게 저장되는지 알았으니, 비교 방법을 알아보겠습니다. Java에서 문자열을 비교하는 방법은 두 가지입니다.
위 예시에서는 둘 다 true이므로 차이가 보이지 않습니다. 둘 다 리터럴이기 때문에 String Pool의 같은 객체를 가리키기 때문입니다. 차이는 new String()을 사용할 때 드러납니다.
a는 String Pool에, c는 Heap에 저장되어 서로 다른 객체이므로 ==는 false입니다. 하지만 값은 같으므로 equals()는 true입니다.
| 비교 방식 | 비교 대상 | "gamja" vs "gamja" | "gamja" vs new String("gamja") |
|---|---|---|---|
== | 객체 주소 | true | false |
equals() | 문자열 값 | true | true |
배열과 == 연산자
== 연산자의 주소 비교는 문자열뿐 아니라 배열에도 동일하게 적용됩니다.
배열은 new로 생성하면 항상 Heap에 별도의 객체가 만들어집니다. 내용이 완전히 같아도 ==로 비교하면 false입니다.
배열의 내용을 비교하려면?
배열의 값을 비교하려면 Arrays.equals() 메서드를 사용합니다.
| 비교 대상 | 주소 비교 (==) | 값 비교 |
|---|---|---|
| String | str1 == str2 | str1.equals(str2) |
| 배열 | a == b | Arrays.equals(a, b) |
정리: == vs equals 한눈에 보기
| 구분 | == | equals() |
|---|---|---|
| 비교 대상 | 객체의 주소 (참조) | 객체의 값 (내용) |
| 리터럴끼리 | true (같은 Pool 객체) | true |
| 리터럴 vs new | false (다른 객체) | true |
| new vs new | false (다른 객체) | true |
| 배열끼리 | false (항상 다른 객체) | - (Arrays.equals() 사용) |
문자열 핵심 정리
| 개념 | 설명 | 예시 |
|---|---|---|
| 인덱싱 | 특정 위치의 문자 한 개를 가져옴 | s[0], s[1], s[-1] |
| 슬라이싱 | 부분 문자열을 가져옴 (start부터 end - 1까지) | s[1:4], s[:3], s[4:] |
| split() | 구분자를 기준으로 문자열을 분리해 리스트로 반환 | s.split(' '), s.split('T') |
| f-string | 중괄호 안에 변수를 직접 삽입하는 포맷팅 방식 | f"{변수}" |
| % 포맷팅 | %s, %d 등의 형식 지정자로 값을 삽입 | "%s" % 변수 |
문자열 인덱싱
Python 문자열의 각 문자에는 인덱스(위치 번호) 가 붙어 있습니다. 인덱스는 0부터 시작하며, 음수 인덱스로 뒤에서부터 접근할 수 있습니다.
문자열 슬라이싱
슬라이싱(Slicing) 은 문자열의 일부를 잘라내는 기능입니다. s[시작:끝] 형식을 사용하며, 끝 인덱스는 포함되지 않습니다.
split() 메서드
split(구분자)는 구분자를 기준으로 문자열을 분리해 리스트로 반환합니다.
f-string과 % 포맷팅
f-string
중괄호 {} 안에 변수나 식을 직접 넣어 문자열을 만듭니다.
% 포맷팅
%s(문자열), %d(정수), %f(실수) 형식 지정자를 사용합니다.