[C] 반복 제어문

JOOYEUN SEO·2023년 8월 11일

C 언어

목록 보기
6/13
post-thumbnail

반복 제어문을 사용하여 지정된 명령어들을 조건이 만족될 때까지 반복 수행할 수 있다.

1. while문

주어진 조건이 참인 동안에만 while문 내부를 반복 수행하고, 조건이 거짓이 되는 순간 루프를 빠져나와 반복문 다음에 나오는 명령문을 수행한다.

⌨️ 예제 1

#include <stdio.h>

int main() {
    int i = 1;				// i 값은 1부터 시작
     
    while(i <= 5) {		 	// i 값이 5일 때까지만 반복
        printf("%d\n", i);	// 반복 실행 문장(i 값 출력)
        i++;				// i 값에 1을 더함
    }
}

🖥️ 실행 결과

1
2
3
4
5

⌨️ 예제 2

// 예제 1을 while문 대신 goto문을 사용해서 구현 가능
#include <stdio.h>

int main() {
    int i = 1;

    repeat :
    printf("%d\n", i);
    if(i < 5) {
        i++;
        goto repeat;
    }
}

🖥️ 실행 결과

1
2
3
4
5

goto문은 안 쓰는 것이 좋기 때문에 참고만 하고 넘어가면 된다.


🔍 while문의 무한 루프

조건문에 항상 참이 되는 값이 올 경우, 무한히 반복되는 루프가 만들어진다.

⌨️ 예제 3

// 실행하면 1씩 증가하는 숫자를 무한히 출력하게 되는 무한 루프
#include <stdio.h>
#include <stdbool.h>

int main() {
    int i = 1;

    while(true) {     // '참'을 의미하는 true를 조건문에 넣기
        printf("%d ", i);
        i++;
    }
}

🖥️ 실행 결과

1 2 3 4 5 6 7 8 9 10 11 12 ...

끝없이 실행되는 코드는 ctrl + c 로 강제 정지시킬 수 있다.


⌨️ 예제 4

// 숫자 0을 입력할 때까지 무한히 반복 요청하는 프로그램
#include <stdio.h>

int main() {
    int n;

    while(1) {      	// 무한 while 루프
        printf("숫자 0을 입력해 주세요.\n");
        scanf("%d", &n);
        if(n == 0)		// n의 값이 0이면 while 루프 종료
            break;		// 루프 밖으로 빠져나가기
    }
    printf("숫자 0을 입력하셨습니다.\n");
}

🖥️ 실행 결과

숫자 0을 입력해 주세요.
2  [Enter↵]
숫자 0을 입력해 주세요.
67  [Enter↵]
숫자 0을 입력해 주세요.
0  [Enter↵]
숫자 0을 입력하셨습니다.

무한 루프를 필요에 따라 break문과 함께 사용할 수도 있다.

2. do~while문

do~while문은 while문과 달리 조건이 아예 만족되지 않더라도 최소한 처음 한 번은 반드시 실행하게 된다는 차이점이 있다. while(조건식)문의 뒤에 세미콜론(;)을 반드시 넣어야 한다. ❗️세미콜론 빠트리면 에러 발생

⌨️ 예제 5

#include <stdio.h>

int main() {
    int i = 10;				// 조건을 만족하지 않는 값
     
    do {                    // i 값과 상관없이 무조건 do 안의 내용을 한 번 실행
        printf("%d\n", i);  // 반복 실행할 문장들
        i++;
    } while(i <= 5);		// 맨 처음 do 안의 내용 실행 후, 조건 확인
}

🖥️ 실행 결과

10

while문이었다면 아예 루프 자체가 실행되지 않아 아무것도 출력되지 않았겠지만, do~while문에서는 반복문이 한 번 실행됐다.

3. for문

while문 대신 for문을 사용하면 좀 더 편하고 짧게 반복문을 작성할 수 있는 특수한 경우들이 있다.

  • 일정하게 증가 또는 감소되는 변수가 필요할 때
  • 특정 횟수만큼 작업을 반복하고자 할 때
  • 배열의 모든 원소에 순차적으로 접근하고자 할 때
    (배열과 for문은 거의 함께 붙음)

for문의 괄호 안은 (초기식; 조건식; 증감식)으로 구성되어 있으며, 초기식은 처음 한 번만 수행된다.
❗️초기식과 조건식 뒤 세미콜론(;) 잊지 말기

⌨️ 예제 6

/* 예제 1을 while문 대신 for문으로 완벽하게 대체 가능
<for문 동작 순서>
1. i 값을 1로 초기화
2. 반복 조건 검사(참이면 3번으로, 거짓이면 루프 종료)
3. 반복 문장 실행 후 i에 증감값 계산(+1)
4. 다시 2번으로 돌아가서 실행 */
#include <stdio.h>

int main() {
    int i;						// 변수 i 선언

    for (i = 1; i <= 5; i++) {	// for문 동작 순서 참고
        printf("%d\n", i);		// 반복 실행 문장
    }
}

🖥️ 실행 결과

1
2
3
4
5

⌨️ 예제 7

// n보다 같거나 작으면서 2의 거듭제곱인 숫자들만 출력하는 프로그램
#include <stdio.h>

int main() {
    int n;
    scanf("%d", &n);
    
    for(int i = 1; i <= n; i *= 2) {
        printf("%d\n", i);
    }
}

🖥️ 실행 결과

15  [Enter↵]
1
2
4
8

이 예제에서는 변수 i의 선언과 초깃값 대입을 for문 안에서 했다.
변수를 for문의 바깥과 안에서 선언하는 것의 차이점은 다음과 같다.

  • for문 바깥에서 선언 : 해당 for문 뿐 아니라 다른 곳에서도 사용 가능
  • for문 에서 선언 : 해당 for문 안에서만 사용 가능한 변수가 됨
    (for문이나 for문 안에 for문이 중첩된 구조를 많이 사용하는 프로그램의 경우, 특정 변수가 어느 for문에 사용되는지 명확히 하기 위해 해당 for문 안쪽에서 선언하는 것이 더 권장된다.)

(1) for문에서 괄호 안의 식을 다양하게 사용하기

괄호 안의 초기식, 조건식, 증감식을 복수로 넣거나 일부를 생략할 수도 있다. 다만 생략을 하더라도 초기식과 조건식 뒤의 세미콜론(;)은 꼭 써 줘야 한다.

1) 초기식 생략

루프의 변수를 for문 앞에서 초기화했다면, 괄호 안에서 생략 가능하다.

int i = 1;
for( ; i <= 5; i++) {

2) 조건식 생략

괄호 안에서 조건식을 생략하고, 반복문 안에서 if문을 사용하는 것으로 대신할 수 있다. 만약 if문 없이 그냥 조건식을 생략한다면, 조건을 무조건 참이라고 간주하여 무한 루프 구조가 된다.

for(int i = 1; ; i++) {
	if(i <= 5)
    	실행할 문장;
    else
    	break;

3) 증감식 생략

반복문 안에서 증감식을 수행하는 것이 더 유용할 때가 있다(예를 들어 for문 안의 특정 if문의 조건을 만족했을 때만 증감값을 계산하고 싶을 경우 등).

for(int i = 1; i <= 5; ) {
	i = i + 1;

4) 여러 개의 초기식이나 증감식

괄호 안에 초기식과 증감식을 여러 개 넣는 것도 가능하다.

⌨️ 예제 8

// 1부터 n까지 모든 숫자의 합을 출력하는 프로그램
#include <stdio.h>

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

    int sum = 0;
    for(int i = 1; i <= n; i++) {
        sum += i;
    }
    printf("%d\n", sum);
}

🖥️ 실행 결과

100  [Enter↵]
5050

⌨️ 예제 9

// 예제 8에선 변수 i만 괄호 안에 정의됐지만, 예제 9에서는 i와 sum 둘 다 초기식으로 넣었다. 
#include <stdio.h>

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

    int i, sum;
    for(i = 1, sum = 0; i <= n; sum += i, i++); // 중괄호 안에 아무것도 없어서 세미콜론으로 마무리
    printf("%d\n", sum);
}

🖥️ 실행 결과

5  [Enter↵]
15

예제 8에서는 "sum += i;"이 중괄호 안에 있었지만, 예제 9에서는 변수 sum을 초기식으로 설정하면서 "sum += i;"도 증감식으로 함께 괄호 안에 들어왔다. 이 때 두 증감식의 순서를 유의해서 사용해야 한다(sum에 i 값을 더해준 후, i에 1을 더해야 함).


⌨️ 예제 10

// n개만큼 별을 출력하는 프로그램
#include <stdio.h>

int main() {
    int n;
    scanf("%d", &n);
    
    for(int i = 1; i <= n; i++) {
        printf("*");
    }
    printf("\n");
}

🖥️ 실행 결과

8  [Enter↵]
********

⌨️ 예제 11

// 입력한 자연수의 약수를 모두 출력하는 프로그램
#include <stdio.h>

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

    for(int i = 1; i <= (n / 2); i++) {   // 마지막 숫자 전까지만 쉼표로 나열하기 위해 n ÷ 2
    if(n % i == 0)				// i가 n의 약수이면, n은 i의 배수
            printf("%d, ", i);
    }
    printf("%d\n", n);        // 마지막은 무조건 입력한 수 자기자신이므로 반복문 종료 후 실행
}

🖥️ 실행 결과

12  [Enter↵]
1, 2, 3, 4, 6, 12

⌨️ 예제 12

// 일의자리수가 3, 6, 9인 경우 * 출력하는 369게임
#include <stdio.h>

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

    for(int i = 1; i <= num; i++) {
        int k = i % 10;     // i의 일의 자리수를 변수 k에 저장
        if(k == 3 || k == 6 || k == 9) 
            printf("* ");
        else
            printf("%d ", i);
    }
    printf("\n");
}

🖥️ 실행 결과

20  [Enter↵]
1 2 * 4 5 * 7 8 * 10 11 12 * 14 15 * 17 18 * 20 

(2) break문, continue문 활용

1) break문

자신이 포함된 반복문 한 개를 강제로 빠져나오는데 사용된다.

⌨️ 예제 13

// 숫자 0을 입력하기 전까지 무한 반복하는 프로그램
#include <stdio.h>

int main() {
    for(int i = 1; ; i++) {
        int n;
        scanf("%d", &n);

        if(n == 0)      // 0을 입력하는 순간 반복 종료
            break;

        printf("%d번째 입력 : %d\n", i, n);
    }
    printf("입력을 종료합니다.\n");
}

🖥️ 실행 결과

6  [Enter↵]
1번째 입력 : 6
33  [Enter↵]
2번째 입력 : 33
0  [Enter↵]
입력을 종료합니다.

2) continue문

루프 실행 도중 해당 루프를 다시 실행해야할 때 사용된다. break문은 루프를 빠져나오지만 continue문은 루프의 남은 부분을 건너뛴 후, 맨 처음으로 실행 순서를 옮겨서 계속 진행한다.

⌨️ 예제 14

// 1부터 n까지 3의 배수를 제외한 숫자들의 합을 구하는 프로그램
#include <stdio.h>

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

    int sum = 0;
    for(int i = 1; i <= n; i++) {
        if(i % 3 != 0) {	// continue문을 사용하지 않을 때 코드	
            sum += i;		// "i ÷ 3"의 나머지가 0이 아닐때만 실행
        }
    }
    printf("%d\n", sum);
}

🖥️ 실행 결과

8  [Enter↵]
27

⌨️ 예제 15

// 예제 14를 continue문을 사용하여 변경
#include <stdio.h>

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

    int sum = 0;
    for(int i = 1; i <= n; i++) {
        if(i % 3 == 0) {    // continue문을 사용할 때 코드
            continue;       // "i ÷ 3"의 나머지가 0일 때만 루프의 선두로 복귀
        }
        sum += i;           // "i ÷ 3"의 나머지가 0이면 건너뛰어져서 실행 안됨
    }
    printf("%d\n", sum);
}

🖥️ 실행 결과

4  [Enter↵]
7

(3) 다중 for문 ⭐️

for문 안에 for문이 중첩된 구조는 실제로 많이 사용되는 구조다.

⌨️ 예제 16

// 기호 *를 가로 n개 x 세로 n개의 형태로 출력하는 프로그램
#include <stdio.h>

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

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            printf("*");
        }
        printf("\n");   // 다음 행으로 넘어가기 위해 줄바꿈
    }
}

🖥️ 실행 결과

4  [Enter↵]
****
****
****
****

중첩된 for문을 사용할 때는 바깥쪽 for문과 안쪽 for문의 변수명을 다르게 하는 것이 좋다(변수명이 같아도 문법적으로 오류는 없지만 헷갈리기 때문).


⌨️ 예제 17

// 예제 16의 변형. 기호 *를 1개부터 n개까지 n줄에 걸쳐 출력하는 프로그램
#include <stdio.h>

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

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= i; j++) {   // "j <= i;"로 변경
            printf("*");
        }
        printf("\n");
    }
}

🖥️ 실행 결과

4  [Enter↵]
*
**
***
****

바깥쪽 for문에 연결된 변수 i와 안쪽 for문에 선언된 변수 j는 서로 영향을 주고받을 수 있다.


⌨️ 예제 18

// n개의 *로 이루어진 대각선을 출력하는 프로그램
#include <stdio.h>

int main() {
    int n;
    scanf("%d", &n);
    // 왼쪽 위에서 오른쪽 아래로 내려가는 대각선
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            if(i == j)
                printf("*");
            else
                printf(" ");
        }
        printf("\n");
    }
    // 오른쪽 위에서 왼쪽 아래로 내려가는 대각선
    for(int i = 0; i < n; i++) {
        for(int j = n-1; j > -1; j--) {
            if(i == j)
                printf("*");
            else
                printf(" ");
        }
        printf("\n");
    }
}    

🖥️ 실행 결과

4  [Enter↵]
*   
 *  
  * 
   *
   *
  * 
 *  
*  

⌨️ 예제 19

 /* 입력한 수 n개만큼 행을 출력,
각 행에는 1부터 시작하는 정수 중 홀수만 작은 순서대로 입력
1번째 행에는 1개, 2번째 행에는 2개를 입력하는 방식 */
#include <stdio.h>

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

    for(int i = 1; i <= n; i++) {       // 행 개수를 결정
        for(int j = 1; j <= i; j++) {   // 열 개수를 결정(1부터 i개 까지)
            printf("%d ", 2 * j - 1);
        }
        printf("\n");
    }
}
 // 위의 예제 다른 버전
#include <stdio.h>

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

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= (2 * i - 1); j += 2) {   // j는 (2 * i - 1)까지, 2씩 증가
            printf("%d ", j);
        }
        printf("\n");
    }
}

🖥️ 실행 결과

5  [Enter↵]
1 
1 3 
1 3 5 
1 3 5 7 
1 3 5 7 9 

⌨️ 예제 20

/* 입력한 수 n개만큼 행을 출력
1번째 행에는 숫자 1을, 2번째 행에는 숫자 1 2 3을,
3번째 행에는 숫자 1 2 3 4 5를 입력하기 */
#include <stdio.h>

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

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= (2 * i - 1); j++) { // i번째 줄에서 출력되는 숫자 개수 조정
            printf("%d ", j);
        }
        printf("\n");
    }
}
// 위의 예제 다른 버전
#include <stdio.h>

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

    for(int i = 1; i <= (2 * n - 1); i += 2) { // 한 줄당 출력되는 숫자 개수를 변수 i에서 조정
        for(int j = 1; j <= i; j++) {
            printf("%d ", j);
        }
        printf("\n");
    }
}

🖥️ 실행 결과

5  [Enter↵]
1 
1 2 3 
1 2 3 4 5 
1 2 3 4 5 6 7 
1 2 3 4 5 6 7 8 9 




▷ 김형근·곽덕훈·정재화, 『C프로그래밍』, 한국방송통신대학교출판문화원, 2020
▷ 서현우, 『뇌를 자극하는 C 프로그래밍』, 한빛미디어, 2005
▷ 두들낙서, “두들낙서의 C/C++ 강좌”, https://youtube.com/playlist?list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&si=s8RNpRcpJTi_Lz8M

0개의 댓글