요약
지금까지 이 강좌의 프로그램은 모두 하나의 블록, 곧 main 함수였고, 그 안에서는 모든 것을 쓰이는 자리에 썼다. 이 수업은 프로그램의 한 부분에 이름을 붙이고, 그 내부를 들여다보지 않고 사용하는 법, 곧 함수를 가르친다. 컴파일러에 이름, 반환 타입, 매개변수를 알리는 선언, 본문을 덧붙이는 정의, 그리고 그 본문으로 제어를 넘기고 반환값을 받는 호출을 공부한다. 컴파일러가 컴파일할 때 확인하는 것(각 호출이 어떤 선언과 맞는지)과 실행할 때 일어나는 것(정의로의 이동과 복귀)을 구별한다. 값을 반환해야 하는 함수의 끝에 return 문 없이 도달하는 것이 왜 정의되지 않은 동작인지 설명한다. 진행 중인 호출마다 프레임을 하나씩 보관하는 호출 스택으로 실행을 따라간다. 그리고 각 함수를 계약, 곧 사전 조건과 사후 조건으로 명세한다. 계약은 함수가 호출하는 쪽에 무엇을 요구하고 그 대가로 무엇을 보장하는지 말한다.
학습 목표
- 매개변수와 반환값이 있는 함수를 선언하고 정의하고 호출하며, 프로그램에서 어느 부분이 선언이고 어느 부분이 정의인지 짚어 낸다.
- 서로를 호출하는 함수들이 있는 프로그램의 실행을 호출 스택 그림으로 따라간다.
- 함수를 사전 조건과 사후 조건으로 명세하고, 사전 조건을 위반하는 호출을 쓴다.
- 어떤 경로에서 값을 반환하지 않는 함수가 왜 정의되지 않은 동작인지 설명하고, 그에 해당하는 컴파일러 경고를 알아본다.
왜 함수인가
앞 단원의 프로그램은 모든 문제를 main 함수 안에서 풀었고, 문제가 작은 동안에는 그것으로 충분했다. 그러나 프로그램이 커지면 곧 세 가지 어려움이 나타난다. 첫째는 반복이다. 같은 계산이 세 곳에서 필요하면 세 번 쓰게 되고, 그 안의 오류도 세 번 고쳐야 한다(또는 한 곳에서 고치는 것을 잊는다). 둘째는 읽기다. 쉰 줄짜리 블록은 무엇을 하는지가 아니라 어떻게 하는지를 말하고, 읽는 사람은 메커니즘에서 의도를 다시 짜 맞춰야 한다. 셋째는 테스트다. 모든 것이 뒤섞여 있으면 나머지를 실행하지 않고 한 부분만 확인할 방법이 없다.
함수는 이름이 있는 프로그램 조각으로, 매개변수라고 부르는 데이터를 받아 반환값이라고 부르는 결과를 넘겨준다. 수학은 이 생각을 수백 년 전부터 알고 있었다. 평면 위의 두 점 사이의 거리는 두 점의 네 좌표의 함수 이며, 삼각형의 둘레를 계산하는 사람은 공식을 세 번 되풀이해 쓰지 않고, 공식에 이름을 붙여 세 번 적용한다. C++에서도 똑같이 쓴다.
이 프로그램은 삼각형의 세 꼭짓점의 좌표를 읽고 그 둘레, 곧 세 변의 길이의 합을 출력한다.
#include <cmath>#include <iostream>#include <print>// 점 (x1, y1)과 점 (x2, y2) 사이의 거리.double distance(double x1, double y1, double x2, double y2){ const double dx{x2 - x1}; const double dy{y2 - y1}; return std::sqrt(dx * dx + dy * dy);}int main(){ double ax{}; double ay{}; double bx{}; double by{}; double cx{}; double cy{}; std::cin >> ax >> ay >> bx >> by >> cx >> cy; const double perimeter{distance(ax, ay, bx, by) + distance(bx, by, cx, cy) + distance(cx, cy, ax, ay)}; std::println("둘레: {}", perimeter);}0 0 3 0 0 4둘레: 12꼭짓점이 , , 인 삼각형의 세 변의 길이는 3, 5, 4이고, 그 합은 12이다.
distance 함수는 한 번 쓰고 세 번 사용한다. main 함수는 둘레의 정의, 곧 “세 거리의 합”으로 읽힌다. 그리고 distance 함수는 거리를 이미 아는 두 점의 쌍으로 따로 테스트할 수 있다. 이렇게 해서 모자랐던 세 가지를 얻는다. 어느 언어에서나 통하는 일반적인 교훈은 함수가 하나의 생각에 이름을 붙인다는 것이다. 함수를 사용하는 사람은 그것이 어떻게 하는지가 아니라 무엇을 하는지를 생각한다. 이처럼 사용과 구현을 나누는 것을 절차적 추상화라고 하며, 이것이 이 단원 전체의 주제다.
콘텐츠를 불러오는 중…