C 자료구조&알고리즘
구조체, 포인터, call by reference or value
제이지연
2022. 3. 7. 23:26
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define STU 5
#define SUB 1
struct info sorti_by_total(struct info *s, int a, int b);
void sorting_score(int *s);
void register_dept(struct info s, struct dept *d, int *deptnum);
void sorti_by_dept(struct info *s);
void sortd_by_average(struct dept *d, int deptnum);
void sortd_by_top(struct dept *d, int deptnum);
int bin_search(char *input, struct dept *d, int deptnum);
void sortd_by_dname(struct dept *d, int deptnum);
void swapint(int *a, int *b);
void swapinfo(struct info *a, struct info *b);
void swapdept(struct dept *a, struct dept *b);
typedef struct info {
char stuname[5];
char deptname[5];
char sub[SUB][5];
int score[SUB][4];
int total;
}INFO;
struct dept{
char dept[5];
int stu_count;
int totalscore;
float average;
struct info *top;
};
int main(){
INFO stu[STU];
struct dept d[STU];
int i, j, k, flag=0, deptnum=0;
//초기화
for(i=0;i<STU;i++){
memset(&stu[i],0,sizeof(struct info));
memset(&d[i],0,sizeof(struct dept));
}
//입력받기
for(i=0;i<STU;i++){
scanf("%s %s", stu[i].stuname, stu[i].deptname);
getchar();
for(j=0;j<SUB;j++){
scanf("%s", &stu[i].sub[j]);
for(k=0;k<3;k++){
scanf("%d", &stu[i].score[j][k]);
stu[i].score[j][3]+=stu[i].score[j][k];
}
getchar();
stu[i].total+=stu[i].score[j][3];
sorting_score(stu[i].score[j]); //과목별 3점수 sorting
}
register_dept(stu[i], d, &deptnum);//학과 등록, 학과별 인원, 총 학과갯수
}
sorti_by_dept(stu); //info를 학과이름올림차순으로 sorting
sortd_by_dname(d, deptnum); //dept를 학과이름올림차순으로 sorting
for(i=0;i<deptnum;i++){
*d[i+1].top=sorti_by_total(stu, flag, d[i+1].stu_count); //학과별info를 총점올림차순으로sorting
printf("%s\n", d[i+1].top->stuname);
flag+=d[i+1].stu_count;}
///no.1
printf("======================\n");
for(i=0;i<STU;i++){
printf("%s %s %d\n", stu[i].deptname, stu[i].stuname, stu[i].total);
for(j=0;j<SUB;j++){
printf("%s ", stu[i].sub[j]);
for(k=0;k<3;k++){
printf("%d ", stu[i].score[j][k]);}
printf("\n");}}
///no.2
flag=0;
printf("======================\n");
for(i=0;i<deptnum;i++){
printf("<%s>\n",d[i+1].dept);
for(j=flag;j<flag+d[i+1].stu_count;j++){
printf("%s %d\n", stu[j].stuname, stu[j].total);
for(k=0;k<SUB;k++){
printf("%s %d %d %d\n", stu[j].sub[k], stu[j].score[k][0], stu[j].score[k][1], stu[j].score[k][2]);
}}
flag+=d[i+1].stu_count;}
//학과별 평균구하기
for(i=0;i<deptnum;i++){
d[i+1].average=(float)(d[i+1].totalscore/d[i+1].stu_count);
}
sortd_by_average(d, deptnum); //dept를 학과평균올림차순으로 sorting
//no.3
printf("======================\n");
for(i=0;i<deptnum;i++){
printf("%s %d %.2f\n", d[i+1].dept, d[i+1].stu_count, d[i+1].average);
}
sortd_by_top(d, deptnum); //dept를 학과수석점수올림차순으로 sorting
//no.4
printf("======================\n");
for(i=0;i<deptnum;i++){
printf("%s %.2f %s %d\n", d[i+1].dept, d[i+1].average, d[i+1].top->stuname, d[i+1].top->total);}
//no.5
printf("======================\n");
char input[5];
printf("name : ");
scanf("%s", input);
i=0;
do{
if(strcmp(input,stu[i].stuname)==0) break; //학생이름으로 학생info 찾기
else i++;
}while(i<=STU);
if(i>STU) printf("NOT FOUND");
else{
sortd_by_dname(d, deptnum);
flag=bin_search(stu[i].deptname, d, deptnum); //학과명으로 이진탐색
printf("stu name : %s dept name :%s dept average : %.2f\n",input, d[flag].dept, d[flag].average);
printf("%s %d",d[flag].top->stuname, d[flag].totalscore);
}
}
//////과목별 점수3개 올림차순으로 sorting
void sorting_score(int *s){
int i, j, k;
for(i=0;i<2;i++){
for(j=i+1;j<3;j++){
if(s[i]>s[j]) swapint(&s[i],&s[j]);
}}}
void swapint(int *a, int *b){
int tmp=*a;
*a=*b;
*b=tmp;}
//////학과등록 (학과이름, 학과별 학생수, 학과갯수)
void register_dept(INFO s, struct dept *d, int *deptnum){ //
int index=0;
do{
if(strcmp(s.deptname, d[index].dept)!=0) index++;
else{
d[index].stu_count++;
d[index].totalscore+=s.total;
break;
}
}while(index<=*deptnum);
if(index>*deptnum){
strcpy(d[index].dept,s.deptname);
d[index].stu_count++;
d[index].totalscore+=s.total;
(*deptnum)++;
}}
///////학과명 올림차순으로 info를 sorting
void sorti_by_dept(INFO *s){
int i,j;
for(i=0;i<STU-1;i++){
for(j=i+1;j<STU;j++){
if(strcmp(s[i].deptname,s[j].deptname)>0) swapinfo(&s[i],&s[j]);
}}}
void swapinfo(INFO *a, INFO *b){
struct info tmp=*a;
*a=*b;
*b=tmp; }
///////dept를 학과이름 올림차순으로 sorting
void sortd_by_dname(struct dept *d, int deptnum){
int i,j;
for(i=0;i<deptnum-1;i++){
for(j=i+1;j<deptnum;j++){
if(strcmp(d[i+1].dept, d[j+1].dept)>0) swapdept(&d[i+1],&d[j+1]);
}}}
void swapdept(struct dept *a, struct dept *b){
struct dept tmp=*a;
*a=*b;
*b=tmp;
}
//총점 올림차순으로 (같은학과별) sorting
struct info sorti_by_total(INFO *s, int a, int b){
int i, j;
for(i=a;i<(a+b-1);i++){
for(j=a+1;j<a+b;j++){
if(s[i].total>s[j].total) swapinfo(&s[i],&s[j]);
}}
return s[a+b-1];}
//////dept를 학과평균점수올림차순으로 sorting
void sortd_by_average(struct dept *d, int deptnum){
int i, j;
for(i=0;i<deptnum-1;i++){
for(j=i;j<deptnum;j++){
if(d[i+1].average>d[j+1].average) swapdept(&d[i],&d[j]);
}}}
///////
void sortd_by_top(struct dept *d, int deptnum){
int i,j,k;
for(i=0;i<deptnum-1;i++){
for(j=i+1;j<deptnum;j++){
if(d[i+1].top->total>(*d[j+1].top).total) swapdept(&d[i+1],&d[j+1]);
}}}
//////이진탐색
int bin_search(char *input, struct dept *d, int deptnum){
int start=1, last=deptnum, mid;
do{
mid=(start+last)/2;
if(strcmp(input, d[mid].dept)>0) start=mid+1;
else if(strcmp(input, d[mid].dept)<0) last=mid-1;
else return mid;
}while(start<=last);
}
오늘 배운점
1. 구조체와 포인터
구조체와 포인터에 관련해서 ① 구조체를 가리키는 포인터와 ②포인터를 멤버로 가지는 구조체 로 크게 나눌 수 있다. 교수님께서 최대한 효율적으로, 즉 메모리를 적게 쓰라고 하시면서 구조체 멤버 중 하나인 구조체를 구조체포인터로 선언하면 좋을 것 같다고 하셨다.
struct dept{
char dept[5];
int stu_count;
int totalscore;
float average;
struct info *top;
};
int main(){
//////
for(i=0;i<deptnum;i++){
*d[i+1].top=sorti_by_total(stu, flag, d[i+1].stu_count); //학과별info를 총점올림차순으로sorting
printf("%s\n", d[i+1].top->stuname);
flag+=d[i+1].stu_count;}
//////
}
고치는 과정에서 구조체 배열 안에 있는 구조체포인터멤버를 참조하는 법에 대해서 배웠다.(설명을 잘 못하겠다..)
//no.4
printf("======================\n");
for(i=0;i<deptnum;i++){
printf("%s %.2f %s %d\n", d[i+1].dept, d[i+1].average, d[i+1].top->stuname, d[i+1].top->total);}
d[i+1].top->stuname은 (*d[i+1].top).stuname과 같다.
2. call by reference와 call by value를 잘 써야 효율적인 코드가 된다!
register_dept(&stu[i], d, &deptnum);
void register_dept(INFO *s, struct dept *d, int *deptnum){ //
int index=0;
do{
if(strcmp((*s).deptname, d[index].dept)!=0) index++;
else{
d[index].stu_count++;
d[index].totalscore+=(*s).total;
break;
}
}while(index<=*deptnum);
if(index>*deptnum){
strcpy(d[index].dept,(*s).deptname);
d[index].stu_count++;
d[index].totalscore+=(*s).total;
(*deptnum)++;
}}
여기서 register_dept함수의 파라미터인 &stu[i]는 call by reference를 할 필요없다!! 함수내부에서 stu[i]값이 바뀌지 않는다!
3. call by address & call by reference
call by address | call by reference |
결과적으로 원본 변수의 값을 변경할 수 있다.
|
|
함수에 매개변수로 포인터형 변수를 선언하고 그 포인터 변수의 공간에 원본의 주소값을 복사. 즉, 메모리 공간 4바이트를 차지한다. |
reference변수는 메모리 공간을 할당 받는것이 아닌 원본 변수의 별명으로써 존재 |