CS 기초/C언어

[CS50] 사용자 정의 함수, 중첩 루프

담크 2021. 8. 2. 23:47

프로그래밍을 하다 보면 반복적으로 같은 코드를 작성해야 할 때가 있는데, 이때 코드를 여러 번 쓰는 게 아니라 함수 형태로 지정해두면 코드를 간결하게 사용이 가능합니다. 더불어 하나의 루프로 수행하기 힘든 작업을 중첩 루프를 사용해 해결하는 방법도 공부해보도록 하겠습니다.

 

만약 "에취!"라고 세번 말하는 C 프로그램을 작성할 때 가장 간단한 방법은 단순히 3번 출력하게 만들어주는 것입니다.

#include<stdio.h>

int main(void){
    printf("에취!\n");
    printf("에취!\n");
    printf("에취!\n");
}

그렇다면 이것을 좀 더 간단하게 코딩해본다면 어떻게 될까요?

지난 시간에 배운 루프를 사용하면 더 간단히 표현할 수 있습니다.

#include<stdio.h>

int main(void){

    for(int i = 0; i < 3;i++){
        printf("에취!\n");
    }
    
}

그럼 이것을 새로운 함수로 만들어보면 어떨까요??

#include<stdio.h>

void cough(void){
	printf("에취!\n");
}

int main(void){

    for(int i = 0; i < 3;i++){
        cough();
    }
    
}

처음 보시는 분들은 조금 복잡해 보일 수 있지만 자세히 보면 지금껏 써왔던 main함수와 비슷하게 사용하는 것을 볼 수 있습니다. main함수 역시 함수니까요 ㅎㅎ 함수의 표현은 void (원하는 함수 이름)(void) {  } 이렇게 적어주면 됩니다.

 

프로토타입을 이용한 선언

그런데 여기에 작은 문제가 있습니다.

지금은 cough함수 1개뿐이지만 나중에 함수가 많아지게 된다면 main함수가 맨 밑으로 내려가 main에서 어떠한 함수나 식을 실행시키는지 확인하려면 매우 힘들 겁니다. 그렇다면 main함수를 위로 올리면 되겠죠?

#include<stdio.h>

int main(void){

    for(int i = 0; i < 3;i++){
        cough();
	}

void cough(void){
	printf("에취!\n");
}
}

하지만 이렇게 작성한 후 실행하면 에러가 발생합니다. 이유는 main에서 불러온 cough함수가 main함수보다 밑에 있어 main함수 입장에서 볼 땐 아직 없는 함수이기 때문입니다. 그렇다면 이것을 해결하기 위해서 어떻게 해야 할까요?

#include<stdio.h>

void cough(void);

int main(void){

    for(int i = 0; i < 3;i++){
        cough();
	}

void cough(void){
	printf("에취!\n");
}
}

이렇게 void cough(void);를 하게 되면 이전에 cough가 선언되었다고 C를 속이는 행동을 하는 것입니다.

이것에 익숙하다면 

#include<stdio.h>

void cough(int n);

int main(void){
	cought(3);
}

void cough(int n){
	for(int i = 0; i < n; i++){
    	printf("에취!");
    }
}

이렇게 원하는 횟수만큼 출력하는 코드도 작성해볼 수 있습니다.

 

이번엔 다른 예제를 한번 살펴보겠습니다.

#include <cs50.h>
#include <stdio.h>

int get_positive_int(void);

int main(void)
{
    int i = get_positive_int();
    printf("%i\n", i);
}

int get_positive_int(void)
{
    int n;
    do
    {
        n = get_int("양의 정수: ");
    }
    while (n < 1);
    return n;
}

여기서 int get_positive_int(void)는 입력을 받지 않고 괄호 안에 아무 양의 정수나 받으면 됩니다. 하지만 이 함수가 정수를 출력하게 해야 하기 때문에 맨 앞에 void 대신 int를 써준 것입니다.

결국 int get_positive_int(void)는 맨 왼쪽에 있는 단어는 출력의 종류를 의미하고 괄호 안의 단어는 입력의 종류를 뜻합니다. (입출력이 없다면 void를 적어주시면 됩니다.)

 

int n; 이라는 식도 처음 접했을 텐데 이것은 n안에 어떤 값을 저장할지 모르기 때문에 그냥 int n;만 적어두는 것입니다. 나중에 제대로 넣으면 되기 때문에 아직은 아무것도 할당할 필요가 없습니다.

 

그다음 do-while문을 살펴보면

do를 한 번은 꼭 수행하고 while(조건); 이 참일 경우 계속해서 질문을 반복할 것입니다.

 

 

중첩 루프

루프 안에 다른 루프를 사용해 루프가 중첩되게 만들어주는 것입니다.

화면에 여러 개의 이미지를 가로나 세로로 여러개 이어서 출력하고 싶다면 중첩 루프를 사용해 쉽게 구현이 가능합니다.

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    int n;

    do
    {
        n = get_int("Size: ");
    }
    while (n < 1);

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            printf("*");
        }
        printf("\n");
    }
}

가장 먼저는 정수 값을 갖는 변수 n을 정의합니다.

그리고 do-while문을 이용해서 { }안의 내용을 실행시킵니다.(do-while을 쓰는 이유는 조건과 상관없이 무조건 한 번은 실행시킬 수 있기 때문입니다.)

 

그리고 for 루프를 중첩시켜 "*"을 출력시킵니다.(내부 루프에서 *을 출력시키고 내부 루프가 끝날 때마다 줄 바꿈을 수행합니다.)

그러면 최종적으로 가로가 n, 세로가 n개인 "*"이 출력되게 됩니다.

 


출처

본 내용은 CS50의 2019년 강의를 듣고 작성했습니다. (개념이 어느 정도 정리되면 최신강의도 다시 듣고 수정할 내용 있으면 수정하겠습니다.)

 

강의 자료는 EdX에서 무료로 사용할 수 있고 boostcourse에서 한글 강의로도 들을 수 있습니다.

'CS 기초 > C언어' 카테고리의 다른 글

[CS50] 하드웨어의 한계  (0) 2021.08.03
[CS50] 자료형, 형식 지정자, 연산자  (2) 2021.08.01
[CS50] 조건문과 루프  (0) 2021.07.30
[CS50] 문자열  (0) 2021.07.29
[CS50] C 기초  (0) 2021.07.28