구조체
-서로 다른 형의 변수들을 하나로 묶어주는 방법을 제공한다.
: 이질적인 데이터 집합을 하나의 단위로 취급할 수 있게 한다.
EX) 성적 처리 프로그램
학생 이름과 그 학생의 점수는 한 쌍으로 다루는 것이 좋다.
구조체 선언
struct name_grade {
char name[10];
int grade;
};
//struct : 구조체 선언을 위한 키워드
//name_grade : 구조체 태그 이름
//name, grade : 구조체 멤버
- 이 선언은 메모리 할당을 받는 변수를 선언한 것이 아니라,
struct name_grade 형을 선언한 것이다.
- struct name_grade는 자료형이 오는 자리에 사용할 수 있다.
-struct name_grade 형의 크기는 단순히 구성 요소 덧셈이 아니라, sizeof 연산자를 사용해야 알 수 있다.
구조체 (struct name_grade)형 변수 선언
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1, st_g2;
- struct name_grade가 자료형이기 때문에 이 코드는 st_g1과 st_g2라는 변수를 선언하는 선언문
- 컴파일러는 st_g1과 st_g2 변수에 메모리 할당
-st_g1과 st_g2는 구조체 변수로 일반 변수처럼 다룰 수 없다.
st_g1 = 10; // 오류
-st_g1과 st_g2의 멤버 변수는 일반 변수처럼 다룰 수 있다.
st_g1.name // char[10]형 변수, char 형 배열
st_g1.grade //int 형 변수
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1, st_g2;
strcpy(st_g1.name, "이순신");
st_g1.grade = 98;
// st_g1.name = "이순신";
// st_g1.name은 char 배열형 이기 때문에, 상수 포인터이므로, 대입을 하면 안되며, strcpy를 이용해야한다.
[예제 프로그램]
#include <stdio.h>
int main(void) {
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1, st_g2;
strcpy(st_g1.name, "이순신");
st_g1.grade = 98;
strcpy(st_g2.name, st_g1.name);
st_g2.grade = st_g1.grade;
printf("%s의 점수는 %d입니다.", st_g2.name, st_g2.grade);
return 0;
};
[출력 결과]
-같은 형의 구조체 변수 간에는 배정이 가능하다.
st_g1 = st_g2;
다양한 구조체 변수 선언
구조체 형 선언과 동시에 변수 선언
struct name_grade {
char name[10];
int grade;
}st_g3;
struct name_grade st_g4;
구조체 태그가 없는 선언
: 해당 구조체 형은 다시 사용할 수 없다.
struct{ char name[10];
int grade;
}st_g5;
struct {
char name[10];
int grade;
}st_g6;
//st_g5와 st_g6는 다른 형이다.
st_g5 = st_g6; //오류
typedef 이용
구조체 형 이름은 보통 길기 때문에, typedef을 많이 사용한다.
예시
typedef struct name_grade name_grade;
name_grade st_g7;
typedef struct {
char name[10];
int grade;
}name_grade;
name_grade st_g8, st_g9;
구조체의 초기화
변수 선언문에서 배열과 유사하게 초기화
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g10= {"둘리",80};
//멤버 순서대로 초기화가 된다.
// st_g10.name = "둘리"
// st_g10.grade = 80;
struct name_grade st_g11 = {"둘리"};
이 경우에는
st_g11.name = "둘리";
st_g11.grade =0;
이 실행된다.
연산자를 사용하여 멤버를 지정하여 초기화 할 수 있다.
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g10= {.grade = 80};
복합 리터럴
구조체 멤버의 값을 배정할 때 유용하다.
캐스트를 사용하여 형을 지정한다.
1. 선언을 함과 동시에 초기화를 안할 경우
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1; //초기화를 구조체 변수 선언할 때 시행을 안 한 경우
//일반적인 경우 : 변수 별로 저장
strcpy(st_g1.name, "이순신");
st_g1.grade = 98;
//복합 리터럴 => 중괄호 & 캐스트 연산자 통해서 한 번에 저장 가능하다.
st_g1 = (struct name_grade){ "이순신",98 };
st_g1 = (struct name_grade){ .grade = 80, .name = "홍길동" };
구조체의 멤버로 구조체가 올 수 있다.
struct name_grade {
char name[10];
int grade;
};
struct subject {
char name[10];
struct name_grade student1;
struct name_grade student2;
struct name_grade student3;
float avg;
};
struct subject math;
math.student1.grade = 80;
예제 프로그램
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct subject {
char name[10];
struct name_grade student1;
struct name_grade student2;
struct name_grade student3;
float avg;
};
int main(void) {
struct subject math = { "수학",{"하나",90},{"둘",44},{"셋",76} };
math.avg =
(math.student1.grade + math.student2.grade + math.student3.grade) / 3.0;
printf("%s: %d점\n", math.student1.name, math.student1.grade);
printf("%s: %d점\n", math.student2.name, math.student2.grade);
printf("%s: %d점\n", math.student3.name, math.student3.grade);
printf("%s 평균은 %.2f점입니다", math.name, math.avg);
return 0;
}
[출력결과]
구조체 포인터
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1;
struct name_grade* st_gp;
st_gp = &st_g1;
(*st_gp).grade = 88;
//오류 코드들
//st_gp.grade = 88; //구조체 포인터는 역연산자 붙여야함
//*st_gp.grade = 88; //역 연산자를 붙일 때는 괄호 붙여야 연산자 우선 순위에 따른 오류 방지
//*st_gp.grade = *(st_gp.grade)
멤버 접근 연산자 ->
구조체 포인터를 통해 멤버를 접근할 때 사용한다.
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_g1;
struct name_grade* st_gp;
st_gp = &st_g1;
strcpy(st_gp->name, "하니");
st_gp->grade = 88;
[예제 프로그램]
구조체 포인터를 통해
1. -> 연산자 사용
2. 역연산자 사용 => (*st_gp).grade
#include <stdio.h>
typedef struct name_grade {
char name[10];
int grade;
}name_grade;
int main(void) {
name_grade st, * st_gp = &st;
st = (name_grade){"이순신",98};
printf("%s의 점수는 %d점 입니다.\n", st_gp->name, (*st_gp).grade);
return 0;
}
구조체 배열
일반 배열과 같은 방법으로 선언하고 사용한다.
구조체 배열 초기화
#include <stdio.h>
struct name_grade {
char name[10];
int grade;
};
struct name_grade st_a[5] = { {"하나",77},{"둘",87},{"셋",65},{"넷",90},{"다섯",98}};
struct name_grade st_a[5] = { [1] = {"둘",87} };
struct name_grade st_a[5] = {[1].grade=87, [1].name="둘"}
[예제 프로그램]
#include <stdio.h>
#define N 5
typedef struct name_grade{
char name[10];
int grade;
}name_grade;
int main(void) {
int sum = 0, i;
float avg = 0.0;
name_grade st_a[N] = { {"하나",77},{"둘",87},{"셋",65},{"넷",90},{"다섯",98} };
printf(" 이름 점수 \n");
for (i = 0; i < N; i++) {
printf("%-10s %3d\n", st_a[i].name, st_a[i].grade);
sum += st_a[i].grade;
}
avg = (float)sum / N;
printf("성적 평균은 %.2f 점입니다\n.", avg);
return 0;
}
구조체와 함수
-구조체는 함수의 인자로써 함수에 전달될 수 있고 함수로 부터 리턴될 수도 있다.
-함수의 인자로서 구조체가 전달될 때 구조체는 값으로 전달된다.
[예제 프로그램 1]
구조체 전달, return 값 void
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct grade {
int grade[3];
char p_f[3];
int sum;
float avg;
}grade;
void grade_proc(grade st) {
st.sum = st.grade[0] + st.grade[1] + st.grade[2];
st.avg = st.sum / 3.0;
st.p_f[0] = st.grade[0] < 60 ? 'f' : 'p';
st.p_f[1] = st.grade[1] < 60 ? 'f' : 'p';
st.p_f[2] = st.grade[1] < 60 ? 'f' : 'p';
}
int main(void) {
grade st = { {0},{0},-1,-1.0 };
printf("성적을 입력하세요.:");
scanf("%d%d%d", &st.grade[0], &st.grade[1], &st.grade[2]);
grade_proc(st);
printf("국어 :%d (%c) \n", st.grade[0], st.p_f[0]);
printf("수학 :%d (%c) \n", st.grade[1], st.p_f[1]);
printf("영어 :% d(%c) \n", st.grade[2], st.p_f[2]);
printf("총점 : %d\n", st.sum);
printf("평균: %.2f", st.avg);
}
main 함수에서 저장한 st.grade[3]은 출력이 제대로 되지만,
값만 복사되서 함수에 전달되었고, return 받지 못했기 때문에 제대로 출력이 안된다(초기값)
[예제 프로그램2]
: return 값 grade형으로 반환
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct grade {
int grade[3];
char p_f[3];
int sum;
float avg;
}grade;
grade grade_proc(grade st) {
st.sum = st.grade[0] + st.grade[1] + st.grade[2];
st.avg = st.sum / 3.0;
st.p_f[0] = st.grade[0] < 60 ? 'f' : 'p';
st.p_f[1] = st.grade[1] < 60 ? 'f' : 'p';
st.p_f[2] = st.grade[1] < 60 ? 'f' : 'p';
return st;
}
int main(void) {
grade st = { {0},{0},-1,-1.0 };
printf("성적을 입력하세요.:");
scanf("%d%d%d", &st.grade[0], &st.grade[1], &st.grade[2]);
st=grade_proc(st);
printf("국어 :%d (%c) \n", st.grade[0], st.p_f[0]);
printf("수학 :%d (%c) \n", st.grade[1], st.p_f[1]);
printf("영어 :% d(%c) \n", st.grade[2], st.p_f[2]);
printf("총점 : %d\n", st.sum);
printf("평균: %.2f", st.avg);
}
=> 구조체가 많은 멤버를 가지거나 큰 배열을 멤버로 가질 경우, 함수의 인자를 구조체를 전달하는 것은 상대적으로 비효율적이다.
: 대부분 응용 프로그램에서 함수의 인자로 구조체의 주소를 사용한다.
[예제 프로그램 3]
구조체의 주소를 넘겨준다.
실행 성공 여부에 따라 int 값을 다르게 return 해준다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct grade {
int grade[3];
char p_f[3];
int sum;
float avg;
}grade;
int grade_proc(grade* st) {
if (st == NULL) {
printf("오류");
return -1;
}
st->sum = st->grade[0] + st->grade[1] + st->grade[2];
st->avg = st->sum / 3.0;
st->p_f[0] = st->grade[0] < 60 ? 'f' : 'p';
st->p_f[1] = st->grade[1] < 60 ? 'f' : 'p';
st->p_f[2] = st->grade[1] < 60 ? 'f' : 'p';
return 0;
}
int main(void) {
grade st = { {0},{0},-1,-1.0 };
printf("성적을 입력하세요.:");
scanf("%d%d%d", &st.grade[0], &st.grade[1], &st.grade[2]);
if (grade_proc(&st))
return 1;
printf("국어 :%d (%c) \n", st.grade[0], st.p_f[0]);
printf("수학 :%d (%c) \n", st.grade[1], st.p_f[1]);
printf("영어 :% d(%c) \n", st.grade[2], st.p_f[2]);
printf("총점 : %d\n", st.sum);
printf("평균: %.2f", st.avg);
}
'c언어' 카테고리의 다른 글
[C언어] 전처리기 (0) | 2022.10.23 |
---|---|
[C언어] 비트 수준 접근 (0) | 2022.10.23 |
[C언어] 공용체(union) / 열거형 (0) | 2022.10.12 |
[C언어] 동적 메모리 할당 (0) | 2022.09.07 |
[C언어] 포인터와 배열 (0) | 2022.09.07 |