대학교/프로그래밍랩

[프로그래밍 랩] 9주차 - 파일 입출력

CodeJin 2022. 1. 10. 02:02

문제 1. FILE 포인터를 이용한 입출력

파일명을 입력받고 그 안의 내용을 출력해보자.

파일 입출력에 관한 함수를 배운다. 그 첫번째로는 fprintf와 fscanf

#include <stdio.h>

void main()
{
    FILE* fp; // 파일을 입/출력하기 위한 파일 포인터
    char ch;
    char filename[80] = "data.txt";
    char buf[80];
    int id = 1234567;
    char name[80] = "홍길동";
    char phone[80] = "010-1234-5678";

    printf("입력 파일 명 : ");
    scanf("%s", filename);
    
    fp = fopen(filename, "r");
    fscanf(fp, "%d", &id);
    printf("학번=%d\n", id);
    fscanf(fp, "%s", buf);
    printf("이름=%s\n", buf);
    fscanf(fp, "%s", buf);
    printf("전화=%s\n", buf);
    fclose(fp);
}

 

문제 1 추가. 입출력을 위한 데이터 파일명과 데이터를 입력받고 처리하기

이번에는 파일에 입력할 내용까지 입력받는다.

#include <stdio.h>

void main()
{
    FILE* fp; // 파일을 입/출력하기 위한 변수
    char ch;
    char filename[80] = "data.txt";
    char buf[80];
    int id = 1234567;
    char name[80] = "홍길동";
    char phone[80] = "010-1234-5678";

    
    printf("데이터 파일 명 : "); scanf("%s", filename);
    printf("학번 : "); scanf("%d", &id);
    printf("이름 : "); scanf("%s", name);
    printf("전화 : "); scanf("%s", phone);
    
    fp = fopen(filename, "w");
    fprintf(fp, "%d\n", id);
    fprintf(fp, "%s\n", name);
    fprintf(fp, "%s\n", phone);
    fclose(fp);
    
    fp = fopen(filename, "r");
    fscanf(fp, "%d", &id);
    printf("학번=%d\n", id);
    fscanf(fp, "%s", buf);
    printf("이름=%s\n", buf);
    fscanf(fp, "%s", buf);
    printf("전화=%s\n", buf);
    fclose(fp);
}

 

문제 2. 구조체(레코드) 저장

이번에는 파일을 binary모드로 열어서 구조체를 저장해보자. 이때 fwrite함수와 fread함수가 쓰인다.

#include <stdio.h>

typedef struct Student {
    int id; // char id[20];
    char name[20];
    char phone[20];
} STUDENT;

void main()
{
    STUDENT data = { 2012345, "홍길동 ", "010-1234-5678" };
    STUDENT data1;
    char filename[20] = "data.txt";
    FILE* fp;

    fp = fopen(filename, "w+b");
    fwrite(&data, sizeof(struct Student), 1, fp);
    fclose(fp);	

    fp = fopen(filename, "r+b");
    fread(&data1, sizeof(struct Student), 1, fp);
    printf("학번=%d\n", data1.id);
    printf("이름=%s\n", data1.name);
    printf("전화=%s\n", data1.phone);
    fclose(fp);
}

 

문제 2 추가. 입출력을 위한 데이터 파일명과 데이터를 입력받고 처리하기

문제 1 추가와 비슷한 맥락.

단, 이번에는 구조체의 int id를 char id[20]으로 바꿔서 써보자.

#include <stdio.h>

typedef struct Student {
    char id[20];
    char name[20];
    char phone[20];
} STUDENT;

void main()
{
    STUDENT data = { 2012345, "홍길동 ", "010-1234-5678" };
    STUDENT data1;
    char filename[20] = "data.txt";
    FILE* fp;
    
    printf("데이타 파일 명 : "); scanf("%s", filename);
    printf("학번 : "); scanf("%s", data.id);
    printf("이름 : "); scanf("%s", data.name);
    printf("전화 : "); scanf("%s", data.phone);
    
    fp = fopen(filename, "w+b");
    fwrite(&data, sizeof(struct Student), 1, fp);
    fclose(fp);	

    fp = fopen(filename, "r+b");
    fread(&data1, sizeof(struct Student), 1, fp);
    printf("학번=%s\n", data1.id);
    printf("이름=%s\n", data1.name);
    printf("전화=%s\n", data1.phone);
    fclose(fp);
}

 

문제 3. Random Access 파일

순차파일은 처음부터 읽어야 하지만, 랜덤 파일은 원하는 위치에서 읽고 쓰는게 가능하다. 이 문제에서는 fseek함수에 관해 배운다.

#include <stdio.h>

typedef struct Student {
    int id;
    char name[20];
    char phone[20];
} STUDENT;

void main()
{
    STUDENT data;
    char filename[80] = "data.txt";
    FILE* fp;
    int i;

    fp = fopen(filename, "wb");
    for (i = 0; i < 3; i++) {
        printf("%d번 data 입력\n", i + 1);
        printf("학번 : "); scanf("%d", &data.id);
        printf("이름 : "); scanf("%s", data.name);
        printf("전화 : "); scanf("%s", data.phone);
        fwrite(&data, sizeof(struct Student), 1, fp);
    }
    fclose(fp);

    fp = fopen(filename, "r+b");
    for (i = 0; i < 3; i++) {
        fread(&data, sizeof(struct Student), 1, fp);
        printf("학번=%d ", data.id);
        printf("이름=%s ", data.name);
        printf("전화=%s\n", data.phone);
    }

    while (1) {
        printf("데이타번호 : ");
        scanf("%d", &i);
        if (i == 99)
            break;
        fseek(fp, (i-1) * sizeof(STUDENT), SEEK_SET);
        fread(&data, sizeof(STUDENT), 1, fp);
        printf("학번=%d\n", data.id);
        printf("이름=%s\n", data.name);
        printf("전화=%s\n", data.phone);
    }
    fclose(fp);
}

 

문제 4. 전화번호 관리

전화번호를 관리하는 프로그램을 파일 입출력을 통해 만들어 보자.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct phone {
    char name[20];
    char phone[20];
} Phone;

#define FILENAME "phone.txt"

void displaymenu()
{
    printf("\n*** 전호번호 ***\n");
    printf("(1) 목록\n");
    printf("(2) 검색\n");
    printf("(3) 추가\n");
    printf("(4) 종료\n");
    printf("---------------\n");
    printf("선택하세요 : ");
}

// 파일에 몇개의 데이타가 있는지 계산
// data 수 = file 크기 / 구조체크기
// file 크기 구하기 file 끝에서 ftell(fp) / sizeof(Phone)
int getnumberofdata(FILE* fp)
{
    int filesize;
    int n;
    fseek(fp, 0, SEEK_END); // 끝으로 이동
    filesize = ftell(fp); // 파일 크기가 return 됨
    n = filesize / sizeof(Phone);
    return n;
}

// data 하나를 display 
void disp_one(Phone* data)
{
    printf("이름: %s\t전화: %s\n", data->name, data->phone);
}

// 전체 데이타 list
void list(FILE* fp)
{
    Phone data;
    int ndata;

    printf("\n** 자료 목록 **\n");
    ndata = getnumberofdata(fp);
    if (ndata == 0) {
        printf("데이타가 없습니다.\n");
        return;
    }
    fseek(fp, 0, SEEK_SET); // 처음으로 이동
    while (ndata--) {
        fread(&data, sizeof(Phone), 1, fp);
        disp_one(&data);
    }
}
void search(FILE* fp)
{
    Phone data;
    char name[20]; // 찾을 이름
    int n;
    int ndata; // 전체 data 수

    printf("\n** 자료 찾기 **\n");
    ndata = getnumberofdata(fp); //record number
    if (ndata == 0) {
        printf("Data가 없습니다.\n");
        return;
    }

    printf("찾을이름 : ");
    scanf("%s", name);

    fseek(fp, 0, SEEK_SET); // 처음으로 이동
    for (n = 0; n < ndata; n++) {
        fread(&data, sizeof(Phone), 1, fp);
        if (strcmp(data.name, name) == 0) {
            disp_one(&data);
            return;
        }
    }
    printf("찾는 데이타가 없습니다.\n");
    return;
}

// 데이타 추가
void add(FILE* fp)
{
    Phone data;
    printf("\n** 자료 추가 **\n");
    printf("이름 : ");
    scanf("%s", data.name);
    printf("전화번호 : ");
    scanf("%s", data.phone);
    fseek(fp, 0, SEEK_END); // 끝으로 이동
    fwrite(&data, sizeof(Phone), 1, fp);
}

void main()
{
    FILE* fp;
    int menu;

    // 파일을 open, 새로운 파일이면 w로 생성
    if ((fp = fopen(FILENAME, "r+b")) == NULL) { // 파일이 없으면
        fp = fopen(FILENAME, "w+b"); // 새로 생성
        if (fp == NULL) {
            printf("파일을 열 수 없습니다.\n");
            exit(0);
        }
    }

    while (1) {
        do {
            displaymenu();
            scanf("%d", &menu);
        } while (menu < 1 || menu>4);
        if (menu == 4) // 종료
            break;
        switch (menu) {
        case 1: list(fp);
            break;
        case 2: search(fp); // 이름으로 찾기
            break;
        case 3: add(fp);
            break;
        }
    }
    fclose(fp);
}

 

문제 5. 문제 4에 데이터 추가, 변경, 삭제 기능 추가

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct phone {
    char name[20];
    char phone[20];
} Phone;

#define FILENAME "phone.txt"
#define DELETED	"DELETED" // record 가 삭제되었다는 표시

void displaymenu()
{
    printf("\n*** 전호번호 ***\n");
    printf("(1) 목록\n");
    printf("(2) 검색\n");
    printf("(3) 추가\n");
    printf("(4) 변경\n");
    printf("(5) 삭제\n");
    printf("(99) 종료\n");
    printf("---------------\n");
    printf("선택하세요 : ");
}

// 파일에 몇개의 데이타가 있는지 계산
// data 수 = file 크기 / 구조체크기
// file 크기 구하기 file 끝에서 ftell(fp) / sizeof(Phone)
int getnumberofdata(FILE* fp)
{
    int filesize;
    int n;
    fseek(fp, 0, SEEK_END); // 끝으로 이동
    filesize = ftell(fp); // 파일 크기가 return 됨
    n = filesize / sizeof(Phone);
    return n;

}

// data 하나를 display 
void disp_one(Phone* data)
{
    printf("이름: %s\t전화: %s\n", data->name, data->phone);
}

// 전체 데이타 list
void list(FILE* fp)
{
    Phone data;
    int ndata;

    printf("\n** 전체 목록 **\n");
    ndata = getnumberofdata(fp);
    if (ndata == 0) {
        printf("데이타가 없습니다.\n");
        return;
    }
    fseek(fp, 0, SEEK_SET); // 처음으로 이동
    while (ndata--) {
        fread(&data, sizeof(data), 1, fp);
        if (strcmp(data.name, DELETED) == 0 && // 삭제된 곳은 skip
            strcmp(data.phone, DELETED) == 0)
            continue;
        disp_one(&data);
    }
}

// 찾아서 display 하고 record 번호를 return
int search(FILE* fp)
{
    Phone data;
    char name[20]; // 찾을 이름
    int n;
    int ndata; // 전체 data 수

    printf("\n** 자료 찾기 **\n");
    ndata = getnumberofdata(fp); //record number
    if (ndata == 0) {
        printf("Data가 없습니다.\n");
        return -1;
    }

    printf("찾을이름 : ");
    scanf("%s", name);

    fseek(fp, 0, SEEK_SET); // 처음으로 이동
    for (n = 0; n < ndata; n++) {
        fread(&data, sizeof(data), 1, fp);
        if (strcmp(data.name, DELETED) == 0 && // 삭제된 곳은 skip
            strcmp(data.phone, DELETED) == 0)
            continue;
        if (strcmp(data.name, name) == 0)
            break;
    }
    if (n >= ndata) {
        printf("찾는 데이타가 없습니다.\n");
        return -1;
    }
    disp_one(&data);
    return n; // 찾은 결과 record 번호를 return
}

void inputone(Phone* data)
{
    printf("이름 : ");
    scanf("%s", data->name);
    printf("전화번호 : ");
    scanf("%s", data->phone);
}

// 비어있는 record 를 찾는다
// 없으면 -1로 return
int getblank(FILE* fp)
{
    Phone data;
    int n;
    int ndata = getnumberofdata(fp); // 전체 data 수
    // 전체 데이타를 읽으면서 DELETED 표시가 있으면 
    // 그 n 번호를 return
    fseek(fp, 0, SEEK_SET);
    for (n = 0; n < ndata; n++) {
        fread(&data, sizeof(Phone), 1, fp);
        if (data.name == DELETED && data.phone == DELETED) return n;
    }

    return -1; // blank record 가 없다.
}
                    
// 데이타 추가
void add(FILE* fp)
{
    Phone data;
    int blank_n = getblank(fp); // 비어있는 record 번호
    printf("\n** 자료 추가 **\n");
    inputone(&data);
    // getblank() 로 비어있는 곳이 있으면 그곳에 write 하고
    // 없으면(-1이면) 끝에 추가 
    if (blank_n == -1) {
        fseek(fp, 0, SEEK_END);
        fwrite(&data, sizeof(Phone), 1, fp);
    }
    else {
        fseek(fp, sizeof(Phone), 0);
        fwrite(&data, sizeof(Phone), 1, fp);
    }
}

// 데이타 변경하기
void updateone(FILE* fp, int n)
{
    Phone data;
    printf("\n** 변경 **\n");
    // n이 -1이면 검색부터 하라고 return
    // n번 위치로 가서 읽고 보여주고
    // 새로운 데이타 입력 받고 data	
    // n번 위치로 가서 data write
    if (n == -1) {
        printf("변경할 데이터를 찾으세요.\n");
    }
    else {
        fseek(fp, sizeof(Phone) * n, 0);
        fread(&data, sizeof(Phone), 1, fp);
        printf("변경할 데이터\n");
        disp_one(&data);
        printf("새로운 데이터 입력\n");
        inputone(&data);
        fseek(fp, sizeof(Phone) * n, 0);
        fwrite(&data, sizeof(data), 1, fp);
    }
}

// 데이터 삭제하기
void deleteone(FILE* fp, int n)
{
    Phone deletedata = { DELETED, DELETED };
    Phone data;
    int ans;
    int ndata;

    printf("\n** 삭제 **\n");
    // n이 -1이면 검색부터 하라고 return
    // n번 위치로 가서 읽고 보여주고
    // 실제로 삭제하겠는지 물어보고 yes 1
    // n번 위치로 가서 write	deletedata
    if (n == -1) {
        printf("삭제할 데이터를 찾으세요.\n");
    }
    else {
        fseek(fp, n * sizeof(Phone), 0);
        fread(&data, sizeof(Phone), 1, fp);
        printf("삭제할 데이터\n");
        disp_one(&data);
        printf("삭제? (1/0) : ");
        scanf("%d", &ans);
        if (ans) {
            fseek(fp, n * sizeof(Phone), 0);
            fwrite(&deletedata, sizeof(Phone), 1, fp);
            printf("삭제되었습니다\n");
        }
        else {
            printf("취소되었습니다.\n");
        }
    }
}
void main()
{
    //Phone data;
    FILE* fp;
    //int i;
    int record_number; // 현재 찾은 record 번호
    int menu;

    record_number = -1; // 변경/삭제 대상 record 번호

    // 파일을 open, 새로운 파일이면 w로 생성
    if ((fp = fopen(FILENAME, "r+b")) == NULL) { // 파일이 없으면
        fp = fopen(FILENAME, "w+b"); // 새로 생성
        if (fp == NULL) {
            printf("파일을 열 수 없습니다.\n");
            exit(0);
        }
    }

    while (1) {
        do {
            displaymenu();
            scanf("%d", &menu);
        } while (menu != 99 && (menu < 1 || menu>5));
        if (menu == 99) // 종료
            break;
        switch (menu) {
        case 1: list(fp);
            break;
        case 2: record_number = search(fp);
            break;
        case 3: add(fp);
            record_number = -1;
            break;
        case 4: updateone(fp, record_number);
            record_number = -1;
            break;
        case 5: deleteone(fp, record_number);
            record_number = -1;
            break;
        }
    }

    fclose(fp);
}

 

문제 6. 백준 2028번

https://codejin.tistory.com/131

 

백준 2028번 C언어 풀이

https://www.acmicpc.net/problem/2028 2028번: 자기복제수 어떤 자연수 N을 제곱했을 때, 그 제곱수의 맨 뒷자리에 원래의 수 N이 다시 나타나면, 우리는 그 수 N을 자기복제수라고 한다. 예를 들면, 5의 제곱

codejin.tistory.com

 

추가) 1 ~ 10000까지의 자가복제수 출력

#include <stdio.h>

int is_selfcopy(int n)
{
    int square = n * n;
    int flag = 1;
    while (n) {
        if (n % 10 != square % 10) { 
            flag = 0;
            break;
        }
        n /= 10; square /= 10;
    }
    return flag;
}
void main()
{
    int i, netst;
    int n;
    scanf("%d", &netst);
    for (i = 1; i <= netst; i++) {
        scanf("%d", &n);
        if (is_selfcopy(n))
            printf("YES\n");
        else
            printf("NO\n");
    }

    printf("\n----- 1 ~ 10,000 자기 복제수 -----\n");
    for (n = 1; n <= 10000; n++)
        if (is_selfcopy(n))
            printf("%d %d\n", n, n * n);
}