문서의 제목 나눔명조r, 40ptcontents.kocw.net/kocw/document/2014/dongguk/choyoungsuk... ·...

31
9 차시 : 함수 프로그래밍 실험 9동국대학교 조영석 문서는 나눔글꼴로 작성되었습니다. 설치하기

Upload: others

Post on 06-Feb-2021

0 views

Category:

Documents


0 download

TRANSCRIPT

  • 9차시: 함수

    • 프로그래밍 및 실험 • 제 9주 • 동국대학교 조영석

    이 문서는 나눔글꼴로 작성되었습니다. 설치하기

    http://hangeul.naver.com/

  • 2

    - 함수의 인자 개수가 가변적 : 생략기호(...)를 사용.

    (예)

    int .... printf(const char * _format, ...);

    - 함수 원형과 컴파일러.

    • 코드를 더 철저히 검사.

    • 함수로 전달되는 값을 적절한 형으로 변환.

  • 3

    5.4 예제 : 거듭제곱표 생성하기

    #include

    #define N 7

    long power (int, int); /* function prototype */ void prn_heading(void); /* function prototype */ void prn_tbl_of_powers(int); /* function prototype */

    int main (void) { prn_heading( ); prn_tbl_of_powers(N); return 0; }

    void prn_heading(void) { printf("\n::::: A TABLE OF POWERS :::::\n\n"); }

  • 4

    void prn_tbl_of_powers(int n)

    {

    int i, j;

    for (i = 1; i

  • 5

    long power(int m, int n) { int i;

    long product = 1;

    for (i = 1; i

  • 6

    5.5 컴파일러 관점에서 함수 선언

    5.6 함수 정의 순서의 다른 방법

    - 함수의 원형이 선언되지 않은 경우

    • 불리우는 함수(callee)는 부르는 함수(caller)보다 먼저 정의 되어야 함.

    • 함수의 정의 순서가 매우 중요함. 따라서,

    함수의 정의 순서에 각별히 유의 해야 함.

    • 재귀호출(recursion)의 경우, 문제가 발생할 우려가 있음.

    • 함수 원형을 선언하고 main부터 정의 하는 것이 바람직함.

  • 7

    (예) #include #define N 7

    void prn_heading(void) { ... } /* main 함수 직전에 */

    /* 정의되어도 무방함. */

    long power(int m, int n) { ... } /* prn_tbl_of_power 앞에*/

    void prn_tbl_of_power (int n) { ... power(i, j); }

    int main(void) { prn_heading( ); prn_tbl_of_powers(N); ... }

  • 8

    5.7 함수 호출과 값에 의한 호출(call-by-value)

    - 항상 main( ) 함수부터 실행.

    - program의 제어가 함수의 이름을 만나면 그 함수가 호출됨.

    즉, program의 제어가 그 함수로 넘어감.

    - 호출된 함수의 실행이 완료되면 program의 제어는 함수를

    호출한 환경으로 다시 넘어감.

  • 9

    - 함수의 호출

    • 함수의 이름과 '(인자목록)'을 사용(argument list).

    • 인자 목록의 각각의 인자는

    매개 변수 목록(parameter list)의 각각의 매개 변수의

    개수와 형이 순서에 따라 일치(또는 호환)해야 함.

    • 모든 인자는 "값에 의한 호출(call-by-value)"로 전달됨.

    - 각 인자가 평가된 후 그 값이 대응되는 형식 매개변수의

    위치에서 지역적으로 사용됨. 즉, caller의 변수 값이

    callee에게 전달되고, callee 환경에서 값이 변경되어도

    caller 환경의 변수의 값은 변경되지 않음.

  • 10

    (예1)

    int callee(int x, int y) /* x, y : 매개변수(parameter) */ { x = x + 1; /* 매개변수 값을 변경 (x : i) */ y = y + 1; /* 매개변수 값을 변경 (y : j) */ return x + y; /* 수식의 값을 return */ }

    void caller(void) { int i = 10, j = 20, k; k = callee(i, j); /* i, j : 인자(argument) */ printf("%d %d %d", i, j, k); /* x, y는 참조 불가능 */ }

    실행결과 : 10 20 32

  • 11

    (예 2) #include int G = 99; int A (int, int); int main ( ) { int i = 10, j = 20, k; k = A(i, j); G ++; printf("\nFrom main : i=%d, j=%d, k=%d, G=%d", i, j, k, G); return 0; } int A (int i, int j) { int k = 0; i = i * 10; j = j * 10; ++G; printf("From A : i=%d, j=%d, k=%d, G=%d", i, j, k, G); return i + j; }

    실행결과 : Form A : i=100, j=200, k=0, G=100 Form main : i=10, j=20, k=300, G=101

  • 12

    - 변수의 범위(scope)

    G

    main

    i j k k = A(i, j);

    k return i + j;

    j 20 i 10

    10 20

    0

    99

    A()

  • 13

    - 인수는 매개변수에 값을 전달.

    - 인수와 매개변수는 이름이 같거나 다르거나 별개의 지역 변수.

    - 매개 변수의 값은 되전달되지 않음.

    - 한 함수 내에서 선언된 변수는 다른 함수내에서는 참조할 수

    없음(local variable).

    - 전역 변수는 선언된 장소 이후에서는 어디서든 참조 가능.

  • 14

    - 함수 호출시의 동작 순서

    1. 인자 목록의 각 수식이 평가됨.

    2. (필요한 경우 각 수식의 값이 매개변수의 형으로 변환 됨.)

    함수 body의 시작 부분에서 그 값이 대응되는 형식 매개

    변수(formal parameters)에 할당됨.

    3. 함수 body의 실행.

    4. return 문을 만나거나 함수의 끝에 다다르면 제어는

    호출한 환경으로 넘어감.

    5. return문이 수식을 가지고 있다면 그 수식의 값이 함수의

    형으로 변환되어 호출한 환경으로 넘어감.

    6. return 문이 수식을 가지지 않으면 값의 return 없음.

    7. 모든 인자는 "값에 의한 호출(call-by-value)"로 넘어감.

  • 15

    5.8 대형 program의 개발

    - 여러개의 .c file을 하나의 실행 file로 만들기.

    • 모든 .c file에 포함되는 .h file을 생성하여

    모든 .c file에 include.

    • 여러개의 .c file을 묶어 compile 한 후 실행 file 생성.

    (ex) gcc -o pgm main.c func1.c func2.c

    main.c, func1.c, func2.c의 3개 file을

    하나의 실행 file pgm을 생성함.

    5.9 단정

    5.10 유효범위 규칙 (Scope Rules)

    - 식별자(identifire)는 그 식별자가 선언된 block 안에서만

    접근(access)이 가능함.

  • 16

    (예)

    {

    int a = 2, b =10;

    printf("%d %d\n", a, b); {

    int a = 5;

    printf("%d %d\n", a, b); }

    printf("%d %d\n", a, b); }

    실행결과 :

    2 10

    5 10

    2 10

  • 17

    a b

    - block 외부에서 내부로의 참조는 불가능.

    - block 내부에서 외부로의 참조는 가능(충돌이 없을 경우).

    2 10

    a 5

  • 18

    - 병렬블럭과 중첩블럭

    { int a, b; ... { float b; /* 바깥 블럭의 b는 참조할 수 없음.-변수명 중복 */ ... } {

    float a;

    /* 바깥 블럭의 a는 참조할 수 없음.-변수명 중복 */

    /* 위 병렬블럭의 float b;는 scope가 달라 참조할 수 없음.*/

    ...

    }

    /* float a; float b;는 scope가 달라 참조 불가능. */

    }

  • 19

    5.11 기억영역 클래스

    - auto : default int a, b; auto int a, b; 제어가 블럭을 빠져나갈 때 auto 변수들을 위한 메모리들은 sysytem에 반환됨.

    - extern extern int a, b; 다른 file에 외부변수(전역변수)로 선언된 변수를 사용하는 경우.

    - register register int i; 실행속도를 증가시키기 위해 변수를 register에 할당.

    - static 한 블럭에서 사용된 변수의 값이 제어가 블럭 밖으로 빠져나와도 유지되어 다시 그 블럭으로 제어가 넘어갈 때 그 값을 재사용 가능함.

  • 20

    (static 변수의 예)

    void call_count ( ) { static int count = 0; ++ count; printf("%d", count); }

    • 최초의 호출 시 count는 0으로 초기화 됨.

    • 함수가 끝날 때 count 값은 memory에 보존 됨.

    • 다시 호출될 때에는 count가 초기화 되지 않고 memory에 보존된 값을 사용.

    • 위의 프로그램으로 이 함수가 몇 번 호출되었는지 알 수 있음.

  • 21

    5.12 정적외부변수

    5.13 디폴트 초기화

    5.14 재귀호출(recursive call, recursion)

    - 함수가 직접적이건 간접적이건 자신을 호출하는것.

    (예 1)

    int A (int b) /* 직접 자신을 호출 */

    {

    int x=10;

    ...

    c = A(x);

    ...

    }

  • 22

    (예 2)

    int A (int b) /* 간접적으로 자신을 호출 */

    {

    ...

    B(x); /* B의 prototype이 A보다 먼저 정의되어야 함 */

    ...

    }

    int B (int t)

    {

    ...

    k = A(y);

    ...

    }

  • 23

    - 재귀 함수의 예

    int Sum(int n) { if (n

  • 24

    동작원리 : int Sum(int n) { int temp;

    n = 4 일 경우 : sum(4)를 호출 if (n

  • 25

  • 26

  • 27

    동작원리 : int Fac(int n) { int temp;

    n = 4 일 경우 : Fac(4)를 호출 if (n

  • 28

    (예 3) 입력된 문자열의 역순 출력

    #include

    void reverse(void);

    void main () {

    printf("\nInput a character string: \n");

    reverse(); }

    void reverse() {

    int c;

    if ((c=getchar()) != '\n')

    reverse();

    putchar(c); /* 출력이 실제로 이루어짐 */ }

  • 29

    동작원리: "abcd'\n'"이 입력됨

    1st call: c == 'a' (!= '\n', ∴ call reverse again)

    2nd call: c == 'b' (!= '\n', ∴ call reverse again)

    3rd call: c == 'c' (!= '\n', ∴ call reverse again)

    4th call: c == 'd' (!= '\n', ∴ call reverse again)

    5th call: c == '\n' (stop recursion)

    putchar('\n'); (return to 4th call environment)

    4th call: putchar('d'); (return to 3rd call)

    3rd call: putchar('c'); (return to 2nd call)

    2nd call: putchar('b'); (return to 1st call)

    1st call: putchar('a'); (function process ends.)

  • 30

    (예 4) Fibonacci Numbers

    - Fibonacci Numbers의 정의

    f0 = 0 f1 = 1 fi+1 = fi + fi-1, for i = 1, 2, ... (== fi = fi-1 + fi-2, for i = 2, 3, ...)

    - 재귀 함수의 정의 int Fibo (int i) { if (i == 0) return 0; else if (i == 1) return 1; else return (Fibo (i - 1) + Fibo(i -2)); }

    간단한 표현 : if (i

  • 이 문서는 나눔글꼴로 작성되었습니다. 설치하기

    감사합니다.

    http://hangeul.naver.com/font

    9차시: 함수슬라이드 번호 2슬라이드 번호 3슬라이드 번호 4슬라이드 번호 5슬라이드 번호 6슬라이드 번호 7슬라이드 번호 8슬라이드 번호 9슬라이드 번호 10슬라이드 번호 11슬라이드 번호 12슬라이드 번호 13슬라이드 번호 14슬라이드 번호 15슬라이드 번호 16슬라이드 번호 17슬라이드 번호 18슬라이드 번호 19슬라이드 번호 20슬라이드 번호 21슬라이드 번호 22슬라이드 번호 23슬라이드 번호 24슬라이드 번호 25슬라이드 번호 26슬라이드 번호 27슬라이드 번호 28슬라이드 번호 29슬라이드 번호 30감사합니다.