Skip to content

Latest commit

 

History

History
306 lines (232 loc) · 10.1 KB

211031.md

File metadata and controls

306 lines (232 loc) · 10.1 KB

Day 30

Review C

서식을 지정해서 파일에 문자열 쓰기

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 포인터로는 값을 비교할 수 없어서 정렬할 배열의 자료형에 따라 변환한 뒤 역참조하여 값을 가져온다.