인프런 커뮤니티 질문&답변

쉽지않네님의 프로필 이미지
쉽지않네

작성한 질문수

홍정모의 따라하며 배우는 C언어

8.5 숫자와 문자를 섞어서 입력받기

8.5강 2분 38초 관련해서 질문이 있습니다.

해결된 질문

작성

·

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줄의 공백을 출력하는 것 같습니다.

 

 

여기서 궁금한 점이..

  1. scanf의 첫 번째 인수로 공백(" ")을 읽고 나머지 rows와 cols는 읽지 못했는데 왜 그대로 진행되어 9개의 공백(붉은색 부분)이 출력되는건가요??

     

     

 

  1. 링크의 문서에는 입력 스트림에 저장된 값이 형식 지정자와 다를 경우 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

    https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-fields-scanf-and-wscanf-functions?view=msvc-170


     

  2. scanf를 실행시켜서 입력 버퍼의 값을 읽고 각각의 인수에 저장한 후에는 입력 버퍼에서 읽은 값을 제거하나요? 아니면 getchar처럼 스트림의 위치를 마지막으로 읽었던 값의 다음 위치로 이동시키나요??

 

  1. 첫 번째 입력이 "A 3 3"이고 두 번째 입력이 두 번째 입력이 "B 1 2"일 때
    첫 번째 출력을 한 후 입력 버퍼에 저장된 값이 "\nB 1 2\n"인데
    scanf가 첫 번째 \n만 읽어서 12번 줄 바꿈 출력 후 종료되는건가요?

 

 

계속 구글링 해보고 있지만 답을 찾지 못해서 질문드립니다..

 

답변 1

4

안녕하세요, 답변 도우미 Soobak 입니다.

 

질문 1) scanf의 첫 번째 인수로 공백(" ")을 읽고 나머지 rows와 cols는 읽지 못했는데 왜 그대로 진행되어 9개의 공백(붉은색 부분)이 출력되는건가요??

: main() 함수의 구성을 살펴보시면, 변수 rowscolswhile() 반복문의 바깥 영역에 선언되어있습니다.

첫 번째 입력 에서 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 문자와의 불일치로 읽기에 실패하는 것입니다)하며, rowscols 는 첫 번째 입력에서 저장된 값 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() 함수의 형식 지정자 불일치 문제로, 변수 rowscols 에 대하여 이전 입력에서의 값인 3 이 그대로 유지되어, rows 에 대한 3 번의 반복문이 실행되면서, cols 의 값 3 에 대한 3 번의 putchar('\n') 호출, 그리고, 마지막의 추가 1 번의 putchar('\n') 의 호출로, 총 3 * 4 = 12 개의 개행 문자가 출력되게 됩니다.

 

정성스러운 이미지 첨부와 좋은 질문 감사드립니다.

쉽지않네님의 프로필 이미지
쉽지않네
질문자

먼저 답변 정말 감사드립니다!

 

질문 1)의 답변 중

두 번째 입력 후에 버퍼에 저장된 (공백)\nB 1 2\n 에 대해서

(공백)%c로 읽고 그 값을 c에 저장한 후에,

\n%d로 읽으려고 할 때, 형식 불일치가 때문에

마지막 위치의 %d를 읽으려고 시도하지 않고

c만 값이 저장된 채로 실행이 종료되었다는 말씀이실까요..??

 

어제 하루 종일 이것만 찾아봤는데

달아주신 답변 덕분에 해결이 될 것같습니다..

정말 감사드립니다..!!

안녕하세요, 답변 도우미 Soobak 입니다.

 
(수정)

조금 다릅니다.

c 의 값만 ASCII 코드 32 (space) 문자로 할당이 되고, rowscols 의 값은 이전 값을 유지합니다. scanf() 함수에서 %d 형식지정자는 '\n' 을 비롯한 공백 문자들을 건너 뛰고, 값을 읽도록 설계 되어 있습니다.
이 과정에서 버퍼의 인덱스가 개행 문자의 뒤로 이동하게 됩니다.
따라서, 이후의 B 문자를 읽으려 시도하는 과정 중 실패하게 됩니다.

추가적으로, 디버거를 활용하여 각 변수에 저장된 값을 확인한 이미지를 첨부드립니다.

image

image

이미 익숙하실 수도 있지만, 디버거를 활용하여 하나씩 하나씩 직접 눈으로 확인하며 학습하시는 것이 학습에 있어서 아주 도움이 많이 되므로 잘 활용해보시면 도움이 많이 되실 것 같습니다.

쉽지않네님의 프로필 이미지
쉽지않네

작성한 질문수

질문하기