본문 바로가기

Programming/C

[ProjectH4C] 코딩도장 Unit 27~31 Write-Up

반복문

여태까지는 변수를 입력받고 입력받은 변수에 대해 한 번 처리하고 종료하는 코드를 작성하였는데, 코드를 작성하다 보면 같은 동작을 여러번 실행해야 하는 경우가 있다. 이러한 경우, 반복문을 이용해 원하는 만큼 반복 실행할 수 있다. 반복문의 종류에는 for, while, do ~ while이 있다.

 

for 구문

for문의 기본 형태는 다음과 같다.

 

for(초기식; 조건식; 변화식)

{

    반복할 내용

}

 

초기식을 통해 변수를 초기화 한 후, 조건식을 판별한다. 조건이 참이면 내용을 실행, 거짓이면 for문을 벗어나게 된다. for문의 동작 과정은 다음과 같다.

for문의 동작 과정. 출처: 코딩도장 27.1

루프(Loop)라고 불리는 부분이 반복 수행되는 부분이다.

보통은 변수를 하나 선언해서 해당 변수를 카운트하면서 횟수를 지정해 주는데, Hello, World!를 100번 출력하는 코드를 작성하면 다음과 같다. 

 

#include <stdio.h>

int main()
{
    for (int i = 0; i < 100; i++)    // 0부터 99까지 증가하면서 100번 반복
    {
        printf("Hello, world!\n");
    }

    return 0;
}

이 때, 카운트를 위한 변수 i를 선언과 동시에 초기화 해주고, 100이 될 때까지 1씩 증가(i++)시켜준다. 실제로 실행시켜보면, 출력문이 100번 반복하는 것을 알 수 있다. i를 1로 초기화하고, 조건을 i<=100으로 해주어도 똑같이 100번 실행되지만, 후에 배우는 배열이라는 것을 사용하기 위해선 i를 0부터 사용하는게 편리하기 때문에, 보통은 0으로 초기화해준다.

변화식은 ++가 아니여도 사용 가능하다. i를 1씩 증가시키는 대신, 1씩 감소시키면서 반복문을 실행해도 결과는 같다. 코드는 다음과 같다.

 

#include <stdio.h>

int main()
{
    for (int i = 100; i > 0; i--)    // 0부터 99까지 증가하면서 100번 반복
    {
        printf("Hello, world! %d \n", i);
    }

    return 0;
}

i의 상태를 확인하기 위해 i를 같이 찍어보면 100부터 시작해서 1까지 출력되는 모습을 볼 수 있다. 이 때, i를 main문 시작점에 따로 선언해주고 for문이 종료된 후에 i를 출력해보면 i는 1이 아닌 0이 된다. i가 1일 때 출력한 후에 i를 1 감소한 다음, 조건식에서 비교한 후에 조건이 거짓이여서 for문을 벗어나게 되기 때문에 i는 1이 아닌 0이 된다.

for문도 if문과 마찬가지로 실행할 내용이 한 줄이라면 중괄호를 생략해도 된다. 하지만 두 줄 이상이라면 중괄호를 꼭 써주어야 한다.

for문을 반복할 횟수를 사용자에 의해 지정해주는 방법도 가능하다. for문을 반복할 횟수를 저장할 변수 input에 사용자로부터 입력을 받고

for문의 조건식을 i<input으로 해준다면, 입력에 따라 반복하는 횟수가 달라진다. 감소식(i--)을 사용하는 경우, 조건식 대신 초기식을 i=input으로 초기화 해주고, 조건은 그대로 사용하면 된다. 

 

for문에서 변수를 두 개 이상 사용하는 것도 가능하다. 아래의 코드를 보면, i와 j를 함께 사용한다.

 

#include <stdio.h>

int main()
{
    for (int i = 0, j = 0; i < 10; i++, j += 2)    // i는 1씩 증가, j는 2씩 증가
    {
        printf("i: %d, j: %d\n", i, j);
    }

    return 0;
}

이를 출력해보면 실행 결과는 다음과 같으며, 동작 원리는 위에 설명한 바와 같다.

 

i: 0, j: 0
i: 1, j: 2
i: 2, j: 4
i: 3, j: 6
i: 4, j: 8
i: 5, j: 10
i: 6, j: 12
i: 7, j: 14
i: 8, j: 16
i: 9, j: 18

이처럼 변화식에는 ++, -- 뿐만 아니라 +=, *= 등등 다양한 산술 연산자가 들어올 수 있다.

 

 

무한 루프

코드를 작성하다보면, 반복 할 횟수를 확실히 입력하기 어려운 경우가 있다. 이럴 때에는 무한 루프를 통해 원하는 조건에 만족할 때까지 반복 실행할 수 있다. for문을 이용해 무한루프를 사용하는 법은 초기식, 조건식, 증감식에 아무것도 쓰지 않는 것이다.

for( ; ; )

 

 

 

변수 선언

원래의 C언어는 main함수의 시작 부분에 모든 변수를 선언해야 했지만, 1999년에 제정된 C언어 표준(이하 C99)에서부터는 중간에 사용할 수 있도록 되었다. 보통 for문을 사용하기 위해 선언하는 변수를 i로 지정하는데, 해당 변수는 for문을 위해서만 쓰이는 경우가 대부분이기 때문에, main 함수의 지역변수로 선언하기 보단, for문을 사용할 때 선언해주고 for문이 끝나면 사라지도록 사용하면 효율적으로 메모리를 사용할 수 있다.

 

 

 

 

while 구문

while의 기본구조는 다음과 같다.

 

while(조건){

    반복할 내용

}

 

이 때의 조건은, for문을 실행하기 위해 작성하는 조건과 같다. for문과 다른 점은 초기식과 변화식이 없다는 것이다. 그렇기에 해당 기능을 구현하기 위해서는 while문 이전에 초기화할 변수를 선언한 후에, 중괄호 내부에 변화식을 작성하면 된다. 위의 Hello, world!를 100번 출력하는 for문을 while문으로 바꾸면 아래와 같다.

 

#include <stdio.h>

int main(){
	int i=0;
	while(i<100){
		printf("Hello, world! \n");
		i++
	}
    
	return 0;
}

이러한 구조를 제외하고, 사용 방법은 for문과 완전히 동일하다. 무한루프를 사용할 때에는 while문의 조건이 항상 참이도록 하면 되는데, 보통은 while(1) 혹은 while(true)로 표현하여 무한루프를 사용한다.

 

 

do ~ while 구문

do ~ while의 기본 형태는 다음과 같다.

 

do{

    반복할 내용

} while (조건식);

 

do while과 while의 다른 점은 while은 조건식을 확인한 다음, 참일 경우 실행하기 때문에 최소 실행 횟수가 0이지만, do while은 조건식을 확인하기 전에 반복할 내용을 쓰기 때문에 최소 실행 횟수가 1번이라는 것이다. 최초에 반복할 내용을 한번 실행한 후에 조건식을 확인하고, 거짓이면 do~while문을 벗어나게 된다. 그 외의 경우는 for, while문과 모두 같다. 다만 무조건 한 번은 실행되는 특성으로 인해, 코드를 한번만 실행되도록 작성할 수도 있다.

do{
	printf("Hello, world! \n");
} while (0);

위와 같이 작성한다면, 무조건 한번은 실행되는 특성 때문에 Hello, world!가 한번 출력되고, 조건식이 거짓이기 때문에 벗어나게 된다.

do while문을 사용할 때에는, do 뒤에는 세미콜론이 붙지 않지만 while의 뒤에는 세미콜론을 붙여야 한다는 점을 주의해야 한다.

 

 

 

break와 continue

break는 switch문에서 필수로 쓰이지만, 그 외에도 반복문의 흐름을 제어하는데 사용된다. 컴파일러는 break를 만나면 반복 횟수가 몇번 남았든 상관없이 반복문을 바로 빠져나오게 된다. break 외에도 continue라는 명령문이 존재하는데, break는 반복문을 완전히 탈출하게 하지만, continue는 해당 명령문 아래의 코드를 전부 건너뛰고 다음 번 반복으로 계속해서 진행되게 된다. 반복문의 흐름을 유지한 채 다음 번 반복을 실행하고 싶다면 continue를, 반복문을 벗어나고 싶다면 break를 사용하면 된다. break의 사용 예시는 다음과 같다.

 

#include <stdio.h>

int main()
{
    int num1 = 0;

    while (1)   // 무한 루프
    {
        num1++;  // num1을 1씩 증가시킴

        printf("%d\n", num1);

        if (num1 == 100)    // num1이 100일 때
            break;          // 반복문을 끝냄. while의 제어흐름을 벗어남
    }

    return 0;
}

num1이 순차적으로 증가하다가, 100이 되면 if문에 의해 break를 실행해서 반복문을 벗어나게 된다. break는 보통 반복횟수를 정하지 않고 반복문을 사용할 때, 무한루프로 반복문을 선언하고 그 안에 반복을 끝내는 조건을 적어줄 때 사용된다.

 

continue의 예시는 다음과 같다.

#include <stdio.h>

int main()
{
    for (int i = 1; i <= 100; i++)    // 1부터 100까지 증가하면서 100번 반복
    {
        if (i % 2 != 0)               // i를 2로 나누었을 때 나머지가 0이 아니면 홀수
            continue;                 // 아래 코드를 실행하지 않고 건너뜀

        printf("%d\n", i);
    }

    return 0;
}

1부터 100까지 반복하는데, 2의 배수가 아니면 continue, 그렇지 않으면 i를 출력해주는 코드이다. 처음 i는 1이기 때문에 if문이 참이므로 continue가 실행되어서 해당 반복구간을 모두 건너뛰고 i++이 된 다음에 다음 번 반복을 진행한다.

 

 

 

이중 반복문

반복문을 한 번 사용하면 가로, 세로의 방향으로 일직선 형태의 출력만 가능하다. 만약 직선 형태가 아니라 가로, 세로가 모두 존재하는 평면의 형태로 출력하고 싶다면 반복문을 이중으로 중첩해서 사용하면 된다.

 

#include <stdio.h>

int main(){
  int i,j;

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

 

위의 코드를 실행하면, 첫 줄에 별이 하나 출력되고, 줄이 바뀌면서 별의 개수가 하나씩 증가하게 된다.

 

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

 

먼저, 처음의 for문에서 i가 0이 된다. 그 후에 j에 관한 for문을 실행한다. i=0이고 조건식은 j<=i이기 때문에 '*'을 한번 출력하고 j=1이 되면 반복문을 벗어나게 되고, 바깥의 for문의 마지막 줄인 '\n'이 출력된다. 이로써 첫 줄에는 '*'이 하나가 출력되게 된다. 그 다음 i가 증가하여 1이 되고 다시 내부의 for문이 실행되는데, 이 때에는 j가 0, 1일 때 참이 되므로 '*'을 두 번 출력하고 for문을 벗어나게 된다. 이렇게 두 번째 줄에는 '*'이 2개 출력된다. 이를 5번 반복한다면 셋째 줄엔 3개, 넷째 줄엔 4개, 다섯째 줄엔 5개가 출력된다.

계단 형태가 아닌 사각형 형태로도 출력이 가능하다. 출력 예시를 먼저 보면 아래와 같다.

 

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

한 줄에 5개씩, 5줄 출력된다. 단순히 생각해서 '*' 한개를 출력하는 동작을 5번 반복하는 반복문을 통해 5개를 연속으로 출력하게끔 해주고, 그 반복문을 5번 반복하면서 줄 바꿈('\n')해주는 반복문을 그 밖에 써주면 된다. 코드는 다음과 같다.

 

#include <stdio.h>

int main()
{
    for (int i = 0; i < 5; i++)    // 5번 반복. 바깥쪽 루프는 세로 방향
    {
        for (int j = 0; j < 5; j++)    // 5번 반복. 안쪽 루프는 가로 방향
        {
            printf("*");               // 별 출력
        }
        printf("\n");              // 가로 방향으로 별을 다 그린 뒤 다음 줄로 넘어감
    }

    return 0;
}

 

처음 공부할 땐 많이 어려워 했던 내용이였지만, 이중 반복문 관련 코드를 많이 보고 예제를 많이 풀다보면 직감적으로 이중 반복문이 필요한 경우를 알게 된다.

 

 

 

 

 

 

 

 

 

#27.10 퀴즈 

i가 조건식의 참이 되는 경우가 몇 가지인지 세어보면 된다.

a는 0~8 => 9개, b는 1~8 => 8개, e는 1~9 => 9개 이고, c는 0~9 => 10개, d는 1~10 => 10개이므로 답은 c, d이다.

 

 

 

10부터 1까지 감소해야하기 때문에 초기식은 i=10이 되어야 한다. 1까지 감소해야 하므로 1보다 크거나 같은지, 혹은 0보다 큰지 확인하면서 1씩 감소하면 된다. 답은 c, d.

 

for문을 선언하는 줄에는 세미콜론(;)을 붙이면 안된다. 답은 b.

 

초기식, 조건식, 변화식을 모두 비워주면 된다. 답은 for( ; ; )

 

 

#27.11 연습문제: for 반복문에서 변수 두 개 사용하기

#include <stdio.h>

int main()
{
    for (_____________________________________)
    {
        printf("%d %d\n", i, j);
    }

    return 0;
}

실행 결과

2 5
4 4
8 3
16 2
32 1

각각을 i, j로 선언하면 되는데, 앞의 숫자는 2부터 시작해서 2배씩 증가하고 뒤의 숫자는 5부터 시작해서 1씩 감소한다. 조건은 i<=32로 작성하거나 j>=1로 작성해주면 된다. 혹은 둘을 ||(OR)연산을 통해 한꺼번에 작성해주어도 된다. 답은

int i=2, j=5; j>=1 || i<=32; i*=2, j--

 

#27.12 심사문제: 알파벳 순서로 출력하기

알파벳 a~z는 a부터 시작해서 1씩 더해주면 모두 출력할 수 있다. 이는 아스키코드를 활용한 방법인데, 소문자 'a'의 아스키코드는 97이며, 이로부터 1씩 더하면 각각 'b', 'c', 'd'의 아스키코드가 되기 때문이다. a부터 출력하기 때문에 i는 0부터 시작하면 된다. 이 때, ch+i가 'z'보다 커질 수 있기 때문에 조건은 ch+i <= 'z'로 써주면 된다. 그 후에 ch+i를 출력해주면 된다. 코드는 아래와 같다.

 

#include <stdio.h>

int main(){
    char ch;
    scanf("%c", &ch);
    
    for(int i=0; ch+i<='z'; i++)
        printf("%c", ch+i);
    
    return 0;
}

 

 

#28.9 퀴즈

b -> 반복문의 초기식은 while문 이전에 정의한다.

c -> while문은 반복 횟수가 불명확해도 사용할 수 있다.

답은 a, d, e.

 

조건이 i>10인데 i의 초기식은 0이다. 거짓이므로 실행되지 않고 바로 넘어간다. 답은 b.

 

 

조건에 true 또는 1을 써주면 된다. 숫자만 사용하라 했으니 답은 while(1).

 

#28.10 연습문제: while 반복문 사용하기

 

#include <stdio.h>

int main()
{
    unsigned char i = 1;
    while (_______)
    {
        printf("%u\n", i);
        i <<= 1;
    }
    return 0;
}

실행 결과

1
2
4
8
16
32
64
128

i가 128까지 실행되었으므로 단순하게 i<=128로 작성해주면 되는 줄 알았지만, 128에서 <<=1 해주면 다시 0이 된다. 결국 무한루프에 빠지게 되므로, 조건을 i != 0과 같이 0일 때 벗어날 수 있도록 작성해주어야 한다.

 

#28.11 심사문제: 교통카드 잔액 출력하기

#include <stdio.h>

int main(){
    int balance;
    scanf("%d", &balance);
    while(balance>=1200){
        balance -= 1200;
        printf("%d \n", balance);
    }
    
    return 0;
}

 

처음 입력한 값은 출력되지 않기 때문에, 잔액에서 1200원을 먼저 빼준 후에 출력해주면 된다. 만약 조건을 balance >=0으로 해준다면, 0일 때도 실행이 되어서 1200원 차감한 후에 -1200을 출력한다. 잔액은 음수가 될 수 없기 때문에 balance >= 0 대신에 balance >=1200으로 조건식을 작성하면 된다.

 

 

#29.8 퀴즈

a -> 횟수가 정해져 있지 않아도 사용 가능하다.

d -> 0을 지정하면 한번, 1을 지정하면 무한 루프가 된다.

답은 b, c, e.

 

처음 내용이 실행되면 i가 1이 된다. 후에 조건을 확인하고 참이되어야하고, 두 번째 실행되고 나면 i가 2가 된다. 조건이 참이되고서 세 번째 실행되면 i가 3이 되는데, 이 때의 조건이 거짓이 되어야 더 이상 반복하지 않고 벗어나게 된다.조건을 i < 3으로 작성한다면 거짓이 되기 때문에 답은 c.

do while 반복문을 한 번 실행하는 방법은 조건에 0을 작성하는 것이다. 답은 c.

 

 

#29.9 연습문제: do while 반복문 사용하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char c1;

    do
    {
        scanf("%c", &c1);
    } while (__________);

    printf("프로그램 종료\n");

    return 0;
}

q가 입력되면 반복문을 벗어나야 하고, 그 외의 문자이면 반복문을 계속 실행해야 한다. 고로 조건식에서 c1이 q인지 비교해주면 된다. c1 != 'q' 로 작성해주면 q가 아닐 때 참이 되어서 계속 반복하고, q가 입력되면 거짓이 되어 반복문을 벗어나게 된다.

 

 

#29.10 심사문제: 숫자의 합 구하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    unsigned int num1;
    unsigned int sum = 0;

    scanf("%d", &num1);

    unsigned int i = 0;
    do
    {
        _____________
        _____________
    } while (i <= num1);

    printf("%d\n", sum);

    return 0;
}

0부터 입력된 숫자까지의 합을 구해야한다. i를 하나씩 증가시키면서 sum에 i를 더해주면 된다. 이 때, i를 증가시키고 sum에 더해주면 값이 달라지므로, sum에 i를 더해준 후에 i를 증가시켜야 한다.

sum += i;

i++;

 

 

#30.5 퀴즈

break는 반복문을 벗어나게 해주는 역할을 하며, continue는 그 아래의 코드를 실행하지 않고 건너뛰며 반복은 중단하지 않는다.

답은 a, d.

10이 되면 break를 이용해 반복문을 벗어나야 한다. 답은 a.

i가 짝수일 땐 아무동작도 하지 않고 넘어가며, 반복문은 유지되어야 하기 때문에 continue를 사용해야 한다. 답은 b.

 

 

#30.6 연습문제: 3으로 끝나는 숫자만 출력하기

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    int i = 1;

    for (;;)
    {
        ① _______________
        ...
        _________________

        ②________________
        _________________

        printf("%d ", i);
        i++;
    }

    return 0;
}

2개의 if문이 들어가야 한다. 하나는 일의 자리 숫자가 3인지 확인해야 하고, 다른 하나는 i가 103보다 큰 지 확인해야 한다.

어떤 수의 1의 자리 숫자를 확인하고자 한다면 해당 숫자와 10을 나머지 연산 해주어서 나온 값을 보면 된다. 만약 1245라는 숫자가 있는데 이를 1245%10으로 계산해주면 5가 나온다. 이러한 방법을 통해 1번 if문을 작성하면 된다. 다만, 아래에 i를 출력해주는 코드가 있기 때문에, 1번 if문에서는 i%3이 0이 아닌 경우, i를 하나 증가시킨 후 아래의 코드를 넘어가는 continue 명령문을 작성해주면 된다.

 

if(i%10 != 3){
	i++;
	continue;
}

if(i>103)
	break;

 

 

#30.7 심사문제: 두 수 사이의 숫자 중 7로 끝나지 않는 숫자 출력하기

i를 이용해서 num1부터 num2까지 하나씩 증가시킨 후, 그 때의 숫자가 7로 끝나는지 (i%10==7)확인 후, 7로 끝나면 i를 1 증가시킨 후 continue해주면 된다.

 

if(i%10 == 7){
    i++;
    continue;
}

if(i>num2)
    break;

 

 

 

#31.5 퀴즈

 

해당 코드는 반복문 내에 반복문이 존재하는 이중 반복문(중첩 루프)이며, i는 세로 방향, j는 가로 방향을 처리한다. 코드를 보면 '*'을 5번 출력하는 반복문을 5번 반복하고 있기 때문에 출력은 정사각형 모양의 별이 된다. 답은 a, d, e.

삼각형 모양으로 출력하려면 j=0부터 j<=i일 때까지만 '*'을 출력해주어야 한다. 답은 b.

 

#31.6 연습문제: 역삼각형 모양으로 별 출력하기

 

#include <stdio.h>

int main()
{
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            ____________________
            ...
            ____________________
        }
        printf("\n");
    }
    return 0;
}

 

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

정상적인 삼각형을 출력해주는 조건식은 j<=i였다. 역삼각형으로 출력하는 조건식은 그와 반대인 j>=i가 된다. j>=i가 참이면 '*'을, 거짓이면 " "를 출력하면 된다. 답은 아래와 같다.

 

if(j>=i)
	printf("*");
else
	printf(" ");

 

#31.7 심사문제: 산 모양으로 별 출력하기

 

코드를 작성하기 전에 출력 예시를 먼저 분석해보았다. 입력이 3일 땐, 3줄이 출력되었고 5일 땐 5줄이 출력되었다. 세로를 담당하는 제일 바깥의 반복문은 해결이 되었다. 문제는 별이 한쪽으로 치우쳐진 형태가 아니라 가운데로 솟은 형태인데, 이를 해결하기 위해 for문 두개를 내부에 각각 써주어서 처음 for문은 띄어쓰기를, 두번째 for문은 별을 출력하는 식으로 작성하기로 했다. 먼저 띄어쓰기의 개수를 보면, 입력이 3일 땐 첫줄에 2개부터 해서 마지막줄엔 0개이고, 입력이 5일 땐, 첫줄에 띄어쓰기가 4개가 들어가고 마지막줄에 0개가 들어간다. 입력을 num이라 하면, 띄어쓰기는 num-1개부터 0개 까지 각 출에 출력해주면 된다. 이를 해결하기 위해 for(j=i; j<num; j++)로 작성하였다. i가 1씩 증가함에 따라 j의 반복횟수가 1씩 줄어들고, 결과적으로 띄어쓰기가 한 개씩 줄어드는 결과를 얻을 수 있다. 그리고 아래에 for문을 따로 하나 더 써주어서 별을 출력하려 했다. 조건식을 어떻게 해야할 지 막막했는데, 별의 갯수를 보면, 1, 3, 5, 7, 9 ... 개씩 출력이 되는 걸 알 수 있다. 여기서 수학적인 지식이 조금 들어가는데 해당 수열은 등차수열로써 일반항은 2n-1이 된다. 그래서 for(j=0; j<i*2; j++)로 작성해주었다. i의 초기값은 1이므로 해당 for문은 초기에 j=0일때 한번 실행 되고, i가 1씩 증가함에 따라 j의 범위가 2씩 늘어나게 되어서 1, 3, 5, 7의 형태로 출력이 가능하다. 코드는 아래와 같다.

#include <stdio.h>

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

  for(int i=1; i <= num; i++){
    for(int j=i; j<num; j++){
      printf(" ");
    }

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