Notes for C

scanf 함수

Sloth Coder 2022. 8. 11. 23:26

<scanf 함수>

  • 표준입력(stdin) 스트림으로부터 형식에 맞는 데이터를 읽어 온다.
  • scanf(형식 문자열, 데이터 저장 포인터)를 인수로 갖는다.
  • 형식에 맞는 데이터를 읽어 오는데 성공하면 읽어온 값의 개수를 integer형으로 반환한다. 만일 사용 가능한 입력이 있었으나, 해당 입력이 형식 문자열의 형식과 맞지 않았을 경우 0을 반환할 수 있다. 또한, 읽어보기도 전에 오류가 발생할 경우 -1을 반환할 수 있다.
  • C언어는 운영체제와 상관없이, 파일의 끝에 도달했을 떄 언제나 특별한 값(EOF, -1)을 반환하도록 돼 있다. EOF는 End Of File의 약자로, 파일의 끝을 표현하기 위해 -1로 정의된 상수이다(Windows에서는 Ctrl + Z 후 Enter, Linux나 Unix 에서는 Ctrl + D를 통해 EOF를 발생시킬 수 있다).

 

<scanf 함수의 작동 방식>

  • scanf는 입력이 들어올 때마다 값을 가져오는 것이 아니다. 예를 들면, a 1 2 b가 입력됐을 때 scanf는 각각의 값이 입력됐을 때마다 값을 가져오는 것이 아닌, 입력값들을 버퍼에 저장해 두었다가 입력이 끝났다고 판단되는 순간에 모두 가져와 형식 문자열에 있는 형식지정자의 수만큼 하나씩 읽게 된다. 입력이 끝났다고 판단하는 순간은 형식 문자열의 형식 지정자에 따라 다를 수 있다.
  • scanf는 형식 문자열에 놓인 문자의 순서대로 값을 읽는다(방향: 왼쪽 -> 오른쪽). ex) scanf("%c %d", &c_val, &int_val); %c먼저 처리 후 %d 처리.

 

<scanf 함수에서의 형식 지정자>

  • scanf의 형식 지정자는 "%* or [] or [^](sub-specifier)폭(width]길이(length)지정자(specifier)"와 같은 형식을 가질 수 있다.
  • *을 사용할 경우, 해당 형식지정자의 데이터타입과 맞는 값을 버퍼에서 읽고 버퍼에서 삭제 후 무시한다. 즉, %*d와 같이 사용하면 버퍼에서 만나는 integer형 데이터를 삭제하는 역할을 한다([] or [^] 와 함께 사용 가능하다). ex) scanf("%*d", &val); 과 같이 저장할 장소를 입력해 주어도 val에는 아무런 값도 입력되지 않는다.
  • []를 사용할 경우, []안에 있는 문자 이외의 문자가 올 때까지 입력을 받고, []안의 문자들은 문자(char)입력으로 처리한다. 즉, []를 사용할 경우 타입을 지정해주지 않아도 된다. - 를 이용해 범위를 지정해줄 수도 있다. ex) scanf("%[A-Za-z0-9]", &char_val);
  • []안에 없는 문자가 올 경우 해당 문자부터 그 뒷부분까지 버퍼에 남겨둔채로 함수를 종료한다. 
  • [^]를 사용할 경우, [^]안에 있는 문자들이 나올 때까지 입력을 받는다. 마찬가지로 타입을 지정해줄 필요가 없으며, - 를 이용해 범위를 지정해줄 수도 있다. ex) scanf("%[^a-c]", &str);
  • [^]안에 있는 문자들 중 하나를 만나면 해당 문자부터 그 뒷부분까지 버퍼에 남겨둔 채로 함수를 종료한다.
  • 폭(width) 부분은 stdin에서 읽어들일 최대 문자 수를 지정한다. ex) scanf("%2c", &val); 두 문자만 읽음.
  • 길이(length) 부분은 int, unsigned int, float형에 대해 입력받는 타입의 크기를 modify할 수 있다.
  • 지정자(specifier) 부분은 데이터를 입력받을 형식을 지정해 주어 어떤 값만을 읽어야 할지 지정한다.

 

- 형식 문자열(format string) 에서의 공백문자(whitespace character)와 일반 문자(non-whitespace character)

  • 형식 문자열에 위 형식에따른 문자열 이외에 공백 문자나 공백문자가 아닌 일부 문자(숫자, 알파벳, 일부 특수문자 등)이 들어갈 수 있다.
  • 공백문자(whitespace): 형식 문자열에 공백문자가 있는 경우, 다음 non-whitespace character를 만날 때까지 공백문자를 읽고 버퍼에서 삭제한다. 형식 문자열에 있는 하나의 공백문자만으로도 입력으로 들어오는 여러개의 공백문자를 모두 무시할 수 있다. 공백문자에는 띄어쓰기(space), 개행(newline), 탭(tab)이 포함된다.
int a = 0, b = 0;
scanf("%d %d", &a, &b);
//입력:1     2 or 1\n2 or 1\t2 모두 가능
scanf("%1d %1d", &a, &b);
//공백 문자의 경우, none(아무런 문자 없음)또한 무시하기때문에
//입력: 12 or 1 2 모두 가능하다.

 

  • 일반 문자(non-whitespace character): 형식 문자열에 non-whitespace character가 있는 경우, scanf가 읽은 문자가 해당 non-whitespace character와 일치하면 해당 문자를 버퍼에서 삭제한 후, 형식 문자열의 다음 형식에 따라 다음 문자를 읽는다. 일치하지 않을 경우 함수는 fail하고 나머지 문자들을 읽지 않은 상태로 버퍼에 남긴채 종료된다.
int a = 0, b = 0;
scanf("%d a %d", &a, &b); // 숫자 하나 입력 받은 후 a가 입력되면 무시, 다음 숫자 읽음
scanf("%d ab %d", &a, &b); //숫자 하나 입력 받은 후 ab가 입력되면 무시, 다음 숫자 읽음
scanf("%d a b %d", &a, &b); //숫자 하나 입력 받은 후 순서대로 a가 입력되면 무시, b가 입력되면 무시, 다음 숫자 읽음
//위 경우 모두 중간에 있는 non-whitespace character를 입력하지 않고 그 다음 %d를 위한 숫자를 입력하면 함수가 종료된다.
//scanf는 형식 문자열에 쓰여진 순서대로 버퍼의 문자를 읽는다는 것을 알 수 있다.

 

 

- 지정자(specifier)의 종류와 특징

specifier type description
i Signed integer 선행 수가 0이면 8진수, 0x이면 16진수, 둘 다 아니면 10진수 정수로 입력을 읽는다.
d 10진수(Decimal) signed integer 10진수 정수로 입력을 읽는다.
o 8진수(Octal) signed integer 선행 수와 상관없이 입력을 8진수 정수로 읽는다.
x X 16진수(Hexadecimal) integer 선행 수와 상관없이 입력을 16진수 정수로 읽는다. x와 X의 차이는 없다.
u 10진수(Decimal) unsigned integer 10진수 양의 정수로 입력을 읽는다.
f e E a 4바이트크기의 실수(Floating point number) 실수를 입력 형태에 따라 일반적인 소수점 표기법 or 지수 표기법(e)을 이용해 입력을 읽는다. 선행 수가 0x 또는 0X일 경우 16진수 소수로 읽는다.
c 문자(Character) 문자를 읽는다. 만일 폭(width)이 1보다 크게 정해져 있을 경우 해당 폭만큼 문자를 읽고 배열과같은 연속된 저장소에 읽은 순서대로 저장한다. 이 경우, 끝에 NULL문자는 붙지 않는다.
s 연속된 문자(String of characters)  일반 문자(non-whitespace character)들을 공백문자(whitespace character)를 만날 때까지 읽는다. 문자열의 끝을 표시하기 위해 맨 마지막에 NULL문자가 자동으로 붙는다.
p 포인터 주소(Pointer adress) 주솟값을 읽어와 포인터 변수에 저장한다.
n 4바이트 크기의 정수(Integer) scanf함수가 읽은 문자의 수를 저장한다. 단, %n은 scanf함수가 읽은 문자의 수를 카운팅할뿐, 버퍼에서 문자를 읽어오는 것이 아니기때문에 %n을 사용해도 scanf의 반환 값에는 카운팅되지 않는다.

**숫자와 문자열 지정자(specifier)들은 정규식을 사용하지 않는 한 공백문자를 무시하고 숫자 or 문자열만을 입력으로 받는 반면에, %c는 공백문자또한 입력으로 간주한다. 따라서 %c를 사용할 때는 항상 버퍼에 남아있는 공백문자에 주의해야 한다. 버퍼에 남아있는 공백문자를 해결하기 위한 방법에는 getchar()등의 함수의 사용, 선행하는 scanf의 형식문자열의 끝에 공백문자를 붙이는 방법, %s사용 등을 고려해볼 수 있다.

**%n을 사용할 때 %n은 scanf가 저장한 문자수가 아니라 읽은 문자수를 저장한다는 것에 주의하자. 예를 들면, %d로 숫자를 읽는데 1234k가 입력됐을 경우, %n의 값은 4가 아니라 5가 저장된다. k까지 읽고 숫자 형태가 아니기때문에 함수가 종료됐을 것이기 때문이다. 또한, %n은 말그대로 읽은 '문자의 수'를 저장하므로, 실수에서의 '.', 공백문자등도 카운트 된다. 

 

 

- 길이 한정자의 종류와 지정자(specifier)와의 결합후 대응되는 입력타입

length specifiers
  d   i u  o  x f e g a c s [] [^] p n
hh signed char unsigned int       signed char
h short int unsigned short int       short int
l long int unsigned long int double wchar_t   long int
ll long long int unsigned long long int       long long int
j intmax_t uintmax_t       intmax_t
z size_t size_t       size_t
t ptrdiff_t ptrdiff_t       ptrdiff_t
L     long double      

**wchar_t: 와이드 문자(wide character)를 저장하기 위한 자료형. 영문 알파벳은 1바이트로 표현하지만 유니코드는 2바이트 이상으로 표현하기 때문에 wchar_t에 저장해야 한다. wchar_t문자와 문자열은 따옴표 앞에 L을 붙여서 표현. 단, wchar_t자료형을 저장하기 위해선 wscaf함수를 사용해야 함.

**intmax_t: 시스템에서 가장 큰 크기의 정수형 변수(maximum-width signed integer type).

**uintmax_t: 시스템에서 가장 큰 크기의 정수형 변수(maximum-width unsigned integer type)

**size_t: C언어에서 크기를 의미하는 정수 자료형(unsigned). 32비트 운영체제에서는 부호 없는 32비트(4바이트) 정수(unsigned int), 64비트 운영체제에서는 부호 없는 64비트(8바이트) 정수(unsigned long long)로 고정된 사이즈를 가진다.

**ptrdiff_t: 두 포인터의 뺄셈 결과를 저장하는 변수(signed). 

 

 

 

 

*참고자료

https://cplusplus.com/reference/cstdio/scanf/

 

scanf - C++ Reference

function <cstdio> scanf int scanf ( const char * format, ... ); Read formatted data from stdin Reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments. The additional arguments should p

cplusplus.com

https://modoocode.com/36