360 likes | 492 Views
Chapter 12. Derived Types-- Enumerated, Structure and Union. 사용자 정의 자료형. 사용자가 실제 문제 해결에 사용하는 자료와 가장 가까운 형태로 자료형을 선언할 수 있게 함 . 단 , 그와 관련된 연산은 직접 선언할 수 없음 . C++, Java 따위는 사용자가 직접 자료형과 연산을 동시에 선언할 수 있음 .
E N D
Chapter 12 Derived Types-- Enumerated, Structure and Union
사용자 정의 자료형 • 사용자가 실제 문제 해결에 사용하는 자료와 가장 가까운 형태로 자료형을 선언할 수 있게 함. 단, 그와 관련된 연산은 직접 선언할 수 없음. • C++, Java 따위는 사용자가 직접 자료형과 연산을 동시에 선언할 수 있음. • 이는 곧 풀려는 문제와 가장 가까운 자료구조를 선언하고, 이를 직접 사용함으로써 프로그램을 쉽게 짤 수 있으면서, 일기 쉽게 하는 것임. 문제 위주 프로그램을 더 쉽게 하게 함.
typedef • 새로운 형을 선언하는 것이 아니고 형을 다른 이름으로 부르게만 함 • typedef long int PNUINT; typedef char *STRING; PNUINT mark; STRING stringPtrAry[20];
열거형 • 정수에 기반을 둔 형 • 정수와 섞어 쓰지 않는 것이 좋음. • 크기 비교 연산이 가능하며, case문에서 쓸 수 있음 • 예 • enum month = {jan, feb, mar, apr, may, jun, july, aug, sep, oct, nov, dec}; /* jan은 0, ….*/ • enum month = {jan=1, feb=2, mar=3, jun=4, may=5, jun=6, july=7, aug=8, sep=9, oct=10, nov=11, dec=12}; • enum month = {jan=1, feb, mar, apr, may, jun, july, aug, sep, oct, nov, dec}; • enum months birthMonth;
#include <stdio.h> int main (void) { /* Local Definitions */ enum TV {fox = 2, nbc = 4, cbs = 5, abc = 11, hbo = 15, show = 17, max = 31, espn = 39, cnn = 51}; /* Statements */ printf("Here are my favorite cable stations:\n"); printf(" ABC: \t%2d\n", abc); printf(" CBS: \t%2d\n", cbs); printf(" CNN: \t%2d\n", cnn); printf(" ESPN:\t%2d\n", espn); printf(" Fox: \t%2d\n", fox); printf(" HBO: \t%2d\n", hbo); printf(" Max: \t%2d\n", max); printf(" NBC: \t%2d\n", nbc); printf(" Show:\t%2d\n", show); printf("End of my favorite stations. \n"); return 0; } /* main */ /* Results: Here are my favorite cable stations: ABC: 11 CBS: 5 CNN: 51 ESPN: 39 Fox: 2 HBO: 15 Max: 31 NBC: 4 Show: 17 End of my favorite stations.*/ TV Channel Number
Structured types • 서로 연관된 자료를 실제형태를 추상화하여 묶어 놓은 것 • 구조형 안의 각 구성 요소를 필드(field)라 부름 • 필드는 변수의 특성을 가지며, 값 할당이 가능함 • 각 구성요소(field)의 형이 다를 수 있고, 각각 따로 심볼에 의한 이름이 있다는 면에서 배열과 다름 구조형은 일종의 템플릿(template)이다. • 구조형 안의 원소는 서로 다른 형일 수 있지만 서로 관계가 있어야 한다
구조형 선언 • 구조형 변수의 선언
태그 구조형 structure student { char id[10]; char name[26]; int gradePoints; }; struct student aStudent; 꼭 “struct”를 넣어야!
형식 정의된 구조형 • typedef를 사용 • 아주 강력함 • 이름은 주로 대문자로 씀 typedef struct {char id[10]; char name[26]; int gradePoints; } STUDENT; STUDENT aStudent; 형 선언할 때 ‘struct’를 안 씀 이유를 잘 생각해볼 것
구조형 초기화 • 초기화하지 않으면 값이 어떤 값인지 알 수 없음
구조형 접근 • 구조형 필드는 개별적으로 접근할 수 있다. 전체로는 복사할 수 있다. 그러나 전체로 비교할 수는 없다. 비교하려면 각각을 모두 비교해야 한다. 슬랙 바이트(slack Bytes) 때문이다. • ‘구조형-변수-이름.필드이름’으로 접근 • sam2.x++; ++sam.x; …
구조형을 가리키는 포인터 • 포인터를 이용하여 구조체에 접근하는 방법을 아주 자주 사용한다 Linked list(14장) SAMPLE *ptr; //구조형 자료에 대한 포인터정의 ptr = &sam1; // 구조형에 대한 포인터 저장 *ptr // 전체 구조형 참조 (*ptr).x, (*ptr).y // 개별 요소 접근 조심 *ptr.x는 *(ptr.x)다!!!
선택연산자 • 구조체를 가리키는 포인터를 편리하게 사용할 수 있게 하기 위해 고안 • (*ptr).x ptr->x
#include <stdio.h> typedef struct { int hr; int min; int sec; } CLOCK; /* Prototype Declaration */ void increment (CLOCK *clock); void show (CLOCK *clock); int main (void) { /* Local Definition */ CLOCK clock = {14, 38, 56}; int i; /* Statements */ for(i = 0; i < 6; ++i) { increment (&clock); show (&clock); } return 0; } /* main */ 시간 출력 I
void increment (CLOCK *clock) { /* Statements */ (clock->sec)++; if (clock->sec == 60) { clock->sec = 0; (clock->min)++; if (clock->min == 60) { clock->min = 0; (clock->hr)++; if (clock->hr == 24) clock->hr = 0; } /* if 60 min*/ } /* if 60 sec */ return ; } /* increment */ 시간 출력 II
/* ==================== show ==================== This function shows the current time in military form. Pre clock time Post clock time displayed */ void show (CLOCK *clock) { /* Statements */ printf("%02d:%02d:%02d\n", clock->hr, clock->min, clock->sec); return; } /* show */ /* Results: 14:38:57 14:38:58 14:38:59 14:39:00 14:39:01 14:39:02 */ 시간출력 III
중첩 구조형 <추천 못함> typedef struct { struct { int month; int day; int year; }date; struct { int hour; int min; int sec; } time; } STAMP; STAMP stamp; < 바람직> typedef struct { int month; int day; int year; } DATE; typedef struct { int hour; int min; int sec; } TIME; typedef struct { DATE date; TIME time; } STAMP; STAMP stamp;
stamp, stamp.date, stamp.date.month, satmp.time.sec typedef struct { …. STAMP startTime; STAMP endTime; } JOB; JOB job; job.startTime.time.hour, job.endTime.time.hour 초기화 STAMP stamp = { {05, 10, 1936}, {23, 45, 00}}; 중첩구조 접근
배열을 포함하는 구조형 • student • student.name • student.name[i] • student.midterm • student.midterm[j] • student.final int *pScores pScores = student.midterm; totalScore = *pScores + *(pScores + 1) + *(pScores +2); STUDENT student = {“John Marcus”, {92, 80, 70}, 87}
포인터를 포함하는 구조형 • 구조형이 포인터를 가진 예 char jan[] = “January”; char feb[] = “February”; ….. char dec[] = “December”; typedef struct { char *month; int day; int year; } DATE stamp.date.month = may;
구조형의 배열 • 구조형의 배열을 사용하면 데이터의 관리와 처리가 쉽다. STUDENT stuAry[50]; int totScore = 0; float average; STUDENT *pStu; STUDENT *pLastStu; …. pLastStu = stuAry +49; for(pStu = stuAry; pStu <= pLastStu; pStu++) totScore += sStu->fianl; average = totScore / 50.0;
구조체 자체를 정렬을 할 때 옮기면 속도가 많이 떨어지므로 구조체를 가리키는 포인터만 이용하여 정렬하면 속도도 빠르고 편리함. 이에 대해서는 이미 포인터에서 실험을 함. 책의 프로그램을 다시 한번 살펴볼 것. 정렬 등을 할 때
구조형 각각에 대한 연산을 하는 함수를 만들어두고 이 함수로 구조체에 대한 연산을 하면 편리하면서 오류를 줄일 수 있다. 이 개념을 확대하여 구조체를 정의하면서 관련 연산도 정의할 수 있으면 이를 추상적 자료형이라 하며, C++나 Java는 이 기능을 제공한다. 그런데 이 기능이 없더라도 함수를 잘 이용하면 같은 효과를 얻을 수 있다. 전달 방법은 지금까지 배운 바와 같이 개별원소나 구조체 전체를 값이나 주소에 의해 전달한다. 구조형과 함수
구조체 전체 전달: 값에 의한 방법 FRACTION multFr (FRACTION fr1, FRACTION fr2) { /* Local Definition */ FRACTION res; /* Statements */ res.numerator = fr1.numerator * fr2.numerator; res.denominator = fr1.denominator * fr2.denominator; return res; } /* multFr */
/* ====================== multFr ===== Multiply two fractions and return the result. Pre fr1, fr2, pRes are pointers to fractions Post product stored at pRes */ void multFr (FRACTION *pFr1, FRACTION *pFr2, FRACTION *pRes) { /* Statements */ pRes->numerator = pFr1->numerator * pFr2->numerator; pRes->denominator = pFr1->denominator * pFr2->denominator; return; } /* multFr */
구조체 전체 전달: 주소에 의한 방법 /* ====================== multFr ===== Multiply two fractions and return the result. Pre fr1, fr2, pRes are pointers to fractions Post product stored at pRes */ void multFr (FRACTION *pFr1, FRACTION *pFr2, FRACTION *pRes) { /* Statements */ pRes->numerator = pFr1->numerator * pFr2->numerator; pRes->denominator = pFr1->denominator * pFr2->denominator; return; } /* multFr */
메모리에 서로 다른 데이터 형식을 공유할 수 있게 함 한쪽이 바뀌면 다른 쪽도 바뀌므로 극히 조심해야 함. (aliasing, side effect) 주로 메모리를 효과적으로 쓰기 위해 사용하며, 특히 하드디스크 등에는 정수나 문자 따위로 두고, 추후에 이 자료를 잘라서 쓸 때 사용함 공용체
공용체 사용의 예 수행결과 Short: 16706 Ch[0]: A Ch[1]: B #include <stdio.h> /* Global Declarations */ typedef union { short num; char chAry[2]; } SH_CH2; int main (void) { /* Local Definitions */ SH_CH2 data; /* Statements */ data.num = 16706; printf("Short: %hd\n", data.num); printf("Ch[0]: %c\n", data.chAry[0]); printf("Ch[1]: %c\n", data.chAry[1]); return 0; } /* main */
구조체 안의 공용체 • 법인과 개인은 법적으로 같은 권리가 있으므로 이를 유형에 따라 같은 위치에 저장하려고 할 때(은행에서 계좌 관리 등에 필요) 공용체가 아주 편리함 • 옆의 예 • Type에 의해 결정 • 회사이름일 때는 마지막 10바이트를 사용하지 않는다.
조심!!!! big endian: 숫자의 큰 부분을 왼쪽에, Little endian: 숫자의 큰 부분은 오른쪽에 왼쪽은 big endiam임. • 이 문제는 프로그램의 이식성에 문제를 발생시키므로 조심!!
153.18.8.105 typedef union { unsigned char chAddr[4]; unsigned long numAddr; } IP_ADDR; 인터넷 주소
12장 Complex number에 대한 구조체를 정의하고, 이를 위한 +, -, *를 할 수 있는 함수를 구현하라. 32번, 33번, 43번 단, 43번은 시간이 많이 걸리면 토요일 오전까지 제출해도 됨. 13장 20, 21, 23 실습 및 13장 예습