개정판 누구나 즐기는 C언어 콘서트 제11장 구조체, 공용체, 열거형 출처: pixabay
구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. 이번 장에서 학습할 내용 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. 구조체의 개념, 정의, 초기화 방법 구조체와 포인터와의 관계 공용체와 typedef
이번 장에서 만들 프로그램
자료형의 분류 자료형 (data type) 기초 자료형 파생 자료형 사용자 정의 자료형 char int float double void 배열 포인터 구조체 공용체 typedef enum
구조체의 필요성 학생에 대한 데이터를 하나로 모으려면? int number; char name[10]; double grade;
구조체의 필요성 int number; char name[10]; double grade; struct student { };
중간 점검 1. 구조체와 배열의 차이점을 이야기해보라. 2. 복소수, 날짜, 화면의 좌표, 사각형 등을 표현하는데 필요한 데이터 를 나열해보라. struct point { int x; int y; } struct rect { int left; int top; int width; int height; }
구조체 선언
구조체 선언 구조체 선언은 변수 선언이 아니다.
구조체 변수 선언
구조체의 초기화 중괄호를 이용하여 초기값을 나열한다. struct student { int number; char name[10]; double grade; }; struct student s1 = { 24, "Kim", 4.3 };
.기호는 구조체에서 멤버를 참조할 때 사용하는 연산자입니다. 구조체 멤버 참조 구조체 멤버를 참조하려면 다음과 같이 .연산자를 사용한다. s1.number = 20170001; // 정수 멤버 strcpy(s1.name, "Kim"); // 문자열 멤버 s1.grade = 4.3; // 실수 멤버 .기호는 구조체에서 멤버를 참조할 때 사용하는 연산자입니다. .
구조체 선언과 구조체 변수 선언 struct point { int x; int y; }; struct point p1; p1.x = 10; p1.y = 20;
예제 #1 … struct student { int number; char name[10]; double grade; };
예제 #1 int main(void) { struct student s; s.number = 20170001; strcpy(s.name,"홍길동"); s.grade = 4.3; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf(“학점: %f\n", s.grade); return 0; }
예제 #2 #include <stdio.h> // 2차원 공간의 점을 구조체로 나타낸다. struct point { int x; int y; }; int main(void) { struct point p = { 1, 2 }; // ① struct point q = { .y = 2,.x = 1 }; // ② struct point r = p; // ③ r = (struct point) { 1, 2 }; // ④ C99 버전 printf("p=(%d, %d) \n", p.x, p.y); printf("q=(%d, %d) \n", q.x, q.y); printf("r=(%d, %d) \n", r.x, r.y); return 0; }
Lab: 점들간의 거리 계산 앞에서 정의한 point 구조체를 사용하여서 2개의 점을 나타내는 변 수를 선언한 후에 사용자로부터 점의 좌표를 입력받는다. 구조체 멤 버의 값을 키보드로 입력할 수 있다. 이때 멤버 앞에 &을 붙여야 한 다 최종적으로 이들 점 사이의 거리를 계산하여 보자.
Sol: #include <stdio.h> #include <math.h> struct point { int x; int y; }; int main(void) { struct point p1, p2; double xdiff, ydiff; double dist;
Sol: printf("점의 좌표를 입력하시오(x y): "); scanf("%d %d", &p1.x, &p1.y); xdiff = p1.x - p2.x; ydiff = p1.y - p2.y; dist = sqrt(xdiff * xdiff + ydiff * ydiff); printf("두 점사이의 거리는 %f입니다.\n", dist); return 0; }
중간 점검 1. 구조체 안에 선언된 각각의 변수들을 ______이라고 한다. 2. 구조체의 선언에 사용하는 키워드는 _______이다. 3. 구조체의 태그는 왜 필요하며, 태그를 사용하는 경우과 사용하지 않 은 경우가 어떻게 다른가? 4. 구조체의 선언만으로 변수가 만들어지는가? 5. 구조체의 멤버를 참조하는 연산자는 무엇인가?
구조체 변수의 대입 구조체 대입은 가능하고 권장된다. struct point { int x; int y; }; struct point p1 = {10, 20}; struct point p2 = {30, 40}; p2 = p1; 구조체 변수 끼리의 대입 연산은 가능하다.
구조체 변수의 비교 구조체 비교는 불가능하다. struct point { int x; int y; }; struct point p1 = {10, 20}; struct point p2 = {30, 40}; if( p1 == p2 ) // 컴파일 오류 { printf("p1와 p2이 같습니다.") }
사각형의 면적 계산 사각형을 구조체로 표현하고 사각형의 면적을 계산해보자. 왼쪽 상단의 좌표를 입력하시오: 1 1 왼쪽 상단의 좌표를 입력하시오: 1 1 오른쪽 상단의 좌표를 입력하시오: 6 6 면적은 25이고 둘레는 20입니다.
예제 #include <stdio.h> struct point { int x; int y; }; struct rect { struct point p1; struct point p2; int main(void) { struct rect r; int w, h, area, peri;
예제 printf("왼쪽 상단의 좌표를 입력하시오: "); scanf("%d %d", &r.p1.x, &r.p1.y); w = r.p2.x - r.p1.x; h = r.p2.x - r.p1.x; area = w * h; peri = 2 * w + 2 * h; printf("면적은 %d이고 둘레는 %d입니다.\n", area, peri); return 0; } 왼쪽 상단의 좌표를 입력하시오: 1 1 오른쪽 상단의 좌표를 입력하시오: 6 6 면적은 25이고 둘레는 20입니다.
구조체 배열 struct student { int number; char name[20]; double grade; }; struct student list[100]; // 구조체 배열 선언
구조체 배열 struct student { int number; char name[20]; double grade; }; int main(void) { struct student list[100]; // 구조체의 배열 선언 list[2].number = 27; strcpy(list[2].name, "홍길동"); list[2].grade = 178.0; }
구조체 배열의 초기화 struct student list[3] = { { 1, "Park", 172.8 }, { 2, "Kim", 179.2 }, { 3, "Lee", 180.3 } };
예제 #1 학생들의 데이터를 반복 구조를 사용하여 입력받는다. 데이터들은 구조체의 배열에 저장된다.
#include <stdio.h> #define SIZE 3 struct student { int number; char name[20]; double grade; }; int main(void) { struct student list[SIZE]; int i; for (i = 0; i < SIZE; i++) printf("학번을 입력하시오: "); scanf("%d", &list[i].number); printf("이름을 입력하시오: "); scanf("%s", list[i].name); printf("학점을 입력하시오(실수): "); scanf("%lf", &list[i].grade); printf("\n"); }
예제 #1 printf("\n=================================================\n"); for (i = 0; i < SIZE; i++) printf("학번: %d, 이름: %s, 학점: %f\n", list[i].number, list[i].name, list[i].grade); printf("=================================================\n"); return 0; }
Lab: 구조체 배열 사용하기 2차원 공간의 점을 구조체로 표현하고 크기가 100인 구조체 배열을 선언한다. 여기에 난수를 저장한 후에 하나씩 꺼내서 화면에 점을 그려보자.
#include <windows.h> #include <stdlib.h> #define SIZE 100 struct point { int x; int y; }; int main(void) { struct point p[SIZE]; int i; for (int i = 0; i < SIZE; i++) { p[i].x = rand() % 500; p[i].y = rand() % 500; } HDC hdc = GetWindowDC(GetForegroundWindow()); Ellipse(hdc, p[i].x, p[i].y, p[i].x + 10, p[i].y + 10); return 0;
구조체와 함수 구조체가 인수나 반환값으로 사용될 때는 “값에 의한 호출” 원칙이 적용된다. 구조체가 인수나 반환값으로 사용될 때는 “값에 의한 호출” 원칙이 적용된다. int equal(struct student s1, struct student s2) { if( strcmp(s1.name, s2.name) == 0 ) return 1; else return 0; }
구조체와 함수 함수의 반환값으로 사용할 수 있다. struct student make_student(void) { struct student s; printf("나이:"); scanf("%d", &s.age); printf("이름:"); scanf("%s", s.name); printf("키:"); scanf("%f", &s.grade); return s; }
예제 #1 두 벡터의 합을 구하는 함수 get_vector_sum()를 제작하여 보자.
예제 #1 #include <stdio.h> struct vector { float x; float y; }; struct vector get_vector_sum(struct vector a, struct vector b); int main(void) { struct vector a = { 2.0, 3.0 }; struct vector b = { 5.0, 6.0 }; struct vector sum; sum = get_vector_sum(a, b); printf("벡터의 합은 (%f, %f)입니다.\n", sum.x, sum.y); return 0; }
예제 #1 struct vector get_vector_sum(struct vector a, struct vector b) { struct vector result; result.x = a.x + b.x; result.y = a.y + b.y; return result; }
구조체와 포인터 struct student s = { 20070001, "홍길동", 4.3 }; struct student *p; p = &s; printf("학번=%d 이름=%s 학점=%f \n", s.number, s.name, s.grade); printf("학번=%d 이름=%s 학점=%f \n", (*p).number,(*p).name,(*p).grade);
-> 연산자 p->number; printf("학번=%d 이름=%s 학점=%f\n", p->number, p->name, p->grade);
예제 #include <stdio.h> struct student { int number; char name[20]; double grade; }; int main(void) { struct student s = { 20070001, "홍길동", 4.3 }; struct student *p; p = &s; printf("학번=%d 이름=%s 학점=%f \n", s.number, s.name, s.grade); printf("학번=%d 이름=%s 학점=%f \n", (*p).number,(*p).name,(*p).grade); printf("학번=%d 이름=%s 학점=%f \n", p->number, p->name, p->grade); return 0; }
실행 결과
공용체 같은 메모리 영역을 여러 개의 변수가 공유하도록 하는 것 union example { char c; // 같은 기억 공간 공유 int i; // 같은 기억 공간 공유 };
예제 #include <stdio.h> union example { int i; char c; }; int main(void) { union example data; data.c = 'A'; printf("data.c:%c data.i:%i\n", data.c, data.i); data.i = 10000; }
열거형
열거형의 초기화 enum levels { low=1, medium, high }; enum levels english; english = high;
예제 요일을 나타내는 열거형을 정의하고 이것을 이용하여 다음과 같이 출력해보자.
예제 소스 #include <stdio.h> enum days { MON, TUE, WED, THU, FRI, SAT, SUN }; // 포인터들의 배열을 만들고 문자열 상수로 초기화한다. char *days_name[] = { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" }; int main(void) { enum days d; for (d = MON; d <= SUN; d++) printf("%d번째 요일의 이름은 %s입니다\n", d, days_name[d]); return 0; }
typedef 새로운 자료형(type)을 정의(define)하는 것
typedef 기존의 자료형 새로운 자료형
typedef의 예 typedef int INT32; typedef unsigned int UINT32; INT32 i; // int i;와 같다. UINT32 k; // unsigned int k;와 같다. typedef struct point { int x; int y; } POINT;
예제 #1 2차원 공간에서의 점을 구조체로 표현한 다음에 이 구조체를 typedef을 이용하여 새로운 타입인 POINT로 정의한다.
예제 소스 #include <stdio.h> typedef struct point { int x; int y; POINT translate(POINT p, POINT delta); int main(void) { POINT p = { 2, 3 }; POINT delta = { 10, 10 }; POINT result; result = translate(p, delta); printf("(%d, %d)+(%d, %d)->(%d, %d)\n", p.x, p.y, delta.x, delta.y, result.x, result.y); return 0; }
예제 소스 POINT translate(POINT p, POINT delta) { POINT new_p; new_p.x = p.x + delta.x; new_p.y = p.y + delta.y; return new_p; }