일
KNK Chap.6 (6.5~Q&A) 본문
6.5 null문
구문은 무형null의 형태를 띨 수 있음. 즉 세미콜론을 제외하고 아무 기호도 없는 구문임.
예를 들어 아래의 코드를 보면
i = 0; ; j = 1;
이 줄에는 3개의 구문이 있음. i 할당문, null 구문, j 할당문.
어디서 많이 본 모양같지 않음? 맞음. 본문이 비어있는 루프에 null문이 쓰임.
예를 들어 6.4에서 배웠던 소수 찾기 루프를 다시 보면
for (d = 2; d < n; d++) {
if ( n % d == 0) {
break;
}
}
여기서 n % d == 0 조건문을 제어식으로 옮기면 아래와 같이 루프 본문이 비게 되는데
for (d = 2; d < n && n % d != 0; d++) {
/* 비어있는 루프의 본문 */;
}
null문을 for문 바로 밑에 새 줄에다가 적었음. 같은 줄에 적어도 무방함.
근데 for문의 본문을 쉽게 파악하게 만들기 위해서 새 줄에 표시해주는 것임.
루프가 돌 때마다 조건 d < n이 먼저 검사됨. 거짓이면 루프 종료되고, 참이면 다음 조건 검사됨.
→ d < n 이 참이라면 n % d != 0 또한 참이어야 함. n의 나눗수를 찾았기 때문임.
[!!!] 실수로 if, while, for문의 괄호 이후에 세미콜론을 적어주면 null문이 생성됨.
그럼 해당 문법은 실행되지 않음. 예를 들어 아래와 같은 경우들임.
○ 이렇게 if문에서 괄호 이후에 세미콜론이 나오면 if문의 본문이 if문의 제어식 결과값과 상관없어짐.
if (d == 0); /*** WRONG ***/
printf("Error: Division by zero\n");
그러나 printf 함수의 호출은 if문의 본문 구문이 아니라서 d가 0과 같든 다르든 실행됨.
○ while문의 경우 아래와 같이 무한루프가 될 수 있음
i = 10;
while (i > 0); /*** WRONG ***/
{
printf("T minus %d and counting\n", i);
--i;
}
또는 아래와 같이 실행되어야 하는 구문이 한번만 실행되고 루프가 종료될 수 있음
i = 11;
while (--i > 0); /*** WRONG ***/
printf("T minus %d and counting\n", i);
실행하면 T minus 0 and counting 이라고 출력됨
○ for문 또한 루프가 딱 한번 실행되고 끝날 수 있음
for (i = 10; i > 0; --i); /*** WRONG ***/
printf("T minus %d and counting\n", i);
이 코드도 실행하면 T minus 0 and counting 이라고 출력됨
→ 그래서 null문이라도 빈 중괄호를 사용하는게 가독성, 통일성을 높임
Q&A
Q: 6.1에서 나온 루프를 좀 더 짧게 만들어도 되지 않나? 가령 >0을 빼도 작동은 똑같이 하는듯.
while (i > 0) {
printf("T minus %d and counting\n", --i);
}
이 코드를
while (i) {
printf("T minus %d and counting\n", --i);
}
이렇게 바꿔도 되지 않느냔 말임
A: 그렇게 하면 단점이 생김.
1. 가독성이 떨어짐. 원래는 i > 0이란 제어식만 봐도 어떤 루프인지 감이 오는데,
저렇게 적으면 i를 통해 숫자를 증가시키면서 수를 세는지, 감소시키면서 세는지 바로 알 수 없음.
2. i가 음수가 되어도 바로 종료되지 않음. 원래 코드는 바로 종료됨.
Q: 6.3에서 언급을 미뤘던, for문이 while문으로 치환되지 않는 경우는?
A: for문의 루프에 continue문이 있는 경우. 예를 들어 아래의 코드처럼
n = 0;
sum = 0;
while (n < 10) {
scanf("%d", &i);
if (i == 0) {
continue;
}
sum += i;
++n;
}
여기서 보면 i가 0일 때 n은 증가되지 않음. 근데 이걸 for문으로 비슷하게 짜보면
sum = 0;
for (n = 0; n < 10; ++n) {
scanf("%d", &i);
if (i == 0) {
continue;
}
sum += i;
}
이 코드는 i가 0일 때도 n을 증가시킴.
Q: while (1)과 for(;;) 중 어떤 무한루프를 쓰는 것이 더 나은가?
A: 사실 현대 컴파일러 기준에서는 둘의 성능 차이가 없음.
옛날 컴파일러에서는 while문의 1 조건을 매번 검사해서 효율성 때문에 for (;;) 선호가 더 많았음.
Q: continue문은 웬만하면 실무에서 쓰지 말라고 하던데 사실인가?
A: 잘 안 쓰긴 함. 근데 while문에서는 써도 무방함.
예를 들어 입력값을 받는 루프 작성 중에 입력값이 유효값이면 특정 처리가 되게 하고 싶다 치자.
이 유효값 판별 코드가 복잡할 경우, continue문은 유용함. 예를 들어 아래 코드처럼.
for (;;) {
read data;
if (data fails first test) {
continue;
}
if (data fails second test) {
continue;
}
.
.
.
if (data fails last test) {
continue;
}
process data;
}
Q: goto문은 왜 안 좋은가? [루프에서 벗어나기]
A: goto문 자체가 나쁘고 좋은게 아니고, goto문보다 더 나은 방법이 있으니까 그걸 쓰라는 것임.
왜냐면 goto문은 가독성이 떨어짐. 뒤로도 가고 앞으로도 갈 수 있어서 소위 "스파게티 코드"가 됨.
goto문은 코드의 특정 부분이 여러 일을 할 수 있게 만들어놔서 수정도 까다로움.
그러니까 웬만하면 더 편한 문법을 추천함.
Q: null문은 루프 본문 비우는 것 말고도 용도가 또 있는가?
A: 실무에선 딱 하나 있음. 복합문 마지막에 라벨 넣을 때 null문 넣어주는 경우.
라벨은 반드시 뒤에 구문이 따라와야 하기 때문임. 예를 들어 아래의 코드처럼.
{
...
goto end_of_stmt;
...
end_of_stmt: ;
}
Q: null문 말고도 빈 루프를 만들 수 있는가? [null문]
A: continue를 사용하거나
for (d = 2; d < n && n % d != 0; ++d) {
continue;
}
빈 복합문을 사용해도 됨
for (d =2; d < n && n % d != 0; ++d) {
}
'C' 카테고리의 다른 글
| KNK 공부 중단 (0) | 2023.02.07 |
|---|---|
| KNK Chap.7 (7.1) (1) | 2022.12.19 |
| KNK Chap.6 (6.4) (0) | 2022.12.16 |
| KNK Chap.6 (6.3) (0) | 2022.12.16 |
| KNK Chap.6 (6.2) (0) | 2022.12.16 |