C에서 char a[] = "cat";는 세 글자 뒤에 null 문자를 포함하는 네 칸 배열을 만듭니다. 반면 char b[3] = "cat";는 세 글자만 담는 세 칸 배열이며 null 종료 문자가 들어가지 않습니다.

sizeof(a)와 sizeof(b)는 배열이 보이는 이 선언 지점에서 각각 4와 3을 나타냅니다. strlen은 null 종료된 문자열을 전제로 하므로 b를 C 문자열이라고 가정해 결과를 예측하거나 안전하게 사용할 수 없습니다.

문자 수와 null 종료에 필요한 저장 공간을 구분합니다

화면에 보이는 cat은 문자 세 개입니다. 하지만 C 문자열은 글자만 나열한 배열이 아니라 끝을 알리는 null 문자 \0까지 포함한 연속된 문자 시퀀스입니다. 따라서 세 글자를 C 문자열로 저장하려면 일반적인 문자 배열 표현에서 네 칸이 필요합니다. \0은 문자열의 마지막을 표시하지만 strlen이 세는 길이에는 포함되지 않습니다. C11 N1570 §6.4.5p6은 문자열 리터럴의 문자 시퀀스 끝에 값 0인 byte를 붙여 배열을 초기화한다고 규정합니다. 같은 문서의 §6.7.9 Example 8은 char s[] = "abc"를 네 칸, char t[3] = "abc"를 세 칸으로 보여 줍니다. 두 배열의 크기를 각각 문자열 길이에 맞출 수 있지만, 뒤의 고정 크기 배열에는 null 종료 문자가 들어갈 자리가 없습니다.

선언의 배열 경계가 null 문자를 담을 수 있는지 결정합니다
선언배열 칸내용C 문자열 여부
char a[] = "cat";4'c', 'a', 't', '\0'null 종료됨
char b[3] = "cat";3'c', 'a', 't'null 종료되지 않음
칸 배치와 안전한 크기 확인을 보여 주는 선언 예입니다. null 종료가 없는 b에 strlen을 호출하지 않습니다.
#include <stdio.h>
#include <string.h>

int main(void) {
    char a[] = "cat";
    char b[3] = "cat";

    printf("sizeof(a)=%zu strlen(a)=%zu\n", sizeof a, strlen(a));
    printf("sizeof(b)=%zu\n", sizeof b);
    /* b is not null-terminated; do not pass it to strlen. */
    return 0;
}

sizeof는 선언된 배열 칸을 보고 strlen은 종료 문자를 찾습니다

a는 크기를 생략했으므로 초기화 항목을 담을 만큼 배열 경계가 정해집니다. cat의 문자 세 개와 문자열 리터럴의 마지막 null byte가 들어가 총 네 칸입니다. 선언 지점에서 sizeof a는 배열 전체 크기인 4를 나타내고 strlen(a)는 null 앞의 문자 수인 3을 셉니다. b는 선언에서 배열 경계를 3으로 고정했습니다. 초기화 뒤 세 칸은 c, a, t이고 종료 문자가 배열에 포함되지 않습니다. sizeof b는 여전히 선언된 배열 전체의 크기 3을 알려 줍니다. 하지만 strlen(b)를 호출하면 함수가 배열 경계를 모른 채 null 문자를 찾게 됩니다. b의 저장 범위 안에서 끝 문자가 없으므로 그 호출의 문자열 전제는 충족되지 않습니다. 이 글은 해당 호출의 결과를 실행하거나 예측하지 않습니다.

배열 크기와 문자열 함수의 전제를 순서대로 확인합니다

  1. 문자열 리터럴의 보이는 문자를 세고, 끝에 추가되는 \0을 별도로 표시합니다.
  2. 배열 선언이 크기를 생략했는지, 숫자로 고정했는지 확인합니다.
  3. 초기화 문자와 종료 문자가 모두 선언된 칸 안에 들어가는지 그립니다.
  4. sizeof를 배열이 실제로 보이는 선언 지점에서 사용하는지 확인합니다.
  5. strlen이나 %s처럼 C 문자열을 요구하는 연산은 null 종료된 배열에만 적용합니다.

풀이할 때 메모리에 칸을 직접 그리는 방법이 가장 단순합니다. a는 네 칸을 만들어 [c][a][t][\0]으로 적고, b는 [c][a][t] 세 칸에서 멈춥니다. 여기서 sizeof의 숫자와 문자열 길이의 숫자는 다르게 나옵니다. 네 칸인 a의 문자열 길이는 3이고, b의 배열 저장 공간은 3이지만 그것만으로 올바른 C 문자열이 되지는 않습니다. 각 연산이 묻는 값의 종류를 먼저 적으세요.

세 칸 배열이 항상 초기화 오류라고 단정하지 않습니다

흔한 오해는 char b[3] = "cat";가 무조건 선언 오류이므로 컴파일 결과가 없다고 보는 것입니다. N1570 예제는 이 배열 선언을 보여 주며, 세 문자만 담는 배열로 구별합니다. 선언이 허용되는지와 그 배열이 null 종료 C 문자열인지 여부는 다른 질문입니다. 세 칸이 실제로 존재해도 종료 문자를 담지 않았다면 문자열을 요구하는 함수의 입력이 될 수 없습니다. 또 sizeof와 strlen을 서로 대체할 수 있다고 생각하기 쉽습니다. sizeof는 해당 식에서 배열이면 배열의 전체 크기를 바이트 단위로 계산하지만, 함수 매개변수로 전달된 배열은 포인터로 조정되는 등 적용 문맥이 달라질 수 있습니다. strlen은 null 종료된 문자열의 종료 지점까지 세므로, 종료 문자가 없는 배열에는 안전한 길이 측정법이 아닙니다. 길이를 별도 정수로 전달하거나 넉넉한 배열을 만들고 경계를 지키는 방법을 선택하세요.

정답을 가리고 확인해 보세요

이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.

char word[4] = "cat";의 배열 칸과 sizeof word, strlen(word)의 값을 설명하세요. char word[3]이면 무엇이 달라지나요?

정답과 해설 확인네 칸 배열에는 c, a, t, \0이 들어가며 sizeof는 4, strlen은 3입니다. 세 칸 배열은 c, a, t만 담아 null 종료되지 않으므로 C 문자열로 쓰거나 strlen 결과를 안전하게 예측할 수 없습니다.

N1570 §6.4.5p6은 문자열 리터럴 뒤의 null byte를 설명하고 §6.7.9 Example 8은 크기 생략 배열과 3칸 배열을 직접 비교합니다. 문자열은 null 종료를 요구합니다.