본문 바로가기

컴퓨터/언어,프로그래밍

C언어 :: 동적 메모리 할당 - 사용

1.2    포인터와 동적 메모리 할당

동적으로 할당받은 메모리도 무언가를 통해 접근할 수가 있어야 할 것입니다.  위에서 보듯이 동적 메모리 할당에 관련된 함수들의 반환형들은 모두 void *로써 포인터형 타입이었다.  해당 함수에서는 무슨 목적으로 메모리를 할당하는 것인지를 알 수 없기 때문에 void *이지만 사용하는 개발자는 자신의 목적에 맞게 강제 형변환을 하여야 할 것입니다.  여기에서는 동적으로 할당받은 메모리를 어떻게 포인터 변수로 유용하게 관리하는 지에 대해서 살펴보기로 합시다.

 

 

 

0.1.1      동적 순수 배열

이 책에서 배열은 크게 정적 순수 배열, 정적 인덱스 배열, 동적 순수 배열, 동적 인덱스 배열로 구분하여 설명하고 있습니다.(통용되는 용어는 아닙니다.)  정적이라는 의미는 배열의 크기가 정적이라는 것이며 동적이라는 것은 배열의 크기가 동적이라는 것입니다.  순수라는 의미는 배열의 각 원소가 관리할 데이터 타입이라는 것이며 인덱스라는 것은 배열의 각 원소는 관리할 데이터의 위치 정보를 갖고 있다는 것을 얘기합니다.  , C언어에서 얘기하는 배열은 정적 순수 배열이 되겠지요.

 

 

 

 

 

 

먼저 동적 순수 배열을 통해 회원 데이터 관리 프로그램의 몇 가지 기능을 설명하고자 합니다.  동적 순수 배열은 배열 원소의 개수를 개발자에 의해 결정하는 것이 아니고 프로그램 사용자(end-user)에 의해 결정을 할 경우에 필요할 것입니다.  그만큼 유연성 있는 프로그램이 되겠지요.

 

 사용자 정의 타입은 다음과 같다고 가정 하겠습니다. /* 이후에도 동일함 */

 

typedef struct _MEMBER mem;

#define MAX_NAME_LEN    20

struct _MEMBER

{

   int mnum;

   char mname[MAX_NAME_LEN+1];

};

 

동적 순수 배열에서 전역 변수로는 관리할 최대 회원 수와 동적으로 할당받은 메모리를 관리할 포인터 변수가 필요할 것입니다. 

 

int max_member=0;

mem  *base=0;

 

해당 프로그램은 초기에 end-user에 의해 관리할 최대 회원수를 입력받는 부분이 필요할 것입니다.  참고로 DEF_MEMBER는 프로그램 개발자가 정한 최소 관리 회원수에 해당하는 상수명입니다. 

 

#define DEF_MEMBER 30       /*헤더 파일에 정의하였다고 가정합시다. */

 

 

void fnInitStruct()

{

    printf(“최대 관리할 회원수를 입력하세요\n”);

    max_member = fnGetNum();

 

    if(max_meber <= DEF_MEMBER) 

{

    max_member = DEF_MEMBER;

}

    base = (mem *)malloc(sizeof(mem)*max_member);

    memset(base,0, sizeof(mem)*max_member);

}

 

그리고, 위와 같이 동적으로 할당받는 구문이 있으면 해제화 하는 구문을 같이 생각을 하여 병행하여 구현을 하면 메모리 누수를 막을 수 있을 것입니다.

 

void CleanStruct()

{

  free(base);

  base = 0; max_member = 0;

}

 

위의 두개의 함수는 정적 순수배열을 사용한다면 필요하지 않은 기능이 될 것입니다.  사실 정적 순수 배열과 동적 순수 배열은 이 두개의 함수가 다를 뿐 나머지 기능은 완벽하게 동일합니다.  정적 순수 배열의 배열명도 원소의 포인터 타입이고 동적 순수 배열에서도 관리명은 원소의 포인터 타입입니다.  , 메모리를 할당받는 방법이 변수 선언과 동적 메모리 할당에 의해 받는 다는 차이 말고는 없다는 것입니다.  다음은 회원 데이터를 삽입받는 함수입니다.  여러분 각자가 간단히 동적 순수 배열을 통해 회원 관리 프로그램을 완성해 보시기 바랍니다.  그리고 나서 정적 순수 배열을 통해 프로그램과 차이를 확인해 보세요.

 

void fnInsert()

{

    int num = 0;

 

    printf(“삽입할 회원 번호를 입력하세요.[1]-[%d]\n”,max_member);   

 

    num = fnGetNum();  //회원 번호 입력

    if((num >=1) && (num <= max_member))  //입력받은 회원 번호의 범위 확인

    {

        if(base[num-1].mnum)  //해당 번호의 데이터가 존재하는지 확인

        {

            printf(“[%d]의 회원 데이터는 이미 존재합니다.\n”,num);

        }

        else

        {

            base[num-1].mnum = num;

            fnGetMemberData(base +(num-1));  //해당 번호의 나머지 데이터 입력받음

        }

    }

    else

    {

        printf(“[%d]는 범위를 벗어난 회원 번호입니다.\n”,num);

    }

}

 

0.1.1      정적 인덱스 배열

정적 인덱스 배열은 배열의 원소의 개수는 정해져 있고 배열의 각 원소는 관리할 데이터의 위치정보를 갖는 배열을 얘기합니다.  , 관리할 최대 회원의 수는 정해져 있지만 실제 회원 데이터가 삽입되기 전에 해당 회원을 위한 메모리를 할당받고 해당 회원 데이터를 삭제할 때 메모리를 해제하겠다는 것입니다.  회원 데이터의 유동성이 심하다면 이를 선택하여 프로그래밍 할 수 있을 것입니다.

 

정적 인덱스 배열에서 전역 변수로는 정적 배열이 필요할 것인데 배열의 원소는 회원의 위치 정보를 관리해야 하기 때문에 관리할 데이터의 포인터가 원소가 되겠지요.  그리고, 배열의 크기는 정적이기 때문에 최대 관리할 회원에 대한 상수가 필요할 것입니다.

 

#define MAX_MEMBER           100 /* 최대 관리 회원수 헤더 파일에 정의하였다고 가정합시다. */

 

mem  *base[MAX_MEMBER];

 

정적 인덱스 배열은 변수 선언을 통해 배열공간을 할당되므로 초기화 함수는 필요치 않을 것입니다.  반면, 프로그램 종료전에 할당된 메모리를 해제하는 부분은 필요하겠지요.

 

void CleanStruct()

{

    int i = 0;

    while( i <MAX_MEMBER)

    {

        if(base[i])

        {

            free(base[i]);

            base[i]=0;

        }

        i++;

    }

}

 

그리고, 회원 데이터를 삽입하는 부분에서는 먼저 메모리를 할당한 후에 데이터를 입력받아야 할 것이며 삭제하는 부분에서는 메모리를 해제하여야 할 것입니다.

 

void fnInsert()

{

    int num = 0;

 

    printf(“삽입할 회원 번호를 입력하세요.[1]-[%d]\n”,MAX_MEMBER);

 

    num = fnGetNum();  //회원 번호 입력

    if((num >=1) && (num <= MEMBER)) //력받은 회원 번호의 범위 확인

    {

        if(base[num-1])  //해당 번호의 데이터가 존재하는지 확인

        {

            printf(“[%d]의 회원 데이터는 이미 존재합니다.\n”,num);

        }

        else

        {

            base[num-1] = (member *)malloc(sizeof(member)); 

//해당 멤버 데이터를 저장하기 위한 메모리 할당

 

            base[num-1]->mnum = num;

            fnGetMemberData(base [num-1]);  //해당 번호의 나머지 데이터 입력받음

        }

    }

    else

    {

        printf(“[%d] 범위를 벗어난 회원 번호입니다.\n”,num);

    }

}

 

void fnDelete()

{

    int num = 0;

 

    printf(“삽입할 회원 번호를 입력하세요.[1]-[%d]\n”,MAX_MEMBER);

 

    num = fnGetNum();  //회원 번호 입력

    if((num >=1) && (num <= MEMBER)) //력받은 회원 번호의 범위 확인

    {

        if(base[num-1])  //해당 번호의 데이터가 존재하는지 확인

        {

            free(base[num-1]);  //메모리 해제

            base[num-1] = 0;    //관리 공간 0으로 reset

            printf(“[%d]의 회원 데이터를 삭제하였습니다.\n”,num);

        }

        else

        {

            printf(“[%d]의 데이터는 존재하지 않습니다.\n”,num);

        }

    }

    else

    {

        printf(“[%d] 범위를 벗어난 회원 번호입니다.\n”,num);

    }

}

 

정적 인덱스 배열에서 각 회원의 데이터를 저장하기 위한 메모리는 미리 할당되어 있지 않습니다.  실제 회데이터를 입력받기 전에 메모리를 할당받아야 하는데 이미 데이터가 있는지 확인하는 구문에 대해서 신경을 써야 합니다.  순수 배열에서는 base[num-1].mnum 값이 참인지를 통해 존재 여부를 판단하였습니다.  하지만 인덱스 배열에서는 메모리가 할당되었는지를 통해 판단을 합니다.  , base[num-1]을 통해 판단한다는 것이지요.  그리고, 해당 회원의 데이터를 입력받을 메모리 주소가 순수 배열에서는 base+(num-1)이지만 인덱스 배열에서는 base[num-1]이 되겠지요.  또한, 데이터 삭제시에도 순수 배열에서는 해당 메모리를 clear시키면 되지만(memset(base+(num-1),0,sizeof(member))) 인덱스 배열에서는 해당 메모리를 제거해 주어야 합니다.  그리고, 해제한 메모리를 관리하는 원소에 0을 대입하는 것을 잊지 말아야 겠지요. 

 

0.1.2      동적 인덱스 배열

이번에는 동적 인덱스 배열에 대해서 알아보기로 합시다.  동적 인덱스 배열에서는 관리할 데이터 개수는 end-user에 의해 선택이 됩니다.  그리고, 실제 데이터가 삽입되기 전에 메모리를 할당을 해야 할 것입니다.  이에 동적 인덱스 배열에서 전역 변수로는 관리할 최대 회원 수와 동적으로 할당받은 메모리를 관리할 포인터 변수가 필요할 것입니다.  그리고, 할당받을 원소가 데이터를 관리하기 위한 위치 정보이기 때문에 할당받을 원소가 관리할 데이터의 포인터이겠지요.  , 전역 변수는 관리할 원소의 포인터에 대한 포인터여야 할 것입니다.

 

int max_member=0;

mem  **base=0;

 

해당 프로그램은 초기에 end-user에 의해 관리할 최대 회원수를 입력받는 부분이 필요할 것입니다.  참고로 DEF_MEMBER는 프로그램 개발자가 정한 최소 관리 회원수에 해당하는 상수명입니다. 

 

#define DEF_MEMBER 30       /*헤더 파일에 정의하였다고 가정합시다. */

 

 

void fnInitStruct()

{

    printf(“최대 관리할 회원수를 입력하세요\n”);

    max_member = fnGetNum();

 

    if(max_meber <= DEF_MEMBER) 

{

    max_member = DEF_MEMBER;

}

    base = (mem **)malloc(sizeof(mem *)*max_member);

    memset(base,0, sizeof(mem *)*max_member);

}

 

그리고, 위와 같이 동적으로 할당받는 구문이 있으면 해제화 하는 구문을 같이 생각을 하여 병행하여 구현을 하면 메모리 누수를 막을 수 있을 것입니다.

 

void CleanStruct()

{

    int i = 0;

    while(i < max_member)

    {

        if(base[i])

        {

            free(base[i]);

            base[i]=0;

        }

        i++;

    }

  free(base);

  base = 0; max_member = 0;

}

 

동적 인덱스 배열을 이용한 회원 관리 프로그램의 나머지 함수는 여러분이 직접 작성해 보시기 바랍니다.

 

이번 장에서 동적 메모리 할당에 관련된 함수들의 기본적인 쓰임새를 이해했으면 좀 더 자세한 동적 메모리 할당 함수를 사용하는 방법에 대해서는 프로그래밍 과정과 프로젝트에서 익히도록 합시다.


제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...