fprintf 사용, fopen 함수로 파일을 열어서 파일포인터를 얻은 후에 사용, stdio.h에 선언
FILE *포인터이름 = fopen(파일명, 파일모드);
- 성공하면 파일 포인터를 반환, 실패하면 NULL 반환
fprintf(파일포인터, 서식, 값1, 값2, ...);
- 성공하면 쓴 문자열의 길이를 반환, 실패하면 음수 반환
fclose(파일포인터);
- 성공하면 0을 반환, 실패하면 EOF(-1) 반환
/*--------------------------------------------------------*/
FILE *fp = fopen("test.txt", "w"); // test.txt 파일을 쓰기 모드로 연다
fprintf(fp, "%s %d", "This is test", 0); // 서식을 지정하여 문자열을 파일에 저장
fclose(fp); // 파일 포인터 닫기
파일 모드 | 기능 | 설명 |
---|---|---|
"r" | 읽기 전용 | 파일을 읽기 전용으로 연다. 파일이 반드시 존재해야 함 |
"w" | 쓰기 전용 | 새 파일을 생성한다. 파일이 있으면 내용을 덮어 쓴다. |
"a" | 추가 | 파일을 열어 파일 끝에 값을 이어 쓴다. 파일이 없으면 파일을 생성한다. |
"r+" | 읽기/쓰기 | 파일을 읽기/쓰기용으로 연다. 파일이 반드시 존재해야 하며, 없으면 NULL을 반환한다. |
"w+" | 읽기/쓰기 | 파일을 읽기/쓰기용으로 연다. 파일이 없으면 생성하고, 있으면 덮어쓴다. |
"a+" | 추가(읽기/쓰기) | 파일을 열어 파일 끝에 값을 이어쓴다. 파일이 없으면 생성한다. 읽기는 파일의 모든 구간에서 가능하지만, 쓰기는 파일의 끝에서만 가능하다. |
t | 텍스트 모드 | 파일을 읽거나 쓸 때 개행문자 \n와 \r\n을 서로 변환한다. ^Z 파일의 끝으로 인식하여 ^Z까지만 파일을 읽는다. |
b | 바이너리 모드 | 파일의 내용을 그대로 읽고, 값을 그대로 쓴다. |
t와 b는 단독으로 사용할 수 없고 r, w, a와 같은 다른 모드와 결합하여 사용한다.
fscanf 함수 사용, stdio.h에 선언
fscanf(파일포인터, 서식, 변수의주소1, 변수의주소2, ...);
- 성공하면 읽어온 값의 개수를 반환, 실패하면 EOF(-1) 반환
/*-----------------------------------------------------*/
char s1[10];
int num1;
FILE *fp = fopen("test.txt", "r");
fscanf(fp, "%s %d", s1, &num1);
printf("%s %d", s1, num1); // This is test 0 출력
fclose(fp);
fputs 함수 사용, stdio.h에 선언
fputs(버퍼, 파일포인터);
- 성공하면 음수가 아닌 값을 반환, 실패하면 EOF(-1) 반환
/*-------------------------------------------------*/
FILE *fp = fopen("test.txt", "w");
fputs("This is test", fp); // 파일에 문자열 저장
fclose(fp);
fwrite함수 사용, stdio.h에 선언
fwrite(버퍼, 쓰기크기, 쓰기횟수, 파일포인터);
- 성공한 쓰기 횟수를 반환, 실패하면 지정된 쓰기 횟수보다 작은 값을 반환
/*--------------------------------------------------------------*/
char *s1 = "This is test";
FILE *fp = fopen("test.txt", "w");
fwrite(s1, strlen(s1), 1, fp); // strlen으로 문자열의 길이를 구하고, 문자열의 길이만큼 한 번 파일에 저장
fclose(fp);
fgets 함수 사용, stdio.h에 선언
fgets(버퍼, 버퍼크기, 파일포인터);
- 성공하면 읽은 문자열의 포인터를 반환, 실패하면 NULL 반환
/*---------------------------------------------------*/
char buffer[20];
FILE *fp = fopen("test.txt", "r");
fgets(buffer, sizeof(buffer), fp);
fclose(fp);
fgets는 중간에 \n이 있으면 버퍼 크기와 상관없이 \n까지만 읽는다.
fread 함수 사용, stdio.h에 선언
fread(버퍼, 읽기크기, 읽기횟수, 파일포인터);
- 성공한 읽기 횟수를 반환, 실패하면 지정된 읽기 횟수보다 작은 값을 반환
/*---------------------------------------------------------------*/
char buffer[20] = {0,};
FILE *fp = fopen("test.txt", "r");
fread(buffer, sizeof(buffer), 1, fp); // test.txt에서 버퍼 크기만큼 한 번 값을 읽는다
fclose(fp);
fread를 쓸 때는 배열을 선언한 후에 반드시 0으로 초기화를 해주어야 한다. 왜냐하면 파일에 저장된 문자열에는 NULL이 들어가 있지 않기 때문에 buffer에 저장되어 있던 쓰레기 값들까지 다 출력되기 때문이다.
fread는 \n이 있어도 무조건 지정된 크기만큼 읽는다.
fseek, ftell 함수 사용, stdio.h에 선언
fseek(파일포인터, 이동할크기, 기준점);
- 성공하면 0, 실패하면 -1 반환
ftell(파일 포인터);
- 파일 포인터의 현재 위치를 반환, 실패하면 -1 반환
/*-------------------------------------------*/
int size;
FILE *fp = fopen("test.txt", "r");
fseek(fp, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동
size = ftell(fp); // 파일 포인터의 현재 위치를 얻는다.
fclose(fp);
fseek 함수의 기준점 종류
기준점 | 설명 | 예 |
---|---|---|
SEEK_SET | 파일의 처음부터 이동을 시작 | fseek(fp, 0, SEEK_SET); // 파일 포인터를 파일의 처음으로 이동 |
SEEK_CUR | 현재 위치부터 이동을 시작 | fseek(fp, -10, SEEK_CUR); // 파일 포인터를 현재 위치에서 10바이트만큼 역방향으로 이동 |
SEEK_END | 파일의 끝부터 이동을 시작 | fseek(fp, 0, SEEK_END); // 파일포인터를 끝으로 이동 |
char *buffer;
int size;
int count;
FILE *fp = fopen("test.txt", "r");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
buffer = malloc(size + 1); // 파일 크기 + 1바이트(NULL)만큼 동적 메모리 할당
memset(buffer, 0, size + 1); // 버퍼의 메모리를 0으로 초기화
fseek(fp, 0, SEEK_SET);
count = fread(buffer, size, 1, fp);
fclose(fp);
free(buffer);
부분적으로 읽기
char buffer[10] = {0, };
FILE *fp = fopen("test.txt", "r");
fseek(fp, 2, SEEK_SET); // 파일 포인터를 파일 처음에서 2파이트만큼 순방향으로 이동
fread(buffer, 3, 1, fp); // 3바이트만큼 읽음, 3바이트만큼 순방향으로 이동
printf("%s", buffer"); // "is " 출력
부분적으로 쓰기
char *s1 = "card";
char buffer[20] = {0, };
FILE *fp = fopen("test.txt", "r+");
fseek(fp, 3, SEEK_SET);
fwrite(s1, strlen(s1), 1, fp); // 문자열의 길이 만큼 문자열을 파일에 저장
rewind(fp); // 파일 포인터를 파일의 맨 처음으로 이동 시킴
fread(buffer, 20, 1, fp);
printf("%s", buffer); // Thicard test 출력
fclose(fp);
feof 함수 사용, stdio.h에 선언, 현재 파일 포인터가 파일의 끝인지 검사
feof(파일포인터);
- 파일의 끝이면 1, 아니면 0 반환
/*---------------------------*/
char buffer[5] = {0, };
int count = 0;
int total =0;
FILE *fp = fopen("test.txt", "r");
while(feof(fp == 0)
{
count = fread(buffer, sizeof(char), 4, fp); // 1바이트씩 4번 읽기
printf("%s", buffer);
memset(buffer, 0, 5); // 버퍼를 초기화
total += count;
}
fclose(fp);
fwrite 함수 사용, 100, 200, 300, 400을 바이너리 형식으로 저장
#pragma pack(push, 1)
struct Data {
short num1; // 2바이트
short num2; // 2바이트
short num3; // 2바이트
short num4; // 2바이트
};
#pragma pack(pop)
struct Data d1 = {100, 200, 300, 400};
FILE *fp = fopen("data.bin", "wb"); // 파일을 쓰기/바이너리 모드로 연다
fwrite(&d1, sizeof(d1), 1, fp); // 구조체의 내용을 파일에 저장
fclose(fp);
fread 함수 사용
struct Data d1;
FILE *fp = fopen("data.bin", "rb"); // 파일을 읽기/바이너리 모드로 연다
fread(&d1, sizeof(d1), 1, fp);
fclose(fp);
파일에서 구조체를 읽고 쓸 때는 반드시 구조체를 1바이트 크기로 정렬해야 한다.
거품 정렬 알고리즘의 규칙
- 처음부터 끝까지 요소를 순회하면서 모든 요소를 비교
- 현재 값과 다음 값을 비교하여 큰 값을 다음으로 보냄(오름차순)
void bubble_sort(int arr[], int count) // 매개변수로 정렬할 배열과 요소의 개수를 받는다
{
int temp;
for (int i = 0; i < count; i++) // 요소의 개수만큼 반복
{
for (int j = 0; j < count - 1; j++) // 요소의 개수 - 1만큼 반복
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
qsort 함수 사용, stdlib.h에 선언, 비교함수는 우리가 구현해서 메모리 주소, 함수 포인터를 넣어 준다.
qsort(정렬할배열, 요소개수, 요소크기, 비교함수);
qsort(정렬할메모리주소, 요소개수, 요소크기, 비교함수);
/*-------------------------------------------------*/
int compare(const void *a, const void *b) // 오름차순 비교 함수 구현
{
int num1 = *(int *)a; // void 포인터를 int 포인터로 변환한 뒤 역참조하여 값을 가져옴
int num2 = *(int *)b;
if (num1 < num2) // a가 b보다 작을 때
return -1; // -1 반환
if (num1 > num2) // a가 b보다 클 때
return 1; // 1 반환
return 0; // a와 b가 같을 때, 0 반환
}
int numArr[10] = {8, 4, 3, 2, 5};
qsort(numArr, sizeof(numArr) / sizeof(int), sizeof(int), compare);
오름차순 정렬 조건
- a < b 일 때 -1 반환
- a > b 일 때 1 반환
- a == b 일 때 0 반환
a < b 일 때 1을 반환하면 내림차순 정렬이 된다.
비교함수를 정의할 때는 반드시 int형 반환값과 const void 포인터 매개변수가 두 개 있어야 한다.
하지만 const void 포인터로는 값을 비교할 수 없어서 정렬할 배열의 자료형에 따라 변환한 뒤 역참조하여 값을 가져온다.