3-7.유도형의 소개

유도형은 기본형의 조합에 의해 만들어지는 타입들이며 기본형 변수 여러 개를 모아서 또는 기본형을 약간 변형하여 만들어지는 타입들이다. 이절의 제목을 보면 알겠지만 상세한 이론은 다루지 않고 간단한 소개만 하기로 한다. 각각의 유도형들에 대한 문법은 분량도 방대하거니와 복잡하기 때문에 여기서 한꺼번에 다 알기는 어렵다. 각 주제들은 개별 장에서 다시 상세하게 다룰 것이므로 여기서는 개념 위주로만 알아보도록 하자.

3-7-가.배열

배열(Array)은 가장 흔한 자료 구조이면서 또한 가장 실용적이다. 돌(silicon)로 만든 돌머리인 컴퓨터는 판단이나 인식같은 것은 할 수 없으며 오로지 주어진 명령을 아무 생각없이 반복하는 것을 제일 잘한다. 배열은 이런 반복적인 작업과 아주 잘 어울린다. 구조가 단순하기 때문에 속도가 빠르며 이해하기 쉽고 사용하기도 쉽다.

우선 배열의 정의부터 문장화해 보면 동일한 타입을 가지는 자료들의 집합으로 정의된다. 동일한 타입이라는 뜻은 정수형이면 정수형끼리만, 문자형이면 문자형끼리만 모여야 배열이 된다는 뜻이다. 다른 타입들이 모이면 배열이 될 수 없으며 다음에 배울 구조체가 되어야 한다. 동일한 타입의 자료 여러 개가 집합을 이루어야만 배열이 될 수 있다.

정수형 변수 하나는 정수값 하나만 기억할 수 있고 실수형 변수 하나는 실수값 하나만 기억할 수 있다. 배열은 이런 개별 변수들을 여러 개 묶어서 하나의 이름으로 선언한 것이며 동종 자료의 집합을 표현할 수 있다. 배열을 구성하는 각 개별 변수들을 요소(Element)라고 한다. 배열은 다음과 같이 선언한다.

 

타입 배열명[크기][크기]...;

 

타입 : 배열의 요소가 어떠한 값을 담는지를 지정한다. 즉, 배열이 어떤 값들의 집합인가를 지정한다. int, char, double 등의 기본 타입은 물론이고 유도형이나 사용자가 만든 타입도 가능하다.

배열명 : 배열도 변수이므로 이름이 있어야 한다. 명칭 규칙에 합당하게 마음대로 이름을 작성할 수 있다.

크기 : 요소의 개수가 몇개인가를 [ ] 괄호안에 정수 상수로 지정한다. 크기 지정이 하나만 있으면 1차원 배열이라고 하며 두 개 이상이면 다차원 배열이라고 한다.

 

다음은 배열을 선언한 예이다.

 

int array[5];           // 정수형 변수 5개의 집합인 배열 array를 선언

double rate[10];      // 실수형 변수 10개의 집합인 배열 rate를 선언

 

컴파일러는 배열 선언문을 만나면 요소의 크기만한 메모리를 개수만큼 연속적으로 할당한다. array는 정수형이므로 4바이트의 메모리 5개, 즉 20바이트가 할당될 것이며 rate는 80바이트가 할당될 것이다. 메모리에는 다음과 같이 array가 생성되며 이 그림에서 각 격자는 정수 하나의 크기인 4바이트이다.

이렇게 할당된 배열에서 요소를 참조할 때는 [ ] 괄호와 첨자(Index)를 사용한다. 첨자란 요소가 그 배열의 몇 번째에 있는지를 나타내는 순서값이다. C는 항상 0부터 수를 세기 때문에(Zero Base) 첫 번째 요소의 첨자는 0이 되며 마지막 요소의 첨자는 배열 크기보다 항상 하나 더 작다. int array[5]의 마지막 요소는 array[5]가 아니라 array[4]가 된다. 배열 요소를 이렇게 첨자로 참조할 수 있는 이유는 같은 배열에 속한 요소들은 모두 연속적인 메모리에 이웃하게 배치되기 때문이다. 그래서 첨자에 타입의 크기를 곱한 위치를 읽으면 쉽게 요소의 메모리를 액세스할 수 있다.

배열의 각 요소는 배열이라는 큰 집합의 일부분이라는 것 외에는 같은 타입의 변수와 완전히 동일한 자격을 가진다. array[3]이라는 요소는 정수형 변수이며 정수형 변수와 똑같이 사용한다. array[3]=123;과 같이 정수를 대입할 수도 있고 printf("%d",array[3]); 과 같이 값을 읽을 수도 있다. array가 정수형 변수를 모아 놓은 것이고 array[3]은 그 중 하나를 떼어 놓은 것이므로 완전한 정수형 변수인 것이다.

배열의 사용예를 보도록 하자. 학생 30명의 성적을 처리하는 프로그램을 작성한다고 해 보자. 30개나 되는 변수를 각각 따로 만들 필요없이 크기 30의 배열을 하나 선언하기만 하면 된다.

 

int Score[30];

 

이렇게 하면 Score라는 이름으로 30개의 성적을 저장할 수 있는 정수형 변수 집합이 생성된다. Score[0]부터 Score[29]까지 정수형 변수 30개가 연속적인 메모리 공간에 생성되는 것이다. 이 배열에 학생들의 성적을 입력받을 때는 다음과 같은 반복문을 사용한다.

 

for (i=0;i<30;i++)

     scanf("%d",&Score[i]);

 

for문은 반복적인 처리를 하는 문장인데 다음 장에서 배우게 될 것이다. 이렇게 입력된 성적을 가공하는 것도 아주 쉽다. 점수의 총합을 구하고 싶으면 Score[0]~Score[29]까지의 값을 더하기만 하면 된다.

 

Sum=0;

for (i=0;i<30;i++)

     Sum=Sum+Score[i];

 

Score라는 하나의 이름으로 성적 자료를 한곳에 모아 두었으므로 평균이나 분산, 최빈값 등을 구하는 것도 아주 쉽다. 뿐만 아니라 특정 학생의 성적을 조회한다거나 바꾸는 조작도 학생 번호를 첨자로 사용하면 간단하게 해결된다. 만약 배열이 없다면 반복을 할 수가 없고 다음과 같이 해야 할 것이다.

 

int Score0, Score1, Score2, Score3, ..... Score29;

scanf("%d",&Score1);

scanf("%d",&Score2);

scanf("%d",&Score3);

....

scanf("%d",&Score29);

 

필요한만큼 변수를 일일이 선언한 후 사용해야 하니 얼마나 끔찍한가? 30명 정도라면 이렇게 할 수 있겠지만 학생이 천 명정도 된다면 도저히 이런 방식으로는 자료를 처리할 수가 없을 것이다. 가끔 다음 코드가 동작할 것이라고 생각하는 순진한 사람도 있다.

 

for (i=0;i<30;i++)

     scanf(%d",&Scorei);

 

i를 0 ~ 29까지 반복하면서 Scorei를 참조하면 차례대로 Score0, Score1, Score2 변수를 사용할 것 같지만 컴파일러는 Scorei를 하나의 명칭으로 인식하므로 이렇게 되지는 않는다. 그래서 배열이 필요한 것이다. 배열은 하나의 이름으로 동일한 자료들의 집합을 다룰 수 있고 반복적인 처리가 가능하다는 점에서 아주 실용적인 타입이다.

배열의 크기값을 두 개 주면 2차 배열이 된다. 2차 배열은 두 개의 첨자를 가지며 요소를 참조할 때는 두 첨자를 밝혀야 한다. 마치 2차원 좌표 공간에서 한 점을 지정할 때 x, y 두 개의 좌표값을 주는 것과 같다. 다음은 학생과 과목번호를 첨자로 사용하는 2차 배열을 선언한 예이다.

 

int Score[3][10];

 

첫 번째 첨자가 과목의 번호이고 두 번째 첨자가 학생의 번호이다. 컴파일러는 이 선언문에 의해 Score라는 배열에 3*10개의 정수형 변수를 담을 수 있는 메모리(총 120바이트)를 할당한다. 이때의 메모리 모양을 그림으로 그려 보면 다음과 같을 것이다. 실제 메모리에는 선형적으로 배치되지만 2차 배열은 개념적인 도표(table)로 생각할 수 있으므로 일반적으로 표 형식으로 그리며 그렇게 생각하는 것이 더 편리하다.

이렇게 배열에 도표 형태로 성적값들이 저장되어 있다면 이 배열로 성적을 처리하는 것은 아주 쉽다.

 

1번 과목의 총합 : Score[1][0] ~ Score[1][9]까지의 합

5번 학생의 총점 : Score[0][5] ~ Score[2][5]의 합

전체 학생 전체 과목의 총점 : Score[0][0] ~ Score[2][9]까지의 합

 

이런 식으로 반복 처리하면 된다. 총점이 구해지면 평균이나 석차는 약간의 처리만 하면 쉽게 구할 수 있다. 3차 배열이나 4차 배열도 만들 수 있는데 메모리만 충분하다면 얼마든지 큰 배열도 가능하다. 배열에 대한 좀 더 자세한 내용에 대해서는 다음에 따로 배우게 될 것이다. 여기서는 배열이 동일 타입 변수의 집합이라는 정의와 반복적인 처리에 유리하다는 점에 대해서만 직관적으로 이해하도록 하자.