해결된 질문
작성
·
376
·
수정됨
3
입력 "A 3 3 "에 대해
입력 버퍼에 저장된 값은 "A 3 3 \n"이며
"A 3 3" 까지만 읽고
AAA
AAA
AAA
를 출력한다는 것은 알겠습니다.
그 다음 입력 "B 1 2 "에 대해
입력 버퍼에 " \n"이 남아있으므로
입력 버퍼에 저장된 값은 " \nB 1 2\n"이며
입력 버퍼에서 개행 문자(\n) 앞의 공백(" ")만 읽어오고
나머지 rows나 cols는 이전에 저장된 값을 재사용해서
3개씩 3줄의 공백을 출력하는 것 같습니다.
여기서 궁금한 점이..
scanf의 첫 번째 인수로 공백(" ")을 읽고 나머지 rows와 cols는 읽지 못했는데 왜 그대로 진행되어 9개의 공백(붉은색 부분)이 출력되는건가요??
링크의 문서에는 입력 스트림에 저장된 값이 형식 지정자와 다를 경우 scanf를 종료한다고 되어있습니다.
그러면 첫 번째 인수로 공백(" ")을 읽고 한 줄에 3개씩 3줄의 공백(" ")를 출력하고 난 뒤에는
개행 문자 ("\n")를 읽어서 9개의 줄 바꿈이 출력되어야 할 것 같은데
왜 바로 BB가 출력되었는지 잘 모르겠습니다..
[입력과 그에 대한 예상 출력 콘솔 화면]
A 3 3 // 첫 번째 입력 : A 3 3
AAA
AAA
AAA // 한 줄당 3개의 'A'를 3줄 출력
B 1 2 // 두 번째 입력 : B 1 2
// 한 줄당 3개의 공백을 3줄 출력
// 9번 + 3번 총 12번의 줄바꿈
BB
scanf를 실행시켜서 입력 버퍼의 값을 읽고 각각의 인수에 저장한 후에는 입력 버퍼에서 읽은 값을 제거하나요? 아니면 getchar처럼 스트림의 위치를 마지막으로 읽었던 값의 다음 위치로 이동시키나요??
첫 번째 입력이 "A 3 3"이고 두 번째 입력이 두 번째 입력이 "B 1 2"일 때
첫 번째 출력을 한 후 입력 버퍼에 저장된 값이 "\nB 1 2\n"인데
scanf가 첫 번째 \n만 읽어서 12번 줄 바꿈 출력 후 종료되는건가요?
계속 구글링 해보고 있지만 답을 찾지 못해서 질문드립니다..
답변 1
4
안녕하세요, 답변 도우미 Soobak 입니다.
질문 1) scanf의 첫 번째 인수로 공백(" ")을 읽고 나머지 rows와 cols는 읽지 못했는데 왜 그대로 진행되어 9개의 공백(붉은색 부분)이 출력되는건가요??
: main()
함수의 구성을 살펴보시면, 변수 rows
와 cols
는 while()
반복문의 바깥 영역에 선언되어있습니다.
첫 번째 입력 에서 A 3 3(공백)
을 입력하고 엔터를 치면, 실제로 입력 버퍼에는 A 3 3(공백)\n
이 저장됩니다.
이 때, scnaf()
함수는 A
, 3
, 3
을 읽고, 공백 문자와 개행 문자('\n'
)는 버퍼에 남아있게 됩니다.
이후, display()
함수가 호출되어 AAA
가 세 번 출력됩니다.
두 번째 입력 에서 B 1 2
를 입력하고 엔터를 치면, 입력 버퍼에는 이전 입력에서 남은 공백 문자, 개행 문자('\n'
)와 함께 (공백)\nB 1 2\n
이 저장됩니다.
이 때, scanf()
함수의 작동 방식을 살펴보면, scanf("%c %d %d, &c, &rows, &cols);
에서 첫 번째 형식지정자 %c
가 입력 버퍼에 남아 있는 공백 문자를 읽어들여 변수 c
에 저장합니다.
그런 다음, scanf()
함수는 두 개의 정수(형식지정자 %d
에 따른)를 읽으려 시도하지만, 버퍼에는 \nB 1 2\n
이 남아있고, scanf()
함수는 rows
에 대하여 형식 지정자의 불일치로 읽기에 실패(%d
형식 지정자는 개행 문자를 건너 뛰는 특성을 가지고 있으며, B
문자와의 불일치로 읽기에 실패하는 것입니다)하며, rows
와 cols
는 첫 번째 입력에서 저장된 값 3
이 유지됩니다.
따라서, display()
함수의 인수로는 최종적으로 (공백 문자
, 3
, 3
)이 전달되어 붉은색으로 표시해주신 부분이 출력되는 것입니다.
질문 2) 링크의 문서에는 입력 스트림에 저장된 값이 형식 지정자와 다를 경우 scanf를 종료한다고 되어있습니다. 그러면 첫 번째 인수로 공백(" ")을 읽고 한 줄에 3개씩 3줄의 공백(" ")를 출력하고 난 뒤에는 개행 문자 ("\n")를 읽어서 9개의 줄 바꿈이 출력되어야 할 것 같은데 왜 바로 BB가 출력되었는지 잘 모르겠습니다..
: 버퍼에 남아있는 개행 문자는 scanf()
함수의 이전 호출에서 읽기를 시도하며 처리되고, 버퍼에서의 인덱스 위치가 이동하였습니다.
즉, scanf()
함수의 이전 호출에서 형식지정자 %d
에 대하여 개행 문자 '\n'
는 형식지정자 %d
의 특성상 처리되었고, 이제 버퍼에서 읽어들여야 할 문자들은 B 1 2\n
입니다.
따라서, display()
함수의 인수로 (B
, 1
, 2
) 가 전달되며 BB
가 출력되는 것입니다.
질문 3) scanf를 실행시켜서 입력 버퍼의 값을 읽고 각각의 인수에 저장한 후에는 입력 버퍼에서 읽은 값을 제거하나요? 아니면 getchar처럼 스트림의 위치를 마지막으로 읽었던 값의 다음 위치로 이동시키나요??
: 보다 명확한 설명은 '시스템 마다의 구체적인 버퍼의 구현 방식' 에 따라서 다르다고 말씀드리는 것이 옳은 것 같습니다.
하지만, 대부분의 표준 C라이브러리 구현에서 scanf()
함수는 지정된 형식에 맞는 데이터를 읽고 나면, 해당 데이터를 버퍼에서 사용된 것으로 간주하고, 버퍼 스트림의 위치를 그 다음으로 이동시킵니다.
질문 4) 첫 번째 입력이 "A 3 3"이고 두 번째 입력이 두 번째 입력이 "B 1 2"일 때 첫 번째 출력을 한 후 입력 버퍼에 저장된 값이 "\nB 1 2\n"인데 scanf가 첫 번째 \n만 읽어서 12번 줄 바꿈 출력 후 종료되는건가요?
: 네, 맞습니다.scanf()
함수의 형식 지정자 불일치 문제로, 변수 rows
와 cols
에 대하여 이전 입력에서의 값인 3
이 그대로 유지되어, rows
에 대한 3
번의 반복문이 실행되면서, cols
의 값 3
에 대한 3
번의 putchar('\n')
호출, 그리고, 마지막의 추가 1
번의 putchar('\n')
의 호출로, 총 3 * 4 = 12
개의 개행 문자가 출력되게 됩니다.
정성스러운 이미지 첨부와 좋은 질문 감사드립니다.
안녕하세요, 답변 도우미 Soobak 입니다.
(수정)
조금 다릅니다.
c
의 값만 ASCII 코드 32
(space) 문자로 할당이 되고, rows
와 cols
의 값은 이전 값을 유지합니다. scanf()
함수에서 %d
형식지정자는 '\n'
을 비롯한 공백 문자들을 건너 뛰고, 값을 읽도록 설계 되어 있습니다.
이 과정에서 버퍼의 인덱스가 개행 문자의 뒤로 이동하게 됩니다.
따라서, 이후의 B
문자를 읽으려 시도하는 과정 중 실패하게 됩니다.
추가적으로, 디버거를 활용하여 각 변수에 저장된 값을 확인한 이미지를 첨부드립니다.
이미 익숙하실 수도 있지만, 디버거를 활용하여 하나씩 하나씩 직접 눈으로 확인하며 학습하시는 것이 학습에 있어서 아주 도움이 많이 되므로 잘 활용해보시면 도움이 많이 되실 것 같습니다.
먼저 답변 정말 감사드립니다!
질문 1)의 답변 중
두 번째 입력 후에 버퍼에 저장된
(공백)\nB 1 2\n
에 대해서(공백)
을%c
로 읽고 그 값을c
에 저장한 후에,\n
을%d
로 읽으려고 할 때, 형식 불일치가 때문에마지막 위치의
%d
를 읽으려고 시도하지 않고c
만 값이 저장된 채로 실행이 종료되었다는 말씀이실까요..??어제 하루 종일 이것만 찾아봤는데
달아주신 답변 덕분에 해결이 될 것같습니다..
정말 감사드립니다..!!