공부/C

C언어로 배우는 프로그래밍 기초 8주차

0202_hyeon 2024. 7. 9. 11:50
반응형
SMALL

제 15장 파일 처리

01. 파일 기초

02. 텍스트 파일 입출력

03. 이진 파일 입출력

04. 파일 접근 처리

 

 

    파일의 유형: 텍스트 파일 or 이진 파일

    함수 fopen(): 파일 스트림 열기

        함수 fopen()과 fopen_s() 함수원형

        FILE * fopen(const char * _Filename, const char * _Mode);

        errno_t fopen_s(FILE ** _File, const char * _Filename, const char * _Mode);

        함수 fopen()은 파일명 _Filename의 파일 스트림을 모드 _Mode로 연결하는 함수이며, 스트림 연결에 성공하면 파일포인터를 반환하며, 실패하면 NULL을 반환한다.

        함수 fopen_s()는 스트림 연결에 성공하면 첫 번째 인자인 _File에 파일 포인터가 저장되고 정수 0를 반환하며, 실패하면 양수를 반환한다. 현재 Visual C++에서는 함수 fopen_s()의 사용을 권장하고 있다.

    함수 fclose(): 파일 스트림 닫기

        함수 fclose()

        int fclose(FILE * _File);

        fclose(f);

        함수 fclose()는 파일 스트림 f를 닫는 함수로서, 성공하면 0을 실패하면 EOF를 반환한다.

 

ex1)이름과 성적 정보 내용으로 간단한 파일을 생성

       #include <stdio.h>

       #include <stdlib.h>

 

int main(){

    char* fname = "basic.txt"; //파일명

    FILE* f; //파일 포인터

 

    char name[30] = "0202"; //파일에 쓰려는 자료

    int point = 99;

 

    /*함수 fopen()의 호출 시, 첫 인자는 파일이름, 두 번째 인자는 모드로 "w"는 쓰기 모드이며, 반환 값을 파인 포인터로 선언한 f에 대입, 만일 파일 열기에 실패하면 f에 NULL이 저장됨*/

    if((f=fopen(fname,"w"))==NULL){

        printf("파일이 열리지 않아 종료합니다.\n");

        exit(1); //파일 열기에 실패하면 메시지 출력하고 exit(1)으로 종료

    };

    //파일 "basic.txt"에 쓰기

    fprintf(f, "이름 %s 학생의 성적은 %d 입니다. \n", name, point); //지정한 파일 f에 출력 printf()를 하는 기능을 수행

    fclose(f);       //파일 처리가 종료되었으면 fclose()로 스트림을 닫음

    //표준출력 콘솔에 쓰기

   printf("이름 %s 학생의 성적은 %d 입니다. \n", name, point);

   puts("프로젝트 폴더에서 파일 basic.txt를 메모장으로 열어 보세요");

 

   return 0;

}

 

ex2) "myinfo.txt"에 데이터 출력

#include <stdio.h>

#include <stdlib.h>

 

int main(){

    FILE * f; //파일 포인터

 

   //if (fopen_s(&f, "myinfo.txt", "w") != 0) 이런 식으로 써도 됨

   if((f=fopen("myinfo.txt","w"))==NULL){

       printf("파일이 열리지 않습니다\n");

       exit(1);

   };

 

//파일에 쓰려는 자료

char tel[15] = "010-1111-1111";

char add[20] = "대구광역시"

int age = 24;

fprintf(f, "전화번호: %s, 주소: %s, 나이: %d \n", tel, add, age);

fclose(f); //파일 닫기

 

//표준 출력 콘솔에 쓰기

printf("전화번호: %s, 주소:%s, 나이: %d\n", tel, add, age);

puts("프로젝트 폴더에서 파일 myinfo.txt를 메모장으로 열어보세요.");

return 0;

 

}

 

텍스트 파일에 자료를 쓰거나 읽기 위한 함수

함수 fprintf()와 fscanf() 함수 원형

int fprintf(FILE * _File, const char * _Format, ...);

int fscanf(FILE * _File, const char * _Format, ...);

int fscanf_s(FILE * _File, const char * _Format, ...);

이 함수에서 _File은 서식화된 입출력 스트림의 목적지인 파일이며, _Format은 입출력 제어 문자열이며, 이후 기술되는 인자는 여러 개의 출력될 변수 또는 상수이다.

 

scanf_s("%s%d%d", name. 30, &point1, &point2);

fprintf(f, "%d %s %d %d \n", ++cnt, name, point1,point2);

fscanf_s(f, "%d %s %d %d\n", &cnt, name, 30, &point1, &point2);

//문자열이 저장되는 name과 그 크기(30)를 지정해야 한다.

 

기호 상수 stdin, stdout, stderr

 

ex1) 이름과 성적 2개를 입력해 그 내용을 파일에 쓰고 다시 읽어 표준 출력에 보이는 프로그램

#include <stdio.h>

#include <stdlib.h>

 

int main(){

    char fname[] = "grade.txt";

    FILE* f;

    char name[30];

    int point1, point2, cnt = 0;

 /* 첫 번째 인자는 파일 포인터의 주소, 두 번째 인자는 파일이름,  세 번째 인자는 모드로 "w"는 쓰기 모드이며, 반환값은 오류 수로 0이 아니면 파일 열기에 문제가 발생한다 */

    if(fopen_s(&f,fname,"w") != 0){

        printf("파일이 열리지 않습니다. \n");

        exit(1);   //파일 열기에 실패하면 메시지 출력하고 exit(1)으로 종료

};

printf("이름과 성적(중간, 기말)을 입력하세요. \n");

scanf("%s %d %d", name, &point1, &point2);

//scanf_s("%s%d%d, name, 30, &point1, &point2);

fprintf(f, "%d %s %d %d \n", ++cnt, name, point1, point2);

//파일 "grade.txt"에 쓰기

fclose(f);

 

//if((f=fopen(fname, "r")) == NULL)

if(fopen_s(&f, fname, "r") != 0){

    printf("파일이 열리지 않습니다. \n");

    exit(1);

};

 

//파일 "grade.txt"에서 읽기

fscanf(f, "%d %s %d %d\n", &cnt, name, &point1, &point2);

//fscanf_s(f, "%d %s %d %d\n", &cnt, name, 30, &point1, &point2);

 

//표준출력에 쓰기

fprintf(stdout, "\n%6s%16s%10s%8s\n", "번호", "이름", "중간", "기말");

fprintf(stdout, "%5d%18s%8d%8d\n", cnt, name, point1, point2);

//함수 fprintf(stdout, ...)은 함수 printf(...)로도 이용 가능

fclose(f);

//파일 읽기가 종료되었으면 fclose()로 스트림 닫기

 

return 0;

}

 

ex1)

코드 작성: 파일 출력

정수 난수(0~99) 10개를 numbers.txt에 출력

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

 

int main(){

    FILE* fp;

    int num;

    int i;

   

    srand((unsigned)time(NULL));

   

    fp = fopen("numbers.txt", "w");

    if(fp == NULL){

        printf("파일을 열 수 없습니다.\n");

        return 1;

    }

    for( i=0; i<10; i++){

        num=rand() % 100;

        fprintf(fp, "%d\n", num);

    }

    fclose(fp);

    printf("파일 쓰기 완료\n");

    return 0;

}

 

ex2)

코드 작성: 파일 입력

numbers.txt에서 정수 데이터 읽어 누적합 계산

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

 

int main(){

    FILE* fp;

    int sum = 0;

    int num;

 

    fp = fopen("numbers.txt", "r");

    if(fp == NULL){

        printf("파일을 열 수 없습니다.\n"); 

        return 1;

    }

    while(fscanf(fp, "%d", &num)==1){

        sum += num;

    }

 

   printf("%d\n", sum);

   fclose(fp);

   return 0;

}

 

함수 fgets()와 fputs()

함수 fgets()와 fputs() 함수 원형

char * fgets(char * _Buf, int _MaxCount, FILE * _File);

int fputs(char * _Buf, FILE * _File);

함수 fgets()는 _File로부터 한 행의 문자열을 _MaxCount 수의 _Buf 문자열에 입력 수행

함수 fputs()는 _Buf 문자열을 _File에 출력 수행

 

char names[80];

FILE *f;

fgets(names, 80, f);

fputs(names, f);

//fscanf는 워드 단위로 입력을 받지만 fgets은 엔터 키 들어올 때 까지 라인 단위로 입력을 받음

 

함수 feof()와 ferror()

함수 feof()와 ferror() 함수원형

int feof(FILE * _File);

int ferror(FILE * _File);

함수 feof()은 _File의 EOF를 검사

함수 ferror()는 _File에서 오류발생 유무를 검사

while(!feof(stdin)){

    ...

    fgets(names, 80, stdin); //표준입력

}

 

ex1)

여러 줄에 걸쳐 이름, 성적을 입력하여 지정된 이름의 파일에 그 내용을 모두 저장

#include <stdio.h>

#include <stdlib.h>

 

int main(){

    char fname[] = "grade.txt";

    char names[80];

    int cnt = 0;

    FILE* f;

 

    // if((f=fopen(fname, "w"))==NULL)

    if(fopen_s(&f, fname, "w") != 0){

        printf("파일이 열리지 않습니다. \n");

        exit(1);

    };

    printf("이름과 성적(중간, 기말)을 입력하세요. \n");

    fgets(names, 80, sdin);  //표준입력으로 받은 한 행을 변수 names에 저장, 한 행이 79열보다 크면 배열 names[]의 크기를 더 크게 조정

 

/*표준입력으로 여러 줄에 걸쳐 적당한 형태로 입력하고 마지막 행에는 반드시 키 ctrl+Z를 입력한 후 Enter을 친다!

 ctrl+Z를 입력하기 전 Enter을 치면 Enter값 역시 입력이 됨*/

    //콘솔에 이름 중간 기말 입력하고 Enter치고

   //계속 여러 줄에 여러 학생의 성적을 입력하다가

   //종료하고 싶을 때 새로운 줄 처음에 ctrl + Z 누르고 Enter 치면 종료

    //표준입력이 있으면 계속, ctrl+Z로 feof()이면 종료  -- while()문 반복 조건 설명

    while(!feof(stdin)){                   //ctrl+Z 표준입력의 종료 확인

    //파일 "grade.txt에 쓰기           

        fprintf(f, "%d ", ++cnt);       //맨 앞에 번호를 삽입

        fputs(names, f);                 //이후에 입력 받은 이름과 성적 2개 저장

        fgets(names, 80, stdin);    //다시 표준입력

    }

    fclose(f);

    return 0;

}

 

ex2)

#include <stdio.h>

#include <stdlib.h>

 

int main(){

    char fname[] = "grade.txt";

    char names[80];

    int cnt = 0;

    FILE* f;

 

    f = fopen(fname,"w");

    if(f==NULL){

        printf("파일이 열리지 않습니다.\n");

        exit(1);

    }

 

    printf("이름과 성적(중간, 기말)을 입력하세요.\n");

 

/*

while(fgets(names, sizeof(names), stdin) != NULL && names[0] != '\n'):

  • fgets 함수는 stdin으로부터 입력을 받아서 names 배열에 저장해요.
  • sizeof(names)는 names 배열의 크기를 의미해요. 즉, 한 번에 names 배열 크기만큼의 문자열을 입력받아요.
  • != NULL은 입력이 성공했는지 확인하는 부분이에요. fgets는 입력이 성공하면 names 포인터를 반환하고, 실패하면 NULL을 반환해요.
  • names[0] != '\n'는 빈 줄(Enter만 입력된 줄)이 입력되었는지 확인해요. 빈 줄이 입력되면 반복문을 종료해요.

*/

    while(fgets(names, sizeof(names), stdin) != NULL && names[0] != '\n'){

        fprintf(f, "%d ", ++cnt);

        fputs(names, f);

    }

 

   fclose(f);

   return 0;

}

 

함수 fgetc()와 fputc()

함수 fgetc()와 fputc() 함수원형

int fgetc(FILE * _File);

int fputc(int _Ch, FILE * _File);

int getc(FILE * _File);

int putc(int _Ch, FILE * _File);

함수 fgetc()와 getc()는 _File에서 문자 하나를 입력받는 함수

함수 fputc()와 putc()문자_Ch를 파일 _File에 출력하는 함수

//fgetc는 파일에서 문자 단위로!!

 

예제: 문자 단위 출력

ex1) 지정한 파일"05flist.c"의 내용을 행 번호를 붙여 표준 출력으로 

#include <stdio.h>

#include <stdlib.h>

 

int main(void){

    FILE* f;

 

    //if((f=fopen("05flist.c","r')) == NULL)

    if(fopen_s(&f, "05flist.c","r")!=0){  //읽기 모드로 파일 열기

        printf("파일이 열리지 않습니다. \n");

        exit(1);

    }

  

    int ch, cnt = 0; //문자를 저장할 ch, 행 번호를 저장할 cnt

   printf("%4d ", ++cnt); //1행 처음에 번호 1 출력

   while((ch=fgetc(f))!=EOF){

        putchar(ch); //putc(ch, stdout);

        if(ch=='\n'){  //2행부터 행 처음에 행 번호 출력 

            printf("%4d: ", ++cnt);  //새로운 줄에 이동했으면 다시 처음에 행 번호 ++cnt 출력

    }

   

    printf("\n");

    fclose(f);

    return 0;

}

 

ex2) 입력 파일 lab2uplowerchar.c의 내용을 읽어서 문자들의 대소문자를 반대로 바꾸고, 결과를 convertchar.c 파일에 저장하는 프로그램이에요.

#include <stdio.h>

#include <stdlib.h>

#include <stdlib.h>

#include <ctype.h>

 

int main(void){

    FILE* f1, *f2;

    if((f1=fopen("lab2uplowerchar.c", "r"))==NULL){

        printf("cannot open this file\n");

        exit(1);

    }

    if((f2=fopen("convertchar.c","w"))==NULL){

        printf("cannot open this file\n");

        fclose(f1);

        exit(1);

    }

 

    char a;

// 파일 내용을 한 문자씩 읽고 처리

    while((a=getc(f1))!=EOF){

        if(isalpha(a)){

// 소문자이면 대문자로 변환

            if(islower(a)){

                a=toupper(a);

            }

// 대문자이면 소문자로 변환

            else if(isupper(a)){

                a = tolower(a);

            }

// 변환된 문자를 출력 파일에 쓰기

        putc(a,f2); //fputc(a,f2);

        }

   }

 

   fclose(f1);

   fclose(f2);

   printf("File convertchar.c is created !!!\n");

 

   return 0;

}

            

 

제 11장 포인터 기초

01. 포인터 변수와 선언

02. 간접연산자 *와 포인터 연산

03. 포인터 형변환과 다중포인터

04. 포인터를 사용한 배열 활용

 

주소 개념 고유한 주소(address)

-메모리 주소는 저장 장소인 변수이름과 함께 기억장소를 참조하는 또 다른 방법

포인터 변수? 메모리의 주소를 저장할 수 있는 변수

포인터 변수는 그 메모리에 해당되는 데이터 타입에 따라 자료형이 결정됨

 

여러 포인터 변수 선언과 NULL 주소값 대입

int *ptr1, *ptr2, *ptr3; //ptr1, ptr2, ptr3모두 int형 포인터다!!(포인터는 *을 써야함)

int *ptr1, ptr2, ptr3; //ptr1은 int형 포인터지만 ptr2와 ptr3는 int형 변수임

 

int *ptr = NULL;

#define NULL ((void*)0)

 

간접연산자(indirection operator) *을 사용한 역참조

p는 그 메모리 주소를, *p는 그 메모리 주소에 있는 값(==즉, 데이터 변수 그 자체)을 쓸 수 있다 

 

포인터 p가 가리키는 변수가 data라면 *p는 변수 data를 의미

*p로 data 변수 저장 장소인 l-value 와 참조 값인 r-value로 참조 가능

변수 data로 가능한 작업은 *p로도 가능

ex) *p = 200;

tip) 주소연산자 &와 간접연산자 *

주소 연산 '&변수'는 변수의 주소값이 결과값

간접 연산 '*포인터변수'는 포인터 변수가 가리키는 변수 자체가 결과값

 

공통점

모두 전위 연산자.

 

차이점

'*포인터 변수'는 l-value와 r-value로 모두 사용이 가능하나, 주소값인 '&변수'는 r-value로만 사용이 가능하다.

'*포인터 변수'와 같이 간접연산자는 포인터 변수에만 사용이 가능하나, 주소연산자는 '&변수'와 같이 모든 변수에 사용이 가능하다.

 

포인터 변수의 연산

주소 연산 : 간단한 더하기와 뺄셈 연산으로 이웃한 변수의 주소 연산을 수행

                  절대적인 주소의 계산이 아니며, 변수 자료형의 상대적인 위치에 대한 연산

 

ex)

int main(){

    int arr[] = (1,2,3,4,5};

    int length = sizeof(arr) / sizeof(arr[0]);

    int* p = arr;

    

    for (int i = 0; i< length; i++){

         printf("%p : %d \n", (p+i), *(p+i));

    }

 

    return 0;

}

 

ex2) 포인터를 이용하여 두 수의 값을 교환하는 프로그램

void swap(int* x, int* y){

    int t;

    t=*x;

    *x=*y;

    *y=t;

}

int main(){

    int num1, num2;

    scanf_s("%d%d", &num1, &num2);

    swap(&num1, &num2);

    printf("%d, %d\n", num1, num2);

    return 0;

}

 

변수의 내부 저장 표현

 

명시적 형변환

포인터 자료형의 변환

 

반응형
LIST