본문 바로가기

cs50 기초강의

2. C언어 - 사용자 정의 함수, 중첩 루프

● 사용자 정의 함수

 

추상화의 개념 : 어떤 함수를 어떻게 구현했는지 보다 그 함수의 기능에만 집중할 수 있게 한다.

 

cough 를 3번 출력하는 코드를 짜보자. 

위와 같은 코드의 문제는 뭘까? 단순히 cough 를 3번 출력하기 위해 printf 함수를 3번 사용하였다. 이러한 반복은 효율적인 관점과 디자인적인 관점에서 더 좋은 코드로 바꿀 수 있다.

 

지난 번에 배운 for 문을 사용하는 방법이 있다.

for 문을 사용하여 반복을 만들고 printf 함수를 반복해서 사용하지 않고 더 좋은 코드를 짠 것이다.

※ 변수 i 를 0으로 초기화 하는 이유는 컴퓨터 과학에서는 0부터 시작하는 것이 일반적인 방법이기 때문

 

이번에는 사용자 정의 함수를 만들어서 문제를 풀어보자.

프로그램을 작성할 때 보통 코드가 길어지기 마련이다. 이때는 사용자 자신만의 함수를 만들어서 간결하게 만들 수 있다.

get_int , printf 와 같이 우리가 사용했던 함수들은 과거 사람이 구현해 놓은 함수들이다. 이처럼 우리가 우리만의 함수를 만들어서 사용할 수 있다.

 

만약 위 코드처럼 화면에 cough 를 출력하는 cough 라는 이름의 함수를 만들고 싶다면

void 함수명(void) { printf("cough\n"); }  을 입력하는 것이다.

우선 void 들은 나중에 알아보고 여기서 중요한 것은 함수명이다.

 

이 cough 함수를 사용하기 위해서

cough();

cough();

cough();

라고 적을 수 있다. 하지만 이는 아까의 문제와 같이 반복의 문제가 발생한다.

따라서, for 문을 사용해 주는 것이다.

 

사용자 정의 함수를 통해서 이제는 cough라는 함수가 어떻게 구현된 것인지는 알 필요없게 되고 단지 코드의 기능에만 집중할 수 있게 되었다. i 를 0부터 3까지 세어가며 cough() 함수를 3번 반복한다는 기능에만 신경을 쓰는 것이다.

이것이 추상화의 개념이다. cough 함수가 printf 로 구현된 것을 몰라도 cough 라는 함수가 있다는 것만 알면 된다.

 

하지만 이 코드 또한 개선의 여지가 있다.

사용자 정의 함수를 윗부분에 만들수록 main 함수 부분이 내려가기 때문에 정작 우리가 실행할 프로그램의 중요한 부분이 보이지 않는 것이다. main 함수는 위에 있을수록 좋다.

 

cough 함수 부분을 아래에 작성하고 main 함수 부분이 위로 올라가게 만든다. 

C 는 절차적 프로그래밍 언어이다 그리고 오래되었기 때문에 단순하고 똑똑하지 않다. 즉 시키는대로만 수행하고 반드시 왼쪽에서 오른쪽, 위에서 아래로 시켜야만 한다.

따라서 우리가 작성한 함수를 C 가 알 수 있도록 main 함수 위에 void cough(void); 를 입력해야 한다. 이로써 C 가 cough 함수를 본 것처럼 속이는 것이다.

 

이번에는 cough 함수를 좀 더 동적으로 만들어보자. 원하는 횟수만큼 cough 출력하게 만들어 보자.

 

 

cough 함수에 입력을 받을 수 있도록 만드는 문제이다.

void cough(void) 에서 (  ) 안의 void 는 입력을 받지 않는 다는 의미이다.

왼쪽 void 는 get_string, get_int 함수 처럼 값을 반환하지 않는다는 의미이다.

 

위 코드에서는 오른쪽 void 부분을 바꿔서 cough 함수가 입력을 받을 수 있게 한 것이다.

즉, cough 함수에 입력을 받도록 해서 원하는 횟수만큼 cough를 출력하게 만든다. (입력 부분을 지정하는 것)

이것을 cough 함수의 매개변수화라고 한다.

 

void cough(int n)

cough 함수의 입력을 int n 과 같은 값으로 변경하여 n 이라는 정수를 받아 그 값만큼 동작을 반복하게 만든 것이다.

따라서 for (int i = 0; i < n; i++) { printf("cough\n"); } 를 통해 n 번 반복할 수 있도록 한다.

 

이때 첫줄의 cough 함수 프로토타입도 같이 바꿔줘야 한다.

 

그리고 main 함수 내의 cough 함수에는 cough(3); 을 통해 n 이 3이 되어 3번 반복할 수 있도록 만든 것이다.

 

 

이번에는 값을 반환하는 사용자 정의 함수를 만들어보자.

 

get_positive_int 함수는 사용자 정의 함수이다. 여기서의 기능은 양의 정수를 받아오는 함수라는 의미이다.

 

get_positive_int 함수를 정의한 부분을 살펴보자.

새로운 do - while 루프가 등장한다.

13 ~ 22 번의 논리는 다음과 같다.

13 .get_positive_int 라는 함수는 입력을 받지 않는다(입력의 종류). 그러나 이 함수는 임의의 int를 반환한다.(출력의 종류) 따라서 void 가 아닌 int 로 작성.

15. 컴퓨터에게 int n 변수를 선언하고 ( 이때 n 에는 어떤 값을 저장할 지 모르기 때문에 단순히 선언만 한것이다. 따라서 n 은 쓰레기 값이라고 부르는 값을 가지게 된다. )

16. 수행한다 {  } 의 내용을

18. get_int 함수를 통해 양의 정수 값을 사용자에게 받아 n 변수에 저장한다.

20. 만약 n 이 1보다 작다면( 불리언이 참이라면 ) 다시 do 부분으로 돌아가 사용자에게 반복해서 프롬프트한다.

21. 그렇지 않고 n이 1보다 크거나 같다면 n을 반환한다.

라는 의미이다.

 

※ do - while 루프가 좋은 점은 while 루프와는 다르게 우선 do { } 부분을 한번 수행한 후 반복이 실행될지 안될지 결정되는 구조이다. while 루프에서는 조건을 먼저 확인한 후 불리언이 참이라면 while 반복이 진행되었다. 하지만 do - while 루프는 먼저 수행한 후 반복의 여부를 결정한다.

 

● 중첩 루프

 

이번에는 좀 더 사용자 친화적인 코드를 작성해보자. 

위 코드는 do-while 루프를 사용하여 사용자에게 width 를 물어서 정수 값을 받도록 하고 만약 그 정수 값이 1보다 작다면 다시 프롬프트하는 방식을 가지고 있고 1보다 같거나 큰 정수값을 받으면 for 문이 진행되는 논리이다.

for 문은 n 번 반복하면서 ? 를 출력한다. 즉, 사용자에게 입력받은 값이 4 라면 ???? 가 출력되는 코드이다. 그리고 for 문이 n 번 반복된 후 \n 를 통해 새로운 줄로 바뀌는 것으로 마무리 된다.

 

이 코드는 이전 논리구조를 배우고 사용한 것이다.

 

이번엔 중첩 루프라는 것을 활용해보자.

위 코드의 논리구조를 살펴보자.

우선 int n을 선언하고

제대로 된 정수 값을 얻을 때 까지 계속해서 프롬프트한다.

제대로 된 정수 값을 얻었다면 외부 for 문을 n번 실행하는데

내부 for 문 역시 n번을 반복한다는 의미이다. 이때 외부 for 문의 변수인 i 대신 j를 넣어 변수를 다르게 한다.

그 이유는 변수를 다르게 넣어서 계산이 꼬이지 않도록 하기 위함이다.

만약 내부 for 문에도 i 라고 써준다면 컴파일 되지 않는다. 왜 그럴까? 어떻게 계산이 꼬이는 걸까?

다시 논리 구조를 살펴보면

처음 for 문에 의해 i 는 0이 된다. 그리고 내부 for 문에 의해 i 가 n 번만큼 변하는 것이다. 내부 for 문이 끝나고 외부 for 문도 반복되어야 하기 때문에 i 는 0이 아닌 1이 된다. 하지만 다시 내부 for 문으로 들어가면 i는 0으로 선언되어 있다. 즉, 계산이 꼬이는 것이다. 따라서 외부 for 문과 내부 for 문의 변수를 i 와 j 로 다르게 놓아 계산이 꼬이지 않도록 한것.

 

다시 돌아와서 내부 for 문이 n 번반복 되면서 #이 n 번 출력된다. 그리고 줄바꿈이 일어나고 다시 외부 for 문을 반복하기 때문에 그에 맞춰 내부 for 문이 수행되고 다시 #이 n 번 출력되는 논리 구조인 것이다.

즉, 가로가 n 개 세로가 n 개인 #을 출력하게 된다.

따라서, 사용자에게 4 값을 입력 받으면 위 이미지와 같은 값이 출력되는 것이다.

 

 

자료출처 : 부스트코스 - https://www.boostcourse.org/cs112/lecture/119009?isDesc=false

 

 

'cs50 기초강의' 카테고리의 다른 글

3. 배열 - 배열(1, 2)  (0) 2021.06.06
3. 배열 - 컴파일링  (0) 2021.06.06
2. C언어 - 자료형, 형식 지정자, 연산자  (0) 2021.06.05
2. C언어 - 조건문과 루프  (0) 2021.06.04
2. C언어 - 문자열  (0) 2021.06.04