[성적처리프로그램] 결과분석
친구 덕에 시작하게 되었지만
나에게 정말 도움이 많이 되었던 프로젝트.
제대 후 할일없어서 방바닥 긁던 나에게
목표를 설정해 준 프로젝트.
이거 때문에 완전 고생했음에도
치킨 두마리 얻어먹고 방긋 웃었던 프로젝트.ㅋㅋ
이렇게 열심히 해다 줬더니만....
결국 기말시험을 망쳐서
'B-'를 받았다고 하더라는....^^;;
자 이제 분석을 해보기에 앞서
만에 하나
이 내용이 어느 포털 사이트 검색의 결과물로 나오더라도, 이 코드 그대로 카피해서 제출하는 일이 없기를 간절히 바랍니다. 이 프로젝트의 내용은 모 대학에서 2007년 여름학기에 실제 과제로 제출되었던 내용입니다. 따라서 추후에도 충분히 과제로 다시 나올 가능성이 있다고 봅니다.
이 허접한 프로그램의 저작권은 본 블로그의 주인에게 있습니다. 본인은 순수히 본인 또는 누군가의 학업증진을 위해 소스코드를 올린 것일뿐,, 여러분의 학점향상의 도구 역할을 하고픈 마음은 없습니다. 그래도 베끼고 싶다면 차라리 제게 연락을 하세요. 치킨 두마리면 진지하게 생각해보겠습니다.ㅋㅋㅋㅋㅋㅋ
베끼지 맙시다. 베껴서 도움되는 것은 하나도 없습니다.
당신만 베끼면 다행이지만 누군가 이걸 또 베껴서 낸다면 어떻게 되겠습니까?ㅋㅋ
공부합시다. 기본적인 내용입니다. 공부하면 이런거 금방 만들 수 있지요.
=============================================================================================================================================================
이 프로그램의 간단한 구조는 다음과 같다.
main()
텍스트파일 읽기 & 메모리에 저장하기
메모리의 내용을 성적순으로 정렬하기(f_sort())
성적과 석차에 맞게 학점 매기기
성적순으로 파일에 출력하기
중간고사와 기말고사 데이터만 따로 뽑아서 분포도 출력
f_sort()
배열을 넘겨받아 내림차순으로 정렬
간단하게 눈으로 죽 훑어본다면 "이거 별거 아니군요"라고 할 수도 있을 것이다.
나도 처음엔 '이거 치킨 두마리 벌기 쉽구나' 생각하면서 금방 끝나겠지 하는 마음으로 뛰어들었다가
세세한 부분으로 파고들면서 점점 짜증이 낫던 기억이 있다.
기본적인 구조는 쉽지만 자세히 파고 들다보면
세부적으로 사소한 것들이 문제가 생기는 경우가 있어서
그러한 부분을 하나하나 처리해주는 것이 어렵다...기 보단 좀 귀찮다.
누구야. 이런 플젝을 내주는 사람은. ㅋㅋ
1. 파일 입출력 *
파일 입출력은 기본내용이므로 생략(소스 참조)
strtok()함수를 사용하여 문자열을 " "단위로 끊어서 필요한 문자열만 배열에 저장한다는 거 정도?
atoi()함수를 사용하여 문자열로 읽어온 숫자 "23"같은 걸 실제 정수 23의 형태로 변환한다는 내용 정도?
굳이 짚고 넘어간다면 위의 두 내용 정도가 될 듯.(역시 소스 참조)
2. 성적순으로 오름차순 정렬 **
이 오름차순 정렬 방식은 본인이 알고 있는 유일한 방법이며
사실 이보다 더 효율적인 방법도 없는거 같다....(있긴 있을것이다.)
f_sort() 함수 내부를 살펴보면,,,
for(i=1 ; i<=num ; i++)
for(j=i ; j<=num ; j++) {
if(score[i]<score[j]) {
temp_score=score[i];
score[i]=score[j];
score[j]=temp_score;
strcpy(temp_name, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], temp_name);
}
}
배열을 처음부터 끝까지 읽어가면서, 현재 값보다 뒤쪽에 있는 값이 더 클 경우 두 값의 자리를 바꿔주어 큰 값이 앞으로 오도록 하는 방식. 배열의 모든 값을 처음거부터 차례로 검사하기 때문에 빠지는 부분 없이 모든 데이터가 순차적으로 정렬된다.
더 효율적인 방법도 분명 있을거라 생각되지만, 나중에 배워야지.ㅋㅋ
3. 학점 매기기(동점자 처리) *****
프로그램에서 제일 고생했던 부분이다. 학점은 참 민감한 부분이라는 걸 다시 느끼는구나;;
주어진 문제에서는 A 20%, B 30%, C 30%, D 15%, F 5%로 끝났고 더 신경쓸 것이 없어 보이지만,
커트라인 근처에서 동점자가 발생할 경우에는 판정이 골치가 아파진다.
동점자의 경우는 동점이 나온 학생 모두를 묶어서 학점을 주어야 한다. 예를 들어 모든 학생이 공부를 열심히 해서 모두 똑같이 100점이 나왔다면, 실제 우리가 다니는 학교에서는 "어이쿠 님하 잘했어여~"하면서 모두 A를 줄 지도 모르지만,... 적어도 이 프로그램 상에서는.... 전원 F학점이 나와야 한다.
A B C D 학점을 줄 수 있는 최대 범위는 모두 합해서 95%인데, 100% 학생전원이 만점을 받았으므로,, 실제로는 들어갈 자리가 F학점 외에는 없게 되는 것.
동점자 처리를 하지 않는다면, 동점자가 발생했을 경우 입력파일에 먼저 있는 사람 순으로 석차가 매겨진다.. 그리하여 시험 점수를 동일하게 받더라도 운이 좋아서(줄을 잘서서 ㅋ) 좋은 학점을 받는 불상사가...
한참을 고민했다. 치킨 두마리가 역시 쉽지 않았다.
하지만 결국 모든 문제는 그 답이 나오기 마련.
크게 두 가지를 생각해야 한다.
* 우선 동점자를 어떻게 찾아낼것인가.
* 찾아낸 동점자에게 학점을 어떻게 부여할 것인가.
동점자를 찾아내는 것은 어렵지 않다. 바로 앞사람 점수와 비교해서 같으면 동점자이므로.
동점자에게 학점을 부여하는 방법은 다음과 같다.
석차순으로 쭉 나열한 다음, 석차가 높은 사람부터 학점을 준다면,
커트라인에 걸쳐있는 동점자는 높은 학점을 받게 된다 즉 학점의 최대 수용범위를 넘어서게 된다.
그러나
석차가 낮은 사람부터 학점을 준다면 즉 밑에서부터 학점을 매긴다면,
커트라인에 걸쳐있는 동점자는 자연스럽게 낮은 학점을 받게 되므로 학점 수용 범위를 지킬 수 있는것.
이거 글로 쓰려고 하니 어려운데..
위에서 보았던 전원 100점의 경우로 예를 들어 설명하자.
석차가 높은 사람부터 학점을 주면
맨 처음 학생은 20% 안쪽에 있으므로 A학점을 주고,
그 다음 학생은 동점자이므로 똑같이 A를 주고,
그 다음 학생도 마찬가지로 A를 주고 또 A를 주고 결국 전원 A를 받게 된다. 그러나
석차가 낮은 사람부터 학점을 주면
꼴등한 학생은 95% 보다 바깥쪽에 있으므로 F를 받게 되고
뒤에서 두번째 학생은 동점자이므로 똑같이 F를 주고,
그다음 그다음 그다음 쭉 학점을 주어서 모두 F가 나오게 되는 것.
사실 별거 아니다.ㅋㅋ 내가 생각해낸거라면 누구나 생각해낼수 있는것.
해당 부분의 코드를 보면 "뭐야 님하 이게 끝이야?"라는 생각이 들 정도로 간단한 부분.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//계산식을 따로 정의. 공식을 수정할 필요가 생길 경우 이 부분을 수정해주면 된다.
#define f(i) (hw_1[i]/10)*5+(mid_term[i]/100)*30+(hw_2[i]/10)*10+(final[i]/100)*40+(project[i]/20)*15
#define MAX_STUDENT 100
void f_sort(char name[100][20], double score[], int num);
void main()
{
/***********************변수 정의*************************/
//텍스트파일에서 읽어온 값을 저장하는 배열
char name[MAX_STUDENT][20]={"\0"};
float hw_1[MAX_STUDENT]={0};
float mid_term[MAX_STUDENT]={0};
float hw_2[MAX_STUDENT]={0};
float final[MAX_STUDENT]={0};
float project[MAX_STUDENT]={0};
char temp[100];
//총점을 저장하는 배열
double score[MAX_STUDENT]={-1};
//학점을 저장하는 배열
char grade[MAX_STUDENT];
int i=0;
int j=0;
//int ranking=0;
int num_of_student=0; //실제 학생수가 저장될 변수
float percentage=0;
/**********************데이터 입력************************/
//파일을 읽어들인다. 오류시 메시지를 출력한다.
FILE *fp;
if((fp=fopen("input.txt", "rt"))==NULL)
{
printf("\"input.txt\" 파일을 읽는데 오류가 있습니다. 프로그램을 종료합니다.\n");
exit(1);
}
printf("\"input.txt\" 파일 읽기...");
//텍스트파일에서 문자열을 한줄씩 읽은 다음
//탭 단위로 문자열을 끊어 순차적으로 배열에 저장함.
while(i<MAX_STUDENT && fgets(temp, 100, fp)!=NULL)
{
strcpy(name[i],strtok(temp," \t\n"));
hw_1[i]=(float)atoi(strtok(NULL," \t\n")); //문자열을 소수형으로 변환
mid_term[i]=(float)atoi(strtok(NULL," \t\n"));
hw_2[i=(float)atoi(strtok(NULL," \t\n"));
final[i]=(float)atoi(strtok(NULL," \t\n"));
project[i]=(float)atoi(strtok(NULL," \t\n"));
i++;
num_of_student++;
}
num_of_student--;
printf("데이터 읽기 성공!\n");
fclose(fp);
/**********************데이터 정렬************************/
//총점계산후 배열에 저장
for(i=1 ; i<=num_of_student ; i++)
score[i]=f(i);
//성적순 정렬(함수)
f_sort(name, score, num_of_student);
/*******************성적 데이터 출력**********************/
if((fp=fopen("grade.txt", "w"))==NULL)
{
printf("\"grade.txt\" 파일을 생성하는데 오류가 있습니다. 프로그램을 종료합니다.\n");
exit(1);
}
printf("\"grade.txt\" 파일 생성...");
percentage=100;
//성적순으로 정렬한 배열의 아래쪽부터 차례대로 학점을 매긴다.
for(i=num_of_student ; i>0 ; i--)
{
if(score[i]!=score[i+1])
percentage=100*(float)i/(float)num_of_student;
if (percentage<=20) grade[i]='A';
else if(percentage<=50) grade[i]='B';
else if(percentage<=80) grade[i]='C';
else if(percentage<=95) grade[i]='D';
else grade[i]='F';
}
fprintf(fp, "이름\t총점\t성적\n");
for(i=1 ; i<=num_of_student ; i++)
fprintf(fp, "%s\t%6.2f\t%c\n", name[i], score[i], grade[i]);
printf("데이터 출력 완료!\n");
fclose(fp);
/*****************중간고사 데이터 출력********************/
if((fp=fopen("midHisto.txt", "w"))==NULL)
{
printf("\"midHisto.txt\" 파일을 생성하는데 오류가 있습니다. 프로그램을 종료합니다.\n");
exit(1);
}
printf("\"midHisto.txt\" 파일 생성...");
for(i=20 ; i<=100 ; i+=20)
{
fprintf(fp, "%d ~ %d\t: ", i-20, i);
for(j=1 ; j<=num_of_student ; j++)
{
if(i!=100){
if(i-20 <= mid_term[j] && mid_term[j] < i) fprintf(fp, "*");
}
else{
if(i-20 <= mid_term[j] && mid_term[j] <= i) fprintf(fp, "*");
}
}
fprintf(fp, "\n");
}
printf("데이터 출력 완료!\n");
fclose(fp);
/*****************기말고사 데이터 출력********************/
if((fp=fopen("finalHisto.txt", "w"))==NULL)
{
printf("\"finalHisto.txt\" 파일을 생성하는데 오류가 있습니다. 프로그램을 종료합니다.\n");
exit(1);
}
printf("\"finalHisto.txt\" 파일 생성...");
for(i=20 ; i<=100 ; i+=20)
{
fprintf(fp, "%d ~ %d\t: ", i-20, i);
for(j=1 ; j<=num_of_student ; j++)
{
if(i!=100){
if(i-20 <= final[j] && final[j] < i) fprintf(fp, "*");
}
else{
if(i-20 <= final[j] && final[j] <= i) fprintf(fp, "*");
}
}
fprintf(fp, "\n");
}
printf("데이터 출력 완료!\n");
fclose(fp);
printf("모든 작업을 이상없이 마쳤습니다. 프로그램을 종료합니다.\n");
}
/**********************************************************
* 함수 f_sort *
***********************************************************/
//
void f_sort(char name[100][20], double score[], int num)
{
int i=0;
int j=0;
double temp_score;
char temp_name[20];
for(i=1 ; i<=num ; i++)
for(j=i ; j<=num ; j++)
{
if(score[i]<score[j])
{
temp_score=score[i];
score[i]=score[j];
score[j]=temp_score;
strcpy(temp_name, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], temp_name);
}
}
}
쓰고보니 글이 참 길다. 읽는 사람이나 있는지 모르겠군.ㅋㅋㅋ
고민하고 있는 누군가에게 도움이 되었길 바랍니다.