본문으로 건너뛰기

배열과 문자열

배열(Array)

  • 동일 타입의 데이터를 연속된 메모리 공간에 저장하는 자료구조
  • 배열 이름이 배열 첫 번째 요소의 포인터처럼 동작
int arr[5]; // 크기가 5인 int형 배열 선언
int arr[3] = {1, 2, 3}; // 선언 + 초기화

메모리 구조

  • 배열은 요소들이 메모리상에 연속된 순서로 배치된다.
  • arr[index]의 주소는 arr[0] + (요소 크기 * index) 방식으로 접근
int numbers[5] = {10, 20, 30, 40, 50};
printf("%d", numbers[2]); // 30

배열과 포인터

배열 이름은 포인터처럼 동작한다.

int arr[5] = {10, 20, 30, 40, 50};
printf("%d\n", *arr); // arr[0] = 10
printf("%d\n", *(arr + 2)); // arr[2] = 30
  • 배열 이름은 상수 포인터처럼 행동하지만, 배열 자체는 포인터가 아니다.
  • 배열은 복사가 안되지만, 포인터는 값(주소)를 복사할 수 있음.

고정 크기

  • 배열은 선언할 때 크기(size)가 고정된다.
  • 한 번 정해진 크기는 변경할 수 없다.
int arr[5]; // 크기는 5로 고정
arr[5] = 10; // error: 유효 인덱스는 0~4
  • 배열 크기는 명시적으로 지정할 수 있고 초기화 값이 있다면 생략 가능
  • C99 이전에는 컴파일 타임에서만 크기를 지정해야 했지만, C99 부터는 런타임에서도 지정 가능
  • 그러나 컴파일러 지원 여부, 메모리 문제 등 현대 C에서는 비추천

다차원 배열

메모리 상에서는 1차원적으로 쭉 이어진다.

int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

printf("%d", matrix[1][2]); // 6

문자열(String)

문자열은 char 배열이고, 끝에 널 문자('\0')를 포함한다.

char str1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str2[] = "Hello"; // 자동으로 널문자(\0) 추가

메모리 구조

  • 문자열은 char들이 연속된 메모리에 저장되고, 마지막은 '\0'으로 끝남
  • 배열과 마찬가지로 이름은 포인터처럼 동작한다.
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("%c\n", str[1]); // e
printf("%d\n", *(str + 2)); // l

널 문자('\0')

C에서 문자열은 반드시 끝에 널 문자를 넣어서 문자열의 끝을 표시해야 한다.

널 문자의 값은 0이다. ('\0' == 0)

  • C에서는 문자열 길이 정보를 따로 저장하지 않는다.
  • 문자 요소를 순차적으로 읽다가 '\0'을 만나면 문자열의 끝이라고 인식함
  • 문자열 리터럴("Hello")은 자동으로 끝에 널 문자가 추가됨
char *p = "Hello"; // {'H', 'e', 'l', 'l', 'o', '\0'}
char str[] = {'W', 'o', 'r', 'l', 'd', '\0'};
  • 널 문자가 없으면 문자열 함수들이 '\0'을 찾을 때까지 메모리를 계속 읽어 메모리 오버런(Overrun) 을 일으킨다.