※요약

fgetc : 개방된 파일의 단일 문자를 읽는다.



※함수 원형 및 설명

int fgetc( FILE *stream );
//stream : 개방된 FILE 구조체의 포인터
//반환값 : 읽은 문자 값(int), 파일 끝 또는 에러 시 EOF(-1)


※예제

#include <stdio.h>

#define print(ch) printf( "%x %c\n", ch, ch )

int main( )
{	
	FILE *pFile = NULL;

	pFile = fopen( "d:\\Text.txt", "r" );
	if( pFile == NULL )
	{
		//에러 처리
	}
	else
	{
		char chTemp;

		while( !feof( pFile ) )
		{
			chTemp = fgetc( pFile );
			print( chTemp );
		}

		fclose( pFile );
	}

	return 0;
}




※요약

fprintf : 개방된 파일에 변수 단위 출력을 한다.



특징

fprintf는 sprintf, printf와 사용법이 같다.

파일 포인터는 자동으로 증가한다.



※함수 원형 및 설명

int fprintf( FILE *stream, const char *format, [, argument].. );
//stream : 개방된 FILE 구조체의 포인터
//format : 형식 제어 문자열
//argument : 가변적인 매개변수
//반환값 : 출력한 바이트의 수. 에러 시 EOF(-1)



※예제

#include <stdio.h>

int main( )
{	
	FILE *pFile = NULL;

	pFile = fopen( "d:\\Text.txt", "w" );
	if( pFile == NULL )
	{
		//에러 처리
	}
	else
	{
		for( int i=0 ; i<3 ; ++i )
		{
			fprintf( pFile, "%d %f %s \n", i, 0.5+i, "String" );	//공백 분리
			fprintf( pFile, "%d, %f, %s \n", i, 0.5+i, "String" );	//콤마 분리
			fprintf( pFile, "%d\t%f\t%s \n", i, 0.5+i, "String" );	//탭 분리
		}
		fclose( pFile );
	}

	return 0;
}




※요약

fscanf : 개방된 파일에서 변수 단위로 입력을 받는다.



※특징

변수 간의 구분은 공백, 탭, 개행 문자로 한다.

*는 값을 읽지 않고 건너뛸 때 사용한다.

파일 포인터는 자동으로 증가한다.



※함수 원형 및 설명

int fscanf( FILE *stream, const char *format [, argument].. );
//stream : 개방된 FILE 구조체의 포인터
//format : 형식 제어 문자열
//argument : 가변적인 매개변수
//반환값 : 읽혀진 필드의 수. 파일 끝 또는 에러 시 EOF(-1)



※예제


읽을 파일 Text.txt


#include <stdio.h>

int main( )
{	
	FILE *pFile = NULL;

	pFile = fopen( "d:\\Text.txt", "r" );
	if( pFile == NULL )
	{
		//에러 처리
	}
	else
	{
		int nCount;
		float fRatio;
		char strDesc[255];

		while( !feof( pFile ) )
		{
			//공백으로 분리된 파일 읽기
			fscanf( pFile, "%d %f %s\n", &nCount, &fRatio, strDesc );
			printf( "공백으로 분리 : %d %f %s\n", nCount, fRatio, strDesc );
			
			//,로 분리된 파일 읽기
			fscanf( pFile, "%d, %f, %s\n", &nCount, &fRatio, strDesc );
			printf( ",로 분리 : %d, %f, %s\n", nCount, fRatio, strDesc );

			//탭으로 분리된 파일 읽기
			fscanf( pFile, "%d\t%f\t%s\n", &nCount, &fRatio, strDesc );
			printf( "탭으로 분리 : %d\t%f\t%s\n", nCount, fRatio, strDesc );

			//선별적으로 읽기 - [%*]을 사용하면 값을 읽지 않는다.
			fscanf( pFile, "%*d %*f %s\n", strDesc );
			printf( "선별적으로 읽기 : %s\n", strDesc );
		}

		fclose( pFile );
	}

	return 0;
}




※요약

당연한 얘기겠지만 비트 연산자는 비트를 연산하기 위한 연산자입니다.

비트란( bit )란 기억 장치의 최소 단위로써 1이나 0을 저장하며 8개가 모여 1Byte를 이룹니다.

비트 연산은 정수나 정수로 변환 가능한 타입만 가능하며, 실수나 포인터 등은 비트 연산을 할 수 없습니다.


아래는 8bit( 1Byte )공간에 10진수로는 89, 16진수로는 0x59가 저장되어 있는 모양입니다.

128

64

32

16

8

4

2

1

0

1

0

1

1

0

0

1

64 + 16 + 8 + 1 = 89 입니다.



※비트 연산자 표

연산자

피연산자 개수

설명

~ (NOT)

1개, 단항

비트를 반전 시킨다.

& (AND)

2개, 이항

두 개의 비트가 모두 1일 때 1

| (OR)

2개, 이항

두 개의 비트 중 1개만 1이어도 1

^ (XOR)

2개, 이항

두 개의 비트가 같으면 0, 다르면 1

<<

2개, 이항

지정한 수만큼 왼쪽으로 비트들을 이동

>>

2개, 이항

지정한 수만큼 오른쪽으로 비트들을 이동

마스크 오프 : 특정 비트를 강제로 0으로 만드는 연산을 mask off라고 하며 &연산자가 쓰인다.

마스크 온 : 특정 비트를 강제로 1로 만드는 연산을 mask on이라고 하며 |연산자가 쓰인다.

마스크 반전 : 반전시키고자 하는 부분만 반전 시키는 연산을 마스크 반전이라 하며 ^연산자가 쓰인다.



※비트 연산자 진리표

b1

b2

b1 & b2

b1 | b2

b1 ^ b2

~b1

0

0

0

0

0

1

0

1

0

1

1

1

1

0

0

1

1

0

1

1

1

1

0

0



※쉬프트 연산자 <<, >>

0

1

0

1

1

0

0

1

상기의 0101 1001을 a라고 하고 쉬프트 연산을 통해 좌측으로 2칸 옮겨 보겠습니다.


a << 2

0

1

0

1

1

0

0

1

<<2

0

1

1

0

0

1

0

0

보시다시피 좌측으로 2칸 이동하였습니다.

이 때 좌측 두 칸은 버리고, 오른쪽 두 칸은 0으로 채웁니다.



※예제

#include <stdio.h>

int main( )
{
	int nNum1 = 3;
	int nNum2 = 5;
	int nResult = 0;

	nResult = nNum1 & nNum2;
	printf( "%d & %d 연산 : %d\n", nNum1, nNum2, nResult );

	nResult = nNum1 | nNum2;
	printf( "%d | %d 연산 : %d\n", nNum1, nNum2, nResult );

	nResult = nNum1 ^ nNum2;
	printf( "%d ^ %d 연산 : %d\n", nNum1, nNum2, nResult );

	nResult = ~nNum1;
	printf( "%d ~ %d 연산 : %d\n", nNum1, nNum2, nResult );

	nResult = nNum1 << 2;
	printf( "%d << %d 연산 : %d\n", nNum1, 2, nResult );

	nResult = nNum1 >> 2;
	printf( "%d >> %d 연산 : %d\n", nNum1, 2, nResult );

	return 0;
}




※요약

rand : 예측할 수 없는 하나의 난수를 생성한다.

난수의 범위는 0~RAND_MAX 까지이며 RAND_MAX는 0x7fff이므로 , 결국 난수의 범위는 0~32767 이다.

srand : rand 함수만으로 생성되는 난수는 일정한데 

srand를 이용, 시간 값을 매개로 초기화하면 일정하지 않고 불규칙적인 난수가 생성된다.



※함수 원형 및 설명

int rand( void );

void srand( unsigned int seed );



※사용법 ( 사용법 부분은 "C언어를 배우자" 카페의 라이터님의 게시물을 허락 후 옮겼습니다. )

1. 기본 사용법

i = rand()%n

이것은 0 ~ n-1 범위의 난수를 i에 대입합니다.

예를 들어 n=6 이라 하면 0, 1, 2, 3, 4, 5, 중 하나가 i에 대입되는 셈이지요.

 


2. 기본 응용

i = rand()%n + m

이것은 1번을 응용한 것으로, 0+m ~ n-1+m 범위의 난수를 i에 대입합니다.

예를 들어 n=6, m=4 라 하면 4, 5, 6, 7, 8, 9, 중 하나가 i에 대입되는 셈이지요.

다른 예로 n=5, m= -2 라 하면 -2, -1, 0, 1, 2 중 하나가 i에 대입되는 것이죠.

 

 

i = rand()%n * m

이것은 0 ~ n-1 으로 나올 수 있는 수에 m을 곱한 수를 i에 대입하는 식입니다.

예를 들어 n=4, m=2 이라 하면, 0, 2, 4, 6 중 하나가 i에 대입되는 것이죠.

m의 값을 2로 주면 2의 배수, 3을 주면 3의 배수가 나오는군요.

 

이제 두개를 섞어서,


i = (rand()%n + m) * o

이것은 0+m ~ n+m-1 으로 나올 수 있는 난수에 o을 곱한 수를 i에 대입하는 식입니다.

n = 3, m = 2, o = 4 라 하면, 8, 12, 16 중 하나가 i에 대입되는 것이죠.

이것도 어떤 수의 배수를 사용할 때 용이하겠습니다.


i = rand()%n * m + o

이건 0 ~ n-1 으로 나올 수 있는 수에 m을 곱하고, o를 더한 수를 i에 대입하는 식입니다.

n = 3, m = 2, o = 5 라 하면, 5, 7, 9 중 하나가 i에 대입되는 것이죠. 




3. 기본 심화 응용

i = rand()%n * m + o

이 식을 다시 한번 봅시다.

n의 값이야 0 이상으로 주고, m = 2, o = 0 으로 주면, 짝수가 생성됩니다.

m = 2, o = 1 으로 주면, 홀수가 생성되는것을 볼 수 있습니다.



4. 배열을 이용한 응용 - 1 기본 기법

배열을 이용한 응용이라...  rand() 의 마법을 보실 수 있겠군요.

int ar[MAX] = {원하는 원소 MAX개}; 라는 배열이 있다고 생각하고...


i = ar[rand()%MAX]

이 식은 상당히 유용합니다. 예를 들어보는게 제일 빠르겠지요.

MAX = 4로 잡고, ar 배열의 원소를 { 2, 5, 9, 3214324 } 이라 합시다.

저 4개의 숫자는 규칙성도 뭣도 없어서 위에서 본 응용법으로는 뽑아 낼 수가 없지요.

하지만 배열과 4번의 식을 이용한다면?


rand()%MAX 는 0 ~ MAX-1 범위의 수를 뽑아낼 것입니다.

MAX 가 4니까 0, 1, 2, 3, 이 나오겠지요? 그런 다음에 ar[rand()%MAX] 으로 ar배열 속에 있는 원소에 접근하는데...

rand()%MAX 가

0 이면 2

1 이면 5

2 이면 9

3 이면 3214324

를 i 에 대입할 수 있는거죠.

 

이렇게 배열을 이용하면 rand() 함수 한번의 호출로 불규칙한 수를 난수로 뽑아내 쓸 수 있는거죠.

응용법은... 아래쪽에 있습니다.



5. 배열을 이용한 응용 - 2 자세한 응용

이번엔 다른 배열 응용법을 알아봅시다.


복권을 만들었는데, 1/10 의 확률로 1등, 3/10의 확률로 2등, 6/10의 확률로 3등이라고 하고,

rand() 를 이용해 랜덤하게 추첨을 하려고 하는데..


" 3가지 경우가 있으니 rand()%3 해서 0 이면 1등, 1이면 2등... "

이런 생각은 떙 !!!!

0, 1, 2, 가 나올 확률은 같습니다!!!


" 그럼 rand()%10 해서 0 은 1등, 1~3 은 2등, 4~9 는 3등으로... 이런 복잡한 걸"

정답인데, 이러면 조건문이 들어가야 하는 복잡함이!!!!


배열 하나면 됩니다.

int ar[10] = { 1, 2, 2, 2, 3, 3, 3, 3, 3, 3 }

이런 배열 하나 준비 하시고!!!!


i = ar[rand()%10]

아하하하하하, 이러면 끝 !! i에는 추첨된 등수가 들어가게 됩니다.

설명해 드리죠.


rand()%10 으로 나올 수 있는 수는

0, 1, 2, 3, 4, 5, 6, 7, 8, 9 이고, 이 10가지 수가 나올 수 있는 수학적 확률은 같습니다.


그러나, 0이 나올 확률은 1/10,

1, 2, 3 이 나올 학률은 3/10,

4, 5, 6, 7, 8, 9 가 나올 확률은 6/10  !!!


배열 원소를 보면, ar[0] 은 1이고

ar[1] ~ ar[3]은 2,   ar[4] ~ ar[9]는 3!!!!


배열로는 이런일이 가능합니다 !!!




※예제

아래는 중복 없는 난수 생성 예제입니다. 

로또 번호 생성 예제이며, 제가 배포하는 로또 프로그램에서 일부 가져와 군더더기를 제거하고  예제에 맞게 수정했습니다.

중복을 방지하기 위해 생성 여부에 대한 일종의 인덱스를 둬서 따로 검사하지 않아도 중복을 방지할 수 있게 했습니다.

흔히 사용하는 배열 요소를 처음부터 끝까지 조사 방식은 배열 개수에 따라 속도가 엄청 느려지므로 추천하지 않습니다.

이렇게 인덱스를 두는 방법은 에라토스테네스의 체를 구할 때도 이용되고 

데이터를 캐싱할 때 이미 불러들인 데이터인지 판별할 때도 사용됩니다.

#include <stdio.h>
#include <stdlib.h>       //srand
#include <time.h>     //time
 
//#define _MAX 6
const int nMAX = 6;
 
void BubbleSort( int *nArr, int nArrSize );
 
int main( )
{
    //변수 생성 및 초기화 부분
    srand( (unsigned)time(NULL) );              //srand로 초기화
 
    int nLottoNum[nMAX] = { 0, };               //생성된 로또 번호를 저장할 변수
    bool bCheckExistOfNum[45] = { false, };     //생성된 번호가 중복인지 체크할 변수(인덱스)
 
    //번호 생성 부분
    for( int i=0 ; i<nMAX ; )                    //번호가 6개 생성될 때까지 돈다.
    {
        int nTemp = rand()%45;                  //0~44 범위의 번호를 생성한다.
 
        if( bCheckExistOfNum[nTemp] == false )  //중복 여부 판단
        {
            bCheckExistOfNum[nTemp] = true;     //번호가 중복 생성되지 않게 존재 여부를 true로 한다.
            nLottoNum[i] = nTemp+1;             //+1을 안해주면 범위가 0~44이다.
            ++i;                                //증감 연산을 for문에서 하지 않고 여기서 한다.
        }
    }
 
    //버블 정렬
    BubbleSort( nLottoNum, sizeof(nLottoNum)/sizeof(int) );
 
    //출력 부분
    for( int i=0 ; i<nMAX ; ++i )
    {
        printf( "%2d ", nLottoNum[i] );
    }
 
    return 0;
}
 
void BubbleSort( int *nArr, int nArrSize )
{
    for( int i=0 ; i<nArrSize-1 ; i++ )
    {
        for( int j=0 ; j<nArrSize-(i+1) ; j++ )
        {
            if( nArr[j] > nArr[j+1] )    //꺽쇠 방향으로 오름 차순, 내름 차순 결정
            {//값 교환 부분
                int temp = nArr[j];
                nArr[j] = nArr[j+1];
                nArr[j+1] = temp;
            }
        }
    }
}




콘솔창은 형형색색으로 꾸며도 정말 촌스럽네요.




※소스 코드

#include <windows.h>
#include <stdio.h>

#define RED         (FOREGROUND_RED | FOREGROUND_INTENSITY)
#define BLUE        (FOREGROUND_BLUE | FOREGROUND_INTENSITY)
#define PINK        (RED | BLUE)
#define WHITE       (RED | GREEN | BLUE)
#define GREEN       (FOREGROUND_GREEN | FOREGROUND_INTENSITY)
#define YELLOW      (RED | GREEN)
#define SKYBLUE     (GREEN | BLUE)

#define RED_BG      (BACKGROUND_RED | BACKGROUND_INTENSITY)
#define BLUE_BG     (BACKGROUND_BLUE | BACKGROUND_INTENSITY)
#define PINK_BG     (RED_BG | BLUE_BG)
#define WHITE_BG    (RED_BG | GREEN_BG | BLUE_BG)
#define GREEN_BG    (BACKGROUND_GREEN | BACKGROUND_INTENSITY)
#define YELLOW_BG   (RED_BG | GREEN_BG)
#define SKYBLUE_BG  (GREEN_BG | BLUE_BG)

void PrintString( HANDLE hStdOut, WORD Attribute, LPCSTR str )
{
    SetConsoleTextAttribute( hStdOut, Attribute );
    puts(str);
}

int main( )
{
    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    PrintString(hStdOut, RED, "빨간색");
    PrintString(hStdOut, BLUE, "파란색");
    PrintString(hStdOut, PINK, "분홍색");
    PrintString(hStdOut, WHITE, "하얀색");
    PrintString(hStdOut, GREEN, "초록색");
    PrintString(hStdOut, YELLOW, "노란색");
    PrintString(hStdOut, SKYBLUE, "하늘색\n");

    PrintString(hStdOut, RED_BG, "빨간배경");
    PrintString(hStdOut, BLUE_BG, "파란배경");
    PrintString(hStdOut, PINK_BG, "분홍배경");
    PrintString(hStdOut, WHITE_BG, "하얀배경");
    PrintString(hStdOut, GREEN_BG, "초록배경");
    PrintString(hStdOut, YELLOW_BG, "노란배경");
    PrintString(hStdOut, SKYBLUE_BG, "하늘배경\n");

    PrintString(hStdOut, YELLOW_BG | PINK, "노란배경 빨간글씨");
	PrintString(hStdOut, WHITE_BG | GREEN, "하얀배경 빨간글씨");
	PrintString(hStdOut, GREEN_BG | WHITE, "초록배경 빨간글씨");
	PrintString(hStdOut, BLUE_BG | RED, "파랑배경 빨간글씨");

    CloseHandle(hStdOut);

    return 0;
}


'C > 기타' 카테고리의 다른 글

[C언어] 플랫폼 독립적 COLORREF <-> RGB 서로 변환  (0) 2014.03.12



출처 : 잡동사니님 블로그


- 1Bytes 변수( char, unsigned char 등 )를 제외한 변수를 초기화 할 때는 0 이외의 값으로 초기화를 하면 안됨

- new, malloc 등을 이용하여 동적으로 배열을 생성하는 변수가 있는 struct, class에서는 memset으로 초기화를 하면 안됨

- CString은 절대 memset으로 초기화를 하면 안됨

- virtual function을 가지고 있는 struct, class에서는 절대 memset으로 초기화를 하면 안됨


memset을 사용할 때 위 4가지 경우만 기억을 하고 있으면 문제없이 동작합니다. 

각각에 대해서 간단하게 살펴보도록 하죠


-1Bytes 변수( char, unsigned char 등 )를 제외한 변수를 초기화 할 때는 0 이외의 값으로 초기화를 하면 안됩니다.

1
2
int n;
memset(&n, 1, sizeof(int));

으로 하면 Byte단위로 처리가 되어 

n = [00000001000000010000000100000001] = 16843009의 원하지 않는 값으로 초기화가 되버립니다. 

따라서 1Byte의 변수를 제외하고는 0으로만 초기화를 하는데 이용해야 합니다.


-new, malloc 등을 이용하여 동적으로 배열을 생성하는 변수가 있는 struct, class에서는 memset으로 초기화를 하면 안됩니다

문제가 되는 경우를 살펴보면,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A
{
   int i;
   char* c;
};
  
void main()
{
   A a;
   a.c = new char[100];
   memset(&a, 0, sizeof(A));
   if(a.c != NULL)
   {
      delete[] a.c;
      a.c = NULL;
   }
}

여기서 sizeof(A)는 struct member alignment가 어떤 값이든 4(int i) + 4(char* c, address는 4) = 8Bytes가 됩니다. 

그러므로 위의 소스는 동적으로 생성한 변수는 초기화가 되지 못하고, char* c가 NULL로 초기화가 됨으로써, 

이전에 생성한 메모리는 메모리 누수가 발생하게 됩니다.

그러므로 위와 같이 동적으로 생성하는 경우는 아래와 같이 각각을 분리하여 초기화를 하여야 합니다.

1
2
a.i = 0;
memset(a.c, 0, sizeof(char)*100);


-CString은 절대 memset으로 초기화를 하면 안됩니다.

1.2와 같은 경우로 CString은 내부적으로 m_pchData 변수를 동적으로 생성하여 문자열을 저장합니다. 

이 변수에 대한 직접적인 접근은 private로 막혀 있습니다.

그래서 CString, 또는 CString을 member variable을 가지고 있는 

struct, class를 memset을 이용하여 초기화를 하면 안됩니다.

CString을 memset으로 초기화를 하면, 1.2와 같이 메모리 누수뿐만 아니라, run-time error도 발생을 합니다.


-virtual function을 가지고 있는 struct, class에서는 절대 memset으로 초기화를 하면 안됩니다.

여기서 virtual은 run-time에 실행함수를 binding하는 역할을 하는 것입니다.

한번 잊어버렸던 기억을 되살리는 의미로 예제를 살펴보면,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A
{
public:
   void fun() { printf("A::fun() "); }
};
  
class B: public A
{
public:
   void fun() { printf("B::fun() "); }
};
  
void main()
{
   A* a = new B();
   a->fun();
}

위의 경우 “A::fun()”이 출력됩니다.

하지만 상속을 하여 재정의를 한다는 목적은 재정의를 한 함수가 호출되기를 바라기 때문이죠.

이때 아래와 같이 class A만 간단히 변경하여 virtual만 추가를 하면,

1
2
3
4
5
class A
{
public:
   virtual void fun() { printf("A::fun() "); }
};

재정의한 함수가 실행이 되어 “B::fun()”이 출력됩니다. 이는 a→fun();가 실행이 될 때,

이 함수가 virtual이므로 a의 실제 instance(=new B)에 대응하는 실제 함수를 run-time으로 binding 되기 때문입니다.

이정도로만 virtual 동작에 대해서 기억을 되살려보는 것으로 마무리를 하고, 다시 memset으로 넘어오면,

1
2
3
4
5
6
class A
{
   int i;
   char* c;
   void fun();
};

을 sizeof(A)를 하면 4(int i)+4(char*c, address)=8Bytes로 member function은 영향을 주지 않습니다. 

하지만,

1
2
3
4
5
6
class A
{
   int i;
   char* c;
   virtual void fun();
};

의 경우는 다릅니다. 

위의 8Bytes외에 실제 fun()이 binding을 위한 

실행함수 주소를 저장할 공간을 가리키는(VPTR) 4Bytes를 추가적으로 가지므로, 

sizeof(A)는 총 12Bytes가 됩니다.

이때

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A
{
public:
   virtual void fun() { printf("A::fun() "); }
};
  
class B: public A
{
public:
   void fun() { printf("B::fun() "); }
};
  
void main()
{
   A* a = new B();
   memset(a, 0, sizeof(B));
   a->fun();
}

와 같이 memset을 이용하여 초기화를 하면, virtual function이 NULL영역으로 binding이 되어

a→fun();에서 run-time에 알 수 없는 에러가 발생한다는 것을 반드시 기억해야 합니다.

memset은 매우 편리하고, 강력하면서도, 조심해서 사용해야 한다는 것을 명심하세요.

※요약

fputs : 개방된 파일에 문자열을 라인 단위로 씁니다.



※특징

개행 문자 '\n'을 자동으로 0x0D, 0x0A 값으로 변환한다.



※함수 원형 및 설명

int fputs( const char *string, FILE *stream );
//string : 파일에 쓸 NULL로 끝나는 문자열 버퍼의 포인터
//stream : 개방된 FILE 구조체의 포인터
//반환값 : 설공 시 0이나 양수, 실패 시 EOF(-1)




※예제

#include <stdio.h>

int main( )
{	
	FILE *pFile = NULL;

	pFile = fopen( "d:\\Text.txt", "w+" );
	if( pFile != NULL )
	{
		for( int i=0 ; i<5 ; ++i )
		{
			int nResult = fputs( "라인 단위 파일 쓰기 fputs\n", pFile );
			printf( "%d번째 라인 쓰기 %s\n", i+1, nResult != -1 ? "성공":"실패" );
		}
		fclose( pFile );
	}
	else
	{
	}

	return 0;
}




※요약

fgets : 개방된 파일에서 텍스트 문자열을 한 줄씩 읽습니다.



※특징

 - 파일 끝이나 개행 문자까지 읽는다.

 - 라인 끝(CR/LF)을 읽으면 개행 문자 '\n'으로 변환한다.

 - string 끝에 NULL문자를 추가한다.



※함수 원형 및 설명

char *fgets( char *string, int n, FILE *stream );
//string : 파일 데이터를 읽어서 저장할 버퍼의 포인터
//n : 읽을 최대 문자의 수 +1, 읽은 문자열의 끝에 NULL이 추가
//stream : 개방된 FILE 구조체의 포인터
//반환값 : 읽은 string의 포인터, 더 읽을 파일이 없거나 에러 시 NULL 포인터



※예제

#include <stdio.h>

int main( )
{
	FILE *pFile = NULL;

	pFile = fopen( "d:\\Text.txt", "r" );
	if( pFile != NULL )
	{
		char strTemp[255];
		char *pStr;

		while( !feof( pFile ) )
		{
			pStr = fgets( strTemp, sizeof(strTemp), pFile );
			printf( "%s", strTemp );
			printf( "%s", pStr );
		}
		fclose( pFile );
	}
	else
	{
		//에러 처리
	}

	return 0;
}


※txt파일 내용

첫 번째줄입니다.

두 번째줄입니다.

세 번째줄입니다.




※요약

fopen : 파일에 대한 입력 및 출력을 합니다.

fclose : fopen함수로 개방한 파일을 닫습니다.


※함수 원형 및 설명

FILE *fopen( const char *filename, const char *mode );
//filename : 개방할 파일의 경로 및 파일명
//mode : 파일 접근 권한(읽기 전용, 쓰기 전용 등 아래 표 참고)
//반환값 : 개방된 파일의 FILE 구조체 포인터, 실패시 NULL포인터

int fclose( FILE *stream );
//stream : 개방된 FILE 구조체의 포인터
//반환값 : 성공 시 0, 실패 시 -1(EOF)



※모드 설명

 모드

 설명

읽기만 가능하며 파일이 존재해야 한다.

존재하지 않을 경우 에러가 리턴된다.

 w

쓰기만 가능하며 파일을 생성한다.

파일이 존재하면 그 파일을 지우고 생성한다.

 a

파일 끝에 추가만 가능하며 

파일이 존재하지 않으면 파일을 새로 생성한다. 

 r+

읽기, 쓰기 모두 가능하며 파일이 존재해야 한다. 

존재하지 않을 경우 에러가 리턴된다.

 w+

 읽기, 쓰기 모두 가능하며 파일을 생성한다.

파일이 존재하면 그 파일을 지우고 생성한다.

 a+

파일을 읽어서 파일 끝에 추가만 가능하다.

파일이 존재하지 않으면 파일을 새로 생성한다. 

 t

 파일을 text 모드로 개방한다. 

입력 시, CF/LF를 “\n”으로 자동 변환하고 

출력 시에는 “\n”을 CF/LF로 자동 변환한다.

t나 b 생략시 텍스트 모드로 개방된다.

 b

 파일을 이진(binary) 모드로 개방한다.

개행 문자 “\n”을 변환없이 그대로 읽고 쓴다.

파일 개방 시 기본 모드는 텍스트 모드인 t모드입니다.

고로 r은 rt와 같고 r+는 r+t와 같습니다.



※모드 조합

 모드

읽기

쓰기

추가

 텍스트 모드

r / rt

w / wt

a / at

 텍스트 갱신 모드

r+ / r+t

w+ / w+t

a+ / a+t

 이진 모드

rb

wb

ab

 이진 갱신 모드

r+b

w+b

a+b



※모드표

모드

읽기

쓰기

갱신

파일 없을 시

파일 생성

파일 존재 시

삭제 여부

fseek함수

사용 여부

r

O

X

X

X

X

O

r+

O

O

O

X

X

O

w

X

O

O

O

O

O

w+

O

O

O

O

O

O

a

X

O(*)

X

O

X

X(*)

a+

O

O(*)

X

O

X

O

모드 a, a+는 현재의 FILE 포인터 위치에 관계없이 항상 파일 끝에 씁니다.

그러므로 fseek함수로 FILE 포인터 위치를 바꿔도 소용이 없으며, a+모드일 때 읽을 위치만을 설정합니다.

기존 파일을 삭제하지 않고 수정하려면 r+모드로 하면 됩니다.



※예제

#include <stdio.h>

int main( )
{
	FILE *pFile = NULL;

	pFile = fopen( "d:\\text.txt", "w+t" );
	if( pFile != NULL )
	{
		fputs( "테스트 입니다.", pFile );
		fclose( pFile );
	}
	else
	{
		//에러 처리
	}

	return 0;
}


+ Recent posts