Derived Types-- Enumerated, Structure and Union 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 months {jan, feb, mar, apr, may, jun, july, aug, sep, oct, nov, dec}; /* jan은 0, ….*/ enum months {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 months {jan=1, feb, mar, apr, may, jun, july, aug, sep, oct, nov, dec}; enum months birthMonth;
TV Channel Number #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.*/
Figure 12-4
Structured types 서로 연관된 자료를 실제형태를 추상화하여 묶어 놓은 것 구조형 안의 각 구성 요소를 필드(field)라 부름 필드는 변수의 특성을 가지며, 값 할당이 가능함 각 구성요소(field)의 형이 다를 수 있고, 각각 따로 심볼에 의한 이름이 있다는 면에서 배열과 다름 구조형은 일종의 템플릿(template)이다. 구조형 안의 원소는 서로 다른 형일 수 있지만 서로 관계가 있어야 한다
구조형 선언 구조형 변수의 선언
태그 구조형 struct student 꼭 “struct”를 넣어야! { 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
시간 출력 I #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 */
시간 출력 II 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 */
시간출력 III /* ==================== 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
중첩 구조형 <추천 못함> typedef struct { struct { int month; int day; int year; }date; { int hour; int min; int sec; } time; } STAMP; STAMP stamp; < 바람직> typedef struct { int month; int day; int year; } DATE; { int hour; int min; int sec; } TIME; { 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 */
구조체 전체 전달: 주소에 의한 방법 void multFr (FRACTION *pFr1, FRACTION *pFr2, 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 */ 수행결과 Short: 16706 Ch[0]: A Ch[1]: B
구조체 안의 공용체 법인과 개인은 법적으로 같은 권리가 있으므로 이를 유형에 따라 같은 위치에 저장하려고 할 때(은행에서 계좌 관리 등에 필요) 공용체가 아주 편리함 옆의 예 Type에 의해 결정 회사이름일 때는 마지막 10바이트를 사용하지 않는다.
조심!!!! big endian: 숫자의 큰 부분을 왼쪽에, Little endian: 숫자의 큰 부분은 오른쪽에 왼쪽은 big endiam임. 이 문제는 프로그램의 이식성에 문제를 발생시키므로 조심!!
인터넷 주소 153.18.8.105 typedef union { unsigned char chAddr[4]; unsigned long numAddr; } IP_ADDR;
엘리베이터 문제(state diagram)
실습 및 13장 예습 12장 Complex number에 대한 구조체를 정의하고, 이를 위한 +, -, *를 할 수 있는 함수를 구현하라. 32번, 33번, 43번 단, 43번은 시간이 많이 걸리면 토요일 오전까지 제출해도 됨. 13장 20, 21, 23