조건분기 제어

위키책, 위키책

당신이 한 번이라도 자동차를 탄 적이 있다면 신호등 앞에 서거나 혹은 신호등을 지나간 적이 있을 것이다. 차를 운전할 때 신호등이 있으면 사람들은 "나는 교차로를 통해 계속 운전할 거야"라고 생각하지 않는다. 오히려 "빨간불이면 멈추고, 초록불이면 가고, 노란불이면 속도를 줄일 거야"라고 생각한다. 이러한 종류의 프로세스를 조건문을 사용하여 C언어에서 만들 수 있다.

조건문(conditional)은 특정 조건이 충족될 경우에만 코드 블록을 실행하거나 데이터를 변경하도록 컴퓨터에 지시하는 문이다. 가장 일반적인 조건식은 If-Else문, 다른 조건문보다 가독성이 좋게 작성할 수 있는 Switch-Case문이다.

조건문을 이해하기 전에 먼저 C가 논리 관계를 어떻게 표현하는지 이해해야 한다. C는 논리와 산술을 같다고 생각한다. 값이 0일 경우 false를 나타내고 그 외의 다른 값은 true를 나타낸다. true를 나타내기 위해 특정 값을 선택하고 값을 비교하면 늦어지거나 예상 값(대부분 1)이 올바르지 않은 것으로 판명되면 오류가 발생한다. C 언어에 익숙하지 않은 사람이 작성한 코드는 종종 #define을 사용하여 'TRUE' 값을 작성하기에 식별할 수 있다.

C에서 산술 연산자와 논리 연산자는 정확히 동일하다. 그럼에도 불구하고 일반적으로 논리와 연관된 몇 가지 연산자가 있다.

관계 연산자의 사용법:[+/-]

a < b

  a가 b보다 작은 경우는 1, 그렇지 않은 경우는 0.

a > b

  a가 b보다 큰 경우는 1, 그렇지 않은 경우는 0.

a <= b

  a가 b 이하인 경우는 1, 그렇지 않은 경우는 0.

a >= b

  a가 b 이상이면 1, 그렇지 않으면 0.

a == b

  a가 b와 같으면 1이고, 그렇지 않으면 0.

a != b

  a가 b와 같지 않으면 1, 그렇지 않으면 0이다.

C언어에 익숙하지 않은 사람은 '같다'연산자를 조심해야 된다. 많은 실수의 원인이 될 수 있다. 보통 if(c=20){} 이런 식으로 실수를 한다. 하지만 이것은 c가 20이 아닐때도 true로 판정되기 때문에 ===을 혼동하면 안된다. 이런 종류의 버그를 피하기 위해서는 상수를 먼저 넣는 것이다. if(20==c){} 이런 식으로 사용하게 되면 실수를 줄일 수 있다. 단, 어떠한 경우에는 안될 수 있다.

C언어에는 다른 언어처럼 bool함수(boolean, 부울)이 없다. 0은 거짓을 의미하고 그 외 나머지는 참을 의미한다. 다음과 같이 사용할 수 있다.

if (foo()) {
   // 코드
}

혹은

if (foo() != 0) {
   // 코드
}

종종 #define TRUE 1#define FALSE 0을 사용하여 boolean 타입이 없는 문제를 해결한다. 하지만 이것은 좋지 않은 습관이다. 왜냐하면 이것은 전제가 성립되지 않기 때문이다. 많은 오류가 발생할 수 있기 때문에 함수 호출 결과로 예상한 값을 표시하는 것이 좋다.

if (strstr("foo", bar) >= 0){
  // bar contains "foo"
}

여기서, strstr는 서브 문자열 foo가 발견된 인덱스를 반환하고, 발견되지 않은 경우는 -1을 반환한다. 이전 단락에서 말했던 true 정의에서 실패하는 것을 주의해야 된다. >=0을 생략해도 원하는 결과를 얻을 수 없다.

주목할 점은 관계식이 수학 관계식처럼 평가되지 않는다는 것이다. 즉, 식 myMin <value <myMax는 당신이 생각하는 것처럼 평가되지 않는다. 수학적으로 value가 myMin과 myMax 사이에 있는지를 확인한다. 하지만 C언어에서는 그 값이 먼저 myMin과 값을 비교하여 나온 결과(참:1, 거짓:0)와 myMax와 비교하게 된다.

int value = 20;
/* ... */
if (0 < value < 10) { // 이렇게 하지마! 항상 참이 된다고!
  /* 일 좀 해 */
}

값이 0보다 크므로 첫 번째 비교에서는 값이 1을 생성한다. 이제 1과 10을 비교하기에 참이 되므로 if문이 실행된다. 이것은 프로그래머가 원했던 방식이 아닐 것이다. 프로그래머가 원한 코드는 다음과 같다.

int value = 20;
/* ... */
if (0 < value && value < 10) { // &&는 'and','그리고'
  /* 일 좀 해 */
}
논리 연산자:[+/-]

a || b

  a 또는 b가 참(또는 둘 다)이면 결과가 1이고, 그렇지 않으면 결과가 0,

a && b

  a와 b가 모두 참이면 결과가 1이고, 그렇지 않으면 결과가 0이다.

!a

  a가 참이면 결과가 0이고, a가 0(거짓)이면 결과가 1이다.

(보통 코딩을 처음 배우는 사람은 |을 사용하지 않기에 어디있는지 모르는 사람들을이 있다. 키보드의 Shift를 누를고 \을 누르면 |가 된다.) 여기 논리식의 예가 있다.

e = ((a && b) || (c > d));

a와 b가 0이 아닌 경우 또는 c가 d보다 큰 경우 e는 1로 설정된다. 다른 모든 경우 e는 0으로 설정된다. C언어는 논리 연산자의 단락 평가를 사용한다. 즉, 논리 연산자가 참을 결정할 수 있게 되면 더 이상의 논리 연산을 하지 않는다. 가끔 다음과 같이 사용된다.

int myArray[12];
....
if (i < 12 && myArray[i] > 3) { 
....
}

위의 코드에서 i와 12를 먼저 비교한다. i < 12가 거짓일 경우 i는 배열의 인덱스 범위를 벗어나므로 myArray[i] > 3을 액세스하지 않고 if문을 종료하고 if문 다음에 있는 코드를 실행한다. 따라서 i가 0보다 크거나 같다는 것을 이미 알고 있는 경우 배열 요소에 액세스하려는 것에 대해 걱정할 필요 없다. 또한 || 연산자를 포함한 표현식에서도 비슷한 일이 발생한다.

if (doThis() || doThat()) {
...
}

doThis()가 0이 아닌(참) 값을 반환하는 경우 doThat()은 호출되지 않는다.

if-else 문[+/-]

if-else는 특정 조건이 충족되는 경우에만 코드를 실행하도록 지시하는 방법이다. if-else 구조의 예시는 다음과 같다.

if (/*조건을 여기에 적어*/) {
 // 조건이 참인 경우 여기 있는 코드가 실행돼
} else {
 // 조건이 거짓인 경우 여기 있는 코드가 실행돼
}

코드의 첫 번째 블록은 if 옆에 괄호 안의 값이 true일 경우 실행되며, false일 경우 두 번째 블록이 실행된다. else의 경우 코드는 적어도 되고 안 적어도 되는 선택 사항이다. 적을 경우 아까 괄호에서 false가 나오면 실행하고 true가 나오면 실행하지 않는다. 안 적을 경우 아까 괄호에서 false가 나오면 if문 다음에 있는 코드가 실행된다. 그리고 else문의 경우 if문 다음에 올 수 있다. 하지만 else문을 2개 이상 사용하는 것은 좋지 않은 습관이기 때문에 나중에 배울 Switch-case문을 사용하는 것이 좋다. 다른 제어문에서도 볼 수 있지만 if문과 else문의 마지막에 세미콜론(;)이 없다는 것을 간과하면 안된다. if문과 else문의 경우 하나의 명령문을 실행하려는 경우 중괄호( { , } ) 필요하지 않다. 중괄호를 사용하지 않고 여러 줄을 적는 경우 맨 윗 줄에만 적용된다. 이해하기 어려운 경우 아래 예시를 확인보자

if (/*조건을 여기에 적어*/)
 명령문1; // 이것만 if문 안에 있다고 할 수 있지.
 명령문2; // 이거는 if문 밖에 있다고 생각할 수 있어!

다음 코드는 변수 c를 두 변수 a와 b 중 더 큰 변수와 같게 설정하거나 a와 b가 같으면 0으로 설정한다.

if ( a > b ) {
 c = a;
} else if ( b > a ) {
 c = b;
} else {
 c = 0;
}

위와 같이 else if(/*조건*/)를 사용해서 조건을 추가할 수 있다. 위의 예시를 보면서 왜 else문을 사용해야 되는지 생각해보자.

if ( a > b ) {
 c = a;
}
if ( b > a ) {
 c = b;
}
if( a == b ) {
 c = 0;
}

그 이유는 여러가지가 있어. 두 번째에서 c = a가 아닌 a == 0으로 바꾼다고 가정했을 때 두 번째 if문을 실행할 수 있기에 else문을 사용하여 a와 b의 크기를 비교하여 각각의 경우에 따라 다르게 대처하는 것이 좋다. 결론적으로 if문의 조건이 거짓이 되는 경우에 대해 else문을 사용하는 것이 좋다.