본문 바로가기

Algorithm/C프로그래밍

[10주차] 동적 할당

반응형

#12.2 동적 메모리 사용 절차(2)

🏃‍♂️ 동적 메모리 할당 함수 사용법을 익힌다.

동적 메모리 해제: free() 함수

지정된 메모리 공간을 해제(free)

 

함수 원형 void free(void *ptr);
함수 인자 해제할 메모리 공간을 가리키는 포인터 변수
기능 ptr이 가리키는 메모리 해제
※ ptr 변수 자체를 해제시키는 것이 아니다.

ex.

int *p = NULL;
p = (int *)malloc(10*sizeof(int));

free(p); 	// p가 가리키는 영역 해제

 

세종대학교 고급C프로그래밍 동적 할당 자료

ex.

1. 정수 한 개를 저장할 수 있는 메모리 공간 할당하고 해제하기

2. float형 실수 한 개를 저장할 수 있는 메모리 공간 할당하고 해제하기

3. double형 실수 15개를 저장할 수 있는 메모리 공간 할당하고 해제하기

4. 다음과 같은 구조체 한 개를 저장할 수 있는 메모리 공간 할당하고 해제하기

struct student{
	int id;
    char name[8];
    double grade;
}

int main() {
	// 1. 
	int *ip=(int*)malloc(1*sizeof(int));
    free(ip);
    
    // 2.
    float *fp=(float*)malloc(1*sizeof(float));
    free(fp);
    
    // 3.
    double *dp=(double*)malloc(15*sizeof(double));
    free(dp);
    
    // 4.
    struct student *sp = (struct student *)malloc(1*sizeof(struct student));
    free(sp);
}

 

동적 메모리를 안전하게 사용하기 위한 주의사항

  • malloc()의 반환 값을 검사하여 메모리 할당의 성공 여부 확인
    • NULL 포인터 반환하는 경우: 요청한 메모리 크기만큼 연속된 메모리 공간을 확보하지 못할 때
  • 비슷하게, 해제하려는 메모리 주소가 NULL인지 검사
int *p = NULL;
p = (int *)malloc(10*sizeof(int));

if(p==NULL) {	// 메모리 할당 실패하면
	printf("Not enough memory!");	// 오류 상황을 알리고
	return -1;		// 함수 종료
}

if(p!=NULL)	// p가 NULL이 아닌 경우에만
	free(p);	// free() 함수 호출

 

메모리 할당 방식 비교

  정적 메모리 할당 동적 메모리 할당
필요한 메모리 크기 결정시점 프로그램 작성 단계 프로그램 실행 중
메모리 할당 및 해제 시점 시스템이 자동으로 할당 및 해제 개발자가 명시적으로 할당 및 해제 함수 호출
프로그램 실행 중 메모리 크기 변경 여부 불가 가능
메모리 누수(leak) 가능성
(할당 받은 메모리를 안 돌려주는 것)
없음 있음
메모리 사용의 효율성 비효율적 효율적

※ 만약 동적 메모리 할당을 한 후 해제(free())를 하지 않을 경우, 프로그램 종료 시 변수만 사라지고, 메모리 안에는 그대로 저장되어 있다.

※ 그러나 일반적인 프로그램은 프로그램 종료 시 메모리 해제된다. 서버 같은 경우에는 메모리 누수가 일어날 수 있다.

세종대학교 고급C프로그래밍 동적 할당 자료

 

#12.3 동적 메모리 사용 예제(1)

🏃‍♂️ 예제를 통해 동적 메모리 할당 사용법을 익힌다.

 

1) 동적으로 메모리를 할당 받아 사용하는 기본 프로그램

하나의 정수를 저장하는 메모리를 동적 할당 받아서 사용(실용성은 없음)

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

int main() {
	int *p = NULL;	// 포인터 변수 선언
    p = (int *)malloc(sizeof(int));	// 동적 할당
    if (p == NULL) {	// 동적 할당 오류 검사
    	printf("Not enough memory!");
        return -1;   
    }
    *p = 15;	// 동적 할당 메모리에 값 저장
    printf("동적 메모리 할당 (정수형): %d", *p);
    
    free(p):
    return 0;
}

 

2) 일차원 배열을 동적 할당 받아 사용하는 프로그램

  • 여러 개의 정수를 저장하는 메모리를 동적 할당 받아 사용
  • 문제: 한 학생의 과목별 점수를 입력 받아 평균 점수를 구한 후 출력하는 프로그램을 작성하시오.
    1. 프로그램 실행 중에 사용자로부터 과목 수 n을 직접 입력 받음.
    2. n개의 정수형 값을 저장할 수 있는 메모리를 동적으로 할당 받아, 할당 받은 메모리의 시작 주소를 score에 저장
    3. 할당 받은 메모리를 score[0]~score[n-1]까지 일반 배열 원소처럼 참조하여 사용
    4. 할당 받은 메모리 해제
#include <stdio.h>
#include <stdlib.h>

int main() {
	int n, i, sum = 0;
	int *score = NULL;
    
    scanf("%d", &n); // 1. 과목 수 입력받기
    
    score = (int *)malloc(n*sizeof(int));	// 2. 배열 동적 할당
    if (score == NULL) {	// 동적 할당 오류 검사
    	....
    }
	for (i = 0; i<n; i++) {
    	scanf("%d", &score[i]);	// 3. 과목별 점수 입력받기
        sum += score[i];	// 누적 합 계산
    }
    printf("%.1f", (double)sum/n); // 평균 계산
    
    free(score);	// 4. 동적 할당 메모리 해제
    return 0;
}

세종대학교 고급C프로그래밍 동적 할당 자료

 

학습 정리

  • free() 함수는 할당된 메모리를 해제하여 시스템에 되돌려 준다.
  • 정적 할당은 할당 메모리가 코드 작성 단계에서 정해지고, 프로그램을 실행할 때마다 동일한 크기로 할당하는 방식
  • 동적 할당은 프로그램 실행 단계에서 결정되는 크기에 따라 메모리를 할당하는 방식
  • 동적 할당과 포인터를 활용하여 일차원 배열을 사용할 수 있다.(예제 2)

 

#12.3 동적 메모리 사용 예제(2)

3) 동적 메모리 할당을 사용한 문자열 처리 프로그램

길이가 다른 여러 개의 문자열을 효율적으로 저장하기 위해 다음과 같은 방식으로 동적 메모리 할당 이용

  1. 문자열을 입력 받기 위한 충분한 크기의 문자 배열을 선언(정적 할당)
  2. 1.의 문자 배열에 문자열을 입력 받는다.
  3. 2.에서 입력된 문자열의 길이를 계산하여 그 크기에 맞게 메모리를 동적으로 할당 받는다.(널 문자 포함)
  4. 할당 받은 메모리 공간에 1.의 문자 배열의 문자열을 복사한다.

 

문제: 사용자로부터 책의 개수 n을 입력 받아, n개의 책 제목을 저장하는 프로그램을 작성하시오.

  • 사용할 메모리 구조
    • 책 하나의 정보를 저장하는 구조체
    • typedef struct book_title {
      	char *title;	// 책 제목(포인터)
          ...		// 기타 책 정보(필요 시)
      } BINFO;
    • 책의 개수를 모르므로 동적 구조체 배열 사용

세종대학교 고급C프로그래밍 동적 할당 자료

typedef struct book_title {
	char *title;	// 책 제목(포인터)
    ...		// 기타 책 정보(필요 시)
} BINFO;

int main() {
	BINFO *bp = NULL;
	int n, i, len;
	char temp[100];	// 1. 문자열을 입력 받기 위한 문자 배열을 선언

	scanf("%d", &n);	// 책 개수 입력
	getchar();	// 개행 문자 버리기

	// 책 배열 동적 할당 및 동적 할당 오류 검사 
	bp = (BINFO *)malloc(n*sizeof(BINFO));
	if (bp == NULL) { ... }

	for (i=0; i<n; i++) {
		gets(tmp);	// 2. 문자 배열 temp에 문자열을 입력 받음
    
    		len = strlen(temp);	// 3. temp에 입력된 문자열 길이를 계산하고,
    		bp[i].title = (char *)malloc((len+1)*sizeof(char));	// 3. 그 크기만큼 메모리를 동적으로 할당 받음(널 문자 포함)
    
    		if(bp[i].title == NULLL) { ... } // 동적 할당 오류 검사
    
    		strcpy(bp[i].title, temp);	// 4. 할당 받은 메모리에 제목 복사
    	}
	for (i=0; i<n; i++)
    		printf("%s\n", bp[i].title);	// 책 제목 출력
	for (i=0; i<n; i++)
    		free(bp[i].title);	// a. 책 제목(문자 배열)에 대한 메모리 해제
	free(bp);	// b. 책 배열(구조체 배열)에 대한 메모리 해제
    
	return 0;
}

세종대학교 고급C프로그래밍 동적 할당 자료
세종대학교 고급C프로그래밍 동적 할당 자료
 세종대학교 고급C프로그래밍 동적 할당 자료

해제할 때 순서(a->b)도 중요하다. 순서 틀리면 접근 불가해질 수 있다.

 

4) 동적 메모리 할당을 사용하여 2차원 배열을 할당하는 프로그램

  • 문제: char array[3][4]라는 2차원 배열을 동적으로 할당하기
  • 착각하기 쉬운 잘못된 방법
    • char *pch = (char *)malloc(3*4*sizeof(char)); -> 사실 상 malloc(12); 호출이다.
    • 이건 2차원 배열 할당이 아니라, 크기가 12인 1차원 배열 할당이다.
    • 세종대학교 고급C프로그래밍 동적 할당 자료
  • 해결방법: 포인터 배열 사용
    • 다른 다차원 배열도 동일한 원리 적용: 2차원 정수 배열, 3차원 배열 등

세종대학교 고급C프로그래밍 동적 할당 자료

※ 정적 할당에서의 2차원 배열과 동적 할당에서의 2차원 배열은 메모리 구조가 완전히 다르다. 그러나, 코드 상으로는 2차원 배열처럼 사용할 수 있다. (cf. 포인터 배열)

 

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

int main() {
	int i;
    char **pch;	// 이중 포인터 선언
    pch = (char **)malloc(3*sizeof(char *));	// 포인터 배열 할당
    
    for (i=0; i<3; i++)
    	pch[i] = (char *)malloc(4*sizeof(char));	// 1차원 배열 할당
        
    strcpy(pch[0],"aaa");
    strcpy(pch[1],"bbb");
    pch[2][0] = '\0';	// 2차원 배열처럼 사용(예제 9.10 참조)
    
    for (i=0; i<3; i++)
    	puts(pch[i]);
        
    for (i=0; i<3; i++)
    	free(pch[i]);	// 1차원 배열 메모리 해제
        
     free(pch);	// 포인터 배열 메모리 해제
     
     return 0;
}

세종대학교 고급C프로그래밍 동적 할당 자료

 

#12.4 기타 동적 메모리 할당 함수

calloc() 함수

함수 원형 void * calloc(unsigned int num, unsigned int size);
함수 인자 num 동적으로 할당 받을 원소의 개수
size 원소 한 개의 크기 (바이트 단위)
반환 값
  • (num*size) 바이트 수 만큼 할당하고, 할당된 메모리를 모두 0으로 초기화 후 시작 위치 반환
  • 실패하면 -> NULL 반환

malloc()과 거의 비슷하나 인자가 다르다. 그리고 0으로 초기화 한다.

int *p = NULL;
p = (int *) calloc(5, sizeof(int)); 크기 5인 int형 배열 할당. malloc(5*sizeof(int));

 

realloc() 함수

어떨 때 쓰는 건지 모르겠음

함수 원형 void * realloc(void *ptr, unsigned int size);
함수 인자 ptr 확장 크기를 변경할 메모리의 시작 주소
new_size 변경 후 메모리의 전체 크기(바이트 단위)
반환 값
  • ptr이 가리키는 메모리의 크기를 new_size 바이트 크기로 조정하고, 조정된 메모리의 시작 위치 반환
  • 실패하면 -> NULL 반환
char *p = (char *)malloc(5); // 5 바이트 만큼 공간 할당
p = (char *)realloc(p,10); // 10 바이트로 공간 크기 변경

 ※ 기존 위치에서 새로운 크기를 확보할 수 없으면, 기존 위치의 공간을 해제하고 새로운 위치에 공간 할당

 

 

학습 정리

  • 동적 할당을 다단계로 적용하여 복잡한 구조의 동적 메모리를 사용할 수 있다.(예3)
  • 2차원 동적 배열은 포인터 배열을 사용하여 두 단계의 동적 할당으로 표현한다.(예4)
  • calloc() 함수는 malloc() 함수와 유사하게 메모리를 할당해 주는데, 추가로 할당 받은 메모리 공간을 0으로 초기화 한다.
  • realloc() 함수는 할당 받은 메모리 공간의 크기를 변경하고자 할 때 사용한다.
반응형

'Algorithm > C프로그래밍' 카테고리의 다른 글

[7주차] 구조체  (0) 2021.11.09
[6주차] 구조체  (0) 2021.11.09
[9주차] 동적 할당  (0) 2021.11.05
[5주차] 문자열  (0) 2021.09.29
[4주차] 문자열  (0) 2021.09.27