본문 바로가기
C, C++/문법 정리

[C언어] 배열의 기초 - 여러개의 자료를 묶어서 관리하려면?

by hseoy 2020. 4. 30.
반응형

[배열의 기초  - 여러개의 자료를 묶어서 관리하려면?]

오늘 글에서는 배열에 대해서 살펴볼 것이다. 배열에 대해서 이야기 하기 전에 한가지 이야기할 것이 있는데 언어에서 제공하는 기능, 문법들은 필요하기 때문에 만들어 진 것이며 가장 기본적인 문법들은 모든 프로그램의 가장 기본이 되며 가장 많이 사용된다는 것이다. 그렇기 때문에 가장 기본적인 문법들을 이해하는 것이 중요하며 기계적으로 사용하는 것이 아니라 왜 필요한 지에 대해서 생각하고 이해하면서 사용하는 것이 중요하다. 그래야 기계적으로 코드를 짜는 것에서 벗어나 재미있게 코드를 짤 수 있다.

그러면 먼저 배열이 왜 필요한 지에 대해서 생각해보자. 주목할 것은 우리가 일상을 살다보면 많은 것들을 보게 되는데 여기서 대부분의 것들은 어떠한 집합 아래 속해있다는 것이다. 예를 들어 학교에서 무언가를 배우는 사람들은 '학생'이라는 집합 아래 속해 있고 봄날을 밝히는 호랑나비, 흰나비들은 '나비'라는 집합 아래 속해있다. 그러면 이것들을 프로그램으로써 나타내려면 어떻게 해야 할까? 오로지 학생으로써의 의미만 가지는 자료들을 관리하기 위해서 student1, student2 ~ student100과 같이 사용하는 것은 매우 비효율적이고 선언문만 100줄이 될 수도 있기에 매우 손이 힘들어진다. 만약 어떤 집합 아래 1억 개의 자료들이 존재한다면? 그리고 이것을 일반적인 변수로 선언하려면? 이는 매우 노가다적인 작업이 될 것이고 구조상으로 봐도 가독성, 효율 등에서 좋지 않다. 

코스모스, 들꽃 등도 꽃이란 집합으로 묶여있다.

C언어는 이러한 작업을 위해서 배열이라는 문법을 제공하고 우리는 어떠한 집합으로 묶인 자료들을 손쉽게 관리하기 위해서 배열을 사용한다. 이것을 이해하면 좋다. 그러면 이제 C언어에서 배열을 선언하는 방법에 대해서 살펴보자. 배열은 `"자료형" "배열 이름" [배열의 크기];`와 같이 선언한다. 방의 번호 자료들을 담는 배열은 아래와 같이 선언할 수 있다.

int room[10];

여기서 `int`는 자료형, `room`은 배열의 이름을 나타낸다. 그리고 대괄호([ ]) 안에 있는 `10`은 배열의 크기로써 배열이 담을 수 있는 자료의 개수를 의미한다. 여기서 자료형은 배열이 담는 자료들의 자료형을 의미한다.

배열은 `"배열 이름" [사용하고자 하는 자료가 있는 인덱스]`와 같이 사용하여 배열 안에 있는 자료에 접근할 수 있으며 사용할 수 있는 인덱스의 범위는 0부터 배열의 크기 -1이다. 예를 들어 배열 변수 room의 경우에는 배열의 크기가 10이므로 사용할 수 있는 인덱스의 범위는 0부터 9까지이다. 

배열 역시 변수와 마찬가지로 '초기화'작업을 해주지 않으면 쓰레기값이 들어가 원하는 결과를 얻을 수 없다. 배열에 초기화하기 위한 방법은 크게 두 가지 방법이 있다. 모두 초기화하는 방법과 특정 인덱스의 값만 초기화하는 방법이다. 모두 초기화하는 방법은 선언할 때 아래와 같이 임의의 배열을 대입하는 것이다.

int room[10] = [10,20,30,40,50,60,70,80,90,100];

 이 경우 1부터 9까지의 값이 각각 해당하는 인덱스의 값으로 매칭되어 대입된다. 즉 room[8]의 값은 90이 되고, room[2]의 값은 30이 된다. 반면 특정 인덱스의 값만 초기화할 때는 아래와 같이 사용할 수 있다. 아래는 특정 인덱스의 값만 초기화 하는 방법으로 위와 같이 0부터 9까지의 모든 인덱스를 초기화하는 코드이다.

room[0] = 10;
room[1] = 20;
room[2] = 30;
room[3] = 40;
room[4] = 50;
room[5] = 60;
room[6] = 70;
room[7] = 80;
room[8] = 90;
room[9] = 100;

 이 경우 뭔가가 반복되는 것이 보이지 않은가? 인덱스값이 규칙적으로 변화하고 있기 때문에 for문을 사용하면 더 쉽게 할 수 있다.

int i = 0;
for(i = 0; i < 10; i++)
{
    room[i] = (i + 1) * 10;
}

 

그러면 이제 일반적인 변수 선언과 배열 선언 사이에는 어떠한 차이가 있는 지에 대해서 살펴보려고 한다. 그 전에 메모리에 대해서 알아야 한다. 데이터가 저장되는 곳은 RAM(Random Access Memory)이다. RAM은 정해진 개수의 메모리 셀이 '물리적'으로 '연결'되어 있고 그 안에 순서대로 데이터가 저장되는 구조이다.

배열 변수의 선언은 물리적으로 연결된 RAM의 구조를 따라 순차적으로 할당되지만 배열이 아닌 변수 선언은 RAM의 여기저기 아무데나 할당되게 된다. 

여기서 좀 더 자세하게 살펴보면 배열 선언으로 선언된 변수는 일반적인 변수선언으로 선언된 변수와는 성격이 다른 값을 저장한다. 일반적인 변수 선언으로 선언된 변수가 value를 담는다면 배열 선언으로 선언된 변수는 address를 담는다. 어떠한 주소를 저장하냐면 바로 배열이 담고 있는 자료들이 위치한 메모리의 첫번째 시작 주소를 저장하게 된다. 위에서 배열은 자료들이 메모리상에서 순차적으로 할당된다고 했다. 이러한 점을 이용해서 배열은 자료들의 메모리 시작주소에서 인덱스 값만큼 이동하여 자료들을 읽어온다. 이를 증명하기 위한 간단한 코드를 작성해보자.

#include <stdio.h>

int main()
{
    int arr[10];
    arr[0] = 5;
    printf("arr[0] = %d\n", arr[0]);
    printf("arr[0]'s address = %p\n", &arr[0]);
    printf("arr[1]'s address = %p\n", &arr[1]);
    printf("arr[2]'s address = %p\n", &arr[2]);
    printf("arr[3]'s address = %p\n", &arr[3]);
    printf("arr[4]'s address = %p\n", &arr[4]);
    return 0;
}

출력하는 변수 앞에 &을 붙히면 변수의 주소값을 반환하고 %p는 메모리 주소값을 출력할 때 사용하는 서식문자이다.  위에서는 배열의 각 주소를 출력하고 있다. Ubuntu 18.04.2 LTS에서 실행해봤을 때 아래와 같은 결과가 나왔다. 결과는 컴퓨터 상황에 따라서 다르게 나올 수 있다. 

0부터 4까지 인덱스를 바꿔가며 자료를 출력해봤을 때 주소값이 연속되고 있는 것을 볼 수 있다. 단 여기서 추가적으로 확인할 수 있는것이 주소가 4씩 차이가 나고 있다는 것인데 그 원인은 배열의 자료형에 있다. 위에서 arr의 자료형은 int형이다. 즉 자료들이 int형의 메모리 크기인 4byte마다 저장 되어 있다는 것이다. 그래서 인덱스를 이동하면 메모리도 자료형의 크기인 4byte만큼 차이난 것이다.

오늘은 배열의 기초적인 내용을 살펴보았다. 사실 이 내용은 좀 더 배워야 이해할 수 있는 부분이지만 오늘은 이만 마치려고 한다. 배열에 대해서는 나중에 다룰 포인터에 대한 내용을 살펴보면 더 자세히 이해할 수 있다. 다음 글에서는 오늘 다룬 기초적인 배열 개념을 가지고 어떻게 활용할 수 있는지에 대해서 이야기 해보려 한다. 이번 글에서 다룬 배열은 가장 기본적인 자료구조이므로 숙지해두는 것이 좋다.

반응형

댓글