작성
·
198
1
while ((c = getchar()) != '\n')
{
scanf("%d %d", &rows, &cols);
display(c, rows, cols);
printf("Press enter to quit\n");
}
위의 코드를 실행하고, * 공백 3 공백 5 공백 \n 을 입력하면
*이 잘 출력됩니다.
그리고 다음 콘솔 입력이 활성화 되는데, % 공백 2 공백 2 \n 를 입력합니다.
그럼 공백이 세줄 출력되고,
%가 2*2로 출력되고 종료됩니다.
Q1 while문의 조건에서 c = 공백 으로 남아있는 버퍼를 한칸 가져오고, 남은 \n은 어떻게 처리한건가요?
scanf에 전달이 되었지만 %d가 \n을 만나 scanf가 종료된건가요?
Q2. 그렇다면 scanf는 형식이 맞지 않는 입력이 들어올때, %d %d 중 뒤에 것까지 가지도 않고 첫 %d에서 바로 종료시키는건가요??
Q3. 또, scanf가 \n를 입력받기를 거부해도, 입력버퍼에서 \n는 소모되는 것이 맞나요?!
답변 3
1
안녕하세요.
1. 위 코드에서 scanf는 \n을 만나지 않습니다. 동작 과정을 말씀드리자면.. 예를 들어 "% 2 2" 이렇게 입력했다면 while문은 총 1번만 돕니다.
c에 '%'가 들어옵니다. 이는 '\n'이 아니므로 반복문 조건 참이 되어 while문 중괄호로 들어갑니다. 현재 입력 버퍼에 남아있는 것은 "공백2공백2\n" 입니다. scanf의 지시자는 "%d %d"이므로 우선 앞에 공백은 무시되고 이 "숫자공백숫자"("%d %d") 형태에 "2공백2"가 일치하므로 rows와 cols에 각각 2와 2가 들어갑니다. 2와 2 사이의 공백은 scanf가 "2공백2"로 읽어 갔으니 읽긴 했지만 변수에 입력하지 않은 것뿐이니까 어쨋든 버퍼에서 나가게 된 것이고 이러면 버퍼에 '\n'만 남아있는 상태가 됩니다. 그리고 다음 while문 조건문을 검사할때 c에 '\n'가 들어옵니다.(이렇게 버퍼는 전부 비워지게됩니다.) 이는 '\n'과 동일하므로, 즉 c=='\n'이 되므로 반복 조건이 거짓이 되므로 더 이상 while문을 돌지 않습니다. 이렇게 while문을 총 1번만 돌게 되며 scanf는 '\n' 만난적이 없습니다.
디버깅을 해보시면 위와 같은 실행 순서를 직접 확인하실 수 있으니 공부하실 때 꼭 디버깅 해보시길 추천합니다!
2. 그렇지 않습니다.
"%d %d" 형태로 입력받겠다는 것에 3 b 를 입력하니 a에만 3이 들어간 것을 확인할 수 있습니다. 입력한 b는 변수 b에 입력되지 않은 것을 확인할 수 있습니다.
3. 소모 되지 않고 남아있습니다. 그저 scanf에 아무것도 입력되지 않은 채로 넘어갑니다. scanf도 리턴값이 있는 함수인데요 이렇게 지시자 형태에 맞지 않아 아무것도 입력하지 않았다면 0을 리턴합니다. 입력에 성공한 변수 개수를 리턴해요.
abcd3 이라고 입력해서 ch에는 a가 성공적으로 입력된 것을 확인할 수 잇습니다.(그래서 scnaf가 1을 리턴)
입력 버퍼엔 그대로 bcd3\n 이 남아있는 상태입니다.
이 상태에서 scanf에 %d 형태를 입력 받으려는데 버퍼의 맨 앞에있는 b는 숫자가 아니므로 scanf는 입력 버퍼로 부터 꺼내와 입력 하는 것을 포기하고 끝납니다. (그래서 scanf가 0을 리턴) 그렇다고해서 b가 소모되는 것은 아니며 입력 버퍼엔 그대로 bcd3\n 이 남아있는 상태입니다.
0
아하 그냥 따로따로의 예시를 드신 것인 줄 알았는데 제가 잘못 이해했네요. 공백이 하나 더 붙어있는 것도 몰랐네요...
디버깅을 해보니 두번쨰 루프에서 c에 공백이 들어가 while문 조건이 참이 되어 두번째로 scanf가 실행되게 되었는데 버퍼엔 \n 만 남아있게되므로 scanf 에서 가져올게 없는 상태입니다. 근데 이때 \n는 버퍼에서 비워집니다.
2가 맞습니다. 저도 이유는 잘 모르겠는데 %d처럼 %c가 아닌 형태를 입력받는 scanf는 버퍼에 b 같은 공백이 아닌 문자가 있으면 scanf는 이를 버퍼에서 비우지 않고 그냥 입력 안하고 지나갈 뿐인데, 이와 달리 \n 이나 공백 같은 whitespace는 scanf가 이를 읽어들여서 버퍼에서 비운 후 입력 안하고 지나가더라구요.
따라서 % 때문에 입력 안하고 넘어간 것입니다. 디버깅으로 확인해보니 그래서 세번째 while문에서는 c에 %가 들어가고 2와 2가 row와 col에 입력이 되네요.
만약 scanf가 공백을 버퍼에서 꺼내 비우지 않았다면 c에는 공백이 들어가야 맞을텐데 a가 들어간 것을 볼 수 있습니다. %c 가 아닌 형태를 입력 받는 scanf는 이렇게 공백이나 \n 문자들을 버퍼에서 꺼내서 읽어들이되 입력은 안하는 것 같아요. (그래서 위의 \n은 이미 버퍼에서 비워진 상태였을 것이고 '%' 때문에 입력 안하고 넘어간듯 합니다.)
공백 문자가 아닌 그냥 'a'를 만났을땐 이를 버퍼에서 꺼내지 않고 냅둬서 c에서 a를 저장할 수 있는 것을 볼 수 있네요.
0
답변 감사드립니다!
답변해주신 내용은 이해가 갔지만, 제 질문이 잘 전달이 되지 않았나 싶어서 다시 여쭙습니다 ㅠㅠ
Q1.첫 콘솔 입력 : "* 공백 3 공백 5 공백 \n" <- 엔터 전에 공백 하나가 더 있습니다.
별 3줄이 잘 출력되고 다음 콘솔 입력이 뜹니다.
두번째 콘솔 입력 : "% 공백 2 공백 2 \n" 입니다!
총 입력된 값들은 순서대로
"* 공백 3 공백 5 공백 \n % 공백 2 공백 2 \n" 입니다.
"* 공백 3 공백 5" <- 까지만 첫 루프에서 소모되고,
다음 루프에서는 공백부터 시작하게 되는 것 같습니다! 그래서
"공백 \n % 공백 2 공백 2 \n" 이 두번째루프의 시작인데,
c 에 버퍼에 남은 공백이 대입된 뒤 scanf가 "\n % 공백 2 공백 2 \n" 순으로 만나는 것 같은데
(콘솔 입력 자체도 while 조건문이 아닌 body의 scanf에서 활성화 됩니다)
이 경우 scanf가 스킵되고 기존 row, column 대입값인 3, 5가 유지되는 둘째 루프를 디버그로 확인했습니다!
scanf 가 스킵되는 이유가,
1. \n을 만나서인지,
2. 아니면 \n을 만났지만 무시하고 %를 만나서 스킵되는 것인지
또 두 경우에서 Q3. 에서 답변 주신 것처럼 space 문자가 아닌 경우는 입력버퍼에 유지되는 것을 이해하였는데 \n은 제가 디버그를 해보아도 사라지는 것으로밖에 확인이 안되어서 ㅠㅠ 질문을 다시 드려봅니다!
Q2. 의 경우는
int a, b;
scanf("%d %d", &a, &b);
와 같은 경우에 답변 주신 것처럼 3 b 를 입력하면 a 에 대입이 되지만,
b 3 을 대입할 경우를 말씀드린 거였습니다! 이 부분은 말씀주신것처럼 디버깅을 통해서 확인해보니 뒤의 값도 대입이 안되는 것으로 확인했습니다 ㅎㅎ!!!