Skip to content

Commit 441c4d1

Browse files
committed
Chap10 - 10.2 까지 공부
1 parent 67fa74d commit 441c4d1

File tree

4 files changed

+347
-1
lines changed

4 files changed

+347
-1
lines changed

Chap10-Functions_basics/Chap10-Functions_basics.md

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ MAX: 3
141141
142142
인터페이스가 아예 없는 프로그램이 아니라면 모든 프로그램은 **UI와 기능**으로 나눌 수 있다. 이 둘은 적어도 함수단위로 구별되어야 한다.
143143
144-
아래의 예제는 계승(factorial)을 계산하는 함수를 구현한 코드이다. 피호출자 함수 `GetFactorial()` 는 `int` 형 매개변수를 통해 계승을 구할 숫자를 받는다. 그리고 화면에 출력할 부분은 `main()` 함수에 정의한다.
144+
아래의 예제는 계승(factorial)을 계산하는 함수를 구현한 코드이다. 피호출자 함수 `GetFactorial()` 는 `int` 형 매개변수를 통해 계승을 구할 숫자를 받는다. 그리고 화면에 출력할 부분은 `main()` 함수에 정의한다. 이렇게 출력하는 부분인 **UI**와 계승을 구하는 **기능** 을 **명확하게 분리**할 수 있다.
145145
146146
```c
147147
// funcdesign02.c
@@ -186,3 +186,190 @@ ERROR: 1~10사이의 정수를 입력하세요.
186186

187187

188188

189+
이번에 살펴볼 예제는 **UI 부분에서도 성적을 입력받는 부분과 학점을 출력하는 부분이 분리** 하여 구현되어 있다.
190+
191+
```c
192+
// funcdesign03.c
193+
194+
#include <stdio.h>
195+
196+
// 계산된 학점을 입력받는 인터페이스
197+
int GetResult(void){
198+
199+
int nResult = 0;
200+
printf("성적(0~100)을 입력하세요. : ");
201+
scanf("%d", &nResult);
202+
return nResult;
203+
}
204+
205+
// 학점을 계산하는 기능
206+
char GetGrade(int nScore){
207+
if(nScore >= 90) return 'A';
208+
else if(nScore >= 80) return 'B';
209+
else if(nScore >= 70) return 'C';
210+
else if(nScore >= 60) return 'D';
211+
return 'F';
212+
}
213+
214+
// 프로그램의 전체적 흐름
215+
int main(void){
216+
int nResult = 0;
217+
218+
nResult = GetResult();
219+
printf("당신의 학점은 '%c'(%d)입니다.\n", GetGrade(nResult), nResult);
220+
return 0;
221+
}
222+
223+
/* 출력결과
224+
성적(0~100)을 입력하세요. : 95
225+
당신의 학점은 'A'(95)입니다.
226+
*/
227+
```
228+
229+
230+
231+
이번에 살펴볼 예제는 실제로는 동작하는 **기능**은 없고, **UI**만 있는 '관리프로그램'의 예제코드이다. 사용자에게 프로그램의 메뉴를 출력해준 뒤 사용자로부터 입력받은 메뉴를 처리하는 기능을 간단하게 구현한 예제이다. 현재 내가 작성한 코드는 Mac(또는 Linux)환경에서 gcc를 이용해 compile하기 때문에 Windows환경의 코드와는 조금 다르다. 아래의 코드를 보면 `PrintMenu()` 함수를 `main()` 함수에서 반복해서 호출하고 반환받은 사용자의 선택을 `switch-case` 문으로 메뉴에 대한 적절한 문자열을 출력한다. 이러한 반복 구조를 **이벤트 루프(event loop)**라고 한다.
232+
233+
```c
234+
// Printmenu01.c
235+
236+
#include <stdio.h>
237+
// #include <curses.h> // gcc (Linux)
238+
// #include <conio.h> // Windows
239+
#include <stdlib.h>
240+
#include <unistd.h> // sleep()을 사용하기 위함
241+
242+
// 화면에 메뉴를 출력하는 함수의 선언 및 정의
243+
int PrintMenu(void){
244+
int nInput = 0;
245+
246+
// 메뉴를 출력하기 전에 화면을 지운다. (Clear screen)
247+
// system("cls"); // Windows
248+
sleep(1); // Linux & Mac에서는 화면이 바로 지워지는 문제로 인해 sleep() 추가
249+
system("clear");
250+
// 메뉴를 출력하고 사용자 입력을 받는다.
251+
printf("[1]New\t[2]Search\t[3]Print\t[4]Remove\t[0]Exit\n");
252+
scanf("%d", &nInput);
253+
254+
// 사용자가 선택한 메뉴 값을 반환한다.
255+
return nInput;
256+
}
257+
258+
int main(void){
259+
int nMenu = 0;
260+
261+
// 메뉴 이벤트 루프
262+
// 사용자가 입력한 값에 따라 정해진 기능을 반복해 수행한다.
263+
// 0을 입력하면 반복문을 끝낸다.
264+
while((nMenu = PrintMenu()) != 0){
265+
switch(nMenu){
266+
case 1: // New
267+
puts("새 항목을 추가합니다.");
268+
break;
269+
270+
case 2: // Search
271+
puts("기존 항목에서 검색합니다.");
272+
break;
273+
274+
case 3: // Print
275+
puts("전체 내용을 출력합니다.");
276+
break;
277+
278+
case 4: // Remove
279+
puts("기존 항목을 삭제합니다.");
280+
281+
default:
282+
puts("알 수 없는 명령입니다.");
283+
}
284+
getchar();
285+
}
286+
puts("Bye~!");
287+
return 0;
288+
}
289+
290+
/* 출력결과
291+
[1]New [2]Search [3]Print [4]Remove [0]Exit
292+
2
293+
기존 항목에서 검색합니다.
294+
295+
[1]New [2]Search [3]Print [4]Remove [0]Exit
296+
0
297+
Bye~!
298+
*/
299+
```
300+
301+
302+
303+
304+
305+
### 10.2.2 재사용 가능한 단위 기능의 구현
306+
307+
불연속적으로 반복되거나 앞으로 다시 사용될 가능성이 높은 코드는 함수로 만드는 것이 좋다. 그 이유는 나중에 유지보수 하기 좋기 때문이다. 하지만 반복이나 재사용 같은 이유가 아니라도 함수로 만드는 것이 좋을 때가 있다.
308+
309+
예를 들어, 프로그램이 제공하는 여러 기능 각각을 하나의 함수로 만들면 코드를 관리하기 좋을 뿐만아니라 구조 또한 깔끔한 프로그램이 될 수 있다. 다음 예제 코드는 위의 `PrintMenu01.c` 의 '관리 프로그램'에 특정 기능을 구현한 함수를 추가하고 확장한 코드이다.
310+
311+
```c
312+
// Printmenu02.c
313+
314+
#include <stdio.h>
315+
#include <stdlib.h>
316+
#include <unistd.h> // sleep()을 사용하기 위함
317+
318+
319+
// 나이를 매개변수로 받고 요금을 반환하는 기능을 제공
320+
int GetFee(int nAge){
321+
int nFee = 1000;
322+
if(nAge < 20) nFee /= 2;
323+
return nFee;
324+
}
325+
326+
// 메뉴를 출력하고 사용자로부터 선택을 입력받는 인터페이스
327+
int PrintMenu(void){
328+
int nInput = 0;
329+
330+
sleep(1); // Linux & Mac에서는 화면이 바로 지워지는 문제로 인해 sleep() 추가
331+
system("clear");
332+
printf("[1]New\t[2]Search\t[3]Print\t[4]Remove\t[0]Exit\n");
333+
scanf("%d", &nInput);
334+
return nInput;
335+
}
336+
337+
// 사용자로부터 나이를 입력받는 인터페이스
338+
int GetAge(void){
339+
int nAge = 0;
340+
printf("나이를 입력하세요. : ");
341+
scanf("%d", &nAge);
342+
return nAge;
343+
}
344+
345+
// 프로그램의 전체 흐름
346+
int main(void){
347+
int nMenu = 0, nAge = 0;
348+
349+
// 간단히 구현한 이벤트 루프
350+
while((nMenu = PrintMenu()) != 0){
351+
if(nMenu == 1){
352+
nAge = GetAge();
353+
printf("요금은 %d원 입니다.\n", GetFee(nAge));
354+
getchar();
355+
}
356+
}
357+
puts("Bye~!");
358+
return 0;
359+
}
360+
361+
/* 출력결과
362+
[1]New[2]Search[3]Print[4]Remove[0]Exit
363+
1
364+
나이를 입력하세요. : 19
365+
요금은 500원 입니다.
366+
367+
[1]New[2]Search[3]Print[4]Remove[0]Exit
368+
0
369+
Bye~!
370+
*/
371+
```
372+
373+
374+
375+
함수설계 원칙보다 더 큰 범위의 설계 원칙으로 **DRY(Don't Repeat Yourself)** 원칙이 있다(실용주의 프로그래머, Andrew Hunt & David Thomas 저). DRY 원칙의 핵심은 **"같은 일을 수행하는 코드가 중복(여러 곳에 존재)되지 않도록 하라"** 이다.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Printmenu02.c
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <unistd.h> // sleep()을 사용하기 위함
6+
7+
8+
// 나이를 매개변수로 받고 요금을 반환하는 기능을 제공
9+
int GetFee(int nAge){
10+
int nFee = 1000;
11+
if(nAge < 20) nFee /= 2;
12+
return nFee;
13+
}
14+
15+
// 메뉴를 출력하고 사용자로부터 선택을 입력받는 인터페이스
16+
int PrintMenu(void){
17+
int nInput = 0;
18+
19+
sleep(1); // Linux & Mac에서는 화면이 바로 지워지는 문제로 인해 sleep() 추가
20+
system("clear");
21+
printf("[1]New\t[2]Search\t[3]Print\t[4]Remove\t[0]Exit\n");
22+
scanf("%d", &nInput);
23+
return nInput;
24+
}
25+
26+
// 사용자로부터 나이를 입력받는 인터페이스
27+
int GetAge(void){
28+
int nAge = 0;
29+
printf("나이를 입력하세요. : ");
30+
scanf("%d", &nAge);
31+
return nAge;
32+
}
33+
34+
// 프로그램의 전체 흐름
35+
int main(void){
36+
int nMenu = 0, nAge = 0;
37+
38+
// 간단히 구현한 이벤트 루프
39+
while((nMenu = PrintMenu()) != 0){
40+
if(nMenu == 1){
41+
nAge = GetAge();
42+
printf("요금은 %d원 입니다.\n", GetFee(nAge));
43+
getchar();
44+
}
45+
}
46+
puts("Bye~!");
47+
return 0;
48+
}
49+
50+
/* 출력결과
51+
[1]New [2]Search [3]Print [4]Remove [0]Exit
52+
1
53+
나이를 입력하세요. : 19
54+
요금은 500원 입니다.
55+
56+
[1]New [2]Search [3]Print [4]Remove [0]Exit
57+
0
58+
Bye~!
59+
*/
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Printmenu01.c
2+
3+
#include <stdio.h>
4+
// #include <curses.h> // gcc (Linux)
5+
// #include <conio.h> // Windows
6+
#include <stdlib.h>
7+
#include <unistd.h> // sleep()을 사용하기 위함
8+
9+
// 화면에 메뉴를 출력하는 함수의 선언 및 정의
10+
int PrintMenu(void){
11+
int nInput = 0;
12+
13+
// 메뉴를 출력하기 전에 화면을 지운다. (Clear screen)
14+
// system("cls"); // Windows
15+
sleep(1); // Linux & Mac에서는 화면이 바로 지워지는 문제로 인해 sleep() 추가
16+
system("clear");
17+
// 메뉴를 출력하고 사용자 입력을 받는다.
18+
printf("[1]New\t[2]Search\t[3]Print\t[4]Remove\t[0]Exit\n");
19+
scanf("%d", &nInput);
20+
21+
// 사용자가 선택한 메뉴 값을 반환한다.
22+
return nInput;
23+
}
24+
25+
int main(void){
26+
int nMenu = 0;
27+
28+
// 메뉴 이벤트 루프
29+
// 사용자가 입력한 값에 따라 정해진 기능을 반복해 수행한다.
30+
// 0을 입력하면 반복문을 끝낸다.
31+
while((nMenu = PrintMenu()) != 0){
32+
switch(nMenu){
33+
case 1: // New
34+
puts("새 항목을 추가합니다.");
35+
break;
36+
37+
case 2: // Search
38+
puts("기존 항목에서 검색합니다.");
39+
break;
40+
41+
case 3: // Print
42+
puts("전체 내용을 출력합니다.");
43+
break;
44+
45+
case 4: // Remove
46+
puts("기존 항목을 삭제합니다.");
47+
48+
default:
49+
puts("알 수 없는 명령입니다.");
50+
}
51+
getchar();
52+
}
53+
puts("Bye~!");
54+
return 0;
55+
}
56+
57+
/* 출력결과
58+
[1]New [2]Search [3]Print [4]Remove [0]Exit
59+
2
60+
기존 항목에서 검색합니다.
61+
62+
[1]New [2]Search [3]Print [4]Remove [0]Exit
63+
0
64+
Bye~!
65+
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// funcdesign03.c
2+
3+
#include <stdio.h>
4+
5+
// 계산된 학점을 입력받는 인터페이스
6+
int GetResult(void){
7+
8+
int nResult = 0;
9+
printf("성적(0~100)을 입력하세요. : ");
10+
scanf("%d", &nResult);
11+
return nResult;
12+
}
13+
14+
// 학점을 계산하는 기능
15+
char GetGrade(int nScore){
16+
if(nScore >= 90) return 'A';
17+
else if(nScore >= 80) return 'B';
18+
else if(nScore >= 70) return 'C';
19+
else if(nScore >= 60) return 'D';
20+
return 'F';
21+
}
22+
23+
// 프로그램의 전체적 흐름
24+
int main(void){
25+
int nResult = 0;
26+
27+
nResult = GetResult();
28+
printf("당신의 학점은 '%c'(%d)입니다.\n", GetGrade(nResult), nResult);
29+
return 0;
30+
}
31+
32+
/* 출력결과
33+
성적(0~100)을 입력하세요. : 95
34+
당신의 학점은 'A'(95)입니다.
35+
*/

0 commit comments

Comments
 (0)