성엽이
KKIMSSI
성엽이
전체 방문자
오늘
어제
  • 분류 전체보기 (454)
    • :) (2)
    • C프로그래밍이론 (9)
    • C++프로그래밍 (64)
      • STL (1)
    • C# (2)
    • Visual studio 10.0 (9)
    • AT91SAM7S256 (21)
    • 논리회로 (14)
    • AVR2560 (11)
    • TCPIP (16)
    • NetWork (4)
      • Ubuntu Linux (2)
    • Assembly (21)
    • UNIX 프로그래밍 (6)
    • RFID 분석 (1)
    • Win32 API (7)
    • Cortex-M3 (4)
    • Unity (91)
    • Flutter (9)
    • OwnProject (11)
      • It's mine (5)
      • 마인드스톰 실습 (1)
      • 보고서 자료 (2)
      • RPi B+ (2)
    • ETC (25)
      • 상식 (3)
    • MFC (40)
    • PostgeSQL (18)
    • 영상제어 (6)
      • VFW_영상처리 (1)
    • Python (0)
    • Java (30)
      • SpringBoot (2)
      • Javascript (1)
      • JSP (13)
      • Spring (8)
    • Oracle (4)
      • SQL (3)
    • HTML (6)
      • Thymeleaf (1)
      • CSS (1)
      • Bootstrap (3)
    • IDE (1)
      • VS Code (1)
    • Android (2)
    • Privacy Policy (0)
    • MYSQL (2)
      • MariaDB (2)
    • AWS (5)
    • 개인공부 (0)

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록
  • 관리자
  • 글쓰기

공지사항

인기 글

태그

  • ARM Reverse Engineering
  • Boot Code 분석
  • MFC
  • WINAPI
  • 문자열 나누기

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
성엽이

KKIMSSI

C프로그래밍이론

2013.04.23_[C언어]표준입력함수_설명

2013. 4. 23. 17:42

C언어는 기본적으로 자주 사용되는 함수들을 미리 정의해 놓았다.

표준 입력 함수들 역시 미리 정의되어 있는 함수들 중 일부이다.

 

여기서 알아볼 함수는 scanf(), gets(), getchar(), sscanf() 이다. (모두 stdio.h 에 선언되어 있다.)

gets() 와 getchar() 는 scanf() 로서 모두 처리해 줄 수 있다. 하지만 gets() 나 getchar() 를 사용하는 경우도 있다.

그 이유는 scanf() 보다 gets() 나 getchar() 가 안정적인 입력이 가능하기 때문이다. scanf() 는 상당히 불안정한 함수이다.

 

sscanf() 는 알아두면 상당히 유용한 함수이다. 문자열에서 원하는 자료형으로 추출이 가능한 엄청난 함수이다.

 

[[ char *gets( char * ) ]]

gets()는 문자열을 키보드로부터 입력받는 함수이다. <Enter>의 입력 전까지의 모든 문자를 입력으로 받아들인다.

입력 문자의 최대치는 통상적으로 256이다. 이건 컴파일러마다 다를 수 있으므로 참고적으로만 알아두기 바란다.

 

gets() 의 특징은 라인 입력이라는 점이고, 마지막에 눌러지는 <Enter>는 입력으로 받아들이지 않고 무시한다.

 

[ 예제 1 ]

#include <stdio.h>

void main()

{

char str[256];

  gets ( str );

  puts ( str );

}

 

[ 예제 1 의 실행 결과 ]

ABCDE<Enter>                        // 입력부 : gets() // 사용자가 입력하는 부분

ABCDE                                   // 출력부 : puts() // 입력된 내용이 출력된다.

 

ABCDE<Enter>를 입력하게 되면 str[0] = 'A'; str[1] = 'B'; str[2] = 'C'; str[3] = 'D'; str[4] = 'E'; str[5] = 0; 이 입력된다.

 

[[ int getchar() ]]

getchar()는 키보드 버퍼에서 한개의 문자를 가져온다. 키보드 버퍼가 비어있다면 사용자의 키보드 입력을 기다린다.

이때는 1개의 문자를 입력한다고 해서 getchar() 함수가 종료되지 않으며, <Enter> 입력이 있을때까지 키보드 입력을 받는다.

리턴값이 int 이지만 통상적으로 char 범위내에서 리턴이 이뤄진다. 값을 받을 변수는 int 여도 되고 char 여도 상관없다.

 

[ 예제 2-1 ]

#include <stdio.h>

void main()

{

char ch;

  ch = getchar();

  putchar ( ch );

  ch = getchar();

  putchar ( ch );

}

 

 

[ 예제 2-1 의 실행 결과 #1 ]

abc<Enter>                    // 입력부 // <Enter>가 입력되어야 getchar()문을 탈출할 수 있다.

ab                                 // 출력부 // putchar() 에 의해 2개의 문자가 출력된다.

 

첫번째 getchar() 에서는 키보드 버퍼가 비어있으므로 키보드 입력 대기상태가 되어 사용자의 입력을 기다리게 된다.

이때 abc<Enter> 가 입력되면 키보드 버퍼에는 a, b, c, 엔터 까지 4개의 문자가 저장되고 첫번째 getchar() 는 첫번째 a 를 가져온다.

두번째 getchar() 에서는 이미 키보드 버퍼에 b, c, 엔터 3개의 문자가 저장되어 있으므로 입력 대기 없이 가장 앞의 b 를 가져온다.

 

입력된 문자는 엔터를 포함해 4개인데 getchar()로 2개의 문자만을 가져왔으므로 키보드 버퍼에는 c 와 엔터가 남은 상태로 종료된다.

이때 뒤에 scanf() 나 gets() 가 있다면 c 와 엔터가 그곳의 입력으로 받아들여지는 불상사가 발생하게 된다. 이게 바로 버그가 된다.

뭐 이게 항상 버그는 아니다. 프로그래머의 의도가 그런 것일수도 있기 때문이다. 하지만 대부분은 버그가 되고, 보통 찾기도 어렵다.

getchar()는 동작 형태를 정확히 알고 사용하는 것이 중요하다. 이같은 점을 잘 알지 못한다면 예기치 못한 버그 때문에 고생하게 된다.

 

[ 예제 2-1 의 실행 결과 #2 ]

a<Enter>                    // 입력부 // <Enter>가 입력되어야 getchar()문을 탈출할 수 있다.

a<Enter>                    // 출력부 // getchar()는 gets()와 다르게 엔터도 입력으로 받아들인다.

 

[ 예제 2-2 ]

#include <stdio.h>

void main()

{

char ch;

  ch = getchar();

  fflush( stdin );

  printf ( "%c\n", ch );

 

  ch = getchar();

  fflush( stdin );

  printf ( "%c\n", ch );

}

 

[ 예제 2-2 의 실행 결과 ]

abc<Enter>                         // 입력부

a                                        // 출력부

defg<Enter>                        // 입력부

d                                        // 출력부

 

fflush( stdin ); 은 stdin 을 비워주는 작업을 한다. stdin 은 표준 입력 장치를 가르키는데 통상적으로 키보드 버퍼를 가르킨다.

즉, 첫번째 getchar() 에서 a, b, c, 엔터 를 입력받아 a 를 가져오고, 남은 b, c, 엔터 는 fflush() 에 의해 제거되는 것이다.

그러므로 두번째 getchar() 에서 키보드 버퍼가 비워져있으므로 또 입력 대기 상태가 되어 입력을 다시 받게 되는 것이다.

 

[[ int scanf( const char *, ... ) ]]

리턴값은 정상적으로 입력이 진행된 포멧의 갯수이다. 사실 잘 모르기 때문에 거의 사용되지는 않는데 리턴값을 잘 이용하면

입력 오류에 대한 예외 처리를 모두 수행할 수 있다. 수치 입력에 대해서 문자를 입력했을 경우 등을 체크할 수 있는 것이다. 

 

scanf() 는 실질적으로 잘못된 입력에 대한 기본적인 예외처리가 불가능한 함수이다.

프로그래머도 잘 짜야하지만 사용자 역시 입력 형식에 맞게 제대로 입력을 주어야만 원하는 실행이 가능한 것이 scanf() 이다.

 

scanf() 는 printf() 와 사용법이 비슷한데.. 한가지 다른 점은.. scanf() 는 함수 내에서 주어진 변수의 값을 변경하여야 하므로..

인수는 모두 주소값으로 전달되어야한다.

 

설명보다는 그냥 예제로..

 

[ 예제 3-1 ]

#include <stdio.h>

void main()

{

char a, b[200];

int c; float d;

int i, j, k, l;

 

  i = scanf ( "%c", &a );

  j = scanf ( "%s", &b[0] );  // b 자체가 주소이므로.. scanf ( "%s", b ); 로 사용해도 무방하다.

  k = scanf ( "%d", &c );

  l = scanf ( "%f", &d );

  printf ( "%c %s %d %f\n", a, b, c, d );

  printf ( "%d %d %d %d\n", i, j, k, l );

}

 

[[[[ 주의할 점 ]]]]

b 는 배열이기 때문에 &b == b == &b[0] 이다. 따라서 scanf( "%s", &b ); 로 해도 동일한 결과를 얻을 수 있다.

하지만 b 가 포인터일 경우에는 달라진다. char s[200]; char *b = str; 일때.. &b != b.. b == &b[0] 가 되므로 주의해야한다.

 

위 [예제 3-1]을 제대로 수행하기 위해서는 입력을 정확하게 해 주어야한다.

 

[ 예제 3-1 의 실행 결과 #1 ]

A<Enter>                          // 입력부

ABC<Enter>                     // 입력부

123<Enter>                       // 입력부

1.5<Enter>                       // 입력부

A ABC 123 1.500000           // 출력부

1 1 1 1                             // 출력부

 

여기서 중요한 점은 이렇게 정상적으로 입력하였어도 키보드 버퍼에는 엔터 문자(0x0A) 1개가 남아있게 된다.

확인하는 방법은 [예제 3-2] 를 실행해보면 된다.

 

[ 예제 3-1 의 실행 결과 #2 ]

AB<Enter>                                            // 입력부

ABC<Enter>                                             // 입력부

A B -858993460 -107374176.000000            // 출력부 // 입력이 잘못되면 완전히 이상한 결과가 초래된다.

1 1 0 0                                                 // 출력부 // c 와 d 의 입력이 정상적이지 않음을 알 수 있다.

 

[ 예제 3-2 ]

#include <stdio.h>

void main()

{

char a, b[200];

int c; float d;

int i, j, k, l; 

  i = scanf ( "%c", &a );

  j = scanf ( "%s", &b[0] );

  k = scanf ( "%d", &c );

  l = scanf ( "%f", &d );

  printf ( "%c %s %d %f\n", a, b, c, d );

  printf ( "%d %d %d %d\n", i, j, k, l );

 

  c = getchar();

  printf ( "%d\n", c );

}

 

[ 예제 3-2 의 실행 결과 ]

A<Enter>                          // 입력부

ABC<Enter>                     // 입력부

123<Enter>                       // 입력부

1.5<Enter>                       // 입력부

A ABC 123 1.500000           // 출력부

1 1 1 1                             // 출력부

10                                   // 출력부  // getchar() 에 의해 사용자 입력을 대기해야 하지만 버퍼에 0x0A 가 있기때문에 그냥 넘어간다.

 

[ 예제 3-3 ]

#include <stdio.h>

void main()

{

char a, b[200];

int c; float d;

 

  scanf ( "%c", &a ); fflush(stdin);

  scanf ( "%s", &b[0] ); fflush(stdin);

  scanf ( "%d", &c ); fflush(stdin);

  scanf ( "%f", &d ); fflush(stdin);

  printf ( "%c %s %d %f\n", a, b, c, d );

}

 

[[ int sscanf( const char *, const char *, ... ) ]]

리턴값은 정상적으로 입력이 진행된 포멧의 갯수이다. 입력 오류나 문자수 부족 등 예외 처리를 위해서는 꼭 필요한 값이다.

 

scanf() 의 기능과 비슷한데.. 다만 입력을 키보드가 아닌 char * 에서 받아온다는게 다른점이다. 그냥 예제로 보도록 하자.

 

[ 예제 4-1 ]

#include <stdio.h>

void main()

{

char a, b[200];

int c; float d;

int i;

  i = sscanf ( "A ABC 123 1.5", "%c %s %d %f", &a, &b[0], &c, &d );

  printf ( "%d %c %s %d %f\n", i, a, b, c, d );

}

 

[ 예제 4-1 의 실행 결과 ]

4 A ABC 123 1.500000

 

[ 예제 4-2 ]

#include <stdio.h>

void main()

{

char a, b[200];

int c; float d;

int i;

  i = sscanf ( "AB ABC 123 1.5", "%c %s %d %f", &a, &b[0], &c, &d );

  printf ( "%d %c %s %d %f\n", i, a, b, c, d );

}

 

[ 예제 4-2 의 실행 결과 ]

2 A B -858993460 -107374176.000000

 

sscanf() 도 scanf() 와 동일하게 입력 오류를 제대로 걸러내지 못하므로 항상 주의가 필요하다.

sscanf() 의 용도는 여러가지가 있는데 사용자 입력이 있는 프로그램을 테스트할때 계속해서 같은 입력을 주어야하는 경우 유용하다.

[출처] [C언어] 표준 입력 함수 ( scanf, getchar, gets, sscanf )|작성자 루딘

저작자표시 (새창열림)

'C프로그래밍이론' 카테고리의 다른 글

2013.09.30 [C 언어 _ 스트림]  (0) 2013.09.30
2013.03.26_컴파일시깨알팁  (0) 2013.03.26
2013.03.26_헤더파일쓰는이유  (0) 2013.03.26
2013.03.26_제일위에 입력되지 않은 함수가 쓰일수있는 이유(ex: printf() )  (0) 2013.03.26
C교재  (0) 2013.03.12
    'C프로그래밍이론' 카테고리의 다른 글
    • 2013.09.30 [C 언어 _ 스트림]
    • 2013.03.26_컴파일시깨알팁
    • 2013.03.26_헤더파일쓰는이유
    • 2013.03.26_제일위에 입력되지 않은 함수가 쓰일수있는 이유(ex: printf() )
    성엽이
    성엽이

    티스토리툴바