5.1.2 동적 배열 구현

먼저 동적 배열을 생성하는 함수를 작성합시다.

Array *New_Array()
{

동적 배열 형식 크기의 메모리를 할당합니다.

    Array *arr = 0;
    arr = (Array *)malloc(sizeof(Array));

자료를 보관할 저장소는 0으로 초기화합니다. 여기서 구현할 동적 배열은 저장소가 꽉 차면 내부적으로 저장소의 크기를 확장해 나갈 것입니다.

    arr->base = 0;

저장소에 용량과 보관한 자료 개수를 0으로 초기화한 후 동적 배열을 반환합니다.

    arr->capacity = arr->usage = 0;
    return arr;
}

동적 배열을 소멸하는 함수를 작성합시다.

void Delete_Array(Array *arr)
{

만약 저장소가 유효하면 저장소를 해제합니다.

    if(arr->base)
    {
        free(arr->base);
    }

그리고 자신의 메모리를 해제합니다.

    free(arr);
}

배열에 원하는 개수만큼 특정 자료로 설정하는 함수를 작성합시다.

void Array_SetSize(Array *arr,int capacity,Element data)
{

먼저 저장소의 크기를 설정하고 해당 크기만큼 자료를 보관할 수 있는 크기의 저장소를 재할당합니다. 만약 보관한 자료가 있다면 이들을 유지하고 있어야 하므로 realloc 함수를 사용합니다.

    arr->capacity = capacity;
    arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
    for(    ;arr->usage<arr->capacity; arr->usage++)
    {
        arr->base[arr->usage] = data;
    }
}

순차적으로 보관할 때 사용할 함수를 작성합시다.

void Array_PushBack(Array *arr,Element data)
{

마지막 보관한 다음 위치에 보관하면 순차적으로 보관할 수 있습니다. 먼저 마지막 보관한 다음 위치를 얻어오는 함수를 호출하여 추가할 위치를 구합니다.

    Iterator at = Array_End(arr);

그리고 해당 위치에 자료를 보관하는 함수를 호출합니다.

    Array_Insert(arr,at,data);
}

특정 위치에 자료를 보관하는 함수를 작성합시다.

void Array_Insert(Array *arr,Iterator pos,Element data)
{

먼저 입력 인자로 들어온 위치를 인덱스로 변환합니다.

    int index = pos - arr->base;

해당 인덱스 뒤에 보관한 요소들을 오른쪽으로 한 칸씩 이동해야 합니다. 먼저 이동해야 할 원소 개수를 구합니다. 만약 현재 보관한 요소 개수가 6이고 추가할 인덱스가 2이면 인덱스 2, 3, 4, 5에 있는 요소를 이동해야 합니다. 따라서 배열에 보관한 요소 개수에 index를 뺀 값이 이동할 요소 개수입니다.

    int mcount = arr->usage - index;

만약 저장소에 자료가 꽉 차면 공간을 늘려주어야 합니다.

    if(arr->capacity == arr->usage)
    {

여기에서는 저장소의 크기가 0일 때는 1로 그렇지 않을 때는 현재  크기의 두 배로 설정합시다.

        if(arr->capacity)
        {
            arr->capacity*=2;
        }
        else
        {
            arr->capacity = 1;
        }

저장소를 재할당합니다.

        arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
    }

저장소의 상대적 거리 index에서 요소 크기 * 이동할 요소 개수만큼의 메모리를 다음 위치로 메모리 복사합니다. 이를 통해 index 위치부터 그 뒤에 있는 요소를 한 칸씩 오른쪽으로 보내는 것입니다.

    memcpy(arr->base+index+1,arr->base+index,sizeof(Element)*mcount);

저장소의 index 위치에 자료를 보관하고 보관한 요소 개수를 1 증가합니다.

    arr->base[index] = data;
    arr->usage++;
}

이번에는 특정 인덱스의 요소를 변경하는 함수를 작성합시다.

Element Array_GetAt(Array *arr,int index)
{

먼저 입력 인자로 전달받은 인덱스가 유효한지 확인합니다.

    if((index>=0)&&(index<arr->usage))
    {

유효하면 저장소의 상대적 거리 인덱스에 있는 자료를 반환합니다.

        return arr->base[index];
    }

유효하지 않을 때는 0을 반환하기로 합시다.

    return 0;
}

저장소의 시작 위치에 마지막 자료를 보관한 다음 위치를 반환하는 함수를 작성합시다.

Iterator Array_Begin(Array *arr)
{
    return arr->base;    
}
Iterator Array_End(Array *arr)
{
    return arr->base+arr->usage;
}

마지막으로 특정 위치의 요소를 제거하는 함수를 작성합시다.

void Array_Erase(Array *arr,Iterator pos)
{

먼저 입력 인자로 전달받은 위치를 인덱스로 변환합니다.

    int index = pos - arr->base;

해당 위치 다음 요소부터 한 칸씩 왼쪽으로 이동합니다. 이를 위해 이동할 요소 개수를 구합니다.

    int mcount = arr->usage - index -1;

입력 인자로 전달받은 위치에 바로 다음 위치부터 요소의 크기에 이동할 요소 개수를 곱한 메모리 크기를 복사합니다. 그리고 보관한 요소 개수를 1 감소합니다.

    memcpy(pos,pos+1,sizeof(Element)*mcount);
    arr->usage--;
}

다음은 동적 배열을 작성한 Array.c 파일의 내용입니다.

//Array.c
#include "Array.h"
#include <malloc.h>
#include <memory.h>
Array *New_Array()
{
    Array *arr = 0;
    arr = (Array *)malloc(sizeof(Array));
    arr->base = 0;
    arr->capacity = arr->usage = 0;
    return arr;
}
void Delete_Array(Array *arr)
{
    if(arr->base)
    {
        free(arr->base);
    }
    free(arr);
}
void Array_SetSize(Array *arr,int capacity,Element data)
{	
    arr->capacity = capacity;
    arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
    for(    ;arr->usage<arr->capacity; arr->usage++)
    {
        arr->base[arr->usage] = data;
    }
}
void Array_PushBack(Array *arr,Element data)
{
    Iterator at = Array_End(arr);
    Array_Insert(arr,at,data);
}
void Array_Insert(Array *arr,Iterator pos,Element data)
{
    int index = pos - arr->base;
    int mcount = arr->usage - index;
    if(arr->capacity == arr->usage)
    {
        if(arr->capacity)
        {
            arr->capacity*=2;
        }
        else
        {
            arr->capacity = 1;
        }
        arr->base = (Element *)realloc(arr->base,sizeof(Element)*arr->capacity);
    }
    memcpy(arr->base+index+1,arr->base+index,sizeof(Element)*mcount);
    arr->base[index] = data;
    arr->usage++;
}
void Array_SetAt(Array *arr,int index,Element data)
{
    if((index>=0)&&(index<arr->usage))
    {
        arr->base[index] = data;
    }
}
Element Array_GetAt(Array *arr,int index)
{
    if((index>=0)&&(index<arr->usage))
    {
        return arr->base[index];
    }
    return 0;
}
Iterator Array_Begin(Array *arr)
{
    return arr->base;
}
Iterator Array_End(Array *arr)
{
    return arr->base+arr->usage;
}
void Array_Erase(Array *arr,Iterator pos)
{
    int index = pos - arr->base;
    int mcount = arr->usage - index -1;
    memcpy(pos,pos+1,sizeof(Element)*mcount);
    arr->usage--;
}