2011-1 학기프로그래밍입문 (1) 참고자료 chap 6-8. 메모리동적할당 박종혁 Tel: 970-6702 Email: jhpark1@seoultech.ac.kr h k 한빛미디어 출처 : 뇌를자극하는 C프로그래밍, 한빛미디어 -1- ehanbit.net
동적할당의필요성 프로그램을작성하는단계에서필요한기억공간의크기를결정하는 것은정적할당이다. - 변수나배열의선언 프로그램의실행중에입력되는데이터에맞게기억공간을확보해야할때는동적할당이필요하다. - 세명의인사말을저장하는배열은낭비가심하다. char greetings[3][20]; // 가장긴인사말이 20 바이트라고할때 한빛미디어 -2- ehanbit.net
동적할당함수 (malloc, free) 메모리를동적으로할당하기위해서는함수를호출해야한다. - int 형변수로사용할기억공간을할당받는경우 - 포인터변수로할당받은기억공간을사용한다. *ip = 10; printf( %d n, *ip); // ip 가가리키는기억공간에 10 을저장한다. // ip 가가리키는기억공간의값을출력한다. 한빛미디어 -3- ehanbit.net
메모리를동적으로할당받는프로그램 #include <stdio.h> #include <stdlib.h> // malloc 함수를사용하기위해서포함시킨다. int main() { int *ip; double *dp; // int형을가리킬포인터변수 // double형을가리킬포인터변수 ip=(int *)malloc(sizeof(int)); dp=(double *)malloc(sizeof(double)); // 기억공간을동적으로할당받아서 // 각포인터변수에연결시킨다. *ip=10; *dp=3.4; // 포인터변수로각각할당받은기억공간을 // 참조하여값을저장한다. printf(" 정수형으로사용 : %d n", *ip); printf(" 실수형으로사용 : %lf n", *dp); return 0; // 포인터변수로저장된값을출력한다. 출력결과정수형으로사용 : 10 실수형으로사용 : 3.400000 한빛미디어 -4- ehanbit.net
동적할당되는메모리는반납해야한다. 동적할당메모리는기억부류 (storage class) 의힙 (heap) 영역에할당된다. 힙 (heap) 영역은프로그램이종료될때까지기억공간이유지된다. 따라서 사용이끝난동적할당메모리는명시적으로반납한다. int *ip; ip=(int *)malloc(sizeof(int)); *ip=20; free(ip); // 포인터를전달인자로주고호출한다. 한빛미디어 -5- ehanbit.net
동적할당되는메모리는확인해야한다. 동적할당함수는힙영역에원하는크기의메모리가존재하지않으면널포인터를리턴한다. 따라서이값을확인하여널포인터를참조하 지않도록해야한다. ip=(int *)malloc(sizeof(int)); if(ip==0){ printf( 메모리가부족합니다. n ); else{ *ip=10; printf( %d n, *ip); // 리턴된포인터가널포인터인지확인한다. // 널포인터이면메시지만출력한다. // 기억공간이할당되었으면사용한다. - 널포인터는보통 NULL 이라는이름으로기호화하여사용하는데전처리단계에서 0으로바뀌므로상수값 0과같다. 한빛미디어 -6- ehanbit.net
동적할당기억공간의활용 메모리의동적할당은많은기억공간을한꺼번에할당받아서배열로사용하는것이효율적이다. - int 형변수 5 개를동적으로할당받는경우 한빛미디어 -7- ehanbit.net
메모리를동적으로할당받아배열로사용하는프로그램 #include <stdio.h> #include <stdlib.h> int main() { int *ip; int i, sum=0; ip=(int *)malloc(5*sizeof(int)); if(ip==0){ printf(" 메모리가부족합니다! n"); return 1; printf(" 다섯명의나이를입력하세요 : "); for(i=0; i<5; i++){ // 전체 20바이트의기억공간할당 // 메모리가할당되었는지확인하여 // 메모리가부족하면메시지를출력하고 // 프로그램을종료한다. scanf("%d", ip+i); i) // 데이터를저장할포인터를전달한다. sum+=ip[i]; // 입력된값을참조하여누적한다. printf(" 다섯명의평균나이 : %.1lf n", sum/5.0); // 평균나이출력 free(ip); // 할당받은메모리반환 return 0; 출력결과 다섯명의나이를입력하세요 : 21 27 24 22 35 ( 엔터 ) 다섯명의평균나이 : 25.8 한빛미디어 -8- ehanbit.net
동적할당을사용하여문자열을처리하자. 메모리동적할당을사용하면입력되는문자열의길이에맞게기억공간을할당할수있다. 1 문자열을입력받기전에는그길이를알수없으므로우선충분한크기의문자배열이필요하다. 2 문자배열에문자열을입력받는다. 뇌를자극하는 C 프로그래밍 3 문자열의길이를계산하여그크기에맞게기억공간을동적으로할당받는다. 4 동적으로할당받은기억공간에입력받은문자열을복사한다. 뇌를자극하는 C 프로그래밍 입력된문자열의길이에딱맞는기억공간 한빛미디어 -9- ehanbit.net
세개의문자열을저장하기위한동적할당프로그램 #include <stdio.h> #include <string.h> #include <stdlib.h> int main() { char temp[80]; char *str[3]; int i; // 문자열처리함수를위한헤더파일포함 // 동적할당함수를위한헤더파일포함 // 임시문자배열, 충분히크게확보한다. // 동적할당된기억공간을연결할포인터배열 // 반복제어변수 for(i=0; i<3; i++){ printf(" 문자열을입력하세요 : "); gets(temp); str[i]=(char *)malloc(strlen(temp)+1); strcpy(str[i], temp); // 문자열입력 // 입력받은문자열의길이에맞게동적할당한다. // 동적할당된기억공간에문자열을복사한다. for(i=0; i<3; i++){ printf("%s n", str[i]); for(i=0; i<3; i++){ free(str[i]); return 0; // 포인터배열의요소를참조하여입력된문자열출력 // 할당받은메모리를반환한다. 한빛미디어 -10- ehanbit.net
세개의문자열을저장하기위한동적할당프로그램 출력결과 문자열을입력하세요 : Hi ( 엔터 ) 문자열을입력하세요 : Let me introduce ( 엔터 ) 문자열을입력하세요 :Hello( 엔터 ) Hi Let me introduce Hello - 포인터배열은각동적할당기억공간을연결하여가변배열을만든다. - 포인터배열은널포인터로초기화하여문자열을출력할때널포인터를검사하는방법을쓸수있다. char *str[100]={0; for(i=0; str[i]!=0; i++){ printf( %s n, str[i]); 한빛미디어 -11- ehanbit.net
가변배열의문자열을함수로출력하자. 가변배열에저장된문자열을출력할때포인터배열의배열명을사용한다. str_prn(str); // 포인터배열의배열명을주고함수호출 포인터배열의배열명은 (char *) 형을가리키므로매개변수는이중포인터변수를사용한다. 매개변수를사용하여가변배열에저장된문자열을출력한다. void str_prn(char **sp) { while(*sp!=0){ printf( %s n, *sp); sp++; 한빛미디어 -12- ehanbit.net
메인함수의전달인자 메인함수의전달인자는실행될때명령행에서만들어진다. - 운영체제는명령행의문자열을가변배열로만들고그개수와포인터를메인함수에전달한다. 한빛미디어 -13- ehanbit.net
명령행전달인자를출력하는프로그램 #include <stdio.h> int main(int argc, char **argv) { int i; for(i=0; i<argc; i++){ printf("%s n", argv[i]); // 명령행전달인자를받을매개변수 // 전달인자 ( 문자열 ) 의개수만큼반복 // 전달인자 ( 문자열 ) 를하나씩출력한다. return 0; 출력결과 C: >mycommand first_arg second_arg ( 엔터 ) MYCOMMAND first_arg second_arg C: >_ - 포인터배열의마지막배열요소는널포인터로채워지므로널포인터를검사하여출력하는것도가능하다. while(*argv!= 0){ printf( %s n, *argv); argv++; // argv가가리키는포인터배열의값이널포인터가아닌동안 // 문자열을출력한다. // 포인터배열의다음배열요소로이동 한빛미디어 -14- ehanbit.net
명령행전달인자와동적할당을사용한문자열입력예제 다음과같이실행되는프로그램을만들어보자. 1. 입력되는문자열을길이에맞게동적으로할당받은기억공간에저장한다. 단, 문자열의최대길이는널문자까지포함하여 80 바이트로한다. 2. 프로그램을작성할때는문자열이몇개가입력될지알수없으나실행할때는명령행전달인자로그최대값을입력해준다. C: > strings 100 // 최대 100개의문자열을입력할수있다. 3. 새로운문자열을입력할때엔터키만입력하면입력을끝내고그동안입력된문자열을출력한다. C: >strings 5 ( 엔터 ) 문자열을입력하세요 : What's up! ( 엔터 ) 문자열을입력하세요 : Good morning~ ( 엔터 ) 문자열을입력하세요 : Hi... *^^* ( 엔터 ) 문자열을입력하세요 : ( 엔터 ) What's up! Good morning~ Hi... *^^* 한빛미디어 -15- ehanbit.net
명령행전달인자와동적할당을사용한문자열입력예제 4. 만약최대입력문자열을모두입력하면메시지와함께그동안입력된문자열을출력하고종료한다. C: >strings 3 문자열을입력하세요 : Cheer up. 문자열을입력하세요 : Good evening. 문자열을입력하세요 : Hello world! 문자열입력이최대값을모두채웠습니다. Cheer up. Good evening. Hello world! 5. 문자열을입력하는부분은함수로작성한다. 한빛미디어 -16- ehanbit.net
문자열을입력하여저장하는프로그램 : PART1 #include <stdio.h> #include <string.h> #include <stdlib.h> void str_prn(char **); int main(int argc, char **argv) { char temp[80]; char **str; int max; int i; // strlen 함수를위한헤더파일 // malloc, atoi 함수를위한헤더파일 // 문자열출력함수의선언 // 명령행전달인자를매개변수에받는다. // 문자열입력을위한임시문자배열 // 포인터배열을연결할이중포인터변수 // 최대입력문자열수를저장할변수 // 반복제어변수 max=atoi(argv[1]); // 문자열을수치값으로변환한다. str=(char **)malloc((max+1) * sizeof(char *)); // 포인터배열도동적할당한다. C: >strings 5 실행하면가변배열이만들어진다. 한빛미디어 -17- ehanbit.net
문자열을입력하여저장하는프로그램 : PART1 max=atoi(argv[1]); - argv[1] 이연결하고있는숫자형태의문자열을수치값으로바꾼다. - atoi함수는문자열을전달인자로받아서수치값으로바꾸어준다. str=(char **)malloc((max+1) * sizeof(char *)); - max의수만큼문자열을연결할포인터배열을동적으로할당받는다. 이때데이터의끝을표시하기위해여분의기억공간을하나더할당받는다. 할당받은기억공간은이중포인터변수 str에연결해둔다. 한빛미디어 -18- ehanbit.net
문자열을입력하여저장하는프로그램 : PART2 i=0; while(1){ printf(" 문자열을입력하세요 : "); gets(temp); if(temp[0]==' 0') break; // 반복제어변수초기화 // 무한반복 // 문자열입력 // 엔터만입력되면 temp배열의첫번째요소는널문자가된다. str[i]=(char *)malloc(strlen(temp)+1); // 문자열을저장할메모리할당하고포인터배열요소에연결한다. strcpy(str[i], t temp); // 문자열복사 i++; // 하나의문자열을입력할때마다하나씩증가한다. if(i==max){ // 입력된문자열의수를검사하여최대값을다채우면바복문종료 printf(" 문자열입력이최대값을모두채웠습니다. n"); break; str[i]=0; // 입력이끝난후에포인터배열의마지막요소는널포인터로마감한다. str_prn(str); t // 입력된문자열은함수를호출하여출력한다. i=0; // 반복제어변수를초기화하고 while(str[i]!=0){ // 포인터배열에연결된동적할당기억공간들을반환한다. free(str[i]); i++; free(str); // 동적으로할당받은포인터배열의기억공간도반환한다. return 0; 한빛미디어 -19- ehanbit.net
문자열을입력하여저장하는프로그램 : PART3 void str_prn(char **sp) { while(*sp!= 0){ printf("%s n", *sp); sp++; // 매개변수는이중포인터변수 // 포인터배열의값이널포인터가아닐때까지 // 포인터배열이연결하고있는문자열출력 // 포인터배열의배열요소를차례로이동한다. 한빛미디어 -20- ehanbit.net
기타동적할당함수 calloc 함수는배열을할당받고초기화한다. - 첫번째배열요소의개수, 두번째는배열요소의크기를전달인자로준다. - double 형변수 5 개로사용할배열을할당받는경우 double *ap; int i; ap=(double *)calloc(5, sizeof(double)); for(i=0; i<5; i++){ printf( %lf n, ap[i]); 출력결과 0.000000000000 // 모두 0 으로 0.000000 // 초기화된다. 0.000000 0.000000 0.000000 한빛미디어 -21- ehanbit.net
realloc 함수로기억공간의크기를조절한다. 저장된데이터에변화가생기면할당받은기억공간을realloc함수로조절할수있다. - 첫번째전달인자는이미할당받은기억공간의포인터를준다. - 두번째는새로할당받고자하는크기를바이트단위로입력한다. 한빛미디어 -22- ehanbit.net
realloc 함수를사용한양수값입력프로그램 #include <stdio.h> #include <stdlib.h> int main() for(i=0; i<cnt; i++){ // 입력된데이터를 { int *ip printf("%5d", ip[i]); // 차례로출력한다. int size=5; // 처음에 5개만입력한다. free(ip); // 할당받은기억공간반환 int cnt=0; // 입력된데이터의수를센다. return 0; int num; int i; ip=(int *)calloc(size, sizeof(int)); while(1){ printf(" 양수를입력하세요 => "); scanf("%d", &num); if(num<=0) break; if(cnt<size){ ip[cnt++]=num; else{ size+=5; ip=(int *)realloc(ip, size*sizeof(int)); ip[cnt++]=num; // 일단 5 개를입력할기억공간만할당받는다. // while(true) // 입력된데이터가 5 개를넘지않으면 // 할당받은기억공간에차례로저장한다. // 그렇지않으면 // 데이터의최대값을 5씩증가한다. // 새로증가된수만큼기억공간을늘린다. // 새로할당된기억공간에저장한다. 한빛미디어 -23- ehanbit.net