코딩일지(2024-01-08)
계절학기-후반부 스케줄
이수 과정
1_15.파일처리 - 텍스트파일(1)
2_11. 포인터 기초(1)
3_11.포인터 기초(2)
4_16. 동적할당(1)
5_14. 함수와 포인터 활용
6_12. 문자와 문자열
7_13. 구조체와 공용체
8_15. 파일처리 - 이진파일(2)
9_16. 동적할당(2) - 연결리스트, 전처리
시험관련
16일날 시험봄
필기 50분
실기 2시간
하 ㅅㅂ… 족보부터 돌려야 겠다.
파일처리(1)
이름과 성적 정보 내용으로 간단한 파일(basic.txt) 생성하기
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
FILE* f;
char* fname = "basic.txt";
char name[30] = "손혜진";
int point = 100;
f = open(fname, "w");
if (f == NULL)
{
printf("파일이 열리지 않습니다.\n");
exit(1); //프로그램 종료
}
fprintf(f, "이름 %s 학생의 성적은 %d 입니다.\n", name, point);
fclose(f);
printf("이름 %s 학생의 성적은 %d 입니다.\n");
puts("프로젝트 폴더에서 파일 basic.txt를 메모장으로 열어보세요.");
return 0;
}
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
int main(void)
{
FILE* fs;
fs = fopen("basic.txt", "r");
char str[MAX_LEN];
fgets(str, MAX_LEN, fs);//파일의 내용을 데이터로 읽어서 버퍼에 넣어줌
printf("%s", str);//버퍼에 있는 데이터를 콘솔에 출력
return 0;
}
코드리뷰::
Q1. #pragma warning(disable:4996)는 왜 썼는지?
Q2. fgets은 왜썼는지?
콘솔창에서 데이터를 출력해줄때, 해당 데이터를 버퍼에서 긁어오는 방식이라서 버퍼에 데이터를 채워주어야 함. 이 동작을 fgets()가 해줌.
이슈: 파일에 한글이 있을때만 깨져서 출력됨.
이는 인코딩 방식의 설정을 잘못해줘서 발생한 문제이다. 영어만 쓸꺼면 UTF-8
을 사용해주면 되지만, 그 외에 한글도 쓰고 싶다면 둘다 가능한 ANSI
방식으로 인코딩처리방식을 변환해주어야 한다.
FILE* fs에서 이 FILE이라는 구조체는 뭘까?
라이브러리를 뒤져보니
//corecrt_wstdio.h
//....
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Stream I/O Declarations Required by this Header
//
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#ifndef _FILE_DEFINED
#define _FILE_DEFINED
typedef struct _iobuf
{
void* _Placeholder;
} FILE;
#endif
이름과 성적 정보 내용으로 간단한 파일(basic.txt) 생성하기(최종본)
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
int main(void)
{
FILE* fs;
char* fname = "basic.txt";
fs = fopen(fname, "r");
//예외처리
if (fs == NULL)
{
printf("파일이 열리지 않습니다.\n");
exit(1);
}
//파일에 read(before)
char str[MAX_LEN];
fgets(str, MAX_LEN, fs);
printf("파일에 적혀있던 내용입니다.>\n", str);
printf("%s", str);
//파일에 write
char name[30] = "손혜진";
int score = 100;
fprintf(fs, "이름: %s 학생의 성적: %d\n", name, score);
fclose(fs);
//파일에 write(after)
printf("\n\n새롭게 편집된 내용입니다>\n");
printf("이름 %s 학생의 성적은 %d입니다.\n", name, score);
puts("\n프로젝트 폴더에서 파일 basic.txt를 메모장으로 열어보세요.\n");
return 0;
}
result>
파일에 적혀있던 내용입니다.> 학생입니다
새롭게 편집된 내용입니다> 이름 손혜진 학생의 성적은 100입니다.
프로젝트 폴더에서 파일 basic.txt를 메모장으로 열어보세요.
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
int main(void)
{
FILE* f;
f = fopen("myinfo.txt", "w");
if (f == NULL)
{
printf("파일이 열리지 않습니다.\n");
exit(1);
}
char tel[15] = "010-3018-3824";
char add[30] = "서초구 대정로 557";
int age = 22;
//파일 "basic.txt"에 쓰기
fprintf(f, "전화번호: %s, 주소: %s, 나이: %d\n", tel, add, age);
fclose(f);
printf("전화번호: %s, 주소: %s, 나이: %d\n", tel, add, age);
puts("프로젝트 폴더에서 파일 myinfo.txt를 메모장으로 열어 보세요.");
return 0;
}
※고찰
애초에 해당 파일을 생성해야만 거기다가 적을 수 있는 줄 알았는데, 그게 아니라, 그냥 입력데이터를 버퍼에 넣고 파일을 알아서 생성하고 버퍼에 저장된 내용을 발로 텍스트 파일에 넣어주는 것 같다.
한개의 이름과 두개의 성적을 입력해 그 내용을 파일에 쓰고 다시 읽어내기
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char fname[] = "grade.txt";
FILE* f;
char name[30];
int point1, point2, cnt = 0;
if (fopen_s(&f, fname, "w") != 0)
{
printf("파일이 열리지 않습니다. \n");
exit(1);
}
printf("이름과 성적(중간, 기말)을 입력하세요.\n");
scanf("%s %d %d", name, &point1, &point2);
fprintf(f, "%d %s %d\n", ++cnt, name, point1, point2);
fclose(f);
if (fopen_s(&f, fname, "r") != 0)
{
printf("파일이 열리지 않습니다.\n");
exit(1);
}
//파일 "grade.txt"에서 읽기
fscanf(f, "%d %s %d %d\n", &cnt, name, &point1, &point2);
fprintf(stdout, "\n%6s%16s%10s%8s\n", "번호", "이름", "중간", "기말");
fprintf(stdout, "%5d%18s%8d%8d\n", cnt, name, point1, point2);
fclose(f);
return 0;
}
이름과 성적(중간, 기말)을 입력하세요. 윤성웅 98 87
번호 이름 중간 기말 1 윤성웅 98 87
다양한 키워드!
feof(FILE* stream): 파일의 끝에 도달했는지 여부를 확인할
파일의 끝에 도달하면 1을 반환, 그렇지 않으면 0 반환
fgets(): 데이터를 라인단위로 읽어들임
get관련 정리
1.getchar()
2.fgets()
put관련 정리
1.putchar()
2.fputs()
여러 줄에 걸쳐 이름, 성적을 입력하여 지정된 이름의 파일에 그 내용을 모두 저장
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char fname[] = "grade.txt";
char names[80];
int cnt = 0;
FILE* f;
if (fopen_s(&f, fname, "w") != 0)
{
printf("파일이 열리지 않습니다.\n");
exit(1);
};
printf("이름과 성적(중간,기말)을 입력하세요.\n");
fgets(names, 80, stdin);
//콘솔에 이름 중간 기말 입력하고 Enter 치고
//계속 여러 줄에 걸쳐 여러 학생의 성적을 입력하다가
//종료하고 싶을 때 새로운 줄 처음에 ctrl + z누르고 Enter 치면 종료
while (!feof(stdin))
{ //파일 "grade.txt"에 쓰기
fprintf(f, "%d ", ++cnt);
fputs(names, f);
fgets(names, 80, stdin);
}
fclose(f);
return 0;
}
이름과 성적(중간,기말)을 입력하세요. 윤성웅 89 100 최준수 60 100 김민수 98 89 ^Z
위와 같이 콘솔창에 입력하면(^Z는 콘솔창 종료) grade.txt라는 파일이 생성되고 거기에 해당 내용이 저장된다.
참고로, 위 while문은 아래와 같이 조건형태를 바꿔볼수도 있다.
while (fgets(names, 80, stdin))
{ //파일 "grade.txt"에 쓰기
fprintf(f, "%d ", ++cnt);
fputs(names, f);
fgets(names, 80, stdin);
}
위와 같이 바꿀수 있는 이유에 대해서는 공식문서를 참고하자!(링크)
좋은 코드를 레퍼런스하려고 신경쓰자!
지정한 파일 “05flist.c”(c파일)의 내용을 행 번호를 붙여 표준출력으로 그대로 출력하는 프로그램
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS
#define MAX_LEN 100
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE* f;
if (fopen_s(&f, "05flist.c", "r") != 0)
{
printf("파일이 열리지 않습니다. \n");
exit(1);
}
int ch, cnt = 0;
printf("%4d: ", ++cnt);
while ((ch = fgetc(f)) != EOF)
{
putchar(ch);
if (ch == '\n')
printf("%4d: ", ++cnt);
}
printf("\n");
fclose(f);
return 0;
}
위 코드를 실행해보면 다음과 같이 텍스트 c파일의 코드들으 모조리 가져와 주는 것을 알수가 있었다.
더 나아가서 c언어로 텍스트 에디터도 만들수 있지 않을까 하는 생각이 든다.그러면?
- 엘리베이터 만들기
- 테트리스 만들기
- C언어로 Editor만들기
이렇게 될수가 있겠다 ㅋㅋㅋ
문자를 숫자로 바꿔주는 법
‘1’-‘0’ -> (int)1
‘0’-‘0’ -> (int)0
파일에서 읽은 문자를 가지고 대소문자 변환후 다른파일에 써보기
//main.c
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
FILE* f1, * f2;
if ((f1 = fopen("main.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;
}
고찰: 처음에 파일 이름은 main.c인데, if ((f1 = fopen("main.c", "r")) == NULL)
부분에서 실행코드의 파일명을 잘못 기입하여 디버그 에러가 발생했다.
코드의 본래의도를 파악하지 못해서 발생한 이슈였다. 코드리뷰를 해보자면, 현재 실행파일의 코드를 긁어와서
그래서 convertchar.c파일을 확인해보면 모두 대문자로 바뀌어 있는 것을 알수가 있다.
//convertchar.c
#PRAGMA WARNING(DISABLE:4996)
#INCLUDE <STDIO.H>
#INCLUDE <STDLIB.H>
#INCLUDE <CTYPE.H>
INT MAIN(VOID)
{
file* F1, * F2;
IF ((F1 = FOPEN("MAIN.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;
}
포인터 기초(1)
메모리 주소 연산자와 주소 출력
//main.c
#pragma warning(disable:4996)
#include <stdio.h>
int main(void)
{
int input;
printf("정수 입력: ");
scanf("%d", &input);
printf("입력 값: %d\n", input);
printf("주소값: %p(16진수)\n", &input);
printf("주소값: %llu(10진수)\n", (uintptr_t)&input);
printf("주소값 크기: %zu\n", sizeof(&input)); //%zd도 가능
return 0;
}
정수 입력: 100 입력 값: 100 주소값: 000000C1E68FF914(16진수) 주소값: 832796883220(10진수) 주소값 크기: 8
참고로 변수를 기본값 0으로 초기화하듯이, 포인터는 기본값 NULL로 초기화한다.
int *ptr = NULL;
물론 이렇게라고 안하면 포인터가 쓰레기 주소값을 저장하게 되니까,, 좀… 그렇다ㅋㅋ(그냥 좋지는 않음ㅇㅇ)
그래서 위와 같이 해주는 건데 좀 귀찮다 싶으면 매크로 상수를 써주면 편하다.일일이 NULL로 초기화해줄 필요가 없다.
#define NULL ((void *)0)
포인터 변수와 간접연산자 *를 이용한 간접참조
//main.c
#pragma warning(disable:4996)
#include <stdio.h>
int main(void)
{
int i = 100;
char c = 'A';
int* pi = &i;
char* pc = &c;
printf("간접참조 출력: %d %c\n", *pi, *pc);
*pi = 200; //*pi가 가리키는 곳(i)에 200을 넣어줌
*pc = 'B'; //*pc가 가리키는 곳(c)에 문자'B'를 넣어줌
printf("직접참조 출력: %d %c\n", i, c);
//만약 이렇게 되면 200은 메모리 상에 아직 남아있는지?
//아니면 메모리가 해제되는지?
pi = NULL;
return 0;
}
위와 같이 마지막줄에 pi = NULL
를 써주면 메모리가 해제되는지 궁금해서 여쭤보았다.
헷갈린게 이렇게 하면 i에 200이 들어가 있는 꼴이니 pi=NULL
을 해주든 안해주든 상관없다.
포인터를 이용하여 두수의 값을 교환해보기
함수는 기본적으로 하나밖에 반환을 못해준다.
그럴때 우리는 포인터를 활용해서 여러개를 반환해주는 게 가능하다.
//main.c
#pragma warning(disable:4996)
#include <stdio.h>
void swap(int* x, int* y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
int main(void)
{
int num1, num2;
scanf_s("%d%d", &num1, &num2);
swap(&num1, &num2);
printf("%d %d\n", num1, num2);
return 0;
}
실습문제2)참조코드
참조1)
“f3.txt”파일에서 숫자를 추출하여 총합을 계산하는 C언어 코드입니다. 코드는 파일을 읽어온 후, 문자열에서 숫잘를 추출하고 총합을 계산합니다.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 100
int main(void)
{
FILE* f;
if (fopen_s(&f, "f3.txt", "r") != 0)
{
printf("파일이 열리지 않습니다. \n");
exit(1);
}
char inputStr[MAX_LEN];
int numbers[MAX_LEN];
int numbersCount = 0;
// 파일 내용 읽기
if (fgets(inputStr, MAX_LEN, f) == NULL)
{
printf("파일 내용을 읽을 수 없습니다.\n");
fclose(f);
exit(1);
}
fclose(f);
// 숫자 추출 및 합 계산
int sum = 0;
const char* currentPos = inputStr;
while (*currentPos != '\0')
{
if (isdigit(*currentPos))
{
printf("number> %d\n", atoi(currentPos));
numbers[numbersCount++] = atoi(currentPos);
while (isdigit(*currentPos))
currentPos++;
}
else
{
currentPos++;
}
}
// 출력
printf("추출된 숫자 배열: ");
for (int i = 0; i < numbersCount; i++)
{
printf("%d ", numbers[i]);
sum += numbers[i];
}
printf("\n");
printf("숫자의 총 합: %d\n", sum);
return 0;
}
참조2
파일에 있는 숫자들을 일의자리씩 추출해서 모두 더하여 출력합니다.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 100
int main(void)
{
FILE* f;
if (fopen_s(&f, "f3.txt", "r") != 0)
{
printf("파일이 열리지 않습니다. \n");
exit(1);
}
int ch, cnt = 0;
int sum = 0;
int countOne = 0;
while ((ch = fgetc(f)) != EOF)
{
if (isdigit(ch))
{
int digit = ch - '0';
printf("\ndigit: %d ", digit);
sum += digit;
printf("\n");
}
}
printf("숫자의 총 합: %d\n", sum);
fclose(f);
return 0;
}
최종 CI코드
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 100
int main(void)
{
FILE* f,*file_export;
if (fopen_s(&f, "f3.txt", "r") != 0)
{
printf("파일이 열리지 않습니다. \n");
exit(1);
}
if ((file_export = fopen("f3out.txt", "w")) == NULL)
{
printf("cannot open this file\n");
fclose(f);
exit(1);
}
int ch, cnt = 0;
int sum = 0;
int countOne = 0;
while ((ch = fgetc(f)) != EOF)
{
if (isdigit(ch))
{
int digit = ch - '0';
sum += digit;
putc(ch, file_export);
}
}
printf("%d\n", sum);
fclose(f);
fclose(file_export);
return 0;
}
댓글남기기