|
http://www.hackerschool.org/HS_Boards/zboard.php?AllArticle=true&no=1744 [복사]
*----------------------------------------------------------------------------------------------------------*
이 카테고리는 그동안 배웠던것이라던가 공부하면서 알게된 내용들을 중심으로 혹여 참고가 될 수 있을까 싶은 내용들을
모아둔 곳입니다. 따라서 이 글들을 대상이 되는 분들은.. 프로그래밍을 갓 시작했거나 개념이 마구마구 흔들리시는 분들
정도가 되겠습니다. 그러니 너무 욕하지는 말아주세요 =_=;;;
혹시 제가 잘못 알고 있는 부분들이라던가 궁금한 것이 있으면 쪽지 남겨주시거나 리플을 달아주시면 감사하겠습니다.
*----------------------------------------------------------------------------------------------------------*
지난번 스터디에서 말씀드린바와 같이 잠시 흐름을 바꿔 프로그래밍의 가장 기초라 할 수 있는 분기문을 연구해 볼까 합니다.
갑자기 왜 이걸 하는가.. 별로 대단한 이유는 아닙니다만 이제 프로그래밍을 갓 시작하신 분들 중에 분기문을 제대로 활용 할 줄 모르는 분들이 꽤 많으신것 같아서 복습 차원에서 필요하겠다 생각이 들었습니다.
제가 생각기에 코드는 얼마나 분기문을 잘 활용하는가에 따라 그 깊이가 달라진다고 생각됩니다.
가장 기본적인것이지만 또 의외로 간과하고 넘어가는 부분도 있는 것 같습니다.
우리가 배운바에 따르면 컴퓨터는 0/1의 2진수 밖에 모릅니다. 따라서 모든 명령들을 1 or 0로 처리를 해야한다는 뜻이지요.
이것을 우리는 Yes or No라고 부르고 유식한(?)말로 True or False라고 합니다.
즉, 컴퓨터가 우리에게 요구하는것은 해? 하지마? 이 두가지 뿐 입니다. 그래서 우리는 아주 간단한 조건들을 제공해서 '~이면 하고 아니면 하지마'라고 명령을 내릴 수 있습니다. 그것이 바로 if입니다.
if문은 아주 간단한, 기본적인 문법입니다. 모든 프로그래밍은 사실상 if에서 시작한다고 해도 과언은 아닐겁니다.
형식은 다음과 같습니다.
if( 조건 )
{
실행 내용;
}
실행 내용이 아주아주 간단해서.. ';' 하나로 마칠 수 있는 코드라면 {}괄호를 생략 할 수도 있습니다.
위에서 조건은 우리가 흔히 말하는 '비교연산자'를 이용해서 주로 사용을 하게 됩니다.
가장 대표적인것은 이런 문장이죠.
if( number < 0 )
{
음수; // 그냥 간단하게.. 단순히 설명만을 위해 표기했습니다. 'ㅁ';;;
}
만약 number라는 변수가 가진 숫자가 음수라면 '음수'라고 표시 될 것이고, 아니라면 무시하고 지나갈 것입니다.
여기까지는 잘 아시는 내용이니 더 자세한 설명은 생략합니다.
다음으로 우리가 관심을 가지고자 하는 것은 else라는 새로운 키워드입니다.
이 else 라는 녀석은 혼자서 단독으로는 사용 할 수 없고, 반드시 if문과 연결하여 사용하여야 합니다. 원래대로라면 if와 반드시 짝을 이루어 쓰였어야 하겠지만, 그럴 필요가 없는 경우가 많으므로 생략이 된 케이스라고나 할까요?
돈이 있으면 버스를 타고 없으면 걸어가야 한다고 생각해 봅시다.
여기는 돈이 있냐없냐라는 한가지 조건에 대해서 두갈래의 길이 나타납니다. 바로 버스를 타느냐 걷느냐. 이걸 만약 우리가 알고 있는 단순한 if 문으로 고른다고 한다면 어떻게 표시를 해야 할까요?
if( 돈 있나? )
버스를 탄다
if( 돈 없나? )
걸어간다.
똑같은 조건을 두번이나 쓰는데다가 위는 positive, 아래는 negative여서 자칫하다가는 조건을 지정하는데 실수하기 딱 좋습니다. 그렇다고 뺄 수도 없는 노릇이고..
사실 if문을 두번 쓴다는 것을 생각하지 못해서 생기는 오류도 많지만, 두개 또는 세개이상의 조건 분기문에서 단 한가지만 선택을 해야 하는 경우에서 가장 많은 실수를 하는 것을 볼 수 있었습니다.
예를들어, 대문자는 소문자로, 소문자는 대문자로 만드는 프로그램을 만드는 경우를 볼까요?
(범위를 한정하기 위해 반드시 대문자 또는 소문자만을 입력받는다고 제한합니다)
if( ch == 대문자 )
ch를 소문자로;
if( ch == 소문자 )
ch를 대문자로;
라고 작성하시는 경우를 종종 보게 되는데요, 과연 위 코드의 결과는 어떻게 될까요?
소문자가 입력 된 경우라면 소기의 목적대로 대문자로 바뀌어 출력이 되므로 정상적인 결과라고 할 수 있습니다. 첫번째 조건인 (ch==대문자)에 위배되기 때문에 그냥 통과 해 버리고 두번째 if문에서는 제대로 동작하기 때문에 소문자->대문자 의 결과를얻을 수 있습니다.
하지만, 대문자->소문자로 하고 싶을땐? 어찌된 일인지.. 그냥 대문자로 나옵니다. 우선 첫번째 조건에서 대문자를 소문자로 바꾸어 줍니다. 그리고 두번째 조건으로 갔을때? 아뿔싸!!!.. 이 녀석이 애써 바꾼 소문자를 다시 대문자로 바꿔버리는군요!!!
대부분이 이래서 생기는 오류입니다. C를 처음 접한 초기에는 이 부분을 잘 짚어내지 못하시는 걸 많이 봐 왔습니다. 물론 저도 처음엔 그랬습니다 =_=;;
그렇다면 이걸 어떻게 처리를 해야할까요? 대략 난감해집니다.
두 if문을 바꿔볼까요? 그래봤자.. 모든 결과가 소문자로 나오는 비슷한 오류에 빠질 뿐 입니다. 물론 조금 경험이 있으신 분들은 또 다른 변수(flag변수)를 쓰는 등의 방법을 쓰실 수 있겠지요. 하지만.. 문제만 복잡해 집니다.
그래서 필요한것이 바로 else입니다. else를 쓰게되면 확실하게 한 조건분기만을 선택해서 사용 할 수 있게 됩니다.
if/else구문의 기본 구조는 다음과 같습니다.
if( 조건 )
{
실행 내용;
}
else
{
실행 내용;
}
if문 때와 마찬가지로 한줄로 끝나는 간단한 코드는 {,}괄호를 생략해도 상관 없습니다. 위에서 나왔던 문제들에 이 구조를 적용해보면,
if( 돈 있나? )
버스를 탄다.
else
걸어간다.
대문자 <-> 소문자 코드는 이렇게 바뀔 수 있겠지요
if( ch == 대문자 )
ch를 소문자로;
else
ch를 대문자로;
코드도 간결해지고, 기능도 확실해졌습니다.
이제 if/else를 어떻게 활용하는지 알아봅시다.
우리는 if/else문을 가지고 두가지 선택지에 대해서 한가지를 선택하는 방법을 알고 있습니다. 그러면 2가지가 아닌 3가지 또는 그 이상의 선택지에 대해서는 어떻게 사용 할 수 있을까를 알아봐야겠죠. if문의 구조를 보시면 아시겠지만, if문의 {}괄호 안에는 또 다른 if, if/else문을 쓸 수있습니다. 마찬가지로 else 안에서도 또다른 if, if/else문을 사용 할 수 있지요. 이렇게요.
if( 조건 1 )
{
if( 조건 2 )
{
수행문 1; // 조건 1이 참이고 조건 2도 참일때
}
else
{
수행문 2; // 조건 1이 참이고 조건 2는 거짓일때
}
}
else
{
if( 조건 3 )
{
수행문 3; // 조건 1은 거짓이고 조건 2는 참일때
}
else
{
수행문 4; // 조건 1도 거짓이고 조건 2도 거짓일때
}
}
더 하위로 얼마든지 확장이 가능합니다.(물론 보기에는 좋지 않겠죠.)
위 코드의 수행문은 짧기 때문에(라는 전제하에) {} 괄호를 정리하면 이런 간단한 코드로 정리가 가능합니다.
if( 조건 1 )
if( 조건 2 )
수행문 1;
else
수행문 2;
else
if( 조건 3 )
수행문 3;
else
수행문 4;
각각의 else 키워드가 적용되는 위치에 주의 하세요. else가 적용되는 대상은 들여쓰기 위치 기준이 아니라 바로 직전에 선언 된 if의 영향을 받습니다.(물론 {} 괄호로 범위가 제한 된것이 아닌 이상엔)
여기서 질문!!! 만약 이런 코드가 있다면
if( 조건 1 ) ------------- 1
if( 조건 2 ) ---------- 2
수행문 1;
else ------------------ Q
if( 조건 3 )
수행문 2;
위 코드의 Q로 마크된 else는 1과 2 중 어느 if와 쌍이 될까요? 정답은 2 입니다. 들여쓰기와는 전혀 무관하게 무조건 바로 직전에 선언된 if와 쌍을 맺게 됩니다.
그렇다면 이 코드에서는?
if( 조건 1 ) ------------- 1
{
if( 조건 2 ) ---------- 2
수행문 1;
}
else ------------------ Q
if( 조건 3 )
수행문 2;
여기서는 1과 쌍을 이루게 됩니다. {}에 의해 2의 if는 {} 블럭 안에서 종결이 이미 되어버린 상태이기 때문이지요.
여기서 마지막으로 질문 하나만 더!! 이거.. 좀 중요한겁니다 주의해서 보세요.
if( 조건 1 ) ------------- 1
if( 조건 2 ) ---------- 2
수행문 1; 수행문 2;
else ------------------ Q
if( 조건 3 )
수행문 3;
이때 else가 걸리는 if는 1과 2 중 어느것일까요?
답은 코드 자체가 오류다입니다. 아니 어째서? 2의 조건문 아래에 수행문이 2개 있기는 하지만 한줄로 들어가 있고, 그렇다면 Q가 쌍을 이루는 것은 2여야 하는것 아닙니까? 라고.. 하시겠죠? 그러나 위 문장은 바람직하지 못한 문법을 사용한 대표적인 예로.. 의외로 많은 분들이 착각하고 계시는 부분입니다. 2번의 if문이 컨트롤하는 코드는 첫번째 ;가 나오는 수행문 1 뿐입니다.
수행문 2는 1번 if에도 2번 if에도 전혀 영향을 받지 않는 독립 코드입니다. 따라서 수행문 2 다음에 나온 else는 짝이 되는 if를 찾지 못하고 컴파일러는 에러를 띄웁니다.
자세한 설명은 피합니다만, 다음 코드를 비교하면서 이해하시면 도움이 될거라 생각됩니다.
void main()
{
int num=0;printf("입력");scanf("%d",&num);if(num<0) num*=-1; printf("%d",num);return;
}
위 코드는 정수를 입력받아서 양수는 양수 그대로, 음수는 양수로 바꾸어주는 절대값 함수와 동일한 역할을 하는 프로그램입니다. 한줄로 늘어놨기때문에 읽기는 어려워도 분명 제대로 작동하는 코드입니다. 이 코드는 심지어 이렇게도 바꿀 수 있습니다.
void main()
{
int
num
=
0
;
printf(
"입력"
)
;
scanf(
"%d",
&num
)
;
if(
num<0
)
num
*=
-1
;
printf(
"%d",
num
)
;
return
;
}
이런 도대체.. 정체를 알 수 없는 코드도 훌륭히 작동 합니다 =_=;;
이와같이 컴퓨터에게 있어서 중요한 것은 문법에 맞춰 썼느냐 아니냐이지 코딩 스타일이 아닙니다. 하지만.. 사용자가 힘들어지겠지요. 코딩 스타일이 중요한 이유는 바로 그것 때문입니다.
언제나.. 제 단점이 드러나는군요.. 삼천포로 빠지기;; 다시 if/else 문으로 돌아갑니다.
위의 예제를 보시면 짐작하시겠지만 if(조건) 실행문; 으로 되어있는 한줄 코드도 제대로 작동합니다. 실제로 아주 짧은 실행코드의 경우는 이렇게 한줄로 작성하는 예가 많이 있습니다. 그리고 또한 가독성도 꽤 높구요. 차후에 그런 대표적인 예를 보여드리겠습니다.
자, 이제 3개 이상의 선택지에서 하나를 선택하는 방법을 알아봅시다. 바로 if/else if/ else 인데요,코드 구조는 다음과 같습니다.
if( 조건 1 )
{
수행문 1; // 조건 1이 참일때
}
else if( 조건 2 )
{
수행문 2; // 조건 1은 거짓이고 조건 2는 참일때
}
else
{
수행문 3; // 조건 1과 조건 2 둘다 거짓일때
}
뭐 많이 보셨을테지만 다시 한번 짚고 넘어가보죠.
위 코드는 사실 세부적으로 분해 해 보면 다음과 같은 구조입니다.
if( 조건 1 )
{
수행문 1; // 조건 1이 참일때
}
else
{
if( 조건 2 )
{
수행문 2; // 조건 1은 거짓이고 조건 2는 참일때
}
else
{
수행문 3; // 조건 1과 조건 2 둘다 거짓일때
}
}
어디서 많이 보던 모양이죠? else 블럭 안에 있던 if문이 한줄 올라간것에 지나지 않습니다. 마찬가지로 4개 5개 등등등.. 모두 최 하위 else문에 if/else문이 하나씩 더 추가 된 것에 불과합니다.
if( 조건 1 )
수행문 1;
else <----
{ <---
<- if( 조건 2 )
수행문 2;
else <------
<- { <----
<--- if( 조건 3 )
수행문 3;
else <-----
<--- { <-------
<------- if( 조건 4 )
수행문 4;
:
:
}
}
}
이 코드가 정리되어 나온 것이 바로
if( 조건 1 )
수행문 1;
else if( 조건 2 )
수행문 2;
else if( 조건 3 )
수행문 3;
else if( 조건 4 )
수행문 4;
:
:
else
수행문 n;
이런 else if 코드가 나오게 되는겁니다. 실제로 어떤 경우에 사용되는지 예를 들어보도록 하지요.
가장 많이 애용되는 예제는 학점 출력입니다 ^^; 딴 예제를 찾아보려했지만.. 역시 많이 쓰이는 예제는 그만한 이유가 있네요 ㅋ...
점수를 입력하는데 0~100점 범위 내에서 성적이 91~100점이면 A학점, 81~90점이면 B학점, 71~80점이면 C학점, 61~70점이면 D학점, 60점 이하이면 F학점이 출력되도록 코드를 작성 해 봅시다.
if( 성적 > 90 && 성적 <=100 )
A학점;
else if( 성적 > 80 && 성적 <=90 )
B학점;
else if( 성적 > 70 && 성적 <= 80 )
C학점;
else if( 성적 > 60 && 성적 <= 70 )
D학점;
else
F학점;
이 코드가 일반적으로 생각할 수 있는 if/else if/else 구문의 대표적인 예 입니다. 하지만 이 코드는 따지고 보면 else if를 효율적으로 사용했다고 볼 수 없는 코드입니다. 왜냐하면 마지막 else F학점; 이 라인을 제외하고는 사실상 else를 뺀다고 해도 원하는 결과를 얻을 수 있는 코드이기 때문입니다. 그렇다면 뭐가 문제일까요? 가만히 살펴봅시다.
맨먼저 성적이 95점이었을때를 생각해 보죠. 그럴땐 첫 실행문을 실행하고는 바로 끝으로 빠져나올 것 입니다. 아무 문제 없죠?
그럼 그 다음 85점일때를 생각해보면, 첫 실행문에서 90<85<=100 의 조건을 만족하지 않기 때문에 다음 else if 조건으로 넘어갑니다. 여기서는 80<85<=90의 조건을 만족하기 때문에 원하는 결과를 얻고 탈출 합니다.
75점일때도 마찬가지이고 65점일때도 55점일때도.. 원하는 결과는 얻을 수 있습니다. 그러나.. 여기서 불필요한 비교가 자꾸 등장합니다.
점수가 72점일때 우선 첫번째.. 90<72<=100 은 틀리니까 그냥 통과 합니다. 그 다음에서 80<72<=90을 비교하는 과정에서.. 궂이 90점보다 작은지 확인을 해야 할까요? 이미 첫 비교를 통해서 점수가 90점을 넘지 않는다는 것은 사실이 되었습니다. 그런데도 또 90점보다 큰가를 확인하고 있습니다. 불필요한 비교이지요. 마찬가지로 70<72<=80 비교에서도 마찬가지 입니다. 이미 80을 넘지 않는다는 것을 알고 있기 때문에 궂이 비교할 필요는 없습니다. 사실 맨 앞의 100점 이하이냐..를 체크하는 과정도 입력단계에서 이미 0~100이라고 범위를 제한하였기 때문에 이런 비교도 필요가 없습니다.
따라서, 이런 점으로 미루어 보아 비교는 다음과 같이 정리 할 수 있을것 같습니다.
if( 성적 > 90 )
A학점;
else if( 성적 > 80 )
B학점;
else if( 성적 > 70 )
C학점;
else if( 성적 > 60 )
D학점;
else
F학점;
굉장히 simple 해졌죠?
여기서 '나 코딩 좀 해봤다' 하시는 분들은 이렇게 코드를 정리하시기도 합니다.
if( 성적 > 90 ) A학점;
else if( 성적 > 80 ) B학점;
else if( 성적 > 70 ) C학점;
else if( 성적 > 60 ) D학점;
else F학점;
굉장히 보기 편하지 않나요? 딱 보기에도 90점 이상은 A, 80점 이상은 B 등등.. 한눈에 봐도 코드의 목적과 흐름을 파악할 수 있는 아주 좋은 코드의 예입니다. 그리고 두줄 이상의 실행문이 필요한 경우도 이런식으로 정리 할 수 있죠.
if( 성적 > 90 ){ A학점; 용돈 만원; }
else if( 성적 > 80 ){ B학점; 용돈 오천원; }
else if( 성적 > 70 ){ C학점; 용돈 0원; }
else if( 성적 > 60 ){ D학점; 용돈 -천원; }
else { F학점; 용돈 -만원; }
'뭐, 조금 편한것 같기도 하지만, 전 제 스타일대로 할래요' 라고 하시는 분들.. 코드가 짧을때야 별 차이를 못 느끼실 수도 있습니다만 코드가 길어진다면? 글쎄요, 과연 얼마나 그 스타일을 고수하실 수 있으실지...
좋은 예라고는 할 수 없겠습니다만.. 제가 제작하고있는 어떤 프로그램의 일부를 발췌해 봤습니다.
if( PrevCoord.Y != Coord.Y )
{
if( Coord.X > 0 )
CurTrack->UnsetLink( Coord.X-1 );
CurTrack->SetNote( Coord.X, Coord.Y );
}
else if( PrevCoord.X-Coord.X == 1 )
{
CurTrack->SetNote( Coord.X, Coord.Y );
CurTrack->SetLink( Coord.X );
if( CurTrack->GetNote(Coord.X-1) != Coord.Y )
CurTrack->UnsetLink(Coord.X-1);
}
else if( PrevCoord.X-Coord.X == -1 )
{
if( CurTrack->GetNote( Coord.X ) != Coord.Y )
CurTrack->SetNote( Coord.X, Coord.Y );
CurTrack->SetLink( Coord.X-1 );
}
else
return 0;
이 코드를 만약.. if 만으로 구성한 코드를 만든다고 봤을때.. 이런 곤란한 일이 벌어집니다.
if( PrevCoord.Y != Coord.Y )
{
if( Coord.X > 0 )
CurTrack->UnsetLink( Coord.X-1 );
CurTrack->SetNote( Coord.X, Coord.Y );
}
if( PrevCoord.Y == Coord.Y && PrevCoord.X-Coord.X == 1 )
{
CurTrack->SetNote( Coord.X, Coord.Y );
CurTrack->SetLink( Coord.X );
if( CurTrack->GetNote(Coord.X-1) != Coord.Y )
CurTrack->UnsetLink(Coord.X-1);
}
if( PrevCoord.Y == Coord.Y && PrevCoord.X-Coord.X != 1 && PrevCoord.X-Coord.X == -1 )
{
if( CurTrack->GetNote( Coord.X ) != Coord.Y )
CurTrack->SetNote( Coord.X, Coord.Y );
CurTrack->SetLink( Coord.X-1 );
}
if( PrevCoord.Y == Coord.Y && PrevCoord.X-Coord.X != 1 && PrevCoord.X-Coord.X != -1 )
return 0;
위 네 단락의 조건문간 연관성이 보이십니까?
분명 네 단락의 조건문은 4중택1의 코드입니다만.. 서로 별개의... 전혀 연관성이 없는 코드로 보일 수 있다는 것이 문제이지요. 이렇게 되면 유지/보수도 힘들어집니다.
조건 하나가 틀려지면.. 모든 조건문들을 전부 수정해야 하는 일까지도 생길 수 있으니까요..
게다가 위의 분기는 4개 밖에 없으니 다행입니다만 어떤 경우는... 분기가 십여개에 달할 정도까지 되버리면 조건을 쓰다가 하루가 다 가버릴지도 모를 일 입니다.
따라서, if/else문은 어떻게 활용하느냐에 따라서 프로그램을 작성할때의 깊이가 달라 질 수 있다는것을 기억해 주시기 바랍니다.
휴.. 또 엄청나게 길어져버렸네요. 그럼.. 다음 스터디에서 뵙겠습니다.
현재 구상중이기론.. 다음 스터디에서는 진리표와 대수함수를 이용해서 비교연산자를 활용하는 법을 공부해 보려고 합니다.
그 다음으로는 다시 포인터로 되돌아가기전에 함수에 대해서 한번 짚고 넘어가 볼 생각이구요.
그럼 다음 스터디때 뵙겠습니다. (__)
P.S 엄청나게 긴 기간에 걸쳐 (근 3개월 가까이 된거 같네요) 글을 작성하다보니 문맥이 이상할수도 있구요.. 흐름도 중간에 많이 바뀐게 눈에 띄는군요 =_=;; 고려하고 읽어주세요 ㅠㅠ
출저= 때릴꺼야 |
Hit : 8133 Date : 2011/05/01 11:31
|