프로그래밍웹 교과서
이 페이지의 목차
2단원 · 16차시

함수로 프로그램 나누기

모듈화기능 분해함수 설계재사용

코드 예제: Python · C · 예상 50분

학습 목표

  • 하나의 문제를 여러 함수로 나누어 설계한다.
  • 함수로 구성된 프로그램을 완성하고 동작을 확인한다.

관련 성취기준

  • 프그02-05

    함수의 개념과 종류, 필요성을 이해하고, 함수 정의 및 사용자 정의 함수를 호출하고 결괏값을 반환하는 프로그램을 작성할 수 있다.

생각 열기 — 한 덩어리로 쓴 프로그램

성적 관리 프로그램을 지금까지 배운 것으로 쭉 이어 쓰면 이렇게 된다.

개수 = int(input())
점수 = []
for _ in range(개수):
    점수.append(int(input()))
인원 = len(점수)
합계 = 0
for s in 점수:
    합계 += s
평균 = 합계 / 인원
최고 = max(점수)
최저 = min(점수)
print(f"인원 {인원}명")
print(f"평균 {평균:.1f}  최고 {최고}  최저 {최저}")

돌아간다. 그런데 3단원 3차시 생각 열기에서 본 문제가 그대로다 — 평균이 이상하게 나왔을 때 어디를 봐야 하는지 알 수 없다.

3단원의 설계를 코드로

3단원 3차시에서 이 프로그램을 이렇게 나눴다.

부품 받는 것 돌려주는 것 하는 일
점수받기 없음 (사용자 입력) 정수 목록 점수를 하나씩 받아 목록으로
통계내기 정수 목록 결과 묶음 인원·평균·최고·최저를 낸다
보여주기 결과 묶음 없음 (화면 출력) 정해진 형식으로 찍는다

이제 그 설계를 코드로 옮긴다.

Python성적 관리 — 세 함수로 나눈 프로그램
def 점수받기():
    개수 = int(input())
    점수 = []
    for _ in range(개수):
        점수.append(int(input()))
    return 점수

def 통계내기(점수):
    return {
        "인원": len(점수),
        "평균": sum(점수) / len(점수),
        "최고": max(점수),
        "최저": min(점수),
    }

def 보여주기(결과):
    print(f"인원 {결과['인원']}명")
    print(f"평균 {결과['평균']:.1f}  최고 {결과['최고']}  최저 {결과['최저']}")

보여주기(통계내기(점수받기()))
입력
확인된 실행 결과
인원 3명
평균 85.0  최고 92  최저 75
C성적 관리 — 세 함수로 나눈 프로그램확인된 출력
#include <stdio.h>

typedef struct { int n; double avg; int high; int low; } Stat;

int read_scores(int a[], int max)
{
    int n;
    if (scanf("%d", &n) != 1) return 0;
    if (n > max) n = max;
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    return n;
}

Stat make_stat(const int a[], int n)
{
    Stat s = {n, 0, a[0], a[0]};
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += a[i];
        if (a[i] > s.high) s.high = a[i];
        if (a[i] < s.low) s.low = a[i];
    }
    s.avg = (double)sum / n;
    return s;
}

void show(Stat s)
{
    printf("인원 %d명\n", s.n);
    printf("평균 %.1f  최고 %d  최저 %d\n", s.avg, s.high, s.low);
}

int main(void)
{
    int a[100];
    int n = read_scores(a, 100);
    if (n == 0) return 0;
    show(make_stat(a, n));
    return 0;
}
입력
3
88
92
75
실행 결과
인원 3명
평균 85.0  최고 92  최저 75

마지막 한 줄이 프로그램 전체다

Python 코드의 마지막 줄을 보자.

보여주기(통계내기(점수받기()))

받아서 → 계산해서 → 보여 준다. 프로그램이 하는 일이 한 줄에 그대로 적혀 있다. 3단원 3차시 설계서의 「주 프로그램의 흐름」이 이것이었다.

안쪽부터 실행된다 — 점수받기() 가 먼저 돌아 목록을 만들고, 그것이 통계내기 로 넘어가고, 결과가 보여주기 로 간다.

나누면 무엇이 좋아지나

한 덩어리와 함수로 나눈 것
한 덩어리함수로 나눔
평균이 틀렸을 때코드 전체를 훑는다통계내기 만 본다
출력 형식을 바꿀 때출력하는 줄을 찾아다닌다보여주기 만 고친다
입력을 파일에서 받게 바꿀 때앞부분을 뜯어 고친다점수받기 만 갈아 끼운다
따로 시험하기못 한다함수마다 단위 테스트 (3단원 7차시)
나눠 만들기한 사람만세 사람이 동시에 (3단원 3차시)

세 번째 줄이 특히 크다. 18차시에서 파일에서 점수를 읽어 오게 바꿀 때, 점수받기 하나만 갈아 끼우면 나머지는 손대지 않아도 된다. 겉모습(정수 목록을 돌려준다)이 같기 때문이다.

어디서 자를지 정하는 기준

3단원 3차시의 기준을 그대로 쓴다.

  • 기준 1

    한 가지 일만

    「받고 계산하고 찍는다」는 셋으로 나눈다. 이름에 「그리고」가 두 번 나오면 다시 쪼갠다.

  • 기준 2

    이름으로 설명된다

    점수받기·통계내기·보여주기. 이름만 보고 하는 일이 짐작되면 잘 나뉜 것이다.

  • 기준 3

    남의 속을 몰라도

    통계내기 는 점수가 어디서 왔는지 모른다. 목록만 받으면 된다.

  • 기준 4

    두 곳 이상에서 쓰이면

    되풀이되는 계산은 따로 떼어 낸다.

여기에 하나를 더한다 — 입력·계산·출력을 섞지 않는다. 14차시에서 계산 함수와 보여 주는 함수를 나눈 이야기가 프로그램 전체 수준에서도 통한다. 계산 함수가 화면을 건드리지 않으면 테스트할 수 있고, 다른 화면에도 붙일 수 있다.

활동

프로젝트

성적 관리 프로그램을 입력·계산·출력 함수로 나눠 구현

약 40분

1단계 — 겉모습을 먼저 적는다 (10분)

코드를 쓰기 전에 3단원 3차시의 다섯 칸을 채운다.

함수 받는 것 돌려주는 것 하는 일 실패하면
점수받기
통계내기
보여주기

「실패하면」 칸을 비우지 않는다. 개수를 0으로 넣으면? 숫자 아닌 값이 들어오면?

2단계 — 껍데기부터 만든다 (10분)

3단원 5차시의 순서를 따른다.

  • 세 함수를 빈 껍데기로 만들고 정해진 값 하나를 돌려주게 둔다.
  • 마지막 줄에서 이어 부르고 한 번 실행해 본다. 결과는 엉터리여도 된다.
  • 여기서 실행이 안 되면 이어지는 부분이 틀린 것이다. 잡고 넘어간다.

3단계 — 안쪽부터 채운다 (10분)

남을 부르지 않는 함수부터 채운다. 하나 채울 때마다 실행한다.

채운 함수 넣은 입력 나온 결과 손으로 낸 기대 결과 같은가

4단계 — 기능을 하나 더한다 (10분)

요구 사항을 늘린다.

0 미만 또는 100 초과인 점수는 계산에서 빼고, 제외한 개수를 함께 보여 준다.

  • 어느 함수를 고쳐야 하는가? 세 함수 중 몇 개를 건드렸는가?
  • 한 덩어리로 썼다면 몇 곳을 고쳐야 했겠는가?
  • 3단원 3차시에서 is_valid 를 따로 떼어 낸 까닭이 여기서 보이는가?

5단계 — 단위 테스트를 붙인다 (남은 시간)

통계내기 만 따로 시험하는 코드를 만든다. 3단원 7차시의 네 갈래를 쓴다.

갈래 넣을 값 기대 결과
정상값 [88, 92, 75] 인원 3, 평균 85.0
값 하나 [77]
경계값 [0, 100]
빈 목록 []

한 덩어리로 썼다면 이 시험을 할 수 있었을까? 왜 그런지 적는다.

개념 확인 문제

보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.

보여주기(통계내기(점수받기())) 에서 가장 먼저 실행되는 것은?프그02-05

입력을 파일에서 받게 바꿀 때 함수로 나눈 프로그램이 유리한 까닭은?프그02-05

계산하는 함수가 화면을 건드리지 않게 만드는 이점은?프그02-05

C의 read_scores(int a[], int max) 에서 max 를 받는 까닭은?프그02-05

「범위 밖 점수를 뺀다」는 요구가 추가되었을 때 함수로 나눈 프로그램에서 주로 고칠 곳은?프그02-05

함수를 나눠 두면 3단원 7차시의 단위 테스트가 가능해지는 까닭은?프그02-05

더 알아보기

심화파일을 여러 개로 나누기

함수가 늘어나면 파일 하나가 길어진다. 그때는 파일을 나눈다. Python에서는 성적계산.py 를 따로 만들고 import 성적계산 으로 불러 쓴다. C에서는 .c 파일과, 함수 선언만 모은 .h 파일을 짝으로 만든다.

3단원 3차시에서 부품 목록을 만들었을 때 이미 파일 나누기의 밑그림이 그려진 셈이다. 설계서의 부품이 함수가 되고, 관련된 함수들이 모여 파일이 된다. 나누는 기준은 같다 — 한 가지 일, 이름으로 설명, 남의 속을 몰라도.

실무main 은 얇게

잘 나뉜 프로그램의 main 은 짧다. 실제 일은 함수들이 하고 main 은 순서만 적는다. 위 코드의 마지막 한 줄이 그 극단적인 예다.

main 이 길어지고 있다면 그 안에 이름 붙일 만한 일이 숨어 있다는 신호다. 반대로 main 만 읽고 프로그램이 무슨 일을 하는지 알 수 있다면 잘 나뉜 것이다. 남이 쓴 프로그램을 처음 읽을 때도 main 부터 보는 것이 요령이다.

심화가짜 부품으로 먼저 돌려 보기

3단원 5차시와 이 차시 활동 2단계에서 껍데기를 먼저 만들었다. 이 방법이 협업에서 특히 힘을 낸다.

통계내기 가 아직 없어도 정해진 결과 묶음을 돌려주게 만들어 두면, 보여주기 를 맡은 사람은 그것으로 출력 형식을 완성할 수 있다. 셋이 서로를 기다리지 않고 동시에 만드는 것이다.

다만 진짜 부품이 완성되면 임시 코드를 반드시 지운다. 남겨 두면 나중에 왜 이 값이 나오는지 아무도 모르게 된다. 3단원 6차시에서 확인용 출력문을 반드시 지우라고 한 것과 같은 이유다.

이어지는 학습

이 차시를 이해하려면 다음을 먼저 알아야 한다.

  • 15차시의 반환값과 유효 범위 — 프로그래밍 프그02-05

교과서에서 찾기

교과서해당 위치쪽수
성림출판(Python)프로그래밍의 기초 › 05 함수156쪽
씨마스커뮤니케이션(Python)프로그래밍 기초 › 5 함수146쪽
삼양미디어(Python)프로그래밍의 기초 › 04 함수126쪽
삼양미디어(C)프로그래밍의 기초 › 04 함수130쪽
씨마스(C)C 프로그래밍의 기초 › 6 함수126쪽
웅보출판사(C)프로그래밍의 기초 › Chapter 05 함수141쪽