프로그래밍 언어/C언어_기초 프로그래밍

[ C언어 기초 ] 5. 조건문

딩드 2024. 9. 16. 13:56
반응형
  • 3가지 기본 제어 구조 : 순차, 선택, 반복

* 5. 조건문에서는 주로 선택 구조에 대해 다룸.
- 순차 구조(sequence) : 명령어들이 순차적으로 실행되는 구조.
- 선택 구조(selection) : 여러 개의 명령어 중에서 하나를 선택하여 실행되는 구조.
- 반복 구조(iteration) : 동일한 명령어가 반복되면서 실행되는 구조.

- 순서도(flowchart)로 나타낸 구조

순서도로 나타낸 3가지 기본 제어 구조

  • if-else 문

- 선택 구조가 필요한 이유
   - 여태까지는 순차 구조를 이용했다. 이 구조만 사용한다면 프로그램은 항상 동일한 동작만을 되풀이할 것이기 때문에, 별로 쓸모 없다(자율 주행 자동차가 장애물 앞에서 멈추지 않는 것처럼).
   - 선택 구조는 조건을 검사하고 조건에 따라 실행되는 명령어를 다르게 할 수 있다.

- if-else 문의 형식

if( score >= 60 ) {
     printf("합격입니다. \n");
}
else {
     printf("불합격입니다. \n");
}

   -
위에서 score >= 60은 조건식이고, if-else 문은 주어진 조건식을 계산하여 참이면 if 이후의 문장을 실행한다. 조건식이 거짓이면 else 이후의 문장을 실행한다.
   - if-else 문에서 조건이 참일 때 실행되는 문장을 then 절(then clause)이라고 한다. 조건이 거짓일 때 실행되는 문장을 else 절(else clause)이라고 한다.
   - 조건에 따라 실행되는 문장이 하나이면 중괄호({})는 생략 가능. 중괄호 안에 두 개의 문장이 오기도하는데, 이러한 문장 그룹핑을 복합문(compound statement)이라고 한다. 복합문은 블록(block)이라고도 하며, 단일문이 들어갈 수 있는 곳이면 어디나 단일문 대신 넣을 수 있다.
   - 위에서 시험 점수가 60점 이상일 때, "합격입니다."만 출력하면 된다면 else절을 생략하여 작성해도 된다.
   - if  문이 끝나면 조건이 참이든 거짓이든 상관없이 if-else 문 다음에 있는 문장이 실행된다.
   - if-else 문 사용 대신 if 문을 여러 개 사용하는 방법도 있는데, 이 방법은 비효율적일 수 있다.
      ex1)
if (number%2==0) //1번
     printf("짝수\n");
if(number%2==1) //2번
     printf("홀수\n");

  
      ex2)
if(number%2==0) //3번
     printf("짝수\n");
else
    printf("홀수\n");

      위 두가지 예시에서, ex1에서는 모든 값에 대하여 항상 문장 1번과 문장 2번이 실행되어야 하므로 비효율적이다. 그러나 ex2에서는 입력 값에 대하여 문장 3번만 실행되므로 효율적이다.

참고) if-else 문에서 if(조건식)하고 다음줄에 '{'가 나오는 경우에는 복합문은 들여쓰기를 하는 편이 읽기 쉬워지므로 좋고, if(조건식) 뒤에 바로 '{'가 오는 경우 공간 절약이 됨.

- 복잡한 조건식을 사용하는 if-else 문
ex)
if( ch == ' ' || ch == '\n' || ch =='\t' )
     white_space++;
 
참고) 참과 거짓 : 피연산자는 0이면 거짓이고 0이 아닌 값은 무조건 참으로 간주함. 따라서 NOT 연산으로 !100을 하면 100의 값을 참으로 간주해 여기에 NOT을 적용하여 0 값이 생성됨. 
 
참고) 
잘못된 예시 : ( 2 < x < 5 ) *Python에서는 가능.
   - 위의 경우 C언어에서는 결합 법칙에 의하여 (( 2 < x ) < 5 )와 같이 연산을 진행함.
올바른 예시 : ( 2 < x ) && ( x < 5 )
 
참고) 드모르간의 법칙 이용
   - 인간은 NOT 연산자를 사용한 음의 논리보다 양의 논리를 더 쉽게 이해한다. 따라서 NOT 연산자가 있으면 드모르간의 법칙을 이용하여 양의 논리로 변경시켜 주는 것이 좋다.
   ex1) if( !( x && y ) )  ->  if( !x || !y )
   ex2) if( !( x || y ) )  ->  if( !x && !y )
 
참고) 난수(random number) : 규칙성 없이 임의로 생성되는 수.
- 암호학, 시뮬레이션, 게임 등에서 필수적.
- C언어에서 난수를 생성하려면 stdlib.h 헤더 파일을 포함시키고 rand() 함수를 호출한다.
   - rand() 함수는 0부터 32,767까지의 정수를 생성한다.
- 0 또는 1이 랜덤하게 나와야하는 경우에는, rand() 함수가 반환하는 값을 2로 나누어서 나머지를 취하면 된다.
   ex) int coin = rand() % 2;
   - 비슷하게, 0부터 5까지의 정수 랜덤 생성을 원할시 rand() % 6, 1부터 3까지의 정수 랜덤 생성을 원할시 (rand() % 3) +1
- rand() 함수 사용시 srand(time(NULL)); 이라는 문장을 넣어주는데, 이는 현재 시간을 난수의 씨앗값으로 하는 것이다.
 

  • 다중 if 문

- 중첩 if 문
   - if 문도 하나의 문장이다. 즉, if(조건식) 문장; 까지가 하나의 문장. 따라서 if 문 안에 다른 if 문이 들어갈 수 있다.
   ex)
   if( score >= 80 )
        if( score >= 90)
             printf("A학점\n");
   이라는 예시에서, 
        if( score >= 90)
             printf("A학점\n");
   이 부분은 하나의 문장으로 취급된다.
   - 위와 같은 원리로 if-else 문도 if 문 안에 들어갈 수 있다.
 
참고) else 절은 무조건 가장 가까운 if와 매치되기 때문에 주의해야한다. 중괄호를 이용하여 블록을 만들어주면 된다.
 
- 연속적인 if 문
   - 하나라도 조건이 만족되어 해당 문장을 실행하고 나면 다른 조건들은 전부 건너뛴다.
   ex)
   scanf("%d", &score);
   if (score >= 90)
        grade = 'A';
   else if (score >= 80)
        grade = 'B';
   else if (score >= 70)
        grade = 'C';
   else if (score >= 60)
        grade = 'D';
   else
        grade = 'F';
 
참고) getchar() : 문자를 받아들이는 함수.
 
참고) char ch; ch = getchar()해서 문자를 받아들인 뒤, if( ch >= 'A' && ch <= 'Z' ){ printf("%c는 대문자입니다.\n", ch)를 하면 받은 문자를 아스키 코드값을 검사하여 올바르게 대문자인지 검사할 수 있다.
 
참고) scanf()로 여러 개의 형식 지정자를 받아들일 때, %d%c%d와 같이 쓴다면, 사이 공백을 허용하지 않겠다는 의미(공백도 하나의 문자로 간주)이며, %d %c %d와 같이 쓰면 사이에 공백 문자를 허용하는 의미가 있다.
 

  • switch 문 : 제어식의 값에 따라서 여러 경로 중에서 하나를 선택할 수 있는 제어 구조.

- C언어의 switch 문은 조건 분기문 중 하나로, 주어진 변수가 다양한 값 중 하나와 일치하는지 여부를 검사하여 각 경우에 해당하는 코드 블록을 실행하는 구문.

- switch 문의 구조
    switch (수식 ) {
   case 값1 :
             문장1;
             break;
   case 값2 :
             문장2;
             break;
   default :
             문장3;
             break;
}

- switch 키워드 다음의 괄호 안에는 검사할 변수(어떠한 수식도 들어갈 수 있음)를 넣는다. 변수의 자료형은 정수형이어야 한다.
- case 키워드를 사용하여 각 경우를 나타내며, 콜론(;)으로 마무리한다. case 뒤에는 비교할 값이 온다. 변수가 해당 값과 일치하면 그에 해당하는 코드 블록이 실행된다.
- break 키워드는 각 case 블록의 마지막에 사용되며, break가 없으면 해당 case 블록 이후의 모든 case 블록도 실행된다.
- default 키워드는 위의 모든 case 블록이 실패했을 때 실행될 코드를 정의하는 블록이다. 필수는 아니지만, 모든 가능한 경우를 다 고려하는 코드를 작성하기 위해 default 블록을 작성하는 것이 좋다.

- break 문이 없다면?
   - 선택된 case 절 안의 문장들을 실행한 다음, 계속해서 다음 case 절의 문장들을 실행 > 중대한 오류 발생 가능 > 따라서 모든 case 문은 일반적으로는 break 문으로 끝나야 함.
   - 의도적으로도 사용 가능.
   ex) case2와 case3을 한번에 처리하기 위해
     case2:
     case3:
          printf("두서너 개 \n");
          break;

   와 같이도 처리 가능하다.


- default 문
   - default 문은 어떤 case 문과도 일치되지 않는 경우 선택되어 실행됨.
   - 생략 가능.
   - default 문도, 일치하는 case 문도 없다면 아무 것도 실행x.
   - 가급적 사용 권장(예상하지 못했던 값을 알아낼 수 있음).
 
- switch 문을 if-else 문으로 바꾸기 가능.
   - 경우의 수가 많아지면(대략 5개 이상) switch 문을 사용하는 것이 간결해보임. 유의할 점은 switch 문에서 제어식의 값은 반드시 정수 상수로 나와야 한다는 점이다. 수식의 값이 정수로 나오지 않는 경우 if-else 문을 사용하여야 한다.

- 주의할 점
   - switch 문에서 제어식의 값은 반드시 정숫값으로 계산되어야 한다. 또 상수이어야 한다. 따라서 case 절에 실수나 변수, 수식, 문자열을 사용하는 것은 컴파일 오류이다. 하나의 문자는 아스키 코드로 표현되고 아스키 코드는 정수이므로 사용이 가능. 하지만 문자열은 사용할 수 없다.
   ex) case 뒤 사용 가능
      x --- 변수 불가
      (x+2) --- 변수 들어간 수식 불가
      0.002 --- 실수 불가
      'a' --- 문자 사용 가능
      '"001" --- 문자열 사용 불가

- goto 문

   - C언어에서 goto 문은 프로그램에서 특정한 위치로 분기할 수 있는 제어문이다.

   - 구조

      1. 전항 참조

      goto label ;

      ~

      ~

      label :

           문장 #1

           문장 #2

           문장 #3

      2. 후항  참조

      label :

           문장 #1

           문장 #2

           문장 #3

      ~

      ~

      goto label :

      - 레이블(label)은 콜론(:)으로 끝나는 식별자, 프로그램에서 위치를 나타내는 역할을 함. goto문이 끝나면 해당 레이블로 분기하게 되며, 레이블 바로 다음에 오는 코드 블록부터 실행됨.

      - goto 문은 프로그램의 흐름을 뒤엉키게 하며 코드의 가독성을 저해할 수 있기 때문에 일반적으로 권장x.

      - 다중 반복 구조 등 유용한 경우가 있음.

 

반응형