C 언어(11) - 반복문

C 언어 강의, 반복문

Featured image

🔚 짧게 하는 복습

✅ 1. if, else if, else, 중첩된 if를 알자

✅ 2. switch 문과 break 문을 이해하자

혹시 기억이 안 난다면, 다시 돌아가자


여기까지 왔다면 축하한다. 이제 50% 정도 왔고 50% 정도 남았다!

보통의 컴퓨터 공학부 수업 기준 중간고사 범위가 여기까지기 때문이다.

오늘은 제어문의 남은 하나, 반복문에 대해 다루겠다.


반복문이란?

반복문이란 말 그대로 정해진 행동 큰 차이 없이 단순 반복할 때 쓰이는 문장이다.

자 여기서 중요한 것은 큰 차이 없이이다. 무조건 똑같은 행동을 반복하는 것뿐만 아니라 어느 정도 비슷한 행동을 반복하는 것도 반복인 것이다.

예를 들어 보자.

printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");

위 코드 같은 경우, 명백히 반복이다. 똑같은 행동을 반복하고 있기 때문이다.

그런데 아래 코드를 한번 보자.

printf("hello world1");
printf("hello world2");
printf("hello world3");
printf("hello world4");
printf("hello world5");
printf("hello world6");
printf("hello world7");
printf("hello world8");

이건 어떤가? 똑같은 행동이 아니라서 반복이라고 할 수 있는가 싶은데, 프로그래밍에서는 이런 것도 반복문으로 처리할 수 있다.

반복문의 종류는 크게 for문과 while 문으로 나뉜다.


for 문이란?

for 문이란 아래의 규칙을 가지는 문장을 말한다.

for(초기 조건; 실행 조건; 연산){
    //code1
}

하나씩 살펴보자.

초기 조건이라는 것은 시작될 때의 상태를 의미한다. 대부분은 정수형 변수를 사용해서 시작 값을 부여한다.(아닐 때도 있다.)

맨 마지막에 연산은 한 번 code1을 실행하고 난 다음, 다음 반복으로 넘어가기 전 초기에 설정한 정수형 변수에 적용할 연산을 정하는 것이다.

실행 조건은 초기에 설정된 정수형 변수 혹은 code1을 실행하고 연산된 정수형 변수가 이 조건을 만족하면 한 번 더 반복하고 아니라면 반복을 종료하고 for 블록 밖으로 나간다.

설명만 듣고는 이게 무슨 말인가 싶은데, 예제 코드를 보며 확인하자.

for(int i = 0; i<9; i++){
    //code1
}

가장 심플하고 자주 쓰이는 방식의 반복문이다..

이 코드가 진행되는 자세한 방법은 우선 초기 조건 i = 0실행 조건 i<9를 비교한다.

0<9로 참이므로, code 1이 실행된다. 한 번 반복이 된 후 변수 i에 정해진 연산 i++을 한다.

여전히 1<9로 참이므로, 한 번 더 code 1이 실행된다. 또 반복된 후 변수 i에 정해진 연산 i++을 한다.

2<9, 또 code 1이 실행이 된다. 또 반복된 후 변수 i에 정해진 연산 i++을 한다.

언제까지 8<9까지 code 1이 실행되고, i++후 9<9가 되면 반복을 종료하고 블록 밖으로 나간다.

총 그렇게 code 1은 9번 반복된다.

일반화하면 초기 조건이 i = 0; 이고 마지막 조건이 i<\n이라면 n번 반복되는 것으로 유추할 수 있다.

그런데 이게 다가 아니다. 조금 응용하면 훨씬 유용한 코드를 짤 수 있는데

for(int i = 0; i<9; i+=2){
    //code1
}

짝수 번째만 실행하고 싶을 때

for(int i = 1; i<9; i*=2){
    //code1
}

2의 거듭 제곱번째만 실행하고 싶을 때

for(int i = 10; i>0; i--){
    //code1
}

거꾸로 감소시키고 싶을 때 등, 여러 가지 변화를 줘서 짤 수 있다.

대부분 교재에서 for 문은 반복 횟수를 아는 경우 사용한다도 적혀있는데, 이는 엄밀히 말하면 잘못된 설명이다.

반복 횟수를 아는 경우 사용하는 때도 쓰지만, 거듭제곱 번째 혹은 짝수 번째 등 반복 횟수를 모를 때에도 사용할 수 있다.


while 문

while 문은 어떻게 보면 더욱 유연한 for 문이라고 말할 수 있다.

정수형 변수에 정해진 연산을 하며 조건을 확인하는 for 문보다, 이쪽은 아예 초기 조건, 연산 다 빼고 실행 조건만 가지고 있다.

while(실행 조건){
    //code1
}

이 문장은 실행 조건이 참인 동안 계속 반복을 한다.

보통 초기 조건은 while 문밖에서 설정하고, 연산을 code1 부분에 포함해 진행한다.

만약 조건과 무관하게 무조건 처음은 실행하고 싶다면, do-while 문이라는 방법도 있다.

do{
    //code1
}while(실행 조건);

code1은 무조건 한 번 이상 실행된다.


예제를 통해 배워보자.

역시나 백문이 불여일견이라고 여러 번 이론 수업을 듣는 것보다 직접 코드를 짜며 배우는 것이 좋다.

우선, 이 아래 코드를 반복문으로 처리해보자.

printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");
printf("hello world");

반복 횟수가 8번이다. 이는 for 문으로 처리하면 사실 편하지만, 연습 중이기에 for, while 둘 다 이용해서 해보겠다.

초기 조건은 둘 다 i = 0;, 연산은 둘 다 i++, 실행 조건은 둘 다 i<9인 것이다.

하나만 더 해보자.

1 ~ 100까지의 숫자를 더하다가 합이 423을 넘으면 반복을 중단하고, 거기까지의 합만 출력하도록 해보겠다.

이번엔 오히려 반복 횟수를 모르기에 while을 이용하면 훨씬 쉽다. 우선 for 문으로 처리해보겠다.

조금 어려워 보이지만, 조건에 논리연산을 넣으면 해결할 수 있다. (이런 코드가 for 문을 단순 횟수로만 생각하면 안 되는 반례이다)

반면, while 문은 실행 조건에 sum만 걸면 되니까 더 쉽다.

어떤가? 이쯤 했으면 for문과 while 문이 거의 차이가 없다는 생각이 들 것이다.


while 문의 유연성

그런데 while 문은 아까 더 유연한 for 문이라고 했듯이, while 문으로만 짤 수 있는 코드를 보여주겠다.

아마 for 문으로 처리하려면 함수라는 기능까지 가져와서, 복잡하게 해야 할 수 있는 코드일 것이다.

특히 무조건 한 번은 실행해야 하는 코드라면, for대신 do-while 문을 쓰는 게 코드상 깔끔하다.

처음에 무조건 한 번은 입력받고 조건을 따져야 할 때 이런 코드가 do-while 문의 전형적인 예이다.


무한 루프와 break

특수한 경우의 반복문을 다룰 것인데, 절대 멈추지 않는 반복문들이다.

for의 경우

for(;;){
    //code1
}

while의 경우, 1이 참임을 이용해서

while(1){
    //code1
}

이렇게 짤 수 있다. 이를 무한 루프, 무한 반복문이라고 한다.

그리고 특히 while 문의 무한 루프는 코드에서 굉장히 유용하게 쓰이는데, 복잡한 문제로 가면 실행조건이 꽤 까다롭기 때문이다.

반면 실행이 종료되는 조건은 그에 비해 명확한데, 종료 조건과 break 문을 이용해서 코드를 효율적으로 짤 수 있다.

반복문에서 break은 해당 반복 루프를 나가는 명령이기 때문이다.

또한, 이렇게 되면 do-while이라는 문법도 사실 쓸 일이 많지 않다.

위에서 나왔던 코드들을 무한 루프로 다시 짜보겠다.

실행 조건의 반대가 종료 조건이니, 종료 조건을 만족하면 나가도록 프로그램을 만들었다.

실행 조건의 반대가 answer와 x가 같을 때이니, 종료 조건을 두 값이 같을 때로 하고 만족하면 break 하게 만들었다.

어떤가? 코드가 점점 깔끔하고 보기 쉬워지는 게 느껴지는가?

특히 이게 읽기 편한 이유는 인간에게 “종료 조건”이 “실행 조건”을 파악하기보다 쉽기 때문이다.

(우리가 평소에도 “물이 끓으면 불을 꺼줘”라고 하지, “물이 끓지 않는 동안 불을 켜줘”라고 하지 않는 것처럼)

정리하자면 코드를 읽기 쉽게 짜려면, 단순 횟수를 알 때 반복은 for 문 그리고 그 나머지 경우는 무한 반복을 이용한 while 문을 이용하면 좋다.


중첩된 반복문

if 문이 중첩되는 경우가 필요했듯이, 반복문이 중첩되는 것이 필요한 경우도 생긴다.

사실 while의 중첩은 많이 필요하지 않은데, for 문의 중첩은 꽤 많은 용도에서 쓰인다.

가장 쉬운 예제로는 구구단의 출력이 있다.

1x1에서 9x9까지 모두 출력하려면, 최소 변수가 두 개가 필요하고 두 변수의 반복문은 중첩된 채로 둘 다 1 ~ 9까지 반복해야 한다.

이를 코드로 짜보면

이런 결과를 가진다.

코드가 돌아가는 과정을 보면

i = 1, 1<=9이고 그래서 안의 반복문이 실행된다. i 값은 여전히 1인 채로 j가 1~9까지 반복된다.

블록 안의 코드(j의 반복)이 끝났으니, i++ 연산이 된다.

i = 2, 2<=9 여전히 실행 조건을 만족하니 반복문이 실행된다. i가 2인 채로 j가 1~9까지 반복된다.

블록 안의 코드(j의 반복)이 또 끝났으니, i++연산이 된다.

i = 9인 반복이 끝났을 때 종료된다.

총 9*9 = 81번의 반복이 끝이 난다.


for 문이냐 while 문이냐

앞에서 while을 찬양하듯 적어놔서 그렇지, 사실 정형적인 코드에서는 for 문이 더 많이 쓰인다.

특히 뒤에 배우게 될 배열에서는 for 문이 압도적으로 편리하다.

아무튼, 두 개 다 자유자재로 쓸 수 있게 연습하는 그것만이 최선이다.


📖 오늘의 핵심(다 알기 전까지는 넘어가지 말자❗)

✅ 1. for 문을 이해하자

✅ 2. while 문을 이해하자

✅ 3. 특히 무한 루프 while이나 중첩된 for 문은 꼭 연습하자.

⚠️ 초기 상태 조건의 변수 초기화를 빼먹거나, 실행 혹은 종료 조건을 헷갈리면 안 된다. (초기화를 안 한 변수는 어떤 값이 나오는지 검색해보자.)

그러고 나서 메모리 구조 부분을 보고 왜 그런지 이해해보자

💣 과제,

  1. 4/1 - 4/3 + 4/5 - 4/7……. 을 무한 번 더하면 pi, 즉 3.14가 나온다고 알려져 있다.(Gregory-Leibniz 수열), 실제로 그런지 10번, 100번, 1000번 반복한 값을 구해보자(난이도 下)

  2. 10%의 이자를 매년 복리로 주는 은행이 있다. 초기 자금 n원을 넣고, m년이 지났을 때 돈이 얼마가 될지 계산하고 싶다. n을 입력받아 m년 후 돈을 출력하는 프로그램을 짜보자. (난이도 下) - (형식지정자를 이용하면 반올림의 자리를 설정할 수 있다. 검색해보자)

  3. 아래의 그림을 출력해보자(난이도 中)

*
**
***
****
*****

🔜 더 공부해보기,

백준(BOJ) 10950번 - A+B -3

정답 보기
#include<stdio.h>

int main(){
    int num1, num2;
    int number;
    scanf("%d", &number);

    for(int i = 0; i<number; i++){
        scanf("%d %d", &num1,&num2);
        printf("%d\n", num1+num2);
    }

    return 0;
}

백준(BOJ) 25304번 - 영수증

정답 보기
#include<stdio.h>

int main(){
    long long target;
    int n;
    scanf("%lld %d", &target, &n);

    for(int i= 0; i<n; i++){
        long long price, num;
        scanf("%d %d", &price, &num);

        target -= price*num;
    }// 영수증 총 금액에서 값을 뺀다.

    if(target){//0이 아니라면 총 금액과 합산액이 다르단 소리이고
        //0이 아닌 모든 경우는 참이니까 No가 여기서 실행된다.
        printf("No");
    }
    else{//반면에 0이라면 같다는 소리이고, 위의 if문에서 실행되지 않고 여기서 실행된다.
        printf("Yes");
    }

    return 0;
}

백준(BOJ) 25314번 - 코딩은 체육과목 입니다

정답 보기
#include<stdio.h>

int main(){
    int number;
    scanf("%d", &number);

    for(int i = 0; i<number/4; i++){
        printf("long ");
    }
    printf("int");

    return 0;
}

백준(BOJ) 2439번 - 별 찍기 -2

정답 보기
#include<stdio.h>

int main(){
    int number;
    scanf("%d", &number);

    for(int i = 1; i<=number; i++){
        for(int k = i+1; k<=number; k++){
            printf(" ");
        }
        for(int j =1; j<=i; j++){
            printf("*");
        }

        if(i!=number){
            printf("\n");
        }
    }

    return 0;
}

백준(BOJ) 10952번 - A+B -5

정답 보기
#include<stdio.h>

int main(){
    int num1, num2;
    while(1){
    scanf("%d %d", &num1, &num2);
        if(num1 == 0 && num2 == 0){
            break;
        }
        printf("%d\n", num1+num2);
    }
    return 0;
}