C에서는 집합(aggregate) 변수를 제공하는데, 이름대로 여러 개의 값을 저장할 수 있다.
배열은 동일한 데이터 형식(데이터 타입)의 여러 요소를 하나의 변수 이름 아래 연속적으로 저장할 수 있게 해주는 자료 구조입니다. 각 요소는 인덱스(위치)를 사용하여 접근할 수 있습니다.
C에는 배열과 구조체 두 가지 집합이 있습니다. 이 포스팅에서는 배열을 선언하고 사용하는 방법에 대해서 정리하고 다루려고 합니다.
고정된 크기: 배열은 생성할 때 크기가 고정되며, 크기를 동적으로 변경할 수 없습니다. 배열의 크기는 요소의 수로 결정됩니다.
동일한 데이터 타입: 배열은 동일한 데이터 타입의 요소만을 저장할 수 있습니다. 예를 들어, 정수 배열은 정수 값만을 저장할 수 있습니다.
연속적인 메모리 공간: 배열의 요소들은 메모리 상에서 연속적으로 저장됩니다. 이로 인해 배열의 요소에 빠르게 접근할 수 있습니다.
인덱스 기반 접근: 각 요소는 0부터 시작하는 인덱스를 사용하여 접근할 수 있습니다. 예를 들어, 첫 번째 요소는 인덱스 0에 저장되고, 두 번째 요소는 인덱스 1에 저장됩니다.
이번 포스팅에서는 8월 19일에 실습한 배열 중에서 1차원 배열에 대해서 정리하려고 합니다.
우선 배열(array)란 특정 개수의 같은 형을 갖는 자료값을 가는 자료구조
입니다.
이러한 값들을 원소(element)라고 부르며, 배열 내의 위치에 따라 각 원소를 선택할 수 있습니다.
가장 간단한 형태의 배열은 일차원의 형태입니다. 개념적으로 일차원 배열의 원소들은 한 행(혹은 한 열에)
순서대로 나열되어있는 구조로 되어있습니다.
같은 자료형을 가진 연속된 메모리 공간으로 이루어진 자료구조입니다.
(여러 개의 저장 공간이 한 줄로 나열되어 있는 구조)
이러한 배열은 같은 자료형을 가진 변수들이 여러 개 필요할 때 사용되며 많은 양의 데이터를 처리할 때 유용합니다.
여러 개의 저장 공간이 한 줄로 나열되어 있는 구조
배열을 선언하기 위해선 우선 배열의 원소들의 형 type과 배열의 크기 number를 결정해야 한다.
예를 들어 배열 a
가 10개의 ìnt
형 원소를 갖는다고 선언하고 싶으면 다음과 같이 선언하면 된다.
배열을 사용하기 위해서는 선언이 필요하다 c언어에서 선언하는 방법은 아래와 같다
int a[10];
C언어는 절차지향언어로 메모리에 배열에 해당하는 메모리를 할당해줘야 하기 때문이다.
배열의 원소들은 아무 형이나 가질 수 있으며, 배열의 크기 또한 (정수) 상수식으로 정할 수 있다.
배열의 길이를 나중에 수정을 해주고 싶다면, 배열의 크기를 매크로 정의를 해주는 것이 좋은 실무 습관이다.
#define N (10)
…
int a[N];
배열의 한 특정 원소에 접근하고 싶다면 해당 배열 이름 다음에 대괄호로 감싼 정수값을 적어주면 된다.
(배열의 첨자[subscript] 혹은 색인[index] 이라고 부른다)
배열의 원소들은 언제나 0부터 첨자가 시작하기 떄문에 크기 n
을 갖는 배열의 색인은
0
부터 n-1
까지다.
예를 들어 배열 à
가 10개의 원소를 갖는다면 원소들을 각각 a[0], a[1], …, a[9]으로 참조할 수 있다
a[i]의 형태를 갖는 표현식은 왼쪽값이므로 일반적인 변수들처럼 사용할 수 있다:
a[0] = 1;
printf("%d\n", a[5]);
++a[i];
배열을 선언할 떄 몇 가지 주의사항이 있다
index
는 0부터 시작하기 때문에 자칫 배열의 길이가 넘어가는 배열의 요소에int arr1[3] = {1,2,3}; // 가능
int arr2[3];
arr2[3] = {1,2,3}; // 불가능
[중괄호를 이용할 경우 arr1과 같이 한 줄로 선언과 동시에초기화를 해주어야 한다.]
배열 길이는 변수로 설정하면 안 된다. 자바가 더 익숙한 사람들에게는 다소 낯설 수 있다.
c의 경우 배열 길이를 변수로 설정하려면 심볼릭 상수를 선언해서 사용해야 한다.
int arr[3] = {1,2}
나머지는 0으로 저장된다.
sizeof
연산자 사용법sizeof
연산자는 배열의 크기(바이트)를 결정할 수 있다.
만약 a
가 10개의 정수를 갖는 배열이라면 sizeof(a)
는 보통 40(각 정수가 4바이트를 필요로 한다고 가장)을 갖는다.
sizeof를 통해 a[0]와 같이 배열의 원소의 크기를 측정할 수 있다. 배열의 크기를 원소의 크기로 나누게 되면 배열의 길이를 알 수 있게 된다:
sizeof(a) / sizeof(a[0])
몇몇 프로그래머는 배열의 길이가 필요할 경우 아래와 같은 표현식을 사용하기도 한다.
배열의 a를 초기 상태로 만들어주기 위해서 다음과 같이 해줄 수 있다:
for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i) {
a[i] = 0;
}
다차원 배열(multi-dimensional array)
다차원 배열이란? 2차원 이상의 배열을 의미하며, 배열 요소로 또 다른 배열을 가지는 배열을 의미합니다.
즉, 2차원 배열은 배열 요소로 1차원 배열을 가지는 배열이며, 3차원 배열은 배열 요소로 2차원 배열을 가지는 배열이고, 4차원 배열은 배열 요소로 3차원 배열을 가지는 요소입니다.
c에서는 다음과 같이 선언합니다.
int m[5][9];
위 선언에 의하면 배열 m
은 5개의 행과 9개의 열을 갖는다.
아래 그림에서 알 수 있듯이, 행과 열 둘다 0부터 첨자(subscript)가 시작된다.
i
번째 형 j
번째 열에 있는 배열 m
의 원소에 접근하려면 m[i][j]
와 같이 작성하면 된다.
위에서 이차원 배열을 표로 시각화를 해주었지만, 실질적으로 컴퓨터의 메모리에 저장되는 형태는 아니다.
C는 배열을 행 우선 순서row-major order로 저장해주기 때문에 0번째 행이 우선적으로 저장이 되고,
그 다음 1번째 행 순으로 저장한다.
다음은 m
배열이 어떤 형식으로 메모리에 저장되는지에 대한 그림이다.
이차원 배열은 일차원 배열 속에서 일차원 배열을 넣어주어 초기화 해줄 수 있다.
int m[5][9] = {{1, 1, 1, 1, 1, 0, 1, 1, 1},
{0, 1, 0, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 1, 0, 0, 1, 0},
{1, 1, 0, 1, 0, 0, 0, 1, 0},
{1, 1, 0, 1, 0, 0, 1, 1, 1}};
모든 내부의 초기자들은 행렬의 한 행에 대한 값을 제공한다.
고차원 배열의 초기자는 이와 비슷한 방법으로 작성한다.
차원과 무관하게 배열을 const를 선언에 추가해주어 "상수"로 만들어 줄 수 있다.
const char hex_chars[] =
{'0'. '1'. '2'. '3'. '4'. '5'. '6'. '7'. '8'. '9'.
'A'. 'B'. 'C'. 'D'. 'E'. 'F'};
const로 선언된 배열은 프로그램에 의해 수정될 수 없다.
컴파일러는 배열의 원소를 수정하려는 모든 시도를 감지할 것이다.
배열을 const로 선언하면 몇가지 장점을 얻을 수 있다.
우선 프로그램이 배열을 변경하지 않도록 문서화해준다.
이를 통해 이 코드를 읽을 다른 사람에게 중요한 정보를 전달해줄 수 있다.
또한 컴파일러가 우리의 의도대로 배열이 수정되지 않도록 오류를 잡아준다.
const는 단순히 배열에만 국한된 것이 아니라, 모든 변수에 가능한다.
이에 대한 내용은 나중에 다룰 것이다. const는 특히나 배열 선언에 유용한 이유는
배열은 주로 프로그램 실행 도중에 변하지 않는 값을 갖기 때문이다.