[C] 표준입출력함수

JOOYEUN SEO·2023년 8월 7일

C 언어

목록 보기
3/13
post-thumbnail

입력 : 자료를 컴퓨터 내부에 기억시킴
출력 : 컴퓨터 내부에 기억된 내용을 컴퓨터 외부로 나타냄
표준입출력함수는 라이브러리 <stdio.h>에 정의되어 있다.

1. 자료의 입출력

1-1. (출력)printf 함수

printf(print formatted) 함수로 프로그램의 실행 결과를 출력할 수 있다.

printf("A=%d, B=%c \n", a, b);

  • 큰 따옴표("") 안 : 출력 양식
  • A=, B= : 문자형 상수
  • %d, %c : 출력 양식 변환기호
  • \n : 출력 제어문자
  • a, b : 변수 1, 변수 2
  • 세미콜론(;) : 마침표처럼 문장의 끝을 알리는 기능 ❗️잊지 말고 붙이도록 습관 들이기

(1) 출력 양식 변환기호

양식 변환기호 퍼센트(%)는 자료의 입출력 양식을 저장하는 문자로, printf()와 scanf()에서 사용 가능하다.

%문자변환 양식
%d부호 있는 10진 정수로 변환하여 출력
%ld부호 있는 10진 long 정수로 변환하여 출력
%lld부호 있는 10진 long long 정수로 변환하여 출력
%u부호 없는 10진 정수로 변환하여 출력
%o부호 없는 8진 정수로 변환하여 출력
%x, %X부호 없는 16진 정수로 변환하여 출력
%f10진 부동소수점 형식으로 변환하여 출력
%lf10진 부동소수점 형식으로 변환하여 출력
%e, %E지수 형태로 출력
%gf으로 출력되나 숫자값이 너무 길면 e로 출력
(유효숫자만 출력함)
%c한 문자로 변환하여 출력
%s문자열로 변환하여 출력
%p포인터 주소값 출력

양식 변환기호가 아닌 '%' 자체를 출력하기 위해선 '%%' 로 입력해야 한다.


⌨️ 예제 1

// printf() 함수로 다양한 데이터 출력하기
#include <stdio.h>

int main() {
    // %d : 정수 출력
    printf("%d + %d = %d\n\n", 2, 3, 5);      //각 %마다 숫자 2, 3, 5,가 차례로 들어감

    // %f : 실수 출력(소수점 여섯째 자리까지)
    printf("%f\n", 3.14);
    
    // %g : 실수 또는 지수 형태로 출력
    printf("%g\n", 3.141592);                 // 실수 형태로 출력
    printf("%g\n\n", 8723984712.12245674657); // 자릿수가 길어서 지수 형태로 출력

    // %c : 문자 출력(한글, 한자 등 유니코드는 출력불가)
    printf("%c %c %c\n\n", 'a', 'b', 'c');

    // %s : 문자열(문자들의 열거) 출력(유니코드 가능)
    printf("%s\n", "안녕하세요");
}

🖥️ 실행 결과

2 + 3 = 5

3.140000

3.14159
8.72398e+09

a b c

안녕하세요

(2) 출력 양식의 편집

printf 함수로 자료를 출력할 때 %문자 다음에 양수, 음수를 써서 출력 폭이나 각 변수에 대한 출력 자릿수를 지정 가능하다.

⌨️ 예제 2

#include <stdio.h>

int main() {
    printf("|%d| \n", 123);     	// 출력 폭 : 숫자 길이만큼 자동 지정
    printf("|%5d| \n", 123);    	// 출력 폭 : 5자리, 오른쪽부터 채움
    printf("|%-5d| \n", 123);   	// 출력 폭 : 5자리, 왼쪽부터 채움
    printf("|%05d| \n", 123);		// 출력 폭 : 5자리, 오른쪽부터 채우고 공백은 0으로 채움
    printf("|%6.1f| \n", 123.45);	/* 출력 폭 : 6자리(소수점 포함),
                                      반올림하여 소수 첫째 자리까지 출력 */
    printf("|%07.2f| \n", 123.456);	/* 출력 폭 : 7자리(소수점 포함),
                                      반올림하여 소수 둘째 자리까지 출력 */
}

🖥️ 실행 결과

|123| 
|  123| 
|123  | 
|00123| 
| 123.5| 
|0123.46| 

1-2. 입력(scanf 함수)

키보드로부터 1개 이상의 자료를 입력받기 위해 scanf 함수를 사용한다. scanf 함수의 입력 양식에 %문자가 아닌 다른 문자는 포함시킬 수 없으며, 모든 변수 앞에는 주소를 의미하는 주소 연산자 &(앰퍼샌드)를 붙여야 한다. 다만 문자열, 배열명은 그 이름 자체가 주소의 의미를 갖고 있으므로 &를 생략한다. ❗️scanf() 쓸 땐 변수명 앞에 & 붙이는 것 잊지 않기
참조 : [C] 포인터

(1) 입력 양식 변환기호

%문자변환 양식
%d키보드를 통해 정수형을 입력받음
%ld키보드를 통해 long 정수형을 입력받음
%lld키보드를 통해 long long 정수형을 입력받음
%f키보드를 통해 실수형을 입력받음
%lf키보드를 통해 double 실수형을 입력받음
%c키보드를 통해 문자형을 입력받음
%s키보드를 통해 문자열을 입력받음

8진수 자료의 입력은 %o, 16진수 자료의 입력은 %x 를 사용한다.

(2) 자료의 입력

scanf() 함수가 실행되면 자료를 입력 후 엔터 키를 누르면 된다. 하나 이상의 자료를 입력할 때는 자료 사이를 화이트 스페이스로 분리를 해야만 컴퓨터가 각각 개별의 자료로 구분할 수 있다.

✏️ 화이트 스페이스
컴퓨터에서 공백을 표현하는 문자들을 의미한다. 구분문자로 사용 가능한 것들이다.

  • 공백문자 : space 키로 입력
  • 탭문자 : tap 키로 입력(문자값은 \t)
  • 새줄문자(newline) : enter 키로 입력(문자값은 \n)

⌨️ 예제 3

// 입력받은 두 정수의 합을 출력하는 프로그램
#include <stdio.h>

int main() {
    int a, b;     // 변수 2개 선언(값을 입력받기 때문에 초기화할 필요 없음)
    
    printf("첫 번째 숫자 : ");
    scanf("%d", &a);
    printf("두 번째 숫자 : ");
    scanf("%d", &b);
    
    printf("%d + %d = %d\n", a, b, a+b);
}

🖥️ 실행 결과

첫 번째 숫자 : 3  [Enter↵]
두 번째 숫자 : 20  [Enter↵]
3 + 20 = 2

⌨️ 예제 4

// 2개의 숫자를 공백으로 구분하여 입력
#include <stdio.h>

int main() {
    int num1, num2;
    
    printf("두 개의 숫자를 순서대로 입력하기 : ");	// num 1과 num2 사이를 스페이스로 구분
    scanf("%d%d", &num1, &num2);
    
    printf("첫번째 숫자 : %d\n", num1);
    printf("두번째 숫자 : %d\n", num2);
}

🖥️ 실행 결과

두 개의 숫자를 순서대로 입력하기 : 2 3  [Enter↵]
첫번째 숫자 : 2
두번째 숫자 : 3

🔍 %c와 관련된 공백 사용

scanf("%d    %d\n", &a, &b);
printf 함수에서는 이렇게 변환문자열 사이에 빈칸을 넣거나, 맨 끝에 줄바꿈을 하는 것이 일반적이지만,
scanf 함수에서는 필요가 없기 때문에 사용하지 않는 것이 더 추천된다.
❗️그러나 변환문자열 %c에서는 공백 사용이 중요한 역할을 한다

⌨️ 예제 5

// 2개의 문자를 공백으로 구분하여 함께 입력
#include <stdio.h>

int main() {
    char ch1, ch2;

    printf("두 개의 문자를 순서대로 입력하기 : ");
    scanf("%c%c", &ch1, &ch2);

    printf("첫번째 문자 : %c\n", ch1);
    printf("두번째 문자 : %c\n", ch2);
}

🖥️ 실행 결과

두 개의 문자를 순서대로 입력하기 : a b  [Enter↵]
첫번째 문자 : a
두번째 문자 :  

첫번째 문자 a는 출력됐지만, b는 출력되지 않았다. 왜냐하면 ch2에는 b가 아니라 a 다음에 입력했던 공백문자가 저장됐기 때문이다.
예제 4처럼 숫자 데이터를 입력할 때는 공백문자 등을 구분문자로 사용하여 자료들을 구분할 수 있지만, 문자를 입력할 때는 화이트 스페이스 또한 문자값을 가진 데이터로 취급된다.

🛠️ 코드 수정

#include <stdio.h>

int main() {
    char ch1, ch2;

    printf("두 개의 문자를 순서대로 입력하기 : ");
    scanf("%c %c", &ch1, &ch2);		// 두번째 %c 앞에 공백문자 함께 작성

    printf("첫번째 문자 : %c\n", ch1);
    printf("두번째 문자 : %c\n", ch2);
}

🖥️ 실행 결과

두 개의 문자를 순서대로 입력하기 : a b  [Enter↵]
첫번째 문자 : a
두번째 문자 : b 

⌨️ 예제 6

// 2개의 문자를 하나씩 따로 입력
#include <stdio.h>

int main() {
    char ch1, ch2;

    printf("첫번째 문자 입력 : ");
    scanf("%c", &ch1);
    printf("두번째 문자 입력 : ");
    scanf("%c", &ch2);

    printf("첫번째 문자 : %c\n", ch1);
    printf("두번째 문자 : %c\n", ch2);
}

🖥️ 실행 결과

첫번째 문자 입력 : a  [Enter↵]
두번째 문자 입력 : 첫번째 문자 : a
두번째 문자 : 

한편 두 문자를 하나씩 따로 입력해도 원하지 않은 출력값이 나오게 된다. 그 이유는 첫번째 문자 입력 후에 입력한 Enter 키가 버퍼에 남아있기 때문이다.
참조 : [C] 파일 입출력

키보드에서 입력하는 데이터는 바로 변수에 저장되지 않고 버퍼라고 하는 저장공간에 잠시 저장되었다가 입력이 되는 과정을 거치게 된다.

  • 과정1 : ch1을 입력받을 때, 키보드로 입력받은 a와 Enter 키의 아스키코드값인 \n이 함께 버퍼에 저장된다.
  • 과정2 : a만 ch1에 저장되고, \n은 그대로 남아있게 된다.
  • 과정3 : 그 다음 ch2을 입력받을 때 버퍼에 남아있던 \n을 바로 가져다가 ch2에 넣는다.

예제 5의 공백문자처럼 새줄문자 또한 하나의 문자로 인식되기 때문에 생기는 문제다.

🛠️ 코드 수정

#include <stdio.h>

int main() {
    char ch1, ch2;

    printf("첫번째 문자 : ");
    scanf("%c", &ch1);
    printf("두번째 문자 : ");
    scanf(" %c", &ch2);     // ch2의 입력문에서 %c 앞에 공백문자 함께 작성

    printf("첫번째 문자 : %c\n", ch1);
    printf("두번째 문자 : %c\n", ch2);
}

🖥️ 실행 결과

첫번째 문자 입력 : a  [Enter↵]
두번째 문자 입력 : b  [Enter↵]
첫번째 문자 : a
두번째 문자 : b

2. 문자 단위의 입출력

⌨️ 예제

// getchar 함수와 putchar 함수
#include <stdio.h>

int main() {
    char ch;            // getchar로 입력받은 문자를 저장할 변수(정수형이나 문자형)
    printf("문자 하나를 입력하세요 : ");

    ch = getchar();     // 문자 1개를 입력받아서 ch에 저장
    putchar(ch);        // ch에 저장된 문자 1개를 출력

    putchar('\n');      // escape 문자 출력(문자 자체를 쓸 땐 작은 따옴표 안에)
}

🖥️ 실행 결과

문자 하나를 입력하세요 : a  [Enter↵]
a

getchar 함수는 괄호 안에 인자를 지정하지 않으며, 문자 하나를 입력 후 엔터 키를 눌러서 자료를 입력한다.


3. 문자열 단위의 입출력

gets 함수는 엔터 키를 누르기 전까지의 문자열(공백 포함)을 입력받는다. 공백 문자를 기준으로 입력받는 scanf 함수와의 차이점이다. 엔터 키를 누르면 맨 끝에 null 문자('\0')가 입력되어 문자열의 끝을 명시한다.

그러나, gets 함수는 보안상 취약점이 있어 더 이상 사용할 수 없으며, 대안으로 쓰는 gets_s 함수는 컴파일러에 따라 지원되지 않을 수도 있다.
예제에서는 이를 대체할 수 있는 fgets 함수를 사용했다. 이 함수는 괄호 안에 세 개의 매개 변수가 필요하다.

  • 첫번째 : 문자열을 저장할 기억공간의 주소(char형 배열 또는 포인터 변수)
  • 두번째 : 문자열의 길이
  • 세번째 : 입력 스트림('stdin'을 사용하여 키보드에 입력된 자료를 읽게 함)

puts 함수는 문자열의 끝('\0' 문자)를 만나면 자동으로 '\n'으로 바꿔서 출력한다는 특징이 있어서, printf 함수처럼 개행문자 '\n'를 쓸 필요가 없다.

⌨️ 예제

// fgets 함수와 puts 함수
#include <stdio.h>

int main() {
    char str1[100];     // gets 함수로 입력받은 문자열을 저장할 변수(char형 배열이나 포인터 변수)

    fgets(str1, sizeof(str1), stdin);       // 문자열을 입력받아서 str에 저장
    puts(str1);                             // str에 저장된 문자열 출력

    char str2[] = "Computer Science";       // 배열 str2를 초기화
    puts(str2);                             // 자동으로 줄이 바뀌어 출력
}

🖥️ 실행 결과

Hello, World!  [Enter↵]
Hello, World! 

Computer Science

Hello, World! 이후에 2줄이 바뀌어 출력된 이유는 fgets 함수가 개행문자('\n')를 포함하여 입력받기 때문이다. 이미 지정한 문자열로 초기화된 배열을 출력할 때는 1줄만 바뀌는 것을 볼 수 있다.


4. 문자열로부터 입출력

scanf 함수가 콘솔(키보드)의 입력을 받는다면, sscanf 함수는 문자열로부터 입력받는다.
printf 함수가 콘솔(모니터)에 출력을 하는 함수라면, sprintf 함수는 문자열(버퍼)에 문자열을 출력한다.

⌨️ 예제

#include <stdio.h>

int main() {
    // sscanf 함수
    char str1[] = "123";
    int n1;

    sscanf(str1, "%d", &n1);    // (입력받을 문자열, "입력받을 자료형", 입력받은 값을 저장할 변수)
    printf("n1 : %d\n", n1);

    // sprintf 함수
    int n2 = 456;
    char str2[100];

    sprintf(str2, "%d", n2);    // (출력할 문자열, "출력할 자료형", 문자열에 출력할 값)
    printf("str2 : %s\n", str2);
}

🖥️ 실행 결과

n1 : 123
str2 : 456




▷ 김형근·곽덕훈·정재화, 『C프로그래밍』, 한국방송통신대학교출판문화원, 2020
▷ 서현우, 『뇌를 자극하는 C 프로그래밍』, 한빛미디어, 2005
▷ 두들낙서, “두들낙서의 C/C++ 강좌”, https://youtube.com/playlist?list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&si=s8RNpRcpJTi_Lz8M

0개의 댓글