85.19 문자열 입출력 함수 사용하기

stdio.h 헤더 파일에는 scanf, printf, fgets, fputs 함수 이외에도 문자열 입출력 함수 gets_s, puts, fgetc, putc가 있습니다.

  • gets_s(버퍼, 버퍼크기);
    • char *gets_s(char *_Buffer, rsize_t _Size);
    • 공하면 입력된 문자열을 반환, 실패하면 NULL을 반환
  • puts(문자열)
    • int puts(char const *_Buffer);
    • 성공하면 음수가 아닌 값을 반환, 실패하면 EOF(-1)를 반환

gets_s_puts.c

#include <stdio.h>

int main()
{
    char buffer[100];

    gets_s(buffer, sizeof(buffer));    // 표준 입력에서 문자열을 입력받음
                                       // Visual Studio 2022

    puts(buffer);    // 문자열을 화면(표준 출력)에 출력

    return 0;
}

소스를 컴파일하여 실행한 뒤 Hello를 입력하고 엔터 키를 누르세요.

실행 결과

Hello (입력)
Hello

gets_s 함수는 표준 입력에서 문자열을 입력받아서 배열이나 포인터에 저장합니다(엔터 키를 누르면 입력이 끝나며 개행 문자 \n은 저장되지 않음). 첫 번째 인수에는 버퍼로 사용할 배열이나 포인터를 넣어주고, 두 번째 인수에는 버퍼의 크기(배열의 크기, 포인터에 할당받은 메모리의 크기)를 넣어주면 됩니다.

puts 함수는 배열(포인터)에 들어있는 문자열을 화면에 출력합니다.

여기서 gets_s 함수를 사용하는 이유는 gets 함수가 보안에 취약했기 때문입니다. 즉, 다음과 같이 gets 함수는 버퍼만 넣어주면 끝이라서 버퍼의 크기를 넘어서는 입력도 받을 수가 있었습니다. 그러다 보니 지속적으로 버퍼 오버플로우(buffer overflow) 공격에 시달렸고 결국 C99 표준에서는 gets 함수가 표준 라이브러리에서 삭제되어 버립니다.

char buffer[100];

gets(buffer);    // gets 함수는 버퍼만 넣어줌

C11 표준(C99 이후에 나온 최신 C 언어 표준)부터는 버퍼의 크기를 설정하는 gets_s 함수가 추가되었고 Visual Studio 2022에서도 gets_s 함수를 제공합니다.

GCC, Clang에서는 아직 gets 함수를 사용할 수는 있지만 위험하다는 경고를 출력하고 있으므로 가급적이면 사용하지 않는 것이 좋습니다.

gets.c: In function 'main':
gets.c:6:5: warning: implicit declaration of function 'gets' [-Wimplicit-function-declaration]
     gets(s1);
     ^
/tmp/cc91hpv3.o: In function `main':
gets.c:(.text+0x24): warning: the `gets' function is dangerous and should not be used.

아직 GCC와 Clang은 gets_s 함수를 제공하지 않습니다(2016년 4월 기준). 문자열을 입력받을 때는 scanf 함수나 뒤에서 설명할 fgets 함수 사용을 권장합니다.

fgetc, fputc 함수는 파일에 문자를 읽고 씁니다.

  • fgetc(파일포인터);
    • nt fgetc(FILE *_Stream);
    • 성공하면 읽은 문자를 반환, 실패하면 EOF(-1)를 반환
  • fputc(문자, 파일포인터);
    • int fputc(int _Character, FILE *_Stream);
    • 성공하면 쓴 문자를 반환, 실패하면 EOF(-1)를 반환

fgetc_fputc.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char buffer[100] = { 0, };
    int c1 = 0;

    FILE *fp = fopen("hello.txt", "w+");    // 파일을 읽기/쓰기 모드로 열기

    for (int i = 0; i < 10; i++)    // 10번 반복하면서
        fputc('a', fp);             // 파일에 문자 a를 쓰기

    rewind(fp);    // 파일 포인터를 파일의 처음으로 이동시킴
    while (1)
    {
        c1 = fgetc(fp);    // 파일에서 문자를 읽음
        if (feof(fp))      // 파일 포인터가 파일의 끝에 있으면
            break;         // 반복을 끝냄

        putchar(c1);        // 문자 출력
    }

    fclose(fp);

    return 0;
}

실행 결과

aaaaaaaaaa

fputc 함수는 파일에 문자 하나를 쓰고, 파일 포인터를 순방향으로 이동시킵니다. 그리고 fgetc 함수는 파일에서 문자 하나를 읽어서 반환하고, 파일 포인터를 순방향으로 이동시킵니다. 여기서는 무한 루프로 반복하면서 fgetc로 문자를 계속 읽다가 feof로 파일의 끝을 확인한 뒤 반복을 종료하도록 만들었습니다.

물론 fputc, fgetc 함수도 stdin, stdout, stderr를 사용할 수 있습니다.