11-2-나.포인터 배열의 활용

앞 장에서 동적 배열을 사용하여 임의의 학생에 대해 성적을 처리하는 예제를 만들어 본 적이 있다. 학생수를 미리 알 수 없을 때는 실행중에 학생 수만큼 메모리를 할당해서 사용해야 한다. 정수형 포인터 변수 arScore를 선언하고 동적할당한 메모리의 번지를 이 변수에 대입함으로써 arScore를 마치 배열인 것처럼 사용했었다. 생각이 잘 안나면 앞 장으로 돌아가 예제를 확인해 보도록 하라.

만약 이런 처리를 여러 학급에 대해서 처리하고자 한다면 이럴 때 포인터 배열이 필요하다. 각 학급의 학생수가 정해져 있지 않으므로 매번 학생수를 물어본 후 학생 수만큼 메모리를 할당해야 하는데 학급이 여럿이므로 포인터 변수도 여러 개가 필요한 것이다. 총 3개 학급의 성적을 처리한다면 다음과 같이 작성해야 한다.

 

: PASung

#include <Turboc.h>

 

void main(void)

{

     int *ar[3];

     int num[3];

     int i;

 

     for (i=0;i<3;i++) {

          printf("%d반의 학생수를 입력하세요 : ",i+1);

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

          ar[i]=(int *)malloc(num[i]*sizeof(int));

     }

 

     // 여기서 성적을 처리한다.

 

     for (i=0;i<3;i++) {

          free(ar[i]);

     }

}

 

각 학급의 학생수는 실행중에 입력받아 num 배열에 저장한다. 그리고 입력된 수만큼 메모리를 동적할당한 후 ar 배열에 차례대로 그 번지를 저장했다. 이렇게 되면 ar배열이 가리키는 포인터들은 각 학급 학생들의 성적을 저장할 수 있는 배열이 되며 학생수만큼만 메모리를 할당해서 사용하므로 메모리도 절약된다. 만약 각 학급 학생이 1반부터 12, 7, 9명이었다면 ar배열은 다음과 같은 모양으로 할당될 것이다.

각 학급의 성적을 저장할 배열이 실제로 어디에 할당될 지는 알 수 없지만 ar 포인터 배열이 이 번지들의 집합을 기억하고 있으므로 ar 배열 요소의 값을 읽기만 하면 정확한 위치를 액세스할 수 있다. 동적으로 할당된 배열은 물론 실행을 끝내기 전에 해제해야 한다. ar배열의 각 요소인 ar[0], ar[1], ar[2]가 동적 할당된 메모리의 선두 번지를 기억하고 있으므로 각 요소에 대해 free 함수를 호출하면 된다.

이렇게 만들어진 ar은 2차 정수형 배열처럼 사용할 수 있다. ar[0][3]은 0번째 학급의 3번째 학생 성적이며 ar[1][5]는 1번째 학급의 5번째 학생 성적이다. 단, 정확히 같지는 않은데 2차원 배열은 각 행의 길이가 모두 똑같지만(Rectangular) 포인터 배열은 각 포인터가 가리키는 배열의 길이가 각각 다를 수 있다(Ragged). 그래서 n반 학생의 성적을 참조할 때 할당된 길이 num[n] 범위를 벗어나지 않도록 주의해야 한다.