350 likes | 587 Views
C By Dissection. 제 4 장 Functions and Structured Programming. 강 의 내 용. 4.1 함수 호출 4.2 함수 정의 4.3 return 문 4.4 함수 프로토타입 4.5 하향식 설계 4.6 정확한 프로그램의 작성을 위한 assert() 매크로의 사용 4.7 컴파일러가 인식하는 함수선언 4.8 문제풀이 : Random Numbers 4.9 함수 정의를 나열하는 방법 4.10 큰 프로그램의 개발
E N D
C By Dissection 제 4 장 Functions and Structured Programming
강 의 내 용 • 4.1 함수 호출 • 4.2 함수 정의 • 4.3 return 문 • 4.4 함수 프로토타입 • 4.5 하향식 설계 • 4.6 정확한 프로그램의 작성을 위한 assert() 매크로의 사용 • 4.7 컴파일러가 인식하는 함수선언 • 4.8 문제풀이 : Random Numbers • 4.9 함수 정의를 나열하는 방법 • 4.10 큰 프로그램의 개발 • 4.11 시뮬레이션 : Game of Heads or Tails • 4.12 값 기반(Call-by-Value) 함수 호출 • 4.13 재귀 호출 • 4.14 프로그래밍 스타일 • 4.15 자주 발생하는 프로그래밍 오류 • C-언어의 함수는 매우 중요 • 함수를 많이 만들어 볼 것 • 함수란? • 기본적으로 명령어 모음
4.1 함수 호출 • Function • C 모든 c-program은 반드시 한 개의main() Function을 포함 • Function의 종류 • Library functions : System이 제공하는 Predefined-Functions • User-defined functions : Programmer에 의해 작성된 Functions • Function Invocation • Function의 호출 : Function_name()의 형식으로 사용. • Function의 종료 : Function을 Call한 곳으로 제어 권의 이동 • Function을 많이 정의(만들어)하여 필요 시 마다 그 function을 Call (simplicity 향상) C Program실행 시 OS에 의해 자동으로 호출되어 수행
4.1 함수 호출 #include <stdio.h> void prn_message(void); int main() { prn_message(); return 0; } void prn_message(void) { printf(“A message for you: ”); printf(“Have a nice day!\n”); } Function Prototype : Function을 사용하기 위해 선언 필요 Function Invocation : ‘hello()’ Function을 사용하기 위해 호출 Function Definition : Function 이 수행할 내용을 정의 A message for you: Have a nice day!
4.2 함수의 정의 • Function Definition • Function이 호출되기 전 반드시 해당 Function을 다음 형식으로 정의 • return-type function_name (parameter type list) • { • declarations • statements • } Function 수행이 끝난 후 Return되는 값의 type Function 에 전달되는 argument의 수와 type Function body
4.2 함수의 정의 • Parameter Type List • Function 호출 시 전달되는 arguments에 대응되는 순서와 data types • Function body내에서 identifier 로 사용될 수 있다. • 정의에 열거된 인자(x와 y)는 함수가 호출될 때 넘겨받는 값을 저장하는데 사용됨 • Return type • Function 종료될 때 return statement에 의해 전달되는 data의 type. • void type : Return Value가 없는 경우 void로 지정 [Ex] int a = 10, b = 20; printf(“sum = %d “, sum(a, b)); int sum(int x, int y){ return x + y; }
4.2 함수의 정의 #include <stdio.h> void prn_message(int k); /* function prototype */ int main(void) { int how_many; printf(“%s”, “There is a message for you.\n”); printf(“How many times do you want to see it? “); scanf(“%d”, &how_many); prn_message(how_many); /* function call or invocation */ return 0; } /* function definition is next page */
4.2 함수의 정의 void prn_message(int no_of_message) /* function definition */ { int n; printf(“Here is the message: “); for (n = 0; n < no_of_message; n++) printf (“Have a nece day!\n”); } function prototype (int k) 와 정의 부분 (int no_of_message) 의 이름은 서로 달라도 됨 여러분이 만들 때는 같은 이름을 사용할 것을 권함 There is a message for you How many times do you want to see it? 2 Here is the message: Have a nice day! Have a nice day!
4.3 return 문 • return 문이 수행되면 함수의 실행이 끝나고 함수를 호출한 함수로 프로그램 제어가 즉시 돌아감 • return 문의 사용 • return; /* return Type이 void 인 경우 */ • return expression; /* return Type이 있는 경우 */ • return 77; • return ++a; • return (a+b+c);
4.3 return 문 (실행 결과?) int min(int first, int second) { if (first < second) return first; else return second; } #include <stdio.h> int min(int a, int b); int main(void) { int j, k, mininum; printf(“Input two integers: “); scanf(“%d%d”, &j, &k); minimum = min(j, k); printf(“\nOf the two voalues %d and %d, “ “the minimum is %d.\n\n”, j, k, minimum); return 0; }
4.4 함수 프로토타입 • Function Prototypes • Function 사용을 위해 호출 전에 반드시 필요한 Function 선언문 • function prototype이 생략 가능한 경우 • main() 함수처럼 사용되기 전에 정의 된 경우 가능. • 선언(prototype) 또는 정의(define) 되기 전에 사용(call) 될 수 없음. • 무조건 선언 한다고 생각하면 됨. • 선언 형식 • return-type function_name ( parameter type list ); [Ex]double sqrt(double); get_interest(double principal, double rate, int months); /* Readability를 위해 Identifier의 사용 가능, get_interest(double, double, int); 와 동일 return type이 생략된 경우 int로 간주 */
4.5 하향식 설계 • Top-down design • One big program => 작은 단위의 subtasks (modules or functions)로 분할하여 subtask단위로 program작성 • 복잡한 기능의 한 program을 간단한 module로 분할, module단위로 code를 작성 함으로서 programming의 용이 • 특정 기능을 수행하는 module별로 Code를 이해 함으로서 Readability의 증가
4.5 하향식 설계 • 정수형의 자료가 기록되어 있는 파일 분석 문제 • 정수를 하나 씩 읽고, 자료의 개수, 자료 값, 합계, 최소값, 최대값 • 한 줄씩 출력, 각 page 상단에 표제 출력 • Running Sum Program의 분해 • 표제를 출력한다…prn_banner(); • 각 열(column)의 제목을 출력한다. …prn_headings(); • 자료를 읽고 처리하여, 열을 맞추어 출력한다. …read_and_prn_data(); • 다음 과정은 man ()함수의 루틴을 설계하고 각 모듈을 완성하는 것이다…
4.6 assert () 매크로의 사용 • The assert() • header file <assert.h>에 정의된 Macro (not Function) • 형식void assert(int exp); • expression의 결과가 0라면, 대개 다음과 같은 statement를 출력하고 종료Assertion failed:<exp>,file <file_name>, line <line_number> • Otherwise, assert() does nothing. • Function의 잘못된 수행의 점검 가능
4.6 assert () 매크로의 사용 #include <assert.h> double f(int a, int b) { double x; assert(a > 0); assert(b >= 7 && b <= 11); …… assert(x >= 3.0); return x; } 함수 f() 가 전달 받은 두 개의 값의 범위 확인(a > 0, 7<= b <= 11) return 값이 (x >= 3.0)인지 확인
4.7 컴파일러가 인식하는 함수 선언 • 이번 절은 전통적인 선언 방법과 ANSI C 형식의 함수 정의 방법을 설명 • 전통적인 방법은 컴파일러에게 충분한 정보를 전달 할 수 없음 • 따라서… • ANSI C 형식으로 선언하는 것이 바람직 함 • 함수 프로토타입에 인자의 이름을 기술하지 않아도 되지만… • 함수의 정의 부분과 같은 이름을 주어 선언하는 것이 도움이 됨 • * 함수를 선언하고…복사해서…정의할 부분에 붙여 넣어 정의
4.8 문제 풀이: Random Numbers • rand() Function • <stdlib.h>와 관련된 Function • Random number의 양의 정수 값 (int)을 반환한다. • 특정 범위의 난수 생성 시 다음과 같은 식 사용rand() % max_bound + lower_bound;Simulation 등 여러 가지 유용한 용도로 사용된다. 0 ~ stdlib.h에서 정의된 RAND_MAX(Ex. 32767)사이의 integer를 return [Ex] int month = rand( )%12 + 1; /* 1~12사이의 값*/
4.8 문제 풀이: Random Numbers • srand() Function (참고 사항임... 직접 확인 바람) • random generator를 위한 seed value를 설정 • srand()의 호출을 명시하지 않은 경우 프로그램이 시작될 때 seed를 1로 하는 srand(1)이 자동으로 호출된다. (숫자의 발생 순서가 같음) • 프로그램이 수행될 때마다 rand()가 다른 value를 return 할 수 있게 하는 Function : rand()를 사용하기 전에 호출되어야 한다. [Ex] #include <time.h> int seed = time(NULL); srand(seed); : rand( ); /* time(NULL)을 쓰기 위해 필요*/ /* srand(time(NULL)); 와 동일*/
4.8 문제 풀이: Random Numbers #include <stdio.h> #include <stdlib.h> /* use for rand () function */ int max(int a, int b); int min(int a, int b); void prn_random_numbers(int k); /* random num 생성 및 출력 */ int main(void) { int n; printf(“Some random numbers will be printed.\n”); printf(“How many would you like to see? “); scanf(“%d”, &n); /* random num 생성 개수 입력받음 */ prn_random_numbers(n); return 0; }
4.8 문제 풀이: Random Numbers void prn_random_numbers(int k) { int i, r, biggest, smallest; r = biggest = smallest = rand(); /* 최초의 발생 숫자를 이용하여 초기화 */ printf(“\n%7d”, r); /* %7d…자릿수를 7개 확보하여 출력함*/ for(i=1; i<k; ++i) { if (i%7 == 0) printf(“\n”); r = rand(); biggest = max(r, biggest); /* 최소값 구하여 저장하기*/ smallest = min(r, smallest); printf(“%7d”, r); } /* k개의 random numbers 발생시켜 최대, 최소 값을 구해 출력*/ printf(“\n\n%s%5d%s%5d\n%s%5d\n\n”, ” Count: “, k, “Maximum: “, biggest, “Minimum: “, smallest); }
4.9 함수 정의를 나열하는 방법 • 한 개의 file로 작성된 program의 일반적 순서 1. #include, #define statements 2. Enumeration types and typedef. 3. struct definition 4. Function Prototypes 5. main() Function 6. Function Definitions 보통 Header File 을 만들어 Header File을 포함시킴 정의 부분…선언 부분…임 function 호출 전 즉 main( ) function 전에 function definition이 먼저 정의 된 경우 function prototypes의 생략 가능
4.9 함수 정의를 나열하는 방법 • 함수를 사용(Call) 하기 위해서는 함수의 프로토타입이 먼저 선언 되거나 함수가 정의 되어 있어야 한다. fun2()에서 fun1() 사용 가능 fun1() 정의는 뒤에 있지만 void fun1(void); void fun2(void){ fun1(); fun3(); } void fun3(void){ fun1(); fun2(); } void fun1(void) {…} fun2()에서 fun3() 사용 불가능 선언이 없고 정의가 뒤에 있음 fun3()에서 fun1()과 fun2() 사용 가능 fun1() : 선언이 먼저 있음 fun2() : 정의가 먼저 있음
4.10 큰 프로그램의 개발 • Developing a large Program • 대규모 Program의 경우, 여러 ~.h파일과 ~.c파일로 나누어 작성할 수 있다. • 프로젝트파일은 이러한 여러 개의 파일을 관리하기 위한 것임 • 메인 함수는 한 개만 있어야 하고…메인 함수에서 시작됨. • Team에 의한 작업분담이 용이해진다. (프로그램 설계 단계) • 정보의 저장 방법의 결정되면…정보의 처리 방법을 결정 함… • 프로그램이 변경될 때마다 변경된 ~.c 파일만을 compile함으로서 시간 절약 가능.
4.10 큰 프로그램의 개발 pgm.h #include #define … /* typedef, struct definition */ function prototypes main.c fct.c prn.c #include “pgm.h” int main(void) { … } #include “pgm.h” … #include “pgm.h” … /* 모든 files (pgm.h, main.c, fct.c, prn.c)이 동일 directory에 저장 */ Compile : cc –o filename main.c fct.c prn.c
4.11 시뮬레이션 : Game of Heads of Tails In file heads_or_tails.h: #include <srdio.h> #include <stdlib.h> #defineMAXWORD100 /* 사용함수 프로토타입 선언 */ intget_call_from_user(void); voidplay(int how_many); voidprn_final_report(int win, int lose, int how_many); voidprn_instructions(void); voidreport_a_win(int coin); voidreport_a_loss(int coin); inttoss(void);
4.11 시뮬레이션 : Game of Heads of Tails 동전의 앞 뒷면 맞추기 개임 random numbers를 이용하여 동전을 던지고…개임 참여자가 맞추게 하는 개임 In file main.c: #include "heads_or_tails.h" int main(void) { charans; intno_of_plays; printf("\nTHE GAME OF HEADS OR TAILS\n\nDo you want instructions? "); scanf(" %c", &ans); putchar('\n'); if (ans == 'y' || ans == 'Y') prn_instructions(); /* 개임 정보 출력*/ printf("How many times do you want to play? "); scanf("%d", &no_of_plays); putchar('\n'); play(no_of_plays); /* 개임 반복 횟수 입력*/ return 0; }
4.11 시뮬레이션 : Game of Heads of Tails In file prn.c: #include "heads_or_tails.h" void prn_instructions(void) /* 개임 정보 출력*/ { printf("%s\n", "This is the game of calling heads or tails.\n" "I will flip a coin; you call it. If you\ncall it correctly, you win; otherwise,\n" "I win.\n\nAs I toss the (simulated) coin, I will\ntell you to \"call it.\“” “To call heads,\ntype 0; to call tails, type 1.\n\n"); } void prn_final_report(int win, int lose, int how_many) /* 개임 결과 출력*/ { printf("\n"); printf("FINAL REPORT:\n"); printf(" Number of games that you won: %3d\n", win); printf(" Number of games that you lost: %3d\n", lose); printf(" Total number of games: %3d\n\n", how_many); }
4.11 시뮬레이션 : Game of Heads of Tails In file play.c: #include "heads_or_tails.h" void play(int how_many)/* machine tosses, user calls */ { intcoin, i, lose = 0, win = 0; /* <- 사람이 맞춤*/ for (i=0; i<how_many; ++i) { coin = toss(); /* <- 컴퓨터 동전*/ if (get_call_from_user() == coin) { ++win; report_a_win(coin); } else { ++lose; report_a_lose(coin); } } prn_final_report(win, lose, how_many); } int toss(void) { return (rand() % 2);/* 0 = heads, 1 = tails */ }
4.11 시뮬레이션 : Game of Heads of Tails In file get.c: #include "heads_or_tails.h" int get_call_from_user(void) /* 입력 받는 과정에서 Error Check 중요*/ { intguess;/* 0 = heads, 1 = tails */ do { printf("Call it: "); if (scanf("%d", &guess) != 1) { /* 숫자 이외의 문자 입력하면 프로그램이 끝남 */ printf("\nSORRY: Serve input error - bye!\n\n"); exit(1); /* 프로그램이 끝남 */ } if (guess != 0 && guess != 1) { /* 0이나 1이 아니면 0과 1만 입력할 수 있다는 메시지 출력 */ printf("\n%s\n\n", "ERROR: Type 0 for heads, 1 for tails."); } } while (guess != 0 && guess != 1); /* 0과 1 이외의 숫자이면 재입력 받기 위해 반복시킴 */ return guess; }
4.12 값기반(Call-by-Value) 함수 호출 • Call-by-Value (값이 복사 되어 전달 됨) • Function Invocation이 일어나면, argument의 value를 전달 받기 위한 parameter를 위해 메모리영역이 새로 생기며 argument의 값이 새 영역에copy된다. • Function Invocation의 parameter를 identifier로 사용하여 그 값을 function내에서 변경한 경우에도 다른 memory영역을 사용 함으로서 실제 argument의 값은 변경되지 않는다. • 함수를 호출한 함수의 변수 값은 변하지 않는다… Call-by-Value
4.12 값기반(Call-by-Value) 함수 호출 #include <stdio.h> intcompute_sum(int n); int main(void) { intn = 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 int's from 1 to n */ { /* in compute_sum(), n은 in main (), n과 전혀 상관이 없음 /* intsum = 0; /* in compute_sum(), n값은 in main (), n값의 복사 값을 가지고 있음 */ for ( ; n > 0; --n)/* in main(), n is unchanged */ sum = sum + n; printf("%d\n", n);/* 0 is printed */ return sum; }
4.13 재귀 호출 • 자기 자신이 자기 자신을 호출하는 함수 • 함수가 반복적을 실행됨 • 재귀 호출과 반복문은 종결 조건이 발생할 때 까지 실행됨 • 초보자 : 재귀호출 사용할 때 실수하기 쉬움(종결 조건) void r_prn_message(int k) { if (k > 0) { /* k값이 0보다 작거나 같으면 재귀 호출 종료 됨*/ printf("Have a nice day!\n"); r_prn_messages(k -1);/* recursive function call */ } }
4.14 프로그래밍 스타일 • 함수의 프로토타입을 반드시 선언하는 것이 좋음 • 함수의 이름과 인자의 이름은 그 기능을 잘 표현되게 • 함수의 프로토타입을 헤더파일에 선언하였다면… 함수 정의 부분의 위치관계는 중요하지 않음…(선택사항) • 함수 정의 부분의 위치는 함수를 Call 하는 함수와 가까이 있으면 좋음 • 관련이 있는 함수를 모아 하나의 파일로 만들면 좋음
4.15 자주 발생하는 프로그래밍 오류 • C 언어의 함수는 call-by-value기반임을 명심 • 함수의 프로토타입은 반드시 선언할 것 • 함수 이름에 일관성을 유지할 것 (대소문자, _, 적절히 혼합하여…) • exit (expr); • main () 함수가 아닌 다른 함수에서 함수가 호출되면… • 프로그램이 중단 됨 • exit (expr); • expr 부분 잘 활용하면…어디에서 중단되었는지 찾을 수 있음…
함수를 많이 만들어 보는 것이 프로그램 공부의 지름길 수고하셨습니다. Functions And Structured Programming