ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바(Java) 사용자 입/출력과 버퍼(butter)
    프로그래밍/Java 2021. 7. 23. 22:42

    프로그램을 사용하다 보면 사용자 입력을 받는 경우가 많다.

     

    c언어나 java의 경우 사용자 입력을 받을 때, 버퍼(buffer)라는 녀석에 값을 임시로 저장해두었다가 한번에 변수에 저장하는데  숫자와 문자가 다르게 동작해서 이상한 의도한 바와 다르게 되기도 한다.

     

    ▶  버퍼(buffer)의 이해

    일단, 왜 버퍼라는 것이 존재하는지부터 알아야할 것 같다.

     

    컴퓨터에 따라 다르겠지만 일반적인 컴퓨터(가정용)는 1초에 약 8천 ~ 1억 번 정도의 연산을 처리할 수 있다고 한다.

     

    만약, 컴퓨터가 사용자에게 정보를 입력 받아야할 때, 우리가 정보를 모두 입력하기를 기다려야 한다면, 우리가 1 / 1억 초 안에 하나의 값을 입력하지 않는 한 컴퓨터는 그동안 계속 대기하고 있어야 한다. 

     

    CPU입장에서는 속터지는 일이 아닐 수 없을 것이다. 그래서 등장한 것이 "버퍼"라는 개념이라고 한다.

     

    어떤 변수에 사용자 입력 값을 저장할 때, 하나하나 차례로 저장하는 것이 아닌 임시로 버퍼에 저장해 두었다가 모든 입력이 완료되면(사용자가 엔터키를 누름) 한 번에 변수에 저장시키는 것이다. 입력을 하는 그 사이사이 시간에 컴퓨터는 다른 일을 하고 있을 수 있다.

     

    키보드로 'WOW'라는 문자를 사용자에게 입력 받는다고 가정하자.

    사용자가 키보드를 입력할때 마다 버퍼에는 문자가 하나씩 쌓이기 시작한다.

     

    ↓버퍼의 상태 변화

    키보드 'W' 입력 W      
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 'O' 입력 W O    
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 'W' 입력 W O W  
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 'Enter' 입력 W O W \n
    사용자 입력 종료

    사용자가 엔터키를 누르는 순간, 입력이 끝난 것으로 간주하고 버퍼에는 엔터를 포함해서 차례로 WOW\n가 남게 된다.

    (\n는 컴퓨터에서 한 줄 띄기, enter를 의미한다.)

     

    그 후 우리가 변수를 저장한다면, 버퍼에 남아있는 값들을 가져와 저장한다.

    ex). 

    >>>Scanner sc = new Scanner(System.in); 

    >>>String wow = sc.nextLine();   // 사용자 입력으로 WOW 저장

     

    wow라는 문자열 변수에 'WOW' 저장

     

    ▶  nextInt()와 nextLine()

    버퍼의 특징 때문에 nextInt() 메서드를 사용해서 정수 값을 입력할 때, 주의해야 할 점이 생긴다.

     

    nextInt() 메서드는 버퍼에 남아있는 연속된 숫자만 리턴한다.

     

    간단한 예를 들어보면

     

    >>> int num = sc.nextInt();

     

    가 실행 되었을 때, 사용자 입력을 123으로 가정해보자 이때, 버퍼의 상태는 아래와 같다.

     

    ↓버퍼의 상태 변화

    키보드 1 입력 1      
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 2 입력 1 2    
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 3 입력 1 2 3  
    다음 입력 값이 있을 때까지 컴퓨터는 다른 작업을 처리...
    키보드 'Enter' 입력 1 2 3 \n
    사용자 입력 종료

    사용자 입력이 종료되면, 이제 버퍼에 값들을 차례로 가져와 선언된 변수 num에 저장한다.

     

    이때, nextInt() 메서드 자체는 연속된 번호만 저장하기 때문에 enter 값인 \n을 만나면 더 이상 버퍼에서 값을 가져오지 않는다.

     

    즉, 123만 버퍼에서 가져오고 \n은 남겨둔다.

     

    ----최종 상태

     

    num == 123

     

    ↓현재 버퍼의 상태 : \n이 남아있다.

    \n      

     

    nextInt() 메소드만 사용하면 큰 문제가 없어 보이지만 문자열 입력을 받아 저장하는 nextLine()을 함께 사용할 때, 문제가 생긴다.

     

    위에서 정수 123을 받은 후 문자열을 추가로 입력 받는 함수로 수정해 보면 아래와 같다.

     

    >>> int num = sc.nextInt();

    >>> String str = sc.nextLine();

    >>> System.out.println(num);

    >>> System.out.println(str);

     

    예상 사용자 입력 :

    123

    안녕 반가워

     

    예상 출력:

    123

    안녕 반가워

     

    실제 출력:

    123

     

    실제로 정수 123을 사용자 입력을 받은 후 문자열 값을 입력받지 않고 프로그램이 종료되어버린다.

     

    이는 nextLine() 메서드의 특징인데 nextLine()은 값을 가져올 때 \n을 만날 때까지의 모든 값을 가져와 변수에 저장하고 \n값 역시 버퍼에서 빼내기 때문이다.

     

    예를 들어 버퍼에 "안녕 반가워"라는 값이 들어있을 경우

     

    전)

    /s \n

    nextLine()은 \n을 만나기 전까지의 값을 변수에 저장하고 \n도 제거한다.

     

    후)

             

    버퍼가 비어진다.

     

     

    다시 돌아와

    >>> int num = sc.nextInt();    // 123 입력

    >>> String str = sc.nextLine();

    >>> System.out.println(num);

    >>> System.out.println(str);

     

    nextInt()로 사용자 입력 123을 num에 저장한 후 버퍼의 상태는 아래와 같다.

     

    ↓현재 버퍼의 상태 : \n이 남아있다.

    \n      

    바로 이어서 nextLine()이 실행되면 버퍼에 \n이 남아있기에 \n까지의 값을 버퍼에서 빼내 오고 \n전까지 이 값을 str에 저장한다.

     

    즉, str에는 아무 값도 저장되지 않고 버퍼는 비어지게 된다.

     

    버퍼는 비어져 있지 않는다면 추가로 사용자 입력을 받지 않기 때문에 이러한 일이 발생한다.

     

    해결 방법은 여러 방법이 존재하는데 str에 사용자 입력을 받기 전에 nextLine() 메서드를 미리 사용하여 버퍼를 비우는 방식이 있다.

     

    ex):

    >>> int num = sc.nextInt();    // 123 입력

    >>> sc.nextLine();  // 버퍼에 남아있는 \n을 가져와 버퍼를 비움

    >>> String str = sc.nextLine();   // 원하는 문자열 입력

    >>> System.out.println(num);

    >>> System.out.println(str);

     

    C언어의 getChar()와 유사한 방식이라고 할 수 있다.

     

    확실히 C와 java는 조금 불편한 부분이 있기는 하지만 더 원론적인 느낌이라서 재미있다.

    댓글

Space_Jin's blog