5 장함수 박종혁교수 UCS Lab Tel: 970-6702 Email: jhpark1@seoultech.ac.kr SeoulTech 2017-1 st 프로그래밍입문 (1)
2 목차 5.1 함수정의 5.2 return 문 5.3 함수원형 5.4 예제 : 거듭제곱표생성하기 5.5 컴파일러관점에서의함수선언 5.6 함수정의순서의다른방법 5.7 함수호출과값에의한호출 5.8 대형프로그램의개발 5.9 유효범위규칙 5.10 기억영역클래스 5.11 정적외부변수 5.12 디폴트초기화 5.13 재귀 5.14 예제 : 하노이탑
3 함수 하향식프로그래밍기법 프로그램은하나이상의함수로구성됨 함수정의 함수가수행할일을기술한 C 코드 함수정의의일반적인형식 type function_name( parameter list ) declarations statements
4 함수헤더 헤더 함수정의에서첫번째여는중괄호의앞부분 type function_name( parameter list )
5 함수헤더 type function_name( parameter list ) type 함수가리턴하는값의형 컴파일러는필요하다면, 함수의리턴값을이 type으로변환함 이것이 void이면리턴하는값이없다는것을나타냄 parameter list 이함수가가지는인자의목록 이함수를호출할때에는이 list에맞게호출해야함 이것이 void이면인자를갖지않음을나타냄
6 함수몸체 몸체 함수정의에서중괄호사이에있는문장들 예제 int factorial(int n) /* header */ /* body starts here */ int i, product = 1; for (i = 2; i <= n; ++i) product *= i; return product;
7 함수정의및호출 함수정의 void wrt_address(void) printf("%s\n%s\n%s\n%s\n%s\n\n", " *********************", " ** SANTA CLAUS *", " ** NORTH POLE *", " ** EARTH *", " *********************"); 함수호출 for (i = 0; i < 3; ++i) wrt_address();
8 함수의실행과정 함수는호출하기전에정의되어있어야한다. 다른함수가먼저있어도프로그램은항상메인함수부터시작된다.
9 함수의실행과정 메인함수의실행중에다른함수를호출하면그때함수가실행된다. 함수가호출될때전달인자는매개변수에복사된다.
10 함수의실행과정 함수가실행을마치고리턴할때는제어와함께리턴값도돌려준다. 함수가리턴하는값은복사되어임시기억공간에저장되며, 이값은 따로저장하지않으면버려지므로다른변수에저장해서사용한다.
11 예 void northing(void) /* this function does nothing */ double twice(double x) return (2.0 * x); int all_add(int a, int b) /* 복합문형태가능 */ int c; /* 선언포함 */... return( a + b +c); /* 연산결과 return */
함수형이정의되지않은경우 ==> 기본적으로 int형 all_add(int a, int b) /* 함수형정의생략가능 */ /* 복합문형태가능 */ int c; /* 선언포함 */... return( a + b +c); /* 연산결과 return */ ==> 함수형정확하게명시하는것이바람직함 12
13 지역적 / 전역적변수 지역변수 함수몸체안에서선언된변수 전역변수 함수외부에서선언된변수
14 지역적 / 전역적변수 int a = 33; /* a is external and initialized to 33 */ int main(void) int b = 77; /* b is local to main() */ printf("a = %d\n", a); /* a is global to main() */ printf("b = %d\n", b); return 0;
15 전통적인 C 전통적인 C 에서는매개변수목록에있는변수들 의선언이매개변수목록과첫번째중괄호사이에 옴 void f(a, b, c, x, y) inf a, b, c; double x, y;...
16 전통적인 C 매개변수가없다면빈괄호만써줌 void f1( )...
17 return 문 return 문을만나면, 그함수의실행은종료되고제어는호출한환경으로넘어감 만일 return 문이수식을포함하고있으면, 그수식의값도호출한환경으로같이넘어감 또한필요하다면, 그수식의값은함수정의에명시된함수의형으로변환됨
18 return 문 일반적인형식 return; return expression; 예 return; return ++a; return (a * b);
19 return 문예제 float f(char a, char b, char c) int i;... return i; /* value returned will be converted to a float */
20 return 문예제 double absolute_value(double x) if (x >= 0.0) return x; else return -x;
21 함수원형 새로운함수선언구문 컴파일러에게함수로전달되는인자의수와형그리고함수의리턴값의형을알려줌 일반적인형식 type function_name(parameter type list);
22 함수원형 type function_name(parameter type list); parameter type list 에서식별자의사용은옵션 void f(char c, int i); void f(char, int); 가변인자는 parameter type list 를 으로표현 printf(const char *, )
23 컴파일러관점에서의함수선언 컴파일러는여러방법으로함수선언을인식함 함수호출 만일함수선언이나정의전에 f(x) 와같은함수호출을사용했다면컴파일러는디폴트로다음과같은형태를가정함 int f(); 함수정의 함수선언 / 함수원형
24 함수정의순서 main() 함수의위치에따라 main() 을다른함수보다먼저정의 다른함수를사용할수있게하기위해다른모든함수의함수원형을 main() 앞에선언해야함 main() 을다른함수다음에정의 ( 예제 )
25 예 ) main() 맨뒤에위치 #include <stdio.h> #define N 7 void prn_heading(void)... long power(int m, int n)...
void prn_tbl_of_powers(int n)... int main(void) prn_heading() prn_tbl_of_powers(n) return 0; 26
27 함수호출 프로그램은하나의 main() 함수와다른함수들로구성됨 함수관점에서의프로그램수행 프로그램은항상 main() 함수부터수행됨 프로그램의제어가함수이름을만나면그함수가호출됨 함수가호출되면프로그램의제어는호출된함수로넘어가고그함수를수행함 호출된함수가실행을완료하면프로그램의제어는그함수를호출한환경으로다시넘어가고, 제어를다시받은함수는자기일을계속수행함
28 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
29 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
30 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
31 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
32 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
33 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
34 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
35 제어의흐름 #include <stdio.h> int test(int); int main(void) int b, a; int test(int c) c = c + 10; return 1; a = 5; b = test(a); printf("test is %d", b); return 0; int printf(... ).....
36 함수예제 정수의제곱을구하는함수 #include <stdio.h> int square(int n); int main(void) int result; result = square(5); printf("%d ", result); int square(int n) return(n * n);
37 함수예제 두수중큰수를찾는함수 #include <stdio.h> int get_max(int x, int y); int main(void) int a, b; printf(" 두개의정수를입력하시오 : "); scanf("%d %d", &a, &b); printf(" 두수중에서큰수는 %d 입니다.", get_max( a, b )); return 0; int get_max(int x, int y) if( x > y ) return(x); else return(y);
매개변수의전달방법 함수를호출하는두가지방법 38 1. Call by value( 값에의한호출 ) 매개변수에값을전달하여호출함 2. Call by reference,( 참조에의한호출 ) 매개변수로주소값을전달하여호출함 - 포인터이용
39 값에의한호출 C에서는값에의한호출로함수를호출함 각인자가평가된후, 그값이대응되는형식매개변수의위치에서지역적으로사용됨 변수가함수로전달되어도, 호출한환경에저장된변수값은변경되지않음
40 값에의한호출의예 #include <stdio.h> int compute_sum(int n); int main(void) int n = 3, sum; printf("%d\n", n); // 3 is printed sum = compute_sum(n); printf("%d\n", n); // 3 is printed printf("%d\n", sum); // 6 is printed return 0; int compute_sum(int n) //sum the integers from 1 to n int sum = 0; for ( ; n > 0; --n) //stored value of n is changed sum += n; return sum;
41 함수호출의의미 1. 인자목록의각수식이평가된다. 2. 필요하다면, 그수식의값이형식매개변수의형으로변환되고, 함수몸체의시작부분에서그값이대응되는형식매개변수에할당된다. 3. 함수의몸체가실행된다. 4. return 문을만나면, 제어는호출한환경으로넘어간다. 5. return 문이수식을가지고있다면, 필요한경우그수식의값이함수의형으로변환된다음그값도호출한환경으로넘어간다. 6. return 문이수식을가지지않는다면, 어떠한유용한값도호출한환경으로리턴되지않는다. 7. return 문이없다면, 제어가함수몸체의끝에도달할경우호출한환경으로넘어간다. 이때아무런값도리턴되지않는다. 8. 모든인자는 " 값에의한호출 " 로넘어간다.
42 대형프로그램개발 큰프로그램은별도의디렉토리에.h 파일과.c 파일로작성됨.h 파일은헤더파일이라고하며, 여기에는프로그램전체에서필요한프로그램구성원소인 #define, #include, 열거형의틀, 구조체와공용체의틀, 다른프로그래밍구조물, 그리고함수원형들을포함함.c 파일에는함수들을정의함 각.c 파일의제일처음에헤더파일을 include함
43 예제 pgm.h 파일 #include <stdio.h> #include <stdlib.h> #define N 3 void fct1(int k); void fct2(void); void prn_info(char *); main.c 파일 #include "pgm.h" int main(void) char ans; int i, n = n; printf("%s", "This program does not do very much.\n" "Do you want more information? "); scanf(" %c", &ans); if (ans == 'y' ans == 'Y') prn_info("pgm"); for (i = 0; i < n; ++i) fct1(i); printf("bye!\n"); return 0;
44 예제 fct.c 파일 #include "pgm.h" void fct1(int n) int i; printf("hello from fct1()\n"); for (i = 0; i < n; ++i) fct2(); void fct2(void) printf("hello from fct2()\n"); wrt.c 파일 #include "pgm.h" void prn_info(char *pgm_name) printf("usage:%s\n\n", pgm_name); printf("%s\n", "This program illustrates how one can write a program\n");
45 유효범위규칙 기본적인유효범위규칙 식별자는그식별자가선언된블록안에서만이용이가능하다 int a = 2; /* outer block a */ printf("%d\n", a); /* 2 is printed */ int a = 5; /* inner block a */ printf("%d\n", a); /* 5 is printed */ /* back to the outer block */ printf(%d\n", ++a); /* 3 is printed */
46 유효범위규칙 외부블록이름은내부블록이그것을다시정의하지않는한, 내부블록에서도유효함 만일다시정의된다면, 외부블록이름은내부블록으로부터숨겨짐
47 유효범위규칙 int a = 1, b = 2, c = 3; printf("%3d%3d%3d\n", a, b, c); // 1 2 3 int b = 4; float c = 5.0; printf("%3d%3d%5.1f\n", a, b, c); // 1 4 5.0 a = b; int c; c = b; printf("%3d%3d%3d\n", a, b, c); // 4 4 4 printf("%3d%3d%5.1f\n", a, b, c); // 4 4 5.0 printf("%3d%3d%3d\n", a, b, c); // 4 2 3
48 병렬블록과중첩블록 int a, b;... /* inner block 1 */ float b;... /* int a is known, but not int b */... /* inner block 2 */ float a;... /* int b is known, but not int a */ /* nothing in inner block 1 in known */...
49 디버깅을위한블록사용 블록은디버깅을위한목적으로많이사용 코드부분에임시로블록을삽입하면, 프로그램의다른부분에영향을주지않는지역변수를사용할수있음 v가이상한값을갖는다고가정 /* debugging starts here */ static int cnt = 0; printf("*** debug : cnt = %d v = %d\n", ++cnt, v);
메모리영역 메모리영역 내용 코드영역실행파일의바이너리코드를저장하는공간 메모리영역분류 데이터영역 스택영역 힙영역 프로그램이종료될때까지유지할데이터를저장할공간 전역변수가저장 함수내에서만사용할데이터 ( 지역변수, 매개변수 ) 저장공간 블록내부 ( 일시적 ) 에서만유효, 블록안에서선언 동적할당메모리공간 (malloc() 으로동적할당 ) 블록내부 ( 일시적 ) 에서유효, 블록안에서 (static 사용 ) 선언 프로젝트내의여러파일에서유효, 함수의밖에서 (extern 사용 ) 선언 하나의파일 ( 영구적 ) 에서유효, 함수의밖에서 (static 사용 ) 선언
52 기억영역 C 의모든변수와함수는두가지속성을가짐 자료형, 기억영역 변수의생존기간을결정하는요인 변수가선언된위치 저장유형지정자 (4가지기억영역 ) 자동 (auto), 외부 (extern), 레지스터 (register) 정적 (static)
53 자동변수 (auto) 함수의몸체에서선언된변수는디폴트로자동 블록안에서선언된변수는묵시적으로자동기억영역이됨 auto를사용하여기억영역을명시할수도있지만, 보통은사용하지않음 블록을들어갈때, 자동변수들을위해메모리가할당되고, 블록을빠져나갈때, 자동변수가할당받은메모리는회수됨 지역변수는 auto가생략되어도자동변수가됨 int main(void) auto int sum = 0; int i = 0;...... 전부자동변수로서함수가시작되면생성되고끝나면소멸된다.
54 외부변수 (extern) 전역변수로만사용 함수밖에선언되고프로그램모든부분에서유효자동변수와외부변수의선언방법은유사하지만 함수내부선언 자동변수 함수외부선언 외부변수 같은파일내에서의외부변수 외부변수는함수의외부에서만정의하는데 extern을생략해도위치로판단할수있음 외부변수가사용하고자하는외부변수보다하단에정의되어있으면반드시 extern을사용해야함 예 ) int x =1 ; // 외부변수정의 main() int y = 2; // 자동변수정의 extern int z;.. int z=10;
55 프로그램이종료될때까지메모리에계속남아있음 외부변수들은자동이나레지스터기억영역을가질수없음 extern 변수는다른곳에서메모리할당을한것이므로선언할때메모리영역을할당하지않음 extern 변수는전방선언 (forward declaration) 할때유용하게사 용 전방선언 : 일반함수들이앞에오고뒤에 main( ) 가위치하는선언방식
56 예제 ) #include <stdion.h> int a = 1, b = 2, c = 3; /* global variables */ /* or extern int a = 1, b = 2, c = 3; */ int f(void); /* function prototype */ int main(void) printf("%3d\n", f()); /* 12 */ printf("%3d%3d%3d\n", a, b, c); /* 4 2 3 */ return 0; int f(void) int b, c; /* b and c are local */ a = b = c = 4; return (a + b + c);
57 register 변수 Register 변수는컴파일러에게가능하다면고속메모리레지스터에저장되도 록함 한정된자원으로인해할당하지못하면, 이변수는디폴트로자동변수가됨 사용하기바로전에선언하는것이좋음 ( 일반적으로컴파일러가사용할수 있는 register 수는한정적임 ) 실행속도증가를위해사용 예 ) register int i; for(i = 0;i < 100; i++) sum += i; CPU 안의레지스터에변수가저장됨
58 정적변수 (static) 정적변수선언은두가지중요한용도로사용됨 블록에서선언된변수가프로그램이끝날때까지그값을계속유지함 일반자동변수는블록을나갈때값이소멸 ( 반환 ) 되고다시블록안으로 들어갈때다시초기화됨. 프로그램에서오직하나만존재하는변수가되어공유 함수내부에서선언되면그블록안에서만유효한지역변수역할 static 지역변수도전역변수처럼선언시점에서한번만초기화 함수외부에서선언되면전역변수로동작하지만, 정적변수의유효범위는파일유효범위를갖음 현재의소스파일에서만사용할수있고, 다른소스파일에서는보이지 ( 차단, 숨겨짐 ) 않아사용할수없음
59 예제 ) #include <stdio.h> void sub(void); int main(void) int i; for(i = 0;i < 3; i++) sub(); return 0; 자동지역변수 void sub(void) int auto_count = 0; static int static_count = 0; auto_count++; static_count++; printf("auto_count=%d\n", auto_count); printf("static_count=%d\n", static_count); 정적지역변수로서 static 을붙이면지역변수가정적변수로된다. 출력값 auto_count=1 static_count=1 auto_count=1 static_count=2 auto_count=1 static_count=3
60 예제 1) 의사난수발생기예제 #define INITIAL_SEED 17 #define MULTIPLIER 25173 #define INCREMENT 13849 #define MODULUS 65536 #define FLOATING_MODULUS 65536.0 static unsigned seed = INITIAL_SEED; /* external */ /* but private to this file */ unsigned random(void) seed = (MULTIPLIER * seed + INCREMENT) % MODULUS; return seed; double probability(void) seed = (MULTIPLIER * seed + INCREMENT) % MODULUS; return (seed / FLOATING_MODULUS);
61 예제 2) 함수의유효범위제한 static 함수는자신이선언되있는파일내에서만접근가능 함수정의를비공개모듈로구현하는데유용함 예 ) static int g(void); /*function prototype*/ void f(int a) /*function definition*/. /* g() is available here, but not in other files */ static int g(void).. /*function definition*/
62 디폴트초기화 외부변수와정적변수는프로그래머가초기화하지않아도시스템에의해 0으로초기화됨 같은방식 : 배열, 문자열, 포인터, 구조체, 공용체 자동변수와레지스터변수는일반적으로시스템 에의해초기화되지않음
63 재귀함수 함수내부에서자기자신의함수를다시호출 ( 재귀호출 ) 하는순환호출함수 복잡한알고리즘을간략하게구현가능 재귀는각호출을위한인자와변수를스택에쌓아두어관리하기때문에많은시간과공간을요구함 즉, 재귀를사용할때에는비효율성을고려해야함 그러나일반적으로재귀적코드는작성하기쉽고, 이해하기쉬우며, 유지보수하기가쉬움
64 재귀 단순한재귀적루틴은일반적인패턴을따름 재귀의일반적인패턴에서는기본적인경우와일반적인재귀경우를처리하는코드가있음보통두경우는한변수에의해결정됨 일반적인재귀함수의제어흐름 1. 변수를검사하여기본적인경우인지일반적인경우인지를결정 2. 기본적인경우일때에는더이상재귀호출을하지않고필요한값을리턴 3. 일반적인경우일때에는그변수의값이결국에기본적인경우의값이될수있게하여재귀호출
65 재귀 예제코드 int sum(int n) if (n <= 1) return n; /* 기본적인경우 */ else /* 일반적인경우 */ return (n + sum(n - 1)); 위예제코드에서는 n 을사용하여두경우를판단 1. n 이 1 보다작거나같으면기본적인경우임 n 을리턴 2. 아니면일반적인경우임 n 에서 1 을빼어재귀호출 ==> n 에서 1 을뺐기때문에언젠가 n 은 1 보다 작거나같아질것임
하노이탑문제 #1 하노이탑문제는막대 A 에쌓여있는원판 3 개를막대 C 로동일한모양으로옮기는것임. 단다음의조건을지켜야함. 한번에하나의원판만이동할수있다 맨위에있는원판만이동할수있다 크기가작은원판위에큰원판이쌓일수없다. 중간의막대를임시적으로이용할수있으나앞의조건들을지켜야한다. A B C
하노이탑알고리즘 // 막대 from 에쌓여있는 n 개의원판을막대 tmp 를사용하여막대 to 로옮긴다. void hanoi_tower(int n, char from, char tmp, char to) if (n == 1) from 에서 to 로원판을옮긴다. else from 에있는한개의원판을 to 로옮긴다.
참고문헌 열혈 C 프로그래밍, 윤성우, 오렌지미디어 쉽게풀어쓴 C 언어 Express, 천인국, 생능출판사 뇌를자극하는 C 프로그래밍, 서현우, 한빛미디어 쾌도난마 C 프로그래밍, 강성수, 북스홀릭 C 프로그래밍기초와응용실습, 고응남, 정익사 68
69