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변수는 메모리 공간을 할당 받는것이 아닌 원본 변수의 별명으로써 존재