03 - 서식 입출력

유현수·2024년 1월 15일
post-thumbnail

printf 함수

printf 함수는 서식 문자열(format string) 기능을 수행하도록 만들어졌다.

printf(string, expr1, expr2,);

서식 문자열은 일반적으로 %로 시작하는 변환 규격(conversion specification)을 포함할 수 있다.

int i;
int j;
float x;
float y;

i = 10;
j = 20;
x = 43.2892f;
y = 5527.0f;

printf("i = %d, j = %d, x = %f, y = %f\n", i, j, x, y);

// i = 10, j = 20, x = 43.289200, y = 5527.000000

변환 규격

형식

변환 규격은 다음과 같은 형식을 갖는다.

  • %m.pX or %-m.pX

최소 범위 너비

m은 최소 범위 너비(minimum field width)를 의미한다. 출력할 글자의 최소 개수를 지정한다. 정수 상수를 사용한다.

printf("%4d", 123);
printf("%4d", 12345);
printf("%-4d", 123);

// 출력(스페이스를 ·로 표기)
// ·123
// 12345
// 123·

정확도와 변환 규격자

p는 정확도(precision)를 의미한다. 정확도는 X 변환 규격자(conversion spcifier)의 종류에 따라 다르게 정의된다. X는 값이 출력되기 전 어떤 방식으 ㅣ변환이 적용되어야 하는지를 결정한다. 가장 자주 사용되는 숫자의 변환 규격자는 다음과 같다.

  • d - 정수를 십진법 형식으로 보여준다. p는 최소 자리수를 의미한다. 만약 필요하다면 숫자가 시작하는 부분에 추가적으로 0을 추가해준다. 만약 p가 포함되지 않았다면 p의 값이 1이라고 가정한다. 다시 말해 %d%.1d는 같은 것이다.
  • e - 소수를 지수 형식(물리량을 나타낼 때 사용하는 방식)으로 보여준다. p는 출력할 소수점 이하 자리수를 결정한다. 기본값은 여섯자리이다. 만약 p의 값이 0이라면 소수점을 출력하지 않는다.
  • f - 소수를 지수 없이 고정 소수점 형식으로 보여준다. pe 규격자와 같은 의미를 갖는다.
  • g - 소수를 숫자의 크기에 따라 지수 형식 혹은 고정 소수점 형식으로 보여준다. p는 최대 유효 숫자 자리수를 의미한다. 이는 소수점 아래 자리수를 의미하는 것이 아니다. f 변환과는 달리 g 변환은 추가적인 0을 출력하지 않는다. 심지어 출력할 값이 소수점 이하 자리수가 없다면 g는 소수점 조차 출력하지 않는다.

g 규격자는 숫자 사이즈를 예측할 수 없거나 사이즈가 다양할 때 유용하다.

/* Prints int and float values in various formats */
#include <stdio.h>

int main(void)
{
  int i;
  float x;
  i = 40;
  x = 839.21f;

  printf("|%d|%5d|%-5d|%5.3d|\n", i, i, i, i);
  printf("|%10.3f|%10.3e|%-10g|\n", x, x, x);

  return 0;
}

// |40| 40|40 | 040|
// | 839.210| 8.392e+02|839.21 |

이스케이프 시퀀스

  • \a : 경보(종소리)
  • \b : 백스페이스
  • \n : 새 줄
  • \t : 수평탭
  • \\ : 특수문자 \
  • \" : 특수문자 "

확장 비트열은 printf의 서식 문자열 중에서 가장 먼저 실행된다. 또한 문자려은 여러개의 확장 비트열을 제한 없이 사용할 수 있다. 다음 예시에서는 여섯 개의 확장 비트열을 사용한다.

printf("Item\tUnit\tPurchase\n\tPrice\tDate\n");

// Item		Unit	Purchase
// 		Price	Date
// "Hello!"
// \

scanf 함수

scanf 함수는 다음과 같이 사용한다.

int i;
int j;
float x;
float y;
scanf("%d%d%f%f", &i, &j, &x, &y);

printf처럼 scanf도 변환 규격과 변수의 개수가 같은지 유의해야 한다. 또한 변수 앞에 &를 붙여 포인터를 생성할 수 있도록 해줘야 한다.

scanf의 작동 방식

scanf는 서식 문자열(format string)과 무관한 문자가 나오면 읽는 것을 멈춘다. 읽기가 완료되면 그 다음 서식 문자열을 처리한다.

숫자를 입력받을 때 scanf 함수는 공란 문자(white-space characters - 빈칸, 탭, 개행문자 등)을 무시한다. 다음 예시를 살펴보자.

scanf("%d%d%f%f", &i, &j, &x, &y);

이 프로그램에 다음 세 줄을 입력했다고 가정해보자.

1

-20 .3

-4.0e3

scanf 함수는 이를 세 줄이 아닌 하나의 문자열로 인식한다.

●●1¤-20●●●.3¤●●●-4.0e3¤

(여기서 ●는 빈 칸을, ¤은 개행문자를 의미한다.)

scanf 함수는 여기서 숫자를 읽어야 하므로 숫자를 찾는 도중에 발견되는 모든 공란문자를 무시한다. 그 결과 네 숫자를 정상적으로 읽을 수 있게 된다.

scanf가 현재 읽고 있는 서식 문자열에 속할 수 없는 문자를 읽게될 경우 해당 문자는 "뒤로 밀려나" 다음 아이템을 찾거나 다음 scan 호출을 기다릴 때까지 대기한다. 아래 예시를 통해 알아보자.

앞서 사용한 예시와 동일한 scanf 함수를 호출한다.

scanf("%d%d%f%f", &i, &j, &x, &y);

그리고 1-20.3-4.0e3¤를 입력하면 scanf 함수는 새로운 입력을 다음과 같이 처리한다.

  • 변환규격 %d : 공란문자가 아닌 첫 문자는 1이다. 정수는 1로 시작할 수 있으므로 scanf 함수는 그 다음 문자인 -를 읽는다. - 문자는 정수에 포함될 수 없으므로 scanf 함수는 1i에 저장하고 -를 뒤로 미룬다.
  • 변환규격 %d : scanf 함수는 이제 다시 - 문자를 읽고, 순서대로 2, 0, .을 읽는다. 정수는 소수점을 갖고 있지 않으므로 scanf은 -20j에 저장하고 . 문자를 뒤로 미룬다.
  • 변환규격 %f : scanf 함수는 ., 3, -를 읽는다. 고정소수는 숫자 이후에 - 기호가 올 수 없으므로 0.3x에 저장하고 - 문자는 뒤로 미룬다.
  • 변환규격 %f : 마지막으로 scanf 함수는 -, 4, ., 0, e, 3¤(개행문자)를 읽는다. 고정소수는 개행문자를 가질 수 없으므로 -4.0 × 10³을 y에 저장하고 개행문자를 뒤로 미룬다.

개행문자는 읽히지 않았으므로 다음 scanf 호출 때 사용될 것이다.

scanf 함수는 입력을 읽을 때 공란문자를 무시하기 때문에 서식 문자열 외의 문자를 거의 추가하지 않는다. 다음과 같이 scanf 함수를 호출하면 어떤 일이 벌어지는지 확인해보자.

scanf("%d, %d", &i, &j);

scanf은 우선 정수값을 찾을 것이고, 이는 i 변수에 저장된다. 그 다음엔 ,을 짝 지어줘야하기 때문에 다음 입력문자는 쉼표여야한다. 만약 다음 입력문자가 빈 칸이라면 거기서 j의 값은 읽지도 않은채로 scanf 함수는 종료된다.

scanf("%d\n", &i);

scanf는 공란문자를 무시하고 정수를 먼저 읽는다. 그리고 또다른 비공란문자가 나올 때까지 \n과 공란문자를 짝지어줄 것이다. 즉, 해당 서식 문자열은 사용자가 비공란문자를 입력할 때까지 scanf 함수를 끝내지 않고 기다릴 것이다.

profile
"Life isn't about finding yourself. Life is about creating yourself."

0개의 댓글