Download presentation
Presentation is loading. Please wait.
1
쉽게 풀어쓴 C언어 Express 제13장 구조체 C Express
2
구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다.
이번 장에서 학습할 내용 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. 구조체 구조체와 포인터 공용체 열거형 typedef
3
자료형의 분류 기본 자료형: char, int, float, double, … 자료형
파생 자료형: 배열, 구조체, 공용체, …
4
구조체를 사용하면 변수들을 하나로 묶을 수 있습니다.
구조체의 필요성 학생 데이터를 하나로 묶어서 처리하려면? 구조체를 사용하면 변수들을 하나로 묶을 수 있습니다. int number; char name[10]; double grade;
5
구조체와 배열 구조체(structure): 레코드(record) 같은 타입의 집합 다른 타입의 집합
6
구조체 선언 구조체 선언 형식 struct student { int number; char name[10];
태그(tag): 이름 구조체 선언 형식 struct 태그 { 자료형 멤버1; 자료형 멤버2; ... }; struct student { int number; char name[10]; double grade; }; 멤버(필드)
7
구조체 선언의 예 // x, y값으로 이루어지는 화면의 좌표 struct point { int x; // x 좌표
int y; // y 좌표 }; // 직사각형 struct rect { int x, y; int width, height; }; // 복소수 struct complex { double real; // 실수부 double imag; // 허수부 }; // 직원 struct employee { char name[20]; // 이름 int age; // 나이 int sex; // 성별 int salary; // 월급 }; // 날짜 struct date { int month; int day; int year; };
8
구조체 변수 선언 구조체 정의(선언)와 구조체 변수 선언은 다름 구조체 정의: 사용자 정의 자료형 선언
9
구조체의 초기화 중괄호를 이용하여 초깃값 나열 struct student { int number; char name[10];
double grade; }; struct student s1 = { 24, "Kim", 4.3 };
10
구조체 멤버 참조 구조체 멤버 참조 연산자: . struct student { int number; char name[10];
구조체 멤버 참조 연산자: . struct student { int number; char name[10]; double grade; }; struct student s1; s1.number = 24; strcpy(s1.name, "Kim"); s1.grade = 4.3;
11
예제 #include <stdio.h> #include <string.h> struct student {
int number; char name[10]; double grade; }; int main(void) { struct student s; s.number = ; strcpy(s.name, "홍길동"); s.grade = 4.3; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf(“학점: %f\n", s.grade); return 0; } 학번: 이름: 홍길동 학점:
12
예제 #include <stdio.h> struct student { int number;
char name[10]; double grade; }; int main(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; } 학번을 입력하시오: 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번: 이름: 홍길동 학점:
13
예제 #include <stdio.h> #include <math.h>
struct point { int x, y; }; int main(void) { struct point p1, p2; int xdiff, ydiff; double dist; printf("점의 좌표를 입력하시오(x y): "); scanf("%d %d", &p1.x, &p1.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 두 점 사이의 거리는 입니다. p2 (x,y) p1 (x,y)
14
구조체 중첩 number name dob grade s1 struct date { int month; int day;
int year; }; number name dob grade month day year s1 struct student { int number; char name[10]; struct date dob; // 구조체 안에 구조체 포함 double grade; }; struct student s1; s1.dob.month = 3; s1.dob.day = 29; s1.dob.year = 1983;
15
예제 x y #include <stdio.h> struct point { int x, y; };
struct rect { struct point p1, p2; }; int main(void) { struct rect 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
16
구조체 변수의 대입과 비교 같은 타입의 구조체 변수끼리 대입은 가능하지만 비교는 불가능
struct point { 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) // 올바른 비교 return 0; }
17
구조체 배열 구조체 배열의 선언 구조체 배열의 초기화 struct student { int number;
char name[10]; double grade; }; struct student list[3]; list[1].number = 24; strcpy(list[1].name, "Kim"); list[1].grade = 4.3; 구조체 배열의 초기화 struct student list[3] = { { 25, "Mun", 3.92 }, { 24, "Kim", 4.3 }, { 23, "Tim", 2.9 } };
18
예제 #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); } for (i = 0; i < SIZE; i++) printf("학번: %d, 이름: %s, 학점: %f\n", list[i].number, list[i].name, list[i].grade); return 0; 학번을 입력하시오: 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번을 입력하시오: 이름을 입력하시오: 김유신 학점을 입력하시오(실수): 3.92 학번을 입력하시오: 이름을 입력하시오: 이성계 학점을 입력하시오(실수): 2.87 학번: , 이름: 홍길동, 학점: 학번: , 이름: 김유신, 학점: 학번: , 이름: 이성계, 학점:
19
구조체를 가리키는 포인터 구조체를 가리키는 포인터 n p ptr … struct student { int number;
char name[10]; double grade; }; struct student s = { , "홍길동", 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); ptr … 3 4 p n int n = 3; struct s { int *ptr; … } p; p.ptr = &n; *p.ptr = 4; // *(p.ptr) = 4; n = 4;
20
-> 연산자 -> : 포인터로 구조체 멤버를 참조할 때 사용 (*p).member p->member
#include <stdio.h> struct student { int number; char name[20]; double grade; }; int main(void) { struct student s = { , "홍길동", 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; } 학번= , 이름=홍길동, 학점=
21
포인터 멤버를 가지는 구조체 number name grade dob s #include <stdio.h>
struct date { int month, day, year; }; struct student { int number; char name[20]; double grade; struct date *dob; }; int main(void) { struct date d = { 3, 20, 1980 }; struct student s = { , "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; } number name grade dob month day year s 학번: 이름: Kim 학점: 생년월일: 1980년 3월 20일
22
구조체와 함수 구조체를 함수의 인자로 전달하는 경우 복사본 전달 구조체가 크면 시간과 메모리 측면에서 비효율적
구조체의 포인터를 함수의 인자로 전달하는 경우 시간과 메모리 절약 가능 원본 훼손 가능 읽기만 하고 변경하지 않는 경우: const 선언 int f(struct student s) { … } int f(struct student *p) { … } int f(const struct student *p) { … } 포인터를 통한 구조체 변경 방지
23
구조체 인자와 구조체 반환 #include <stdio.h> struct vector { 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; 벡터의 합은 ( , )입니다.
24
구조체 포인터 인자 #include <stdio.h>
void vector_input(struct vector *p) { struct vector { float x, y; }; printf("벡터 입력: "); scanf("%f %f", &p->x, &p->y); void vector_input(struct vector *p); void vector_output(const struct vector *p); void vector_output(const struct vector *p) { int main(void) { printf("(%g, %g)", p->x, p->y); struct vector v; vector_input(&v); vector_output(&v); return 0; } 벡터 입력: (1.2, 3.4)
25
구조체 포인터 반환 #include <stdio.h> } struct vector { float x, y; };
struct vector *vector_input(struct vector *p) { struct vector *vector_input(struct vector *p); printf("벡터 입력: "); scanf("%f %f", &p->x, &p->y); void vector_output(const struct vector *p); return p; int main(void) { void vector_output(const struct vector *p) { struct vector v; vector_output(vector_input(&v)); printf("(%g, %g)", p->x, p->y); return 0; 벡터 입력: (1.2, 3.4)
26
인자 전달: 배열과 구조체 배열 인자: 포인터로 전달(원본 전달) 구조체: 복사본 전달
void f(int ary[ ]) { ++ary[0]; } // void f(int *ary) { ++*(ary + 0); } … int a[3] = { 10, 20, 30 }; f(a); // a[0]: 11 struct s_array { int a[3]; }; void f(struct s_array sa) { ++sa.a[0]; } … struct s_array s = { { 10, 20, 30 } }; f(s); // s.a[0]: 10
27
공용체 공용체(union) 같은 메모리 영역을 멤버들이 공유 공용체 선언 및 사용 방법은 구조체와 유사
union example { char c; // 메모리 공유 int i; // 메모리 공유 }; 공용체는 첫째 멤버로만 초기화 가능 union u_tag { float v; char *s; }; union u_tag u = 3.4F; // O union u_tag u = "name"; // X
28
예제 #include <stdio.h> union example { char c; int i; };
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 i 10000 v.c = A v.i = 10000
29
IP 주소 예제 (little endian) (big endian) (little endian) (big endian)
#include <stdio.h> union ip_address { unsigned char saddr[4]; unsigned int iaddr; }; int main(void) { union ip_address addr = { 0x7F, 0x00, 0x00, 0x01 }; printf("%08X\n", addr.iaddr); return 0; } addr saddr 7F 00 01 iaddr F (little endian) addr saddr 7F 00 01 iaddr 7F (big endian) F (little endian) 7F000001 (big endian)
30
공용체 활용 예제 #include <stdio.h> // variable types #define INT 1 #define REAL 2 #define STR 3 struct s_var { // variable structure char *name; int type; union { // value int ival; double rval; char *sval; } u; }; void out_var(const struct s_var *p); int main() { struct s_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); return 0; } void out_var(const struct s_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
31
구조체와 공용체의 크기 정렬 제한 조건(alignment constraint) 자료형 short(2B) int(4B)
float(4B) double(8B) 메모리 위치 2의 배수 4의 배수 4/8의 배수 // anonymous structure struct { char c; int n; } s; sizeof s : 8 union { char c; int n; } u; sizeof u : 4 c n c n struct { char a; char b; int n; } s; sizeof s : 8 struct { char a; int n; char b; } s; sizeof s : 12 a b n a n b
32
열거형 열거형(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
33
열거형 기호 상수(symbolic constant) 정의 #define보다 편리하고 오류 가능성이 적음
literal을 사용하는 것보다 가독성이 좋고 수정이 용이 #define보다 편리하고 오류 가능성이 적음 자동으로 연속된 값 설정 가능 블록 구조 적용 단점: 정수형 상수만 정의 가능 #define PI // 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 }; // , , 3
34
열거형 literal #define 열거형 switch (code) { case 1: printf("LCD TV\n");
break; case 2: printf("PDP TV\n"); } #define LCD 1 #define PDP 2 case LCD: case PDP: enum { LCD, PDP }; 기억하기 어렵고, 가독성이 나쁘며, 수정이 어려움 실수 가능성이 있고, 블록 구조가 적용되지 않음 #define PDP 1 실수 가능성이 적고, 블록 구조가 적용됨 정수형만 가능
35
열거형 초기화 enum { E0, E1 = 3, E2 }; // E0 = 0, E1 = 3, E2 = 4
enum { C1 = 'A', C2, C3 }; // C1 = 'A', C2 = 'B', C3 = 'C' enum Colors { Red = 0xFF << 16, Green = 0xFF << 8, Blue = 0xFF }; enum Boolean { FALSE, TRUE }; enum levels { low = 1, medium, high }; enum CarTypes { sedan, suv, sports_car, van, pickup, convertible };
36
예제 #include <stdio.h>
enum days { SUN, MON, TUE, WED, THU, FRI, SAT }; char *days_name[ ] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; int main(void) { enum days d = WED; printf("%d번째 요일은 %s입니다\n", d, days_name[d]); return 0; } 3번째 요일은 Wednesday입니다
37
typedef typedef: 기존 자료형에 새로운 타입 이름 부여 typedef old_type new_type;
typedef unsiged char BYTE; BYTE index; // unsigned char index; typedef int INT32; typedef unsigned int UINT32; INT32 i; // int i; UINT32 k; // unsigned int k; struct point { int x, y; }; typedef struct point POINT; POINT a, b; // struct point a, b; typedef struct { int x, y; } POINT; POINT a, b; // struct { int x, y; } a, b;
38
예제 #include <stdio.h> typedef struct { 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 }; return new_p; 새로운 점의 좌표는 (12, 13)입니다.
39
typedef 이식성(portability) 향상 #define은 블록 구조가 적용되지 않고, 타입 정의 기능이 제한적임
기계 독립적인 코드 작성 가능 typedef unsigned long size_t; #define은 블록 구조가 적용되지 않고, 타입 정의 기능이 제한적임 문서화 기능 별도의 주석 없이도 자체적으로 설명력이 있음 가독성 향상 // int: 2B, long: 4B 인 경우 typedef long INT32; // 4B 정수형 // int: 4B, long: 8B 인 경우 typedef int 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 * typedef int Height; Height h1, h2; typedef int Weight; Weight w1, w2;
40
예제 #include <stdio.h> typedef struct { int number;
char name[20]; double grade; } Student; Student LIST[ ] = { { , "홍길동", 4.2 }, { , "김철수", 3.2 }, { , "김영희", 3.9 } }; int main(void) { Student *best = LIST; Student *p = LIST + 1; Student *end = LIST + (sizeof LIST / sizeof LIST[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; } 수석: 홍길동, , 4.2
Similar presentations