C, 반복문, while, do while, for


반복문이란?


사용자가 입력하는 자연수만큼 ‘*‘을 출력하는 프로그램을 가정해보겠습니다.

만약 사용자가 10을 입력한다면 다음이 출력되야 합니다.

**********

이렇게 똑같은 작업을 반복해서 할 수 있는 문법을 반복문이라 합니다.




이번 챕터의 목표


1. 피라미드 출력

c_repeat_goal1


2. x5를 제외한 구구단 출력

c_repeat_goal2




while


먼저 1부터 10까지 출력하는 프로그램 예시입니다.

#include <stdio.h>

int main(void)
{
    int i = 1;
    
    while(i < 11)
    {
        printf("i = %d\n",i);
        i++;
    }
    
    printf("\n");
    return 0;
}

/*
 i = 1
 i = 2
 i = 3
 i = 4
 i = 5
 i = 6
 i = 7
 i = 8
 i = 9
 i = 10
*/

while()에서 괄호 안에 있는게 조건문 입니다.

이 조건문이 일동안은 계속 스코프({})안의 내용이 실행되다가

조건문이 거짓이 되는 순간 while문은 끝나게 됩니다.


다른 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    char ch = 0;
    
    while((ch = getchar()) != '\n')
    {
        putchar(ch);
        printf(" printf in while loop\n");
    }
    
    printf("\n");
    return 0;
}

/*
 teemo
 t printf in while loop
 e printf in while loop
 e printf in while loop
 m printf in while loop
 o printf in while loop
*/

while문은 입력받은 문자가 개행문자(엔터키)가 아니면 계속 반복됩니다.

예를 들어 예제와 같이 teemo 를 입력 후 엔터를 치면

‘t’, ‘e’, ‘e’, ‘m’, ‘o’, ‘\n’ 이 6개의 문자는 버퍼에 저장됩니다.

그 상태에서 getchar()를 통해 버퍼에 있는 문자열을 하나하나씩 가져오면서

while문의 조건을 확인하고, 스코프 안의 구문들이 실행되게 됩니다.


이번엔 맨 처음에 반복문에 대해서 설명할 때 예로 들었던

자연수를 입력받고, 그만큼 ‘*‘을 출력하는 프로그램에 코드입니다.

#include <stdio.h>

int main(void)
{
    int n = 0, index = 0;
    printf("자연수를 입력받아, 그만큼 *을 찍는 프로그램\n");
    printf("0이하 수일 경우 1로 인식\n\n");
    
    printf("자연수 입력: ");
    scanf("%d", &n);
    
    if(n <= 0) n = 1;
    
    while(++index <= n) printf("*");
    
    printf("\n\n");
    return 0;
}

/*
 자연수를 입력받아, 그만큼 *을 찍는 프로그램
 0이하 수일 경우 1로 인식
 
 자연수 입력: 5
 *****

*/

while문도 이전 챕터에서 살펴봤던 제어문처럼

실행할 구문이 한줄이면, 위 코드처럼 스코프없이 한줄로 쓸 수 있습니다.


while뿐 아니라 밑에서 살펴볼 for문도 마찬가지로

반복문은 무한 루프를 조심해야합니다.

while문은 괄호안에 조건문이 거짓일 때 루프를 빠져나오게 됩니다.

그런데 논리적 오류로 인해 조건문이 거짓인 경우가 안나올 수 있습니다.

무한루프의 간단한 예를 들어보겠습니다.

#include <stdio.h>

int main(void)
{
	int x = 0;

	while(x >= 0)
	{
		printf("x = %d\n", x);
	}

	return 0;
}

위의 코드에서 x의 값은 초기값이 0이고, 그 뒤로도 바뀌는 일이 없습니다.

즉, while문의 조건인 x >= 0은 계속 참이므로

끝나지 않는 while문 즉, 무한루프가 됩니다.


또다른 무한루프 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    int x = 0;
    
    while(x >= 0)
    {
        x++;
    }
    
    printf("x = %d\n", x);
    return 0;
}

/*
x = -2147483648
*/

이 코드를 실행하면 컴퓨터 성능에 따라 2초~10초 후에

결과값이 출력되면서 프로그램이 끝납니다.

그런데 while문을 보면 x는 계속 증가만 하니

while문의 조건문은 항상 참이 되서 무한루프가 될 것 같은데

시간이 좀 걸리긴 하지만 프로그램이 정상종료됩니다.

그 이유는 x값이 계속 증가하다가 마침내 int의 최대값에 도달하고 나면

거기서 1이 더해지면 int의 최소값이 되기 때문입니다.

비트 연산으로 살펴보면, int의 최대값은

0111 1111 1111 1111 1111 1111 1111 1111

이고 여기에 1을 더하게 되면

1000 0000 0000 0000 0000 0000 0000 0000

이 되어 -2147483648가 됩니다.


이 while문은 중첩이 가능합니다.

2중 while문의 예제 코드 입니다.

#include <stdio.h>

int main(void)
{
    int a = 0, b = 0;
    
    while(a < 5)
    {
        while(b < 5)
        {
            printf("$\t");
            b++;
        }
        printf("\n");
        a++;
        b = 0;
    }
    
    printf("\n");
    return 0;
}

/*
 $    $    $    $    $
 $    $    $    $    $
 $    $    $    $    $
 $    $    $    $    $
 $    $    $    $    $
*/




for


먼저 for문을 이용해 1부터 10까지 출력하는 프로그램 코드입니다.

#include <stdio.h>

int main(void)
{
    int n = 0;
    
    for(n = 1; n < 11; n++)
    {
        printf("n = %d\n", n);
    }
    
    printf("\n");
    return 0;
}

/*
 n = 1
 n = 2
 n = 3
 n = 4
 n = 5
 n = 6
 n = 7
 n = 8
 n = 9
 n = 10

*/

for문도 괄호안에 조건식이 들어가있습니다.

위 코드의 조건식을 해석해보면 다음과 같습니다.

n은 1부터 시작하되, n < 11을 만족하는 한 계속 돌아가고
n값은 한번 돌때마다 1씩 증가한다.


for문 안에 있는 조건식은 일부 또는 전부를 생략할 수 있습니다.

예를 들어 다음과 같이 쓰는게 가능합니다.

for(; n<11; n++)
for(n=1; n<11; )
for(;;)

이 중, for(;;)는 아무 조건식이 없으므로 while(1)과 같은 의미입니다.


for문 예제 2개만 더 살펴보겠습니다.

먼저 1부터 입력받은 수까지의 합을 구하는 프로그램입니다.

#include <stdio.h>

int main(void)
{
    int n = 0, sum = 0;
    printf("1부터 입력받은 자연수까지의 합 구하는 프로그램\n\n");
    
    printf("자연수를 입력하세요: ");
    scanf("%d", &n);
    
    for(int i=1; i<=n; i++) sum += i;
    
    printf("sum: %d\n\n", sum);
    return 0;
}

/*
 1부터 입력받은 자연수까지의 합 구하는 프로그램
 
 자연수를 입력하세요: 10
 sum: 55
*/


다음으로 직각삼각형 찍는 프로그램입니다.

#include <stdio.h>

int main(void)
{
    for(int i=1; i<6; i++)
    {
        for(int j=1; j<=i; j++) printf("#");
        printf("\n");
    }
    
    printf("\n");
    return 0;
}

/*
 #
 ##
 ###
 ####
 #####
*/




do while


while문과 비슷한 do while문입니다.

차이점이 있다면, do while문은 조건문이 참이든 거짓이든

무조건 맨처음 한번은 실행한다는 것입니다.

다음 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    int x = 2;
    
    do
    {
        printf("x = %d\n", x);
        x++;
    }while(x % 2 == 1);
    
    printf("\n");
    return 0;
}

/*
 x = 2
 x = 3

*/

do while문은 스코프의 끝부분에 while을 쓰고 조건문을 씁니다.

여기선 x가 홀수여야 스코프 안이 돌아가는 조건입니다.

맨 처음엔 x = 2 로 짝수이지만, 검사하는 부분이 마지막에 있으므로

일단 실행이 되고 x++을 통해 x값이 증가합니다.

이미 x = 3인 상태에서 조건문의 검사를 받으니 통과가 되고,

다음 루프로 이어집니다. 다음 루프에선 x = 4가 되므로

조건문이 거짓이 되어 do while문을 벗어나게 됩니다.




break, continue


break와 continue는 지금까지 살펴본 반복문을 빠져나가는 제어문입니다.

먼저 break부터 예제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    for(int i=1; i<=10; i++)
    {
        if(i == 4)
        {
            break;
        }
        printf("i = %d\n", i);
    }
    
    return 0;
}

/*
 i = 1
 i = 2
 i = 3
*/

break의 정의를 적어보자면 다음과 같습니다

if문(의 스코프)을 제외하고 가장 가까운 스코프를 빠져나간다.

일단 위 코드의 for문은 1부터 10까지를 출력하는 코드입니다.

그런데 i == 4이면 break를 하라 되어있습니다.

그러면 이 break로 인해 이 break가 소속된 if문을 제외하고,

가장 가까운 스코프인 for문의 스코프를 그냥 빠져나가게 됩니다.

그래서 출력문은 i = 3 까지만 나오게 됩니다.


이번엔 continue 에제를 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    for(int i=1; i<=10; i++)
    {
        if(i == 4)
        {
            continue;
        }
        printf("i = %d\n", i);
    }
    
    return 0;
}

/*
 i = 1
 i = 2
 i = 3
 i = 5
 i = 6
 i = 7
 i = 8
 i = 9
 i = 10
*/

위의 break코드에서 break를 continue로만 바꿧습니다.

출력결과는 1부터 10까지 모두 잘 출력된 것 같지만

잘 살펴보면 i = 4 가 출력되지 않았습니다.

즉, continue의 뜻은 다음과 같습니다.

자기가 소속된 if문을 제외하고 가장 가까운 스코프의 나머지 내용을 무시합니다.

그리고 바로 다음 루프로 넘어갑니다.

그래서 i == 4 가 참일 때 continue가 실행되고,

if문을 제외한 가장 가까운 스코프인 for반복문의 continue 아래내용이 모두 무시되고,

바로 다음 루프인 i == 5 로 넘어가게 됩니다.


가장 가까운 스코프라는 구문을 이해하기 위해

2중 for문에서 break를 사용해보겠습니다.

#include <stdio.h>

int main(void)
{
    for(int i=1; i<5; i++)
    {
        for(int j=1; j<5; j++)
        {
            if(j == 3) break;
            printf("i = %d, j = %d\n", i, j);
        }
        printf("\n");
    }
    
    return 0;
}

/*
 i = 1, j = 1
 i = 1, j = 2
 
 i = 2, j = 1
 i = 2, j = 2
 
 i = 3, j = 1
 i = 3, j = 2
 
 i = 4, j = 1
 i = 4, j = 2
*/

잘 살펴보면 break를 통해 안쪽의 for문만 빠져나갔고,

바깥쪽에 for문은 계속 실행되는 것을 볼 수 있습니다.

continue도 마찬가지라 보면 되겠습니다.




Back to the Goal


1. 피라미드 출력

c_repeat_goal1

#include <stdio.h>

int main(void)
{
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 4 - i; j++) printf("\t");
		for (int j = 0; j < 2 * i + 1; j++) printf("*\t");
		printf("\n");
	}

	printf("\n");
	return 0;
}


2. x5를 제외한 구구단 출력

c_repeat_goal2

#include <stdio.h>

int main(void)
{
	int n = 0;
	printf("자연수를 입력받아, 해당 구구단을 출력하는 프로그램\n");
	printf("단 x5는 제외하고 출력\n\n");

	printf("자연수를 입력하세요: ");
	scanf("%d", &n);

	for (int i = 1; i < 10; i++)
	{
		if (i == 5) continue;
		printf("%d * %d == %d\n", n, i, n*i);
	}

	printf("\n");
	return 0;
}