요약
이 수업은 강좌의 5단원, 곧 함수를 다루는 단원을 연다. 단원이 무엇을 위한 것인지 설명한다. 문제를 이름 붙은 부분들로 분해하되 각 부분에 인터페이스와 계약을 주는 법과, 어떤 문제들을 그 자신의 더 작은 사례로 환원하여 푸는 법, 곧 재귀를 가르치는 것이다. 단원의 네 수업과 그것들을 잇는 실을 소개한다. 단원이 이미 안다고 전제하는 것, 특히 4단원의 반복문과 그 불변식을 되짚는다. 단원이 해결하는 문제를 제시한다. 같은 계산을 복사해서 되풀이하다가 복사할 때의 부주의 때문에, 컴파일러가 아무 말도 하지 않는 가운데 틀린 답을 내는 프로그램의 문제이다. 단원이 각 부분을 명세하는 형식으로서 계약(사전 조건과 사후 조건)을 미리 소개한다. 그리고 단원이 뒤의 단원들과 C++ 프로그래밍 II 강좌에서 어디로 이어지는지 보여 준다.
학습 목표
- 단원의 내용 순서를 설명하고, 각 수업이 뒤이은 수업에 무엇을 보태는지 설명한다.
- 4단원의 알고리즘(반복문의 추적, 그 불변식과 변량)을 떠올리고, 필요하면 복습한다.
- 예를 통해 계약이라는 생각을 미리 익힌다. 프로그램의 한 부분이 그것을 쓰는 쪽에 무엇을 요구하고, 그 대가로 무엇을 보장하는가이다.
- 단원을 마쳤을 때 할 줄 알아야 하는 것이 무엇인지 알고, 그것을 뒤의 단원들에서 배울 것과 구별한다.
입문 평가
단원을 시작하기 전에 출발점을 재어 두면 좋다. 이 평가는 자기 평가이며 점수를 매기지 않는다. 목적은 오직 학습의 방향을 잡는 데 있다. 처음 다섯 문항은 단원이 이미 안다고 전제하는 것을 확인한다. 반복문의 추적, 그 불변식, 명세의 사전 조건, 초기화에서 일어나는 값의 복사, 그리고 4단원의 한 프로그램 안에서 자기만의 입력과 출력을 가진 계산을 찾아내는 일이다. 그 뒤의 다섯 문항은 수업 순서대로 단원의 핵심 개념을 다룬다. 호출 스택, 인자의 전달, 계산과 표시의 분리, 팩토리얼의 재귀적 정의, 그리고 자기 자신을 호출하는 함수의 실행이다. 아직 맞힐 의무는 누구에게도 없으며, 그중 몇 문항에서는 “아직 모르겠다”가 정직한 답이다. 맞든 틀리든 모든 답이 요점을 설명하고 그 요점을 다루는 수업을 알려 주기 때문이다. 같은 능력은 단원 끝의 종합 수업에서 다시 측정한다.
단원을 시작하기 전에 출발점을 확인해 보세요. 짧은 자기 평가입니다. 점수가 매겨지지 않으며 결과는 브라우저에만 저장됩니다.
문제 1이전 단원에서
int n{305}; int c{1}; while (n >= 10) { n = n / 10; ++c; } std::println("{}", c);코드는 무엇을 출력하는가?회차를 세면서c변수가 1에서 시작한다는 것을 잊었다.한 회차를 더 돌았다. 일 때n >= 10조건은 이미 거짓이다.카운터를 첫 회차 뒤의n변수의 값과 혼동했다.문제 2이전 단원에서반복문
int total{0}; int k{1}; while (k <= n) { total += k; ++k; }에서(의 경우), 조건을 계산할 때마다 성립하는 관계는 무엇인가?회차의 중간, 곧 더한 뒤 증가시키기 전에는 성립하지만, 조건을 계산할 때는 성립하지 않는다.끝났을 때만 성립한다. 이것은 사후 조건이지 불변식이 아니다.이것은 반복문의 조건이며, 바로 빠져나올 때 거짓이 된다. 불변식은 그때에도 성립한다.처음에 성립한다. 합은 비어 있고 이다. 또 어떤 회차 전에 성립하면 그 뒤에도 성립한다. 그 회차는 를 더한 뒤 그것을 1 증가시키기 때문이다. 빠져나올 때 이고, 불변식은 1부터 까지의 합을 준다. 재귀 수업은 같은 귀납적 추론으로 자기 함수들을 정당화한다.복습: 올바른 반복문 설계
문제 3이전 단원에서나눗셈의 명세는 “정수 과 이 주어졌을 때, 와 을 구하라. 단, 이고 .”이다. 이 명세의 사전 조건은 무엇인가?
사전 조건을 사후 조건과 혼동했다. 그것은 결과가 만족하는 것이지 데이터에 요구하는 것이 아니다.출력에 대한 조건이지 입력에 대한 조건이 아니다.일 때는 어떤 도 을 만족하지 않는다. 문제에 해가 없으며, 사전 조건은 그런 경우를 배제한다.사전 조건은 문제에 해가 있도록 데이터에 요구하는 것이고, 사후 조건은 결과가 만족하는 것이다. 단원은 이 짝을 각 함수의 계약으로 바꾼다. 사전 조건은 호출하는 쪽을 구속하고, 사후 조건은 함수를 구속한다.복습: 문제에서 알고리즘으로
문제 4이전 단원에서
int a{3}; int b{a}; b = 7;코드를 실행한 뒤a변수의 값은 얼마인가?b변수와a변수가 영원히 묶여 있다고 생각한다. 초기화가 복사하는 것은 값이지 칸이 아니다.복사를 초기화되지 않은 변수와 혼동했다.a변수는 3을 받았고, 그것을 바꾼 것은 아무것도 없다.초기화int b{a}코드는b변수의 칸에a변수가 가지고 있던 값을 복사한다. 그 뒤로 두 칸은 서로 독립이다. 매개변수와 유효 범위 수업은 매개변수도 같은 방식으로, 곧 인자의 복사본으로 초기화된다는 것을 보이고, 다른 가능성인 같은 칸의 두 번째 이름을 가르친다.복습: 변수와 메모리
문제 5이전 단원에서100보다 작은 소수를 출력하는 4.4강의 프로그램에는 후보들을 차례로 도는 반복문이 있고, 그 안에 후보의 약수를 시험하는 반복문이 또 있다. 자기만의 입력과 출력을 가진 계산으로서 이름을 붙일 만한 부분은 어디인가?
프로그램 전체의 입력과 출력을 안쪽 계산의 입력과 출력과 혼동했다.그것은 하나의 문이지, 자기만의 의미를 가진 계산이 아니다. 누군가 쓰고 싶어 할 입력과 결과가 없다.데이터를 작업과 혼동했다. 변수는 계산의 결과를 보관하지만, 계산 자체는 아니다.문제 6프로그램은
main함수에서 시작한다.main함수는g함수를 호출하고,g함수는 또 다른 함수인h함수를 호출한다.h함수가 실행되는 동안 진행 중인 호출은 어느 것인가?호출하는 쪽이 호출하는 순간 사라진다고 생각한다. 실제로는 멈춘 곳에서 이어 가기 위해 기다린다.g함수가h함수를 호출하면서 끝났다고 생각한다. 그 함수는h함수가 제어를 돌려줄 때 끝난다.정직한 답이다. 5.1강에서 스택 그림으로 설명한다.문제 7함수
int f(int x) { x = x + 1; return x; }가 있을 때,int a{3}; int b{f(a)}; std::println("{} {}", a, b);코드는 무엇을 출력하는가?함수가 인자를 수정한다고 생각한다. 기본적으로 함수는 복사본을 받는다.x변수의 변경이 반환값에조차 미치지 않는다고 생각한다.매개변수는 수정할 수 없다고 생각한다.const키워드로 선언하지 않는 한 수정할 수 있다.매개변수x변수는 인자의 복사본으로 초기화되는f함수의 변수이다. 함수는 복사본을 바꾸고 4를 반환하며,a변수는 자기 값 3을 그대로 지닌다. 이것이 값 전달이며, C++의 기본 방식이다.복습: 매개변수와 유효 범위
문제 8어떤 프로그램이 날짜를 읽고 그 요일을 출력해야 한다. 계산과 표시를 분리하는 분해는 어느 것인가?
두 작업을 섞었다. 계산한 것을 재사용할 수도, 기대하는 값과 비교할 수도 없다.작업을 나누기는 하지만, 숨은 효과로 둘을 잇는다. 호출을 읽는 사람은 데이터가 어디서 오는지 보지 못한다.정직한 답이다. 5.3강에서 어떤 함수를 쓸지 결정하는 법을 가르친다.이렇게 하면 계산을 화면을 보지 않고 수로 테스트할 수 있고, 결과를 다른 방식으로 출력하는 다른 프로그램에도 쓸 수 있다. 5.3강은 이 기준을 “함수 하나에 작업 하나”라고 부른다.복습: 함수로 설계하기
문제 9아래 정의 가운데 를 정의하는 것은 어느 것인가(모든 자연수 에 대해)?
기저 사례가 없으면 정의는 결코 멈추지 않는다. 는 를 가리키고, 그렇게 끝없이 이어진다.를 올바르게 정의하지만(일 때), 는 정의하지 않은 채로 둔다. 그 값은 1이다.를 그 자신으로 정의한다. 정의가 순환하며, 문제를 줄이지 않는다.문제 10
int f(int n) { if (n == 0) { return 0; } return n + f(n - 1); }함수가 있을 때,std::println("{}", f(3));코드는 무엇을 출력하는가?호출이 한 번만 실행된다고 생각하거나, 인자를 결과와 혼동했다.기저 사례의return 0문이 호출 사슬 전체의 결과라고 생각한다. 그것은 마지막 호출의 결과일 뿐이다.함수의 이름은 그 헤더에서부터 알려져 있으므로, 자기 본문 안에서 쓸 수 있다.f(3)호출은f(2)호출을 기다리고, 그것은f(1)호출을, 그것은f(0)호출을 기다린다. 마지막 호출이 0을 반환하고, 돌아오면서 1, 2, 3이 더해진다. 이 함수는 을 계산하며, 이는 둘째 문항의 반복문과 같은 합이다.복습: 재귀
콘텐츠를 불러오는 중…