[Visual Studio 2015버전]


숫자를 입력한 뒤 Enter키를 누르게 되면, 다음에 입력받는 단계를 건너뛰는 경우가 발생한다.


<Example>


 #include"stdio.h"

 #pragma warning(disable : 4996)


 void main(){


 int num1, num2;

 char op;

 

 printf("Enter the 1st number : ");

 scanf("%d", &num1);


 printf("Enter the operation : ");

 scanf("%c", &op);


 printf("Enter the 2nd number : ");

 scanf("%d", &num2);


 printf("%d%c%d = %d", num1, op, num2, num1+num2);


}


  예제를 실행하게 되면, enter the 1st number : 에 커서가 깜빡거린다.


 그 곳에다가 3을 입력하고 Enter키를 누르게 되면,  다음과 같은 결과가 나오게 된다.



즉, 연산자를 입력할 공간이 사라지고, 다음 숫자를 넣을 공간에 커서가 깜빡거리게 된다.






[원인]


"이렇게 되는 이유는 Enter키 때문이다."


원리를 설명하자면,


scanf함수를 이용하여 값을 입력하게 되면, 변수에 값이 저장되기 전에 입력버퍼에 먼저 그 값이 쓰여지게 된다.



여기서 \0는 'Null'값을 말하며, 이는 Enter를 칠 경우 입력버퍼에 \0의 형태로 들어가게 된다.


이렇게 쓰여진 값들은 데이터타입에 따라 변수에 저장되게 된다.


num1에 저장되는 것은 오직 3뿐이다. 이유는 num1의 데이터 타입이 int 이기 때문이다.


'\0'는 char 타입이기 때문에, num1에는 저장될 수 없다. 그렇기 때문에 '\0'는 입력버퍼에 그대로 잔류하게 된다.


다음에 입력 받는 연산자가 char타입이기 때문에, 이 변수 op는 추가적인 입력없이 입력버퍼에 남아있는 '\0'를 저장하게 된다.



그렇기 때문에, 프로그램을 실행시켰을 때는 위와 같이, 연산자를 입력할 공간이 건너 뛰어, 다음숫자를 입력할 단계로 넘어가는 것처럼 보이게 된다.







[해결 방안]


1. getchar()이용


  getchar함수는 입력버퍼에서 문자 하나를 가져오는 함수이다.


  getchar()를 이용하게 되면, 입력버퍼에 '\0'를 가져오게 됨으로써, 입력버퍼가 비게 되어 다음 값을 입력받을 수 있다.


  <사용 예시>



 + 응용버전.


 getchar()는 문자하나만을 가져오기 때문에, 입력버퍼에서 있는 문자전체를 가져와서 입력버퍼를 비우고 싶을 경우에는


 위의 getchar()가 적혀있는 부분에, getchar() 대신, while(getchar()!='\n') 를 적어주면 된다. 


 while 문의 조건을 통해, 문자가 '\n'(개행문자)가 아닌 경우에는 모두 가져와서 입력버퍼를 비워주는 역활을 한다.





2. %*c 이용



 scanf함수에서 '%*c' 는 'read the data but do not assign it to a variable in the argument list' 이다.


 즉, 입력버퍼의 값을 읽어오지만, 그 값을 변수에 대입하지는 않는 다는 뜻이다.



<사용예시>


  #include"stdio.h"

  #pragma warning(disable : 4996)


  void main(){


  int num1, num2;

  char op;

 

  printf("Enter the 1st number : ");

  scanf("%d", &num1);


  printf("Enter the operation : ");


  scanf("%c", &op);     -> scanf("%*c%c", &op); 로 변환 : 입력버퍼에 있는 '\0'를 %*c에서 가져가게 된다. 


    그러나, %*c는 가져간 값을 변수에 대입하지는 않기 때문에, 다음 %c로 넘어가게 된다.


    (원래 입력버퍼에 있던 값을 한번, scanf로 입력하는 값 한번) = 두개의 문자를 입력받는 방식.


  printf("Enter the 2nd number : ");

  scanf("%d", &num2);


  printf("%d%c%d = %d", num1, op, num2, num1+num2);


 }





3. scanf("%c", &op) 한번 더 이용



<사용예시>



scanf("%c", &op)를 처음 사용하게 되면 op에는 '\0'의 값이 들어오게 된다.


두번째 이용 시에는, 입력버퍼에 남은 값이 없기 때문에 op변수에 키보드를 통해 값을 입력할 수 있게 된다.





4.  rewind(stdin) 이용


[ 기본형태 :  void rewind ( FILE * stream ) ]


rewind함수는 스트림의 위치를 재설정하는 함수이다.


스트림은 프로그램과 장치사이를 연결해 주는 통로라고 할 수 있으며, 


표준 스트림은 모든 프로그램에서 기본적으로 사용하는 3개의 스트림(stdin, stdout- 표준 출력, stderr - 표준 오류)을 말한다.


그 중에서도 stdin(standard input)은 표준 입력 스트림으로써, 


키보드에서 입력받는 값이 변수에 저장되기 전에 임시로 저장되는 공간으로 가는 통로라고 할 수 있으며, 


사용자의 개별적인 지정없이는 키보드에서 받아 오게 된다. 


또한 이 통로를 통해 값이 임시로 저장되는 공간을 입력버퍼라고 한다.



rewind함수는 스트림의 위치를 스트림의 시작점으로 이동하게 하는 함수로서, 


주는 곳에 stdin를 주게 되면, 입력 스트림의 위치를 처음 위치로 이동시키게 된다. 


rewind함수를 이용 후, 값을 입력하게 되면, 이전에 쓰여있던 값을 덮어 쓰고, 입력하게 된다. 



<사용예시>



+추가


비슷한 예시로는 fseek함수가 있다.


[ 기본형식 : int fseek(FILE *stream, long offset, int whence) ]


fseek함수는 rewind함수와 유사하게 위치를 재설정해주나,


시작점으로 이동하는 rewind함수와 다르게 위치를 이동시키는 함수로서, 인자를 3개를 요구한다.


offset는 기준점에서 부터 byte 단위로 사용자가 위치를 지정할 수 있으며, 


whence는 그 위치를 변경할 기준점으로 SEEK_SET, SEEK_CUR, SEEK_END 3가지가 있다.


SEEK_SET는 스트림의 시작점을, SEEK_CUR은 현재 스트림의 위치를, SEEK_END는 스트림의 마지막점을 말한다. 


<사용예시>

fseek(stdin, 0, SEEK_SET)을 이용하여 현재 스트림의 위치를 시작점으로 이동시켜 입력을 받을 수도 있지만,


fseek(stdin, -1, SEEK_CUR)를 통해, 현재스트림의 위치에서 -1한 위치로 이동시켜, 입력을 받을 수도 있다.



<사용예시>

참고자료 : https://www.joinc.co.kr/w/man/3/fseek





5. 공백(White Space) 이용


scanf함수의 기본적인 사용형식은 scanf("문자 서식 및 구분자", 데이터의 값) 이다. 


구분자란 문자를 여러개 입력 받는 경우 값을 구분해 주는 요소이다.


구분자는 공백(white space)혹은 개행문자(\n), Tab(\t) 등 여러가지가 있는데, 


이 구분자가 들어가게 되면 값 입력시 구분자형식과 동일한 값이 들어오게 되면


해당값을 입력에서 제외하고 입력을 받는다. 


+ 지정 구분자와 다른 형식의 구분자을 입력할 시에는 입력 값을 구분자로 인식하지 않고,


   값으로 인식하여 입력을 받아들인다.



<사용예시>



++예외적으로 안되는 함수


1. fflush함수


fflush함수는 원래는 출력버퍼를 비우는 함수로 이용되나, fflush(stdin)로 입력버퍼를 비우는 함수로도 이용할 수 있었다.


그러나, visual studio 2015년도 버전부터 보완을 강화시켜 이용이 불가능하다.


'C' 카테고리의 다른 글

포인터  (0) 2018.01.08
배열  (0) 2018.01.08

+ Recent posts