ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 정수의 입력 함수 (scanf), 버퍼의 추상화
    C언어 2020. 2. 19. 18:27

    앞의 포스트에서 다룬 내용은 문자열과 문자의 입력 출력 함수와 함수가 내부적으로 버퍼를 통해 어떤 식으로 동작하는지 알아보았다. 이번 포스트에서는 정부의 입력 함수와, 정수의 오버플로우, 앞에서 계속 설명한 버퍼에 대해서 다룰 것이다.

    정수를 입력받기 위해 필요한 함수는 scanf함수이다. printf 함수와 마찬가지로 형식문자열을 받는 형태이다.

    scanf : 형식 문자열에 맞추어 표준입출력장치(stdin) 로 부터 정보를 읽어들이는 함수이다. 인자값으로는 사용자가 입력한 값을 저장할 메모리의 주소를 받게 된다.

    + stdin : 표준입출력장치 즉 콘솔을 추상화 시킨 개념

     

    위의 자료는 콘솔에 대한 입력 버퍼 구조체를 확인하면서 버퍼에 대해 자세히 살펴보기 위한 코드이다. stdin는 표준입출력 장치를 파일 형태로 추상화시킨 개념이다 즉 콘솔에 대한 버퍼를 살펴볼 수 있게 해준다. 

    현재 getchar 함수를 호출하기 전 이기 때문에 아직 버퍼가 할당 되지 않은 모습이다. 이제 표준 입력 함수인 getchar를 통해 콘솔 창을 띄운뒤 표준입출력장치를 통해 입력 값을 넣으면 해당 구조체에 어떤 값이 들어가는지 확인할 수 있을 것이다.

    위의 그림은 콘솔을 통해 TEST + \n ( 엔터 ) 를 입력한 뒤 앞서 설정한 버퍼 (fp 구조체)의 값을 확인한 모습이다. 해당 버퍼의 주소 0x 59C1C700 를 확인해 보면 TEST라는 문자 상수가 성공적으로 버퍼에 담겨있는 것을 확인할 수 있다. 또한 TEST값 뒤에 0a 0a 와 같은 자료가 담긴 것을 볼 수 있는데 이는 \n 즉 엔터키를 의미한다. 하나는 사용자가 입력한 개행 문자이고 나머지 하나는 scanf 함수가 자체적으로 개행을 하기 때문에 붙는다.

    _ptr : 현재 버퍼의 포인터

    _base : 버퍼의 기본 주소

    조사식을 한번 자세히 살펴보자 

    버퍼의 기본 주소인 59C1C700 에 TEST0a0a 의 값이 담긴것이 보인다. 여기서 위쪽에 _ptr 는 현재 버퍼의 상태를 나타낸다. 보면 주소가 c701로 되어 있는 것과 cnt가 4인 것을 확인 할 수 있다. 이것은 즉 getchar 함수가 콘솔로 부터 읽어 버퍼에 담아 둔 값중 가장 첫번 째 문자인 T를 반환 하였기 때문에 다음번 주소인 EST0a0a의 값들이 버퍼에 남아 있다. 또한 cnt는 현재 버퍼에 남아있는 값들이 4개가 있다는 것을 의미한다. E,S,T,\n

     

    추가적으로 다음 자료를 보자

    위의 자료는 표준입력함수를 통해 100이라는 값을 data 변수에 저장한 모습이다. 성공적으로 100이 저장 된 것을 볼 수 있다. 현재 그림은 변수에 할당된 값을 보여주는 그림이다. 그렇다면 버퍼에는 어떤식으로 값이 들어와 지는지 살펴보자

    다음과 같이 입력한 100이 문자 100 0a 0a 이렇게 버퍼에 담기는 것을 확인할수 있다.

    이는 scanf, gets, getchar 등 표준입력함수 중 버퍼를 사용하여 동작하는 함수는 사용자에게 입력값을 문자 or 문자열 로 받아서 사용자가 정의한 자료형의 형태로 의미있는 자료로 변환하여 값을 반환하며 반환한 값을 인자값으로 들어온 변수 or 배열에 저장한다는 것이다. 따라서 버퍼에 입력되는 값은 단순한 문자 or 문자열이며 표준입력함수가 의미있는 자료로 바꾸어 반환하여 변수 또는 배열에 저장한다.

     

    앞에서 설명한 입력 : scanf 와 gets 함수, 출력 : printf 함수를 사용하여 나이와 이름을 입력받아 한 행으로 출력하는 프로그램을 만들어 보자

    입력

    나이를 입력하시오 : 20

    이름을 입력하시오 : 철수

    출력

    당신의 나이는 20살이고 이름은 철수 입니다.

     

    * 자주하는 실수 *

    1. scanf 에서 정수를 입력할 때 인자 값은 주소를 넘겨준다 (변수명X)

     

    2. scanf 함수는 여러개의 형식 문자를 사용할 수 있으며 구분은 화이트 스페이스 문자를 통해 한다 추가적으로 형식이 다를 경우에는 그 자체로 구분이 가능

    ex )

    int a, b ;

    char ab ;

    "%d%d", a,b => 34 불가능 => 3 (화이트 스페이스) 4 가능

    "%d%c%d", a,ab,b => 10A20 가능

     

    3. 문자열 입력시 공백은 처리되지 않는다

    ex )

    char ls[10] = {0} ;

    scanf ("%s", ls) ;

    입력 : jong seok

    출력 : jong

    위와 같이 공백에 대해서는 처리하지 않는다. 따라서 문자배열을 2개 선언 or gets 함수를 호출하여 문자열 상수 처리의 방법이 존재한다.

     

    4. scanf 함수는 자체적으로 개행 문자를 버퍼에 남기기 때문에 다음 입력 함수 호출시 바로 개행 문자를 반환하는 문제가 있다.

    ex )

    위와 같이 코드를 작성시 scanf를 통해 정수 10까지는 받아와서 &age의 주소에 해당하는 메모리에 10을 저장했지만 다음 gets_s 함수를 호출과 동시에 해당 get_s 함수는 버퍼에 개행 문자가 남았기 때문에 개행문자를 입력이 완료 되었다고 처리하면서 바로 반환해 버린다. ( 사용자가 입력한 \n이 남아있음 ) 따라서 사용자는 따로 버퍼를 비우는 작업을 통해 정상적인 프로그램을 작성할 수 있다.

    위의 자료에는 안나오지만 구조체 포인터를 잡고 해당 주소를 따라가서 값을 확인해 보면 cnt 1이 남아있는 것이 확인 되며 따라서 \n이 버퍼에 남아있기 때문에 입력이 끝났다고 보고 바로 반환해버린다.

     

    " %*c " 는 문자하나를 입력 버퍼에서 읽어와서 바로 버리겠다는 의미이다.

    댓글

Designed by Tistory.