Coding Test/Logic Memo

JAVA) System.in.read()로 정수 입력받기

6uiw 2024. 12. 28. 17:22

목차

     

    📌System.in.read()

    💡System.in.read()의 주요 특징

    1. 입력 데이터 처리
      • 한 번 호출 시 1바이트(8비트)를 읽음
      • 반환값은 0부터 255 사이의 정수 값.  ASCII 코드로 입력받음
        • 예:  'A'입력 -> 65
      • 만약 입력이 없으면 -1 반환 = EOF(End Of File)
    2. 입력이 있을 때까지 프로그램 실행이 멈추는(블로킹) 방식으로 동작
      • 사용자가 키보드로 Enter를 누를 때까지 대기
    3. 버퍼 사용
      • 사용자가 입력한 내용은 내부적으로 입력 버퍼에 저장
      • System.in.read()는 버퍼에서 데이터를 하나씩 읽어온다. 예를 들어, 사용자가 abc\n를 입력하면:
        1. 'a'를 읽고 반환
        2. 'b'를 읽고 반환
        3. 'c'를 읽고 반환
        4. '\n'(줄 바꿈 문자)를 읽고 반환
    4. 입력은 문자로 다뤄짐
      • 입력값 은문자(ASCII 코드 값)로 반환되므로, 숫자로 사용하려면 추가 처리가 필요
        • 예: 입력 '1'(ASCII 값 49)를 숫자 1로 변환하려면 '1' - '0' 연산을 수행

    📌System.in.read()로 공백으로 구분된 정수 입력받기 

    💡입출력 예시

     

    다음과 같이 입력했을 때 

    3 -23 6

     

    다음과 같이 출력되도록 코드를 구현해보자. 

    3
    -23
    6

     

     

    💡구현 코드

    import java.io.IOException;
    
    public class Sir {
        //실행 부분
         public static void main(String[] args) throws IOException {
            int ex1 = readInt();
            int ex2 = readInt();
            int ex3 = readInt();
    
            System.out.println("첫 번째 입력: " + ex1);
            System.out.println("두 번째 입력: " + ex2);
            System.out.println("세 번째 입력: " + ex3);
    
        }
    
        //구현 부분 
        private static int readInt() throws IOException {
            int ans = 0;
            boolean isNegative = false;
    
            while (true) {
                //System.in.read() : 입력받은 데이터를 한 문자씩 읽음
                int n = System.in.read();
    
                if(n<=32) { //공백이 나오면 리턴
                    return isNegative ? ans * (-1) : ans;
                }
                else if (n == '-') isNegative = true; //음수면 부호 저장
                //아스키 코드를 숫자로 변환
                else  ans = (ans <<3) + (ans <<1) + (n&15) ;
    
            }
        }
    }

     

     

     

     

     

    💡설명 

     

    구현 부분 코드를 자세히 살펴보자.

     

    ans 는 최종 결과물을 담을 변수고, isNegative는 음수/양수를 확인하기 위해 선언한 변수이다.

    (System.in.read()는 '문자'를 입력받기 때문에 -3이란 정수가 나와도 음수,양수를 판단할 수 없으므로 우리가 직접 판단해주어야 한다.)

     int ans = 0;
     boolean isNegative = false;

     

     

    while 문을 살펴보자.

     while (true) {
                //System.in.read() : 입력받은 데이터를 한 문자씩 읽음
                int n = System.in.read();
    
                if(n<=32) { //공백이 나오면 리턴
                    return isNegative ? ans * (-1) : ans;
                }
                else if (n == '-') isNegative = true; //음수면 부호 저장
                //아스키 코드를 숫자로 변환
                else  ans = (ans <<3) + (ans <<1) + (n&15) ;
    
            }

     

     

    공백을 만나면 음수면 -를 붙여서, 양수면 그대로 출력한다. 

      if(n<=32) { //공백이 나오면 리턴
          return isNegative ? ans * (-1) : ans;
                }
    ❗n<=32로 설정하는 이유
      → 공백관련 문자가 32 이하에 있기 때문 
           9 - Tab 
          10 - Line Feed, 줄 바꿈
          13 - Carriage Return, Enter
           0 - 종료(Null)

     

     

    -가 나오면 음수이므로, isNegative에 음수임을 저장해준다. 

    else if (n == '-') isNegative = true; //음수면 부호 저장

     

     

    아스키코드를 숫자로 변환하고, 각 자리수를 맞춰준다. (0 = 48, 1=49, ...)

    //아스키 코드를 숫자로 변환
       else  ans = (ans <<3) + (ans <<1) + (n&15) ;

     

          ans << 3 = ans * 8
          ans << 1 = ans * 2 
          →  (ans << 3) + (ans << 1) = ans * 10 을 의미한다.

    ❗(ans << 3) + (ans << 1)을 해주는 이유 → 입력값이 10 이상일 경우, 자리수를 맞춰주기 위해 

    예시: 입력 값 123

    첫 번째 입력 문자  '1' : ans = 0 → ans = (0 * 10) + 1 = 1
    두 번째 입력 문자  '2' : ans = 1 → ans = (1 * 10) + 2 = 12
    세 번째 입력 문자  '3' : ans = 2 → ans = (12 * 10) + 3 = 123         
            ❗& 15 연산을 사용하는 이유
            ASCII 코드에서 숫자 문자 '0'~'9'의 마지막 4비트가

     실제 숫자 값(0~9)과 동일하기 때문 15는 2진수로 00001111
       → &15 연산을 통해 뒤의 4비트만 추출하면 숫자 값을 바로 얻을 수 있다.

           '0' → 48 (2진수: 00110000)   48&15 = 00110000&00001111 = 00000000 = 0

           '1' → 49 (2진수: 00110001)   49&15 = 00110001&00001111 = 00000001 = 1
           '2' → 50 (2진수: 00110010)   50&15 = 00110010&00001111 = 00000010 = 2
           '3' → 51 (2진수: 00110011)   51&15 = 00110011&00001111 = 00000011 = 3
           '4' → 52 (2진수: 00110100)   52&15 = 00110100&00001111 = 00000100 = 4
           '5' → 53 (2진수: 00110101)   53&15 = 00110101&00001111 = 00000101 = 5
           '6' → 54 (2진수: 00110110)   54&15 = 00110110&00001111 = 00000110 = 6
           '7' → 55 (2진수: 00110111)   55&15 = 00110111&00001111 =  00000111 = 7
           '8' → 56 (2진수: 00111000)   56&15 = 00111000&00001111 = 00001000 = 8
           '9' → 57 (2진수: 00111001)   57&15 = 00111001&00001111 = 00001001 = 9

     

    💡구현 부분 정리

    System.in.read()로 입력받은 문자열을 ASCII 코드에서 숫자로 변환한 후 공백을 만나면 변환을 멈추고, 음수인지, 양수인지 판별하여 return한다. 

    private static int readInt() throws IOException {
            int ans = 0;
            boolean isNegative = false;
    
            while (true) {
                //System.in.read() : 입력받은 데이터를 한 문자씩 읽음
                int n = System.in.read();
    
                if(n<=32) { //공백이 나오면 리턴
                    return isNegative ? ans * (-1) : ans;
                }
                else if (n == '-') isNegative = true; //음수면 부호 저장
                //아스키 코드를 숫자로 변환
                else  ans = (ans <<3) + (ans <<1) + (n&15) ;
    
            }

     

     

     

     

    끝까지 읽어주셔서 감사합니다 :)

    Have a good day🐱


    📢

    1. 개발자 준비생이 공부한 내용을 정리한 글입니다. 내용에 오류가 있을 수 있습니다.
    2. 위와 같은 이유로 내용에 대한 지적과 조언은 감사하게 받습니다.
    3. 이 글의 내용은 계속 공부함으로써 언제든지 추가/수정 될 수 있습니다.