[C언어] 08. 문자열 (String)
다른 언어에는 문자열 타입이 따로 있지만, C에는 없다. C에서 문자열은 문자(char)들의 배열이다. 이 단순한 사실에서 C 문자열의 모든 특징과 주의점이 나온다는 걸 오늘 정리하며 알았다.
1. 문자열과 NULL 문자
문자열은 문자들이 죽 늘어선 것이고, 문자 배열(char[])에 저장한다. 그런데 배열만으로는 "어디까지가 문자열인지" 알 수 없다. 그래서 C는 문자열의 끝에 특별한 표식을 둔다.
모든 C 문자열은 끝에 NULL 문자('\0')가 붙는다. printf나 strlen 같은 함수는 이 '\0'을 만날 때까지를 하나의 문자열로 인식한다. 즉 "abc"는 사실 a, b, c, '\0' 네 글자가 저장된 것이다.

char str[4] = {'a', 'b', 'c', '\0'}; // 직접 NULL 지정
char str[4] = "abc"; // "abc"는 자동으로 끝에 '\0' 추가 → 4칸 필요
char str[] = "abc"; // 크기 자동 결정 (4)
char str[4] = "abcdef"; // 공간 부족 → 오류
여기서 "abc"를 담으려면 배열 크기가 3이 아니라 4여야 한다는 점이 핵심이다. '\0' 자리를 깜빡하면 문자열 처리 함수가 배열 밖으로 폭주하는 사고가 난다. 처음엔 3칸으로 잡았다가 출력이 이상하게 나와서, '\0' 자리를 빠뜨렸다는 걸 알았다.
출력은 형식 지정자 %s로 한다.
char str[] = "Seoul";
printf("%s\n", str); // Seoul
2. 문자·문자열 입출력 함수
| 함수 | 설명 |
|---|---|
| getchar / putchar | 문자 하나 입력 / 출력 |
| scanf("%c") / printf("%c") | 문자 하나 입출력 |
| scanf("%s") / printf("%s") | 문자열 입출력 |
| gets_s / puts | 한 줄(공백 포함) 입력 / 출력 |
scanf의 %s는 공백·탭·줄바꿈을 만나면 거기서 입력을 멈춘다. 그래서 "Hello World"를 입력해도 "Hello"만 저장된다. 공백이 포함된 한 줄 전체를 받으려면 gets_s 같은 함수를 써야 한다.
"Hello World"를 넣었는데 "Hello"만 저장돼서 한참 갸웃했는데, %s가 공백에서 끊긴다는 걸 알고 나서야 원인을 찾았다.
3. 문자 검사·문자열 처리 함수
문자 하나의 종류를 검사하는 함수들은 ctype.h에 있다.
| 함수 | 검사 내용 |
|---|---|
| isalpha(c) | 영문자인가 |
| isupper / islower | 대문자 / 소문자인가 |
| isdigit(c) | 숫자(0-9)인가 |
| isalnum(c) | 영문자 또는 숫자인가 |
| isspace(c) | 공백류(' ', \n, \t 등)인가 |
문자열을 다루는 함수들은 string.h에 있다.
| 함수 | 설명 |
|---|---|
| strlen(s) | 문자열 길이 ('\0' 제외) |
| strcpy(s1, s2) | s2를 s1에 복사 |
| strcat(s1, s2) | s1 뒤에 s2를 이어 붙임 |
| strcmp(s1, s2) | 두 문자열 비교 |
| strchr / strstr | 문자 / 부분 문자열 찾기 |
배열은 =나 ==로 복사·비교할 수 없는데, 문자열도 마찬가지다. 그래서 복사는 strcpy, 비교는 strcmp를 써야 한다. if (s1 == s2)는 내용이 아니라 주소를 비교하는 흔한 실수다. 문자열이 결국 배열이라는 사실에서 이 제약이 그대로 따라온다는 게 보였다.
숫자와 문자열 변환: sprintf / sscanf

char str[20] = "36.5";
float v;
sscanf(str, "%f", &v); // 문자열 "36.5" → 숫자 36.5
sprintf(str, "값: %f", v); // 숫자 → 문자열로 서식 저장
printf가 화면에 출력한다면, sprintf는 그 결과를 문자열 변수에 담는다. 숫자를 문자열로 만들거나 그 반대를 할 때 요긴하다.
4. 문자열 배열
여러 개의 문자열을 담으려면 2차원 char 배열을 쓴다.

char s[3][6] = {
"init",
"open",
"close"
};
각 행이 하나의 문자열이고, 행마다 끝에 '\0'이 들어간다. s[0]은 "init", s[1]은 "open"처럼 행 인덱스로 각 문자열에 접근한다.
5. 수업 코드로 보는 암호 유효성 검사
check_password_prg.c는 문자열을 한 글자씩 검사해서 암호 조건을 확인하는 예제였다. 조건은 소문자, 대문자, 숫자가 각각 하나 이상 있는지 확인하는 것이다.
#include <ctype.h>
#include <string.h>
char sPassword[20];
int iIndex;
int iLength;
int iLowerCheck;
int iUpperCheck;
int iDigitCheck;
int iPasswordCheck;
printf("암호 입력: ");
scanf("%19s", sPassword);
iLength = strlen(sPassword);
iLowerCheck = 0;
iUpperCheck = 0;
iDigitCheck = 0;
iPasswordCheck = 0;
for (iIndex = 0; iIndex < iLength; iIndex++)
{
if (islower(sPassword[iIndex]) != 0)
{
iLowerCheck = 1;
}
if (isupper(sPassword[iIndex]) != 0)
{
iUpperCheck = 1;
}
if (isdigit(sPassword[iIndex]) != 0)
{
iDigitCheck = 1;
}
}
if (iLength >= 7 && iLowerCheck == 1 && iUpperCheck == 1 && iDigitCheck == 1)
{
iPasswordCheck = 1;
}
printf("암호 검사 결과: %d\n", iPasswordCheck);
| 입력 | 길이 | 소문자 | 대문자 | 숫자 | 결과 |
|---|---|---|---|---|---|
abc1234 |
7 | O | X | O | 실패 |
ABC1234 |
7 | X | O | O | 실패 |
Abcdef1 |
7 | O | O | O | 성공 |
Ab1 |
3 | O | O | O | 실패 |
수업 코드에서는 조건별로 반복을 나누어 검사했지만, 한 번의 반복 안에서 세 조건을 함께 확인해도 된다. 중요한 건 sizeof(sPassword)가 아니라 strlen(sPassword)로 실제 입력된 문자열 길이를 기준으로 검사하는 것이다.
오늘 느낀 점
- "C에 문자열 타입은 없고 문자 배열일 뿐"이라는 한 문장이 모든 걸 설명했다. '\0', 크기 +1, strcpy·strcmp 필요까지 전부 여기서 따라 나왔다.
- 3칸 실수,
%s공백 끊김처럼 직접 겪은 함정이 글로 읽은 것보다 훨씬 또렷하게 남았다. - 배열에서 본 "이름은 주소", "통째 비교 불가"가 문자열에 그대로 재현되는 걸 보며, 개념이 따로가 아니라 이어진다는 걸 느꼈다.
한 걸음 더
strlen과sizeof는 다르다.char s[10] = "abc"에서strlen(s)는 '\0' 전까지의 길이 3을 반환하지만,sizeof(s)는 배열 전체 크기 10을 반환한다. 하나는 "내용의 길이", 하나는 "그릇의 크기"라는 점을 구분해야 한다.- C 문자열의 많은 보안 취약점이 '\0'과 배열 크기에서 비롯된다.
strcpy는 대상 배열 크기를 검사하지 않아, 큰 문자열을 작은 배열에 복사하면 넘쳐서 인접 메모리를 덮어쓴다(버퍼 오버플로). 그래서 크기를 함께 받는strncpy,strcpy_s같은 안전한 버전을 쓰는 게 권장된다. - 한글 같은 멀티바이트 문자는 한 글자가 여러 바이트라,
strlen이 글자 수가 아니라 바이트 수를 센다. C의 문자열 함수는 기본적으로 1바이트=1문자를 전제하므로, 한글 처리에는 별도의 인코딩(UTF-8 등) 고려가 필요하다.
'language > c' 카테고리의 다른 글
| [C언어] 07. 배열 (Array) (0) | 2026.08.17 |
|---|---|
| [C언어] 06. 함수 (Function) (0) | 2026.08.10 |
| [C언어] 05. 반복문 (0) | 2026.08.03 |
| [C언어] 04. 조건문 (0) | 2026.07.27 |
| [C언어] 03. 수식과 연산자 (0) | 2026.07.20 |