티스토리 뷰
출판사 매출관리 프로그램을 만듭니다.
책 제목, 매출 단가 (단위는 만원), 판매 부수(양수는 출고, 음수는 반품)를 저장한 파일에서 데이터를 읽어
도서별 최종 매출액을 출력합니다.
책의 종류는 10개 이하로 가정하며 매출이 가장 높은 책부터 정렬하여 파일로 출력합니다.
책 제목, 매출 단가(단위는 만원), 판매 부수(양수는 출고, 음수는 반품)를 저장한 파일은 "a.txt"이고,
프로그램을 실행한 결과로 생기는 파일은 "b.txt"이며 내용은 다음과 같습니다.
a.txt | b.txt |
해커와 화가 1.62 150 빅데이터 분석 3.2 -15 케스케이팅 완벽 가이드 2.0 80 해커와 화가 1.8 75 알고리즘 트레이닝 2.5 95 안드로이드 프로그래밍 3.15 125 빅데이터 분석 3.2 50 알고리즘 트레이닝 2.5 -5 알고리즘 트레이닝 2.5 29 케스케이팅 완벽 가이드 2.0 -35 |
1. 안드로이드 프로그래밍-3937500원 2. 해커와 화가-3330000원 3. 알고리즘 트레이닝-2975000원 4. 빅데이터 분석-2720000원 5. 케스케이팅 완벽 가이드-900000원 |
다음은 제가 작성한 코드입니다.
#include <stdio.h>
#include <string.h>
typedef struct
{
double sales;
char name[80];
} Book;
int main(void)
{
FILE* pFileA, * pFileB;
Book book[10];
Book* pBook[10];
//Book 포인터에 순서대로 주소 대입
for (int i = 0; i < 10; i++)
{
pBook[i] = book + i;
}
//book 구조체 배열의 모든 요소의 멤버 초기화
for (int i = 0; i < 10; i++)
{
char str[80] = {'\0'};
book[i].sales = 0;
strcpy(book[i].name, str);
}
//a.txt 파일 개방
pFileA = fopen("a.txt", "r");
if (pFileA == NULL)
{
printf("파일을 열지 못했습니다.\n");
return 1;
}
//a.txt의 데이터 읽고 구조체에 저장
int count = 0;
while (1)
{
char* res;
int bookCount;
double bookPrice;
char bookName[80];
res = fgets(bookName, 79, pFileA);
if (res == NULL) break;
bookName[strlen(bookName) - 1] = '\0';
fscanf(pFileA, "%lf", &bookPrice);
fscanf(pFileA, "%d", &bookCount);
fgetc(pFileA);
//같은 이름의 책이 이미 저장되어 있는지 검사하고 저장
for (int i = 0; i < 10; i++)
{
//같은 이름의 책이 없으면 새로 저장
if (book[i].name[0] == '\0')
{
strcpy(book[i].name, bookName);
book[i].sales += bookCount * bookPrice * 10000;
count++;
break;
}
//같은 이름의 책이 있으면 해당 구조체에 저장
if (strcmp(bookName, book[i].name) == 0)
{
book[i].sales += bookCount * bookPrice * 10000;
break;
}
}
}
fclose(pFileA);
//b.txt 파일 새로 생성(미리 만들지 않았다면)
pFileB = fopen("b.txt", "w");
if (pFileB == NULL)
{
printf("파일을 생성하지 못했습니다.\n");
return 1;
}
//sales의 값이 큰 것부터 순서대로 정렬
while (count >= 2)
{
for (int i = 0; i < count - 1; i++)
{
if (pBook[i]->sales < pBook[i + 1]->sales)
{
Book* temp;
temp = pBook[i];
pBook[i] = pBook[i + 1];
pBook[i + 1] = temp;
}
}
count--;
}
//b.txt 파일에 출력
for (int i = 0; i < 10; i++)
{
if (book[i].name[0] == '\0') break;
fprintf(pFileB, "%d. ", i + 1);
fputs(pBook[i]->name, pFileB);
fprintf(pFileB, "-");
fprintf(pFileB, "%.0lf", pBook[i]->sales);
fprintf(pFileB, "원\n");
}
fclose(pFileB);
return 0;
}
먼저 해당 프로그램을 실행하면서 b.txt파일을 확인해 봤을 때 한글이 제대로 출력되지 않고 깨져 있었습니다.
이는 인코딩의 문제입니다.
컴퓨터는 1과 0의 조합으로 데이터를 저장합니다.
그리고 1과 0으로 똑같이 구성된 데이터라고 해도
이를 어떤 규칙에 의해 읽을 것이냐에 따라서 데이터를 읽었을 때의 값이 달라집니다.
1과0의 조합을 어떤 규칙을 통해 읽을 것이냐 하는 것이 바로 인코딩이라고 볼 수 있습니다.
a.txt 텍스트 파일에는 한글이 저장되어 있으나 이를 프로그램에서 읽는 과정에서 읽는 방식이 맞지 않았기 때문에
한글을 제대로 표현하지 못했습니다.
이를 해결하는 방식은 인코딩 방식을 알맞게 바꿔주는 것입니다.
a.txt파일을 열고 '다른이름으로 저장'을 클릭하면 다음과 같은 창이 열립니다.
해당 창에서 인코딩 방식을 ANSI로 바꾸어 줍니다.
이후 코드를 살펴보겠습니다.
typedef struct
{
double sales;
char name[80];
} Book;
구조체의 형식 선언과 동시에 재정의까지 수행했습니다.
구조체는 매출 단가와 판매 부수를 곱해서 더하는 총 매출과 책의 이름을 저장합니다.
FILE* pFileA, * pFileB;
Book book[10];
Book* pBook[10];
//Book 포인터에 순서대로 주소 대입
for (int i = 0; i < 10; i++)
{
pBook[i] = book + i;
}
구조체 배열을 선언하고 같은 개수의 구조체 포인터 배열도 선언했습니다.
이후 구조체 포인터 배열에 각각 구조체 배열들의 주소를 대입해주었습니다.
res = fgets(bookName, 79, pFileA);
if (res == NULL) break;
bookName[strlen(bookName) - 1] = '\0';
무한 반복문 내에서 fgets 함수를 사용해 a.txt 파일의 책 제목을 입력합니다.
fgets는 더 이상 읽을 데이터가 없으면 NULL포인터를 반환합니다.
fgets 함수는 문자를 입력받으면서 마지막에 엔터까지 문자에 포함합니다.
따라서 마지막에 저장된 엔터는 널문자로 바꿔주었습니다.
fscanf(pFileA, "%lf", &bookPrice);
fscanf(pFileA, "%d", &bookCount);
fgetc(pFileA);
이후 fscanf 함수를 이용해 매출 단가와 판매부수도 저장합니다.
fscanf 함수로 숫자를 입력 받을 경우 화이트스페이스 문자들은 모두 무시됩니다.
이후 fscanf함수는 데이터를 입력하면서 마지막 엔터는 입력하지 않습니다.
때문에 버퍼에 남아있는 개행문자를 fgetc 함수를 사용해 버려주었습니다.
나머지는 어려운 부분이 없습니다.
다음 시간엔 '전처리와 분할 컴파일'에 대해서 배우겠습니다.
'공부 일지 > C언어 공부 일지' 카테고리의 다른 글
분할 컴파일 (0) | 2021.02.05 |
---|---|
전처리와 분할 컴파일 (0) | 2021.02.04 |
파일 입출력 실전문제2 (2) | 2021.02.01 |
파일 입출력 실전문제1 (0) | 2021.02.01 |
다양한 파일 입출력 함수 (0) | 2021.02.01 |