400 likes | 893 Views
제 13 장 구조체. 쉽게 풀어쓴 C 언어 Express. C Express. 이번 장에서 학습할 내용. 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. 구조체 구조체와 포인터 공용체 열거형 typedef. 자료형의 분류. 기본 자료형 : char , int , float, double, …. 자료형. 파생 자료형 : 배열 , 구조체 , 공용체 , …. 구조체의 필요성. 학생 데이터를 하나로 묶어서 처리하려면 ?. 구조체를 사용하면 변수들을 하나로 묶을 수 있습니다.
E N D
제13장 구조체 쉽게 풀어쓴 C언어 Express C Express
이번 장에서 학습할 내용 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. • 구조체 • 구조체와 포인터 • 공용체 • 열거형 • typedef
자료형의 분류 기본 자료형:char, int, float, double, … 자료형 파생 자료형:배열, 구조체, 공용체, …
구조체의 필요성 • 학생 데이터를 하나로 묶어서 처리하려면? 구조체를 사용하면 변수들을 하나로 묶을 수 있습니다. int number; char name[10]; double grade;
구조체와 배열 • 구조체(structure): 레코드(record) 다른 타입의 집합 같은 타입의 집합
구조체 선언 태그(tag): 이름 • 구조체 선언 형식 struct태그 { 자료형 멤버1; 자료형 멤버2; ... }; structstudent { intnumber; char name[10]; double grade; }; 멤버(필드)
구조체 선언의 예 // x,y값으로 이루어지는 화면의 좌표 struct point { int x; // x 좌표 int y; // y 좌표 }; // 직사각형 structrect { intx, y; intwidth, height; }; // 복소수 struct complex { double real; // 실수부 double imag; // 허수부 }; // 직원 struct employee { char name[20]; // 이름 int age; // 나이 intsex;// 성별 int salary; // 월급 }; // 날짜 struct date { int month; int day; int year; };
구조체 변수 선언 • 구조체 정의(선언)와 구조체 변수 선언은 다름 • 구조체 정의: 사용자 정의 자료형 선언
구조체의 초기화 • 중괄호를 이용하여 초깃값 나열 struct student { intnumber; charname[10]; doublegrade; }; struct student s1 = { 24, "Kim", 4.3 };
구조체 멤버 참조 • 구조체 멤버 참조 연산자: . struct student { int number; char name[10]; double grade; }; struct student s1; s1.number = 24; strcpy(s1.name, "Kim"); s1.grade = 4.3;
예제 #include<stdio.h> #include<string.h> structstudent { int number; char name[10]; doublegrade; }; int main(void) { struct student s; s.number = 20070001; strcpy(s.name, "홍길동"); s.grade = 4.3; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf(“학점: %f\n", s.grade); return 0; } 학번: 20070001 이름: 홍길동 학점: 4.300000
예제 #include<stdio.h> structstudent { int number; char name[10]; double grade; }; intmain(void) { struct student s; printf("학번을입력하시오: "); scanf("%d", &s.number); printf("이름을입력하시오: "); scanf("%s", s.name); printf("학점을입력하시오(실수): "); scanf("%lf", &s.grade); printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf("학점: %f\n", s.grade); return 0; } 학번을 입력하시오: 20070001 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번: 20070001 이름: 홍길동 학점: 4.300000
예제 #include<stdio.h> #include<math.h> structpoint { int x, y; }; int main(void) { struct point p1, p2; intxdiff, ydiff; double dist; printf("점의좌표를입력하시오(x y): "); scanf("%d %d", &p1.x, &p1.y); printf("점의좌표를입력하시오(x y): "); scanf("%d %d", &p2.x, &p2.y); xdiff = p1.x - p2.x; ydiff= p1.y - p2.y; dist = sqrt(xdiff * xdiff + ydiff * ydiff); printf("두 점 사이의거리는 %f입니다.\n", dist); return 0; } 점의 좌표를 입력하시오(x y): 10 10 점의 좌표를 입력하시오(x y): 20 20 두 점 사이의 거리는 14.142136입니다. p2 (x,y) p1 (x,y)
구조체 중첩 struct date { int month; int day; int year; }; struct student { intnumber; charname[10]; structdate dob; // 구조체 안에 구조체 포함 doublegrade; }; struct student s1; s1.dob.month = 3; s1.dob.day = 29; s1.dob.year = 1983; s1 number name dob grade month day year
예제 #include<stdio.h> struct point { int x, y; }; structrect { struct point p1, p2; }; int main(void) { structrect r; int w, h, area, peri; printf("왼쪽상단의좌표를입력하시오: "); scanf("%d %d", &r.p1.x, &r.p1.y); printf("오른쪽하단의좌표를입력하시오: "); scanf("%d %d", &r.p2.x, &r.p2.y); w = r.p2.x - r.p1.x; h = r.p2.y - r.p1.y; area = w * h; peri= 2 * (w + h); printf("면적은 %d이고둘레는 %d입니다.\n", area, peri); return 0; } 왼쪽 상단의 좌표를 입력하시오: 1 1 오른쪽 하단의 좌표를 입력하시오: 6 6 면적은 25이고 둘레는 20입니다. x y
구조체 변수의 대입과 비교 • 같은 타입의 구조체 변수끼리 대입은 가능하지만 비교는 불가능 structpoint { int x, y; }; int main(void) { struct point p1 = { 10, 20 }; struct point p2 = { 30, 40 }; p2 = p1;// 대입 가능 if (p1 == p2)// 비교 불가능 컴파일오류!! printf("p1과 p2가같습니다."); if (p1.x == p2.x && p1.y == p2.y) // 올바른 비교 printf("p1과 p2가같습니다."); return 0; }
구조체 배열 • 구조체 배열의 선언 struct student { int number; charname[10]; double grade; }; structstudent list[3]; list[1].number = 24; strcpy(list[1].name, "Kim"); list[1].grade = 4.3; • 구조체 배열의 초기화 structstudent list[3] = { { 25, "Mun", 3.92 }, { 24, "Kim", 4.3 }, { 23, "Tim", 2.9 } };
예제 #include<stdio.h> #define SIZE 3 structstudent { int number; char name[20]; double grade; }; int main(void) { struct student list[SIZE]; inti; for (i = 0; i < SIZE; i++) { printf("학번을입력하시오: "); scanf("%d", &list[i].number); printf("이름을입력하시오: "); scanf("%s", list[i].name); printf("학점을입력하시오(실수): "); scanf("%lf", &list[i].grade); } for (i = 0; i < SIZE; i++) printf("학번: %d, 이름: %s, 학점: %f\n", list[i].number, list[i].name, list[i].grade); return 0; } 학번을 입력하시오: 20070001 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번을 입력하시오: 20070002 이름을 입력하시오: 김유신 학점을 입력하시오(실수): 3.92 학번을 입력하시오: 20070003 이름을 입력하시오: 이성계 학점을 입력하시오(실수): 2.87 학번: 20070001, 이름: 홍길동, 학점: 4.300000 학번: 20070002, 이름: 김유신, 학점: 3.920000 학번: 20070003, 이름: 이성계, 학점: 2.870000
구조체를 가리키는 포인터 • 구조체를 가리키는 포인터 struct student { int number; char name[10]; double grade; }; structstudent s = { 20070001, "홍길동", 4.3 }; struct student *p = &s; printf("학번=%d ,이름=%s, 학점=%f \n", s.number, s.name, s.grade); printf("학번=%d, 이름=%s, 학점=%f \n", (*p).number, (*p).name, (*p).grade); intn = 3; struct s { int *ptr; … } p; p.ptr = &n; *p.ptr = 4; // *(p.ptr) = 4; n = 4; n p ptr … 3 4
->연산자 • -> : 포인터로 구조체 멤버를 참조할 때 사용(*p).member p->member #include<stdio.h> struct student { int number; char name[20]; double grade; }; int main(void) { struct student s = { 20070001, "홍길동", 4.3 }; struct student *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; } 학번=20070001, 이름=홍길동,학점=4.300000 학번=20070001, 이름=홍길동,학점=4.300000 학번=20070001, 이름=홍길동,학점=4.300000
포인터 멤버를 가지는 구조체 #include<stdio.h> struct date { int month, day, year; }; struct student { int number; char name[20]; double grade; structdate *dob; }; intmain(void) { struct date d = { 3, 20, 1980 }; struct student s = { 20070001, "Kim", 4.3, &d }; // s.dob = &d; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf("학점: %f\n", s.grade); printf("생년월일: %d년 %d월 %d일\n", s.dob->year, s.dob->month, s.dob->day); return 0; } s number name grade dob month day year 학번: 20070001 이름: Kim 학점: 4.300000 생년월일: 1980년 3월 20일
구조체와 함수 • 구조체를 함수의 인자로 전달하는 경우 • 복사본 전달 • 구조체가 크면 시간과 메모리 측면에서 비효율적 • 구조체의 포인터를 함수의 인자로 전달하는 경우 • 시간과 메모리 절약가능 • 원본 훼손 가능 • 읽기만 하고 변경하지 않는 경우: const선언 intf(structstudent s) { … } intf(structstudent *p) { … } intf(conststructstudent *p) { … } 포인터를 통한 구조체 변경 방지
구조체인자와 구조체 반환 #include<stdio.h> structvector { float x, y; }; struct vector get_vector_sum(struct vector a, struct vector b); int main(void) { struct vector a = { 2.0F, 3.0F }, b = { 5.0F, 6.0F }, sum; sum = get_vector_sum(a, b); printf("벡터의합은 (%f, %f)입니다.\n", sum.x, sum.y); return 0; } 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; } 벡터의 합은 (7.000000, 9.000000)입니다.
구조체 포인터 인자 #include<stdio.h> structvector { float x, y; }; void vector_input(structvector *p); void vector_output(const struct vector *p); int main(void) { struct vector v; vector_input(&v); vector_output(&v); return 0; } void vector_input(struct vector *p) { printf("벡터입력: "); scanf("%f %f", &p->x, &p->y); } void vector_output(const struct vector *p) { printf("(%g, %g)", p->x, p->y); } 벡터 입력: 1.2 3.4 (1.2, 3.4)
구조체 포인터 반환 #include<stdio.h> structvector { float x, y; }; structvector*vector_input(structvector *p); void vector_output(const struct vector *p); int main(void) { struct vector v; vector_output(vector_input(&v)); return 0; } structvector*vector_input(struct vector *p) { printf("벡터입력: "); scanf("%f %f", &p->x, &p->y); return p; } void vector_output(const struct vector *p) { printf("(%g, %g)", p->x, p->y); } 벡터 입력: 1.2 3.4 (1.2, 3.4)
인자 전달: 배열과 구조체 • 배열인자: 포인터로 전달(원본 전달) • 구조체: 복사본 전달 void f(intary[ ]) { ++ary[0]; } // void f(int*ary) { ++*(ary + 0); } … int a[3] = { 10, 20, 30 }; f(a); // a[0]: 11 structs_array { int a[3]; }; void f(structs_arraysa) { ++sa.a[0]; } … structs_array s = { { 10, 20, 30 } }; f(s); // s.a[0]: 10
공용체 • 공용체(union) • 같은 메모리 영역을 멤버들이 공유 • 공용체 선언 및 사용 방법은 구조체와 유사 union example { char c; // 메모리 공유 inti; // 메모리 공유 }; • 공용체는 첫째 멤버로만 초기화 가능 unionu_tag { float v; char *s; }; unionu_tag u = 3.4F; // O unionu_tag u = "name"; // X
예제 #include<stdio.h> union example { char c; inti; }; int main(void) { union example v; v.c = 'A'; printf("v.c= %c\n", v.c); v.i = 10000; printf("v.i = %d\n", v.i); return 0; } v.c = A v.i = 10000
IP 주소 예제 #include<stdio.h> unionip_address { unsignedcharsaddr[4]; unsignedintiaddr; }; int main(void) { unionip_addressaddr = { 0x7F, 0x00, 0x00, 0x01 }; printf("%08X\n", addr.iaddr); return 0; } (little endian) (big endian) 0100007F (little endian) 7F000001 (big endian)
공용체 활용 예제 #include <stdio.h>// variable types#define INT 1#define REAL 2#define STR 3 structs_var { // variable structurechar *name;int type;union { // valueintival;doublerval;char *sval; } u;};voidout_var(conststructs_var *p);int main() {structs_var v; v.name = "n"; v.type = INT;v.u.ival = 1; out_var(&v); v.name = "r"; v.type = REAL;v.u.rval = 3.4; out_var(&v); v.name = "s"; v.type = STR;v.u.sval = "C Language"; out_var(&v); return0;}voidout_var(conststructs_var *p) {printf("%s: ", p->name);switch (p->type) {case INT:printf("INT, %d\n", p->u.ival); break;case REAL:printf("REAL, %g\n", p->u.rval); break;case STR:printf("STR, %s\n", p->u.sval); break;default:printf("unknown type\n"); break; }} n: INT, 1 r: REAL, 3.4 s: STR, C Language
구조체와 공용체의 크기 • 정렬 제한 조건(alignment constraint) // anonymous structure struct { char c; int n; } s; sizeof s : 8 union { char c; int n; } u; sizeof u : 4 struct { char a; char b; int n; } s; sizeof s : 8 struct { char a; int n; char b; } s; sizeof s : 12
열거형 • 열거형(enumeration type): 정수형 상수 심볼 정의 enum days { SUN, MON, TUE, WED, THU, FRI, SAT }; // 0, 1, 2, 3, 4, 5, 6 태그 이름 정수형 상수 심볼 열거형변수 enum days today; today = SUN; // today = 0; printf("%d\n", MON); // 1 #define SUN 0 #define MON 1 … #define SAT 6
열거형 • 기호 상수(symbolic constant) 정의 • literal을 사용하는 것보다 가독성이 좋고 수정이 용이 • #define보다 편리하고 오류 가능성이 적음 • 자동으로 연속된 값 설정 가능 • 블록 구조 적용 • 단점: 정수형 상수만 정의 가능 • #define PI 3.14 // O • #define UNIV "SKHU" // O • enum { PI = 3.14 }; // X • enum { UNIV = "SKHU" }; // X #define INT 1 #define REAL 2 #define STR 3 // anonymous enum enum { INT = 1, REAL, STR }; // 1, 2, 3
열거형 초기화 enum{ E0, E1 = 3, E2 };// E0 = 0, E1 = 3, E2 = 4 enum{ C1 = 'A', C2, C3 };// C1 = 'A', C2 = 'B', C3 = 'C' enumColors { Red = 0xFF << 16, Green = 0xFF << 8, Blue = 0xFF }; enum Boolean { FALSE, TRUE }; enum levels { low = 1, medium, high }; enumCarTypes{ sedan, suv, sports_car, van, pickup, convertible };
예제 #include<stdio.h> enumdays { SUN, MON, TUE, WED, THU, FRI, SAT }; char*days_name[ ] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; intmain(void) { enumdays d = WED; printf("%d번째 요일은 %s입니다\n", d, days_name[d]); return0; } 3번째 요일은 Wednesday입니다
typedef • typedef: 기존 자료형에 새로운 타입 이름 부여 typedefold_typenew_type; typedefunsigedchar BYTE; BYTE index; // unsigned char index; typedefint INT32; typedefunsigned int UINT32; INT32 i; // inti; UINT32 k; // unsigned int k; struct point { int x, y; }; typedefstructpoint POINT; POINT a, b; // struct point a, b; typedef struct { int x, y; } POINT; POINT a, b; // struct { int x, y; } a, b;
예제 #include<stdio.h> typedefstruct { int x, y; } POINT; POINT move(POINT p, POINT delta); int main(void) { POINT p = { 2, 3 }, delta = { 10, 10 }, result; result = move(p, delta); printf("새로운점의좌표는 (%d, %d)입니다.\n", result.x, result.y); return 0; } POINT move(POINT p, POINT delta) { POINT new_p = { p.x + delta.x, p.y + delta.y }; returnnew_p; } 새로운 점의 좌표는 (12, 13)입니다.
typedef • 이식성(portability) 향상 • 기계독립적인 코드 작성 가능 • typedef unsigned long size_t; • #define은블록 구조가 적용되지 않고, 타입 정의 기능이 제한적임 • 문서화 기능 • 별도의 주석 없이도 자체적으로 설명력이 있음 가독성 향상 • // int: 2B, long: 4B 인 경우 • typedef long INT32; // 4B 정수형 • // int: 4B, long: 8B 인 경우 • typedefint INT32; // 4B 정수형 • #define INT32 int • INT32 n; // int n; • #define String char * • String s1, s2; // char * s1, s2; • // s1: char *, s2: char • typedef char *String; • String s1, s2; // char *s1, *s2; • // s1: char *, s2: char * • typedefintHeight; • Height h1, h2; • typedefintWeight; • Weight w1, w2;
예제 #include<stdio.h> typedefstruct { intnumber; char name[20]; double grade; } Student; Student LIST[ ] = { { 20120001, "홍길동", 4.2 }, { 20120002, "김철수", 3.2 }, { 20120003, "김영희", 3.9 } }; int main(void) { Student *best = LIST; Student *p = LIST + 1; Student *end = LIST + (sizeofLIST / sizeofLIST[0]); for ( ; p < end; p++) if (p->grade > best->grade) best = p; printf("수석:%s, %d, %g\n", best->name, best->number, best->grade); return 0; } 수석: 홍길동, 20120001, 4.2