본문으로 바로가기

[C언어] 메모리 동적 할당

category C 2014. 6. 4. 11:24

<상황1>

#include <stdio.h>

#define MAX 258555

void main()

{

    int a[MAX];

    for (int i = 0; i < MAX; ++i)

    {

        a[i] = i;

        printf("%d ", a[i]);

    }

}

시스템마다 차이가 있겠지만, 
#define MAX 258556 으로 바꾼다면 어떤 일이 일어 날까?
 
<생각해보기>
아주 큰 메모리를 차지하는 배열을 만들고 싶다면 어떻게 할까?
 
<상황2>
공식적인지 비공식적인지 모르겠지만, 한국에서 가장 긴 이름은 "황금독수리온세상을놀라게하다" 라고 인터넷으로 검색할 수 있었다. 보통 사람들의 이름은 한글로 3~4자이다. 4자가 최대라고 한다면 4자 * 2 bytes = 8 bytes 가 된다.
char name[10]; 라고 해도 충분하다.
 
"황금독수리온세상을놀라게하다"라는 사람의 이름 14자를 저장하기 위해서는 28bytes가 소모 될 것이며 NULL 문자를 포함해서 대략 30 bytes 정도라고 해두자.
char name[30]; 라고 선언해야 할 것이다.
 
10,000명의 고객을 관리하는 프로그램을 만든다고 하면 char name[10000][30]; 이라고 선언해야 할 것이며, 단 한명의 고객을 위해 9999명 * 20 bytes =  199980 bytes가 더 소모되는 될 것이며,
19,998명의 보통사람의 이름을 저장할 수 있는 공간이 낭비되는 셈이다.
 
<생각해보기>
메모리를 낭비하지 않고 가변적으로 메모리를 생성할 수는 없을까?
 
<상황3> 
#include <stdio.h>
void main()
{
    int iMax;
    printf("학생의 수를 입력하시오\n");
    scanf("%d", &iMax);
    char name[iMax][10];
    int kor[iMax], eng[iMax], mat[iMax], tot[iMax], rank[iMax], i, j;
    float ave[iMax];
    for(i = 0; i < iMax; ++i)
    {
        printf("이름 국어 영어 수학 순으로 입력하세요\n");
        scanf("%s%d%d%d", name[i], &kor[i], &eng[i], &mat[i]);
        tot[i] = kor[i] + eng[i] + mat[i];
        ave[i] = tot[i] / 3.0f;
        rank[i] = 1;
    }
}
위와 같이 코딩하면 컴파일 에러가 날 것이다. 배열의 크기를 정할때는 컴파일 시간에 미리 정해져야 하므로 상수가 와야지 변수가 올 수 없기 때문이다.
<생각해보기>
실행시간(Run-time)에 배열의 크기를 결정할수는 없을까? 
 
메모리 동적 할당
malloc
void *malloc( size_t size );
메모리 동적 할당이란 실행시간에 메모리를 할당한다는 의미이며 메모리 정적 할당이란 컴파일 시간에 메모리를 할당한다는 의미이다. malloc 함수를 통해 실행시간에 메모리 동적 할당을 한다. 또한 메모리 부분 중 Heap 영역에 할당되며 메모리(가상메모리 포함) 한계 내에서 동적 할당을 할 수 있다.
 
size 에는 할당될 바이트의 수를 입력하며 int를 100 개를 할당하고 싶다면 400 을 입력하면 된다. 보통 갯수 * sizof(자료형)라고 입력한다. 예를 들면 앞에서 말한 경우는 100 * sizeof(int)라고 쓰면 된다.
 
리턴값은 할당된 메모리의 시작주소값이며, 메모리 할당에 실패한다면 NULL를 리턴하게 된다. 
또한 void * 로 넘어오기 때문에 해당되는 자료형으로 반드시 형변환해야 한다. 예를 들어 int형으로 100개를 동적 할당 하고 싶다면 아래와 같이 기술한다.
 
int *pBuffer = (int*)malloc(100 * sizeof(int));
 
free
다른 응용프로그램이 동적 할당 했던 메모리를 쓸 수 있게  해제하는 기능을 한다.
 
free(pBuffer);
 
2차원 배열처럼  메모리 할당하기
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
    int iMaxGuest = 3, iLenName = 4, i;
    char **p=(char **)malloc(iMaxGuest*sizeof(char *));
    for (i = 0;i < iMaxGuest;i++) {
        p[i] = (char *)malloc(iLenName * sizeof(char));
    }
    strcpy(p[0], "Neo");
    strcpy(p[1], "Bob");
    strcpy(p[2], "Tom");
    for (i = 0;i < iMaxGuest;i++) {
        printf("%s\n", *(p + i)); //printf("%s\n", p[i]);
    }
    for (i = 0;i < iMaxGuest;i++) {
        free(*(p + i)); //free(p[i]);
    }
    free(p);
}

&p

100

1000

p

 

1000

1004

1008

2000

3000

4000

*p

p[0]

*(p+1)

p[1]

*(p+2)

p[2]

 

2000

2001

2002

2003

N

e

o

\0

**p

p[0][0]

*(*p+1)

p[0][1]

*(*p+2)

p[0][2]

*(*p+3)

p[0][3]

 

3000

3001

3002

3003

B

o

b

\0

**(p+1)

p[1][0]

*(*(p+1)+1)

p[1][1]

*(*(p+1)+2)

p[1][2]

*(*(p+1)+3)

p[1][3]

 

4000

4001

4002

4003

T

o

m

\0

**(p+2)

p[2][0]

*(*(p+2)+1)

p[1][1]

*(*(p+2)+2)

p[2][2]

*(*(p+2)+3)

p[2][3]

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main()
{
    int iMaxGuest = 3, iLenName = 4, i;
    char **p=(char **)malloc(iMaxGuest*sizeof(char *));
    for (i = 0;i < iMaxGuest;i++) {
        p[i] = (char *)malloc(iLenName * sizeof(char));
    }

    strcpy(p[0], "Neo");
    strcpy(p[1], "Bob");
    strcpy(p[2], "Tom");
    printf("&p = %p p = %p\n", &p, p);
    for (i = 0;i < iMaxGuest;i++) {

        printf("(p+%d):%p &p[%d]:%p *(p+%d):%p = %s\n",
            i, p+i, 
            i, &p[i],
            i, *(p + i), 
            *(p + i)); 

    }

    for (i = 0;i < iMaxGuest;i++) {
        free(*(p + i)); //free(p[i]);
    }
    free(p);
}



 

<해결1>
#include <stdio.h>
#include <stdlib.h>
//#define MAX 258555
#define   MAX 250000000
void main()
{
    int *pa = (int *)malloc(MAX * sizeof(int));
    for (int i = 0; i < MAX; ++i)
    {
        pa[i] = i;
        printf("%d ", pa[i]);
    }
    free(pa);
}
 
<해결2>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
    int i, iMaxGuest, iLenName;
    char szName[1000];
    printf("고객의 수를 입력하세요\n");
    scanf("%d", &iMaxGuest);
    char **p = (char **)malloc(iMaxGuest*sizeof(char *));
    for (i = 0;i < iMaxGuest;i++) {
        printf("고객명을 입력하세요\n");
        scanf("%s", szName);
        iLenName = strlen(szName) + 1;
        p[i] = (char *)malloc(iLenName * sizeof(char));
        strcpy(p[i], szName);
    }
    for (i = 0;i < iMaxGuest;i++)
    {
        printf("p[%d] = %s, size(%d)\n", i, p[i], strlen(p[i]));
    }
    for (i = 0;i < iMaxGuest;i++) {
        free(p[i]);
    }
    free(p);
 
<해결3>
#include <stdio.h>
#include <stdlib.h>
void main()
{
    int iMax;
    printf("학생의 수를 입력하시오\n");
    scanf("%d", &iMax);
    char (*name)[10]=(char (*)[10])malloc(iMax*10*sizeof(char));
    int *kor = (int *)malloc(iMax*sizeof(int));
    int *eng = (int *)malloc(iMax*sizeof(int));
    int *mat = (int *)malloc(iMax*sizeof(int));
    int *tot = (int *)malloc(iMax*sizeof(int));
    int *rank = (int *)malloc(iMax*sizeof(int));
    float *ave = (float *)malloc(iMax*sizeof(float));
    int i, j;
    for(i = 0; i < iMax; ++i)
    {
        printf("이름 국어 영어 수학 순으로 입력하세요\n");
        scanf("%s%d%d%d", name[i], &kor[i], &eng[i], &mat[i]);
        tot[i] = kor[i] + eng[i] + mat[i];
        ave[i] = tot[i] / 3.0f;
        rank[i] = 1;
    }
    for (i = 0; i < iMax; ++i) //  자기 자신 i
    {
        for (j = 0; j < iMax; ++j)//  비교대상 다른사람 j
        {
            if (tot[i] < tot[j])
            {
                ++rank[i];
            }
        }
    }
    for (int ranking = 1; ranking <= iMax; ++ranking)
    {
        for(i = 0; i < iMax; ++i)
        {
            if (ranking == rank[i])
            {
                printf("이름: %s kor(%d) eng(%d) mat(%d) tot(%d) ave(%.1f) rank(%d)\n", 
                    name[i], kor[i], eng[i], mat[i], tot[i], ave[i], rank[i]);
            }
        } 
    }
    free(name);
    free(kor);
    free(eng);
    free(mat);
    free(tot);
    free(ave);
    free(rank);

}
<실습> 달팽이 문제!!!