C언어 배열과 문자열, 실기 예제 정리
배열은 같은 자료형의 데이터를 한 묶음으로 관리하는 가장 기본적인 자료구조이며, 문자열은 그 배열 위에서 만들어지는 가장 자주 쓰이는 응용 형태이다. C언어는 별도의 문자열 자료형을 제공하지 않고 char 배열을 문자열로 사용하기 때문에, 배열과 문자열은 사실상 같은 메커니즘을 다른 관점에서 다루는 두 얼굴이라고 할 수 있다. 두 개념을 정확히 이해해야 메모리 동작·포인터 연산·표준 라이브러리 함수가 모두 자연스럽게 연결된다. 정보처리기사 실기에서도 배열의 초기화 결과와 문자열 함수의 동작을 묻는 문제가 매회 출제되므로, 본 글은 코드 예시와 함께 핵심 개념을 한 번에 정리한다.

배열의 선언, 초기화, 그리고 다차원 배열
배열(Array)이란 같은 자료형의 변수 여러 개를 메모리상에 연속적으로 배치하고 하나의 이름으로 묶어 관리하는 자료구조이다. C언어에서 배열을 선언할 때는 "자료형 배열명[크기];" 형식을 사용하며, 크기는 컴파일 시점에 결정되어야 한다. 배열의 인덱스는 0부터 시작해 크기-1까지의 범위를 가지며, 이 범위를 벗어난 인덱스에 접근하면 정의되지 않은 동작(Undefined Behavior)이 발생해 프로그램이 비정상적으로 종료될 수 있다.
배열은 선언과 동시에 초기화할 수 있으며, 초기화 방법에 따라 미세한 차이가 발생한다. 시험에서 자주 묻는 패턴이므로 정확히 외워두어야 한다.
int a[5] = {1, 2, 3, 4, 5}; // 모든 원소 명시
int b[5] = {1, 2}; // 나머지는 0으로 초기화 → {1, 2, 0, 0, 0}
int c[5] = {0}; // 모든 원소 0으로 초기화
int d[] = {1, 2, 3}; // 크기 자동 결정 → 크기 3
int e[5]; // 초기화 X → 쓰레기 값
핵심 포인트는 두 가지이다. 첫째, 일부만 초기화하면 나머지는 자동으로 0이 채워진다. 둘째, 크기를 비워두면 컴파일러가 초기화 값의 개수만큼 자동으로 크기를 결정한다. 다만 e처럼 초기화하지 않은 지역 배열은 쓰레기 값을 가지므로 반드시 사용 전에 초기화해야 한다.
다차원 배열은 배열의 배열로, 행렬이나 격자 형태의 데이터를 다룰 때 사용된다. 가장 흔한 형태가 2차원 배열이며 "자료형 배열명[행][열];" 형식으로 선언한다.
int mat[2][3] = { {1, 2, 3}, {4, 5, 6} };
printf("%d\n", mat[0][1]); // 2
printf("%d\n", mat[1][2]); // 6
// 첫 번째 차원 크기는 생략 가능, 두 번째는 필수
int mat2[][3] = { {1, 2, 3}, {4, 5, 6} }; // 자동으로 [2][3]
2차원 배열은 메모리상 행 우선(Row-major) 방식으로 저장된다. 즉 mat[0][0], mat[0][1], mat[0][2], mat[1][0], mat[1][1], mat[1][2] 순서로 연속 배치되며, 이 특성 때문에 같은 행 안에서의 순회가 다른 행으로 점프하는 것보다 캐시 적중률 측면에서 훨씬 효율적이다. 시험에서는 mat[i][j]의 값을 추적하거나 1차원으로 펼쳤을 때의 인덱스를 묻는 형태로 출제된다.
문자열 처리 — char 배열과 표준 함수
C언어에서 문자열은 별도의 자료형이 아니라 마지막에 NULL 문자(\0)가 붙은 char 배열이다. NULL 문자는 ASCII 코드 0이며, 문자열의 끝을 표시하는 종료 신호로 작동한다. 따라서 "HELLO"라는 5글자 문자열은 실제로는 6바이트(H, E, L, L, O, \0)를 차지한다는 사실을 정확히 이해해야 한다.
char s1[] = "HELLO"; // 6바이트 (NULL 포함)
char s2[10] = "HELLO"; // 10바이트 (나머지는 \0)
char s3[] = {'H','E','L','L','O','\0'}; // s1과 동일
char *s4 = "HELLO"; // 문자열 리터럴 포인터 (읽기 전용)
s1과 s4는 비슷해 보이지만 결정적인 차이가 있다. s1은 스택에 할당되는 수정 가능한 char 배열이고, s4는 데이터 영역의 읽기 전용 문자열 리터럴을 가리키는 포인터이다. s4[0] = 'h'처럼 수정하려고 하면 런타임 오류가 발생하므로 주의해야 한다.
C 표준 라이브러리는 string.h 헤더에 다양한 문자열 함수를 제공한다. 시험에 자주 출제되는 핵심 함수는 네 가지이다. strlen은 문자열의 길이를 반환하되 NULL 문자는 제외한다. strcpy는 문자열을 복사하고, strcmp는 두 문자열을 비교해 같으면 0, 다르면 음수 또는 양수를 반환한다. strcat은 한 문자열 끝에 다른 문자열을 이어 붙인다.
#include <string.h>
char dest[20] = "Hello, ";
char src[] = "World!";
printf("%lu\n", strlen(src)); // 6 (NULL 제외)
strcat(dest, src); // dest = "Hello, World!"
printf("%s\n", dest); // Hello, World!
char copy[20];
strcpy(copy, dest); // copy = "Hello, World!"
printf("%d\n", strcmp("ABC", "ABD")); // 음수 (B < D 한 글자 차이)
printf("%d\n", strcmp("ABC", "ABC")); // 0 (동일)
strcpy와 strcat은 대상 배열의 크기가 충분한지 사용자가 직접 확인해야 한다. 크기를 초과해 쓰면 인접 메모리를 침범하는 버퍼 오버플로(Buffer Overflow)가 발생하며, 이는 가장 빈번한 보안 취약점 중 하나이다. 안전한 대안으로 strncpy, strncat, strncmp 같은 n자 제한 버전이 제공되며, 현대 코드에서는 이러한 안전 버전이 권장된다.
정보처리기사 실기 빈출 배열·문자열 예제
정보처리기사 실기에서 배열과 문자열은 단골 출제 영역이다. 출제 패턴은 크게 네 가지로 정리되며, 각 패턴별로 코드와 출력 결과를 손으로 추적해보는 연습이 가장 효과적인 시험 대비법이다.
유형 1: 배열 초기화 결과 추적.
int a[5] = {1, 2};
for (int i = 0; i < 5; i++) {
printf("%d ", a[i]);
}
// 출력: 1 2 0 0 0
부분 초기화 시 나머지가 0으로 채워진다는 규칙을 정확히 적용해야 한다.
유형 2: 2차원 배열의 인덱스 접근.
int m[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int sum = 0;
for (int i = 0; i < 3; i++) {
sum += m[i][i]; // 대각선 원소 합
}
printf("%d\n", sum); // 1 + 5 + 9 = 15
대각선·역대각선·특정 행/열 합산 형태로 자주 변형되어 출제된다.
유형 3: 문자열 길이와 NULL 문자 처리.
char s[] = "PROGRAM";
int len = 0;
while (s[len] != '\0') {
len++;
}
printf("%d\n", len); // 7
// strlen 함수와 동일한 결과
printf("%lu\n", strlen(s)); // 7
while 루프로 NULL 문자를 만날 때까지 카운트하는 패턴이 strlen의 내부 동작 원리이며, 시험에서는 이를 직접 구현해 결과를 묻는 형태로 출제된다.
유형 4: 문자열 역순 출력 또는 변환.
char s[] = "HELLO";
int len = strlen(s);
for (int i = len - 1; i >= 0; i--) {
printf("%c", s[i]);
}
// 출력: OLLEH
문자열을 역순으로 순회하거나, 특정 문자를 다른 문자로 치환하거나, 대소문자를 바꾸는 패턴이 자주 출제된다. 대소문자 변환은 ASCII 코드의 차이(소문자 - 대문자 = 32)를 이용해 구현된다.
유형 5: 배열을 함수에 전달.
void modify(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2; // 원본 배열 수정됨
}
}
int main() {
int data[3] = {1, 2, 3};
modify(data, 3);
for (int i = 0; i < 3; i++) {
printf("%d ", data[i]);
}
// 출력: 2 4 6
return 0;
}
이 마지막 패턴이 가장 중요하다. 배열을 함수에 전달하면 배열 이름이 첫 원소의 주소로 변환되어 전달되기 때문에, 함수 내부에서의 수정이 호출자의 원본에 그대로 반영된다는 사실을 묻는다. 이는 #28 함수 글에서 다룬 Call by Reference의 자연스러운 결과이며, 의도하지 않은 부작용을 막고 싶다면 매개변수에 const 키워드를 붙여 함수 내부에서 수정하지 못하도록 강제할 수 있다. 결국 배열과 문자열은 단순히 데이터를 담는 그릇이 아니라, 메모리·포인터·함수의 모든 개념이 만나는 가장 본질적인 영역이며, 이 영역을 정확히 이해할 때 비로소 자료구조와 알고리즘의 학습이 자유로워진다.
메타 디스크립션: C언어 배열의 선언과 초기화, 다차원 배열의 메모리 구조, 문자열의 NULL 종료 표현과 string.h 표준 함수(strlen·strcpy·strcmp·strcat), 그리고 정보처리기사 실기 빈출 5패턴을 코드 예시와 함께 정리합니다.