입력 출력 스트림


데이터의 입력과 출력은 프로그램의 흐름을 뜻하는 것이다. 입력장치는 키보드 혹은 파일 등이 될 수 있고, 출력장치는 모니터 혹은 파일등이 될 수 있다.

이때 , 데이터의 이동수단이 되는것이 스트림이다. 입력장치와 프로그램 사이에는 입력스트림이, 출력장치와 프로그램 사이에는 출력스트림이 존재한다.

( 스트림은 운영체제에서 제공하는 소프트웨어로 구현되어있는 가상의 다리이다 ) 


스트림의 생성과 소멸


콘솔 ( 일반적으로 키보드와 모니터 ) 입출력과 파일 입출력 사이에는 차이점이있다. 파일과의 연결을 위한 스트림의 생성은 직접 요구해야하지만 , 콘솔과의 연결을 위한 스트림의 생성은 요구할 필요가 없다. ( 콘솔 입출력을 위한 스트림은 자동으로 생성된다 )


콘솔 입출력을 위한 입력 스트림과 출력 스트림은 프로그램이 실행되면 자동으로 생성되고, 프로그램 종료시 자동으로 소멸되는 스트림이다.

이 둘은 표준스트림 ( standard stream ) 이다. 그리고 표준스트림에는 에러 스트림도 존재한다.


stdin : 표준 입력스트림  // 키보드 대상으로 입력

stdout : 표준 출력 스트림 // 모니터 대상으로 출력

stderr  : 표준 에러 스트림 // 모니터 대상으로 출력


문자 출력 함수 : putchar , fputc


#include <stdio.h>

int putchar( int c );

int fputc ( int c , FILE * stream ); // 함수호출 성공시 문자정보가 , 함수호출 실패시 EOF가 반환되는데, EOF 값이 int형 이기때문에 반환형식이 int이고, 그에따라 인자도 int로 받는것이다.


putchar 함수는 인자로 전달된 문자정보를 stdout ( 표준출력스트림 ) 으로 전송하는 함수이다 . fputc는 출력 스트림을 지정할 수 있다. ( stdout을 스트림으로 지정하면 putchar과 같은 함수가 된다 ) fputc 를 이용하면 파일로 문자를 출력할 수 있다.


문자 입력 함수 : getchar , fgetc


#include <stdio.h>

int getchar( void ) ; 

int fgetc ( FILE * stream ); // 파일의 끝에 도달하거나 함수호출실패시 EOF 반환


getchar 함수는 stdin ( 표준입력스트림) 으로부터 하나의 문자를 입력받아서 반환하는 함수이다. fgetc는 입력 스트림을 지정할 수 있다. ( stdin 을 승트림으로 지정하면 getchar과 같은 함수가 된다 ) fgetc를 이용하면 파일에서 문자를 입력받을 수 있다.


EOF


EOF는 End OF File 의 약자로서 , 파일의 끝을 표현하기위해서 정의해놓은 상수이며 , 그 값은 -1이다 ( 이에따라 putchar , fputc , getchar , fgetc 의 반환형은 int 형이다 ) EOF가 반환되는상황은 이하 둘중 하나이다.


함수 호출의 실패

windows에서 CTRL +Z 키 혹은 Linux 에서 CTRL +D 키가 입력되는 경우


문자단위 입출력 함수의 존재 이유


printf함수 와 scanf함수가 존재함에도 불구하고 , 문자단위 입출력 함수를 정의해놓은 이유는 printf 와 scanf 는 서식지정을 통해 새로운 입출력의 형태를 구성하는 함수이며 , 이렇듯 화려한 기능을 제공하는 함수는 사용하는 메모리공간도 크고 , 연산의 양도 많아 상대적으로 속도가 느리고 , 별도의 서식지정을 해야하니 문장을 구성하는것도 번거로운 편이다 . 다라서 단순히 문자하나를 입출력하는 것이 목적이라면 문자 입출력함수를 이용하는것이 효율적이다.



문자열 출력함수 : puts , fputs


#include < stdio.h >

int puts ( const char * s ); 

int fputs ( const char * s , FILE * stream );// 성공시 음수가 아닌값을, 실패시 EOF 반환


puts 함수는 출력의 대상이 stdout 으로 정해져있지만 fputs 함수는 출력의 대상을 지정할 수 있다. puts 함수가 호출되면 문자열 출력후 자동으로 개행이 이루어지지만 , fputs 함수가 호출되면 문자열 출력후 자동으로 개행이 이뤄지지 않는다.


문자열 입력함수 : gets , fgets


#include < stdio.h>

char * gets ( char * s );

char * fgets ( char * s , int n , FILE * stream ); // 파일의 끝에 도달하거나 함수호출 실패시 NULL 포인터 반환


int main (void)

{

char str[7];

gets(str); 

}

이렇게 선언시 str 에 길이가 7이넘어가는 문자열이 입력되면 메모리공간을 침범하여 에러가 발생할 수 있으니 , fgets 함수를 호출하는편이 좋다.


int main (void)

{

char str[7];

fgets(str,sizeof(str),stdin); // stdin으로부터 문자를 입력받아서 str에 저장

}


이때, 문자열은 널문자가 반드시 들어가야하기 때문에 , 길이가 7이상의 문자열이 입력되면( 1234567 ) 6까지만 입력되고 마지막 배열은 널문자로 채워지게된다. 그리고 입력되지않은 나머지 문자열은 입력버퍼에 남게된다

fgets 함수는 \n을 만날때까지 문자열을 읽어들이는데 \n을 제외시키지 않고 문자열의 일부로 받아들인다. fgets 함수는 \n을 만날때까지 문자열을 읽어들이기때문에 공백 (스페이스바) 이 있는 문자열도 입력받을 수 있다.


표준 입출력과 버퍼


printf , scanf , fputc , fgetc 등을 가리켜 표준 입출력함수라고 하는데 , 이 표준입출력함수를 통해서 데이터를 입출력하는경우, 해당 데이터들은 운영체제가 제공하는 메모리버퍼를 중간에 통과하게된다. ( 메모리버퍼는 데이터를 임시로 저장하는 메모리 공간이다 )

예를들어 , 키보드를 통해 입력되는 데이터는 입력버퍼에 저장된 후 프로그램에 읽혀진다.  //fgets함수를 이용해서 문자열 데이터를 입력할때 입력버퍼로 데이터가 이동하는 순간은 \n가 입력되는 순간이다


버퍼링을 하는 이유


데이터 버퍼링의 가장 큰 이유는 데이터 전송의 효율성과 관련이있다 . 버퍼링 없이 키보드가 눌릴때마다 눌린문자의 정보를 목적지로 바로 이동시키는 것보다 중간에 메모리버퍼를 둬서 데이터를 한데 묶어서 이동시키는것이 보다 효율적이고 빠르다.


출력버퍼를 비우는 fflush 함수


출력버퍼가 비워진다는것은 출력버퍼에 저장된 데이터가 버퍼를 떠나서 목적지로 이동됨을 뜻한다. 출력버퍼가 비워지는 시점은 시스템에따라 그리고 버퍼의 성격에따라 달라져 출력버퍼가 비워지는 시점이 동일하지 않기때문에 이함수를 알아둘 필요가 있다.


#include < stdio.h >

int fflush( FILE * stream ); // 함수 호출 성공시 0 , 실패시 EOF 반환


fflush(stdout) // 표준출력버퍼를 비워라!


입력버퍼를 비우는 방법


입력버퍼의 비워짐은 데이터의 소멸을 의미한다. C언어의 표준에서는 입력버퍼를 비우는 함수를 따로 정의해두지 않았기때문에 따로함수를 정의해야한다


void ClearLineFromReadBuffer( void )

{

while(getchar() != '\n'); // getchar()로 입력버퍼에있는 문자들을 \n까지 하나씩 비워간다 ( 값을 비우는게 목적이므로 값을 저장하지는 않는다 )

}


문자열 관련함수


string.h 헤더파일


문자열의 길이를 반환하는 함수


size_t strlen (const char * s); : 문자열 s의 길이를 size_t 형태로 반환 ( size_t = unsigned int), 널문자는 길이에 포함하지않는다


문자열을 복사하는 함수


char * strcpy ( char * a, char * b); : 문자열 b를 문자열 a에 복사, 주소값을 반환한다.

char * strncpy ( char * a, char *b , n); : 문자열 b를 문자열 a에 n의 값만큼만 복사(보통 sizeof(a)-1를 이용하여 a의 크기 대입). 주소값을 반환.

- 단, n의값을 대입할때,  sizeof(a)-1의값을 대입해서 복사한 뒤 , 배열의 마지막에 널문자를 입력해줘야한다. ( 후에 문자열을 출력할때, 널문자까지 문자열을 출력하는데, 마지막에 임의로 널문자를 넣어주지않으면 strncpy는 마지막에 자동으로 널문자를 넣어주지않기 때문에 엉뚱한 영역까지 출력하게된다.


문자열뒤에 문자열을 덧붙이는 함수


char * strcat ( char *  a, const char * b); : 문자열 b를 문자열 문자열 a 뒤에 붙임. a의null 문자부터 붙임.

char * strncat ( char * a, const char * b , size_n); : 문자열 b를 문자열 a 뒤에 길이 n 만큼만 붙임.

- 단, n개의 값을 이어붙일 때 , n개에는 null 문자가 포함되지 않기때문에, null 문자를 포함시키기 위해 n+1개의 문자가 이어붙여진다.


문자열을 비교하는 함수


int strcmp ( const char * a, const char *b); : 문자열 a와 문자열 b를 비교하여 같다면 0을, 같지 않다면 0이 아닌값을 반환.

int strncmp ( const char * a, const char *b, size_t n); : 문자열 a와 문자열 b를 앞에서부터 n개만큼 비교하여 같다면 0을, 같지 않다면 0 이 아닌값을 반환.

// strcmp , strncmp 모두 a가 더 크면 0보다 큰 값 반환, b가 더크면 0보다 작은값 반환, 같으면 0을 반환한다.


문자열을 int, long, double 자료형의 데이터로 변환시키는 함수.


stdlib.h 헤더파일


int atoi ( const char * a); : 문자열 a를 int형의 자료형으로 바꿈. ex) atoi(a) : 문자열a를 int자료형으로 바꿈

long atol ( const char * a); : 문자열 a를 long 형의 자료형으로 바꿈. 

double atof ( const char * a); : 문자열 a를 double 형의 자료형으로 바꿈.

 

+ Recent posts