제9장 구조체 및 공용체 문봉근
제9장 구조체 및 공용체 9.1 구조체(structure) 9.2 공용체(union) 9.3 열거형(enumeration) 9.4 형 정의(typedef) 9.5 비트-필드(bit-field) 9.6 구조체 응용 프로그램
9.1.1 구조체 정의 및 변수 선언 구조체(structure)는 여러 개의 변수를 쉽게 사용할 수 있도록 하나의 이름으로 묶어 놓은 하나 이상의 변수의 집합 구조체에 포함되는 변수는 배열과는 달리 서로 다른 데이터형들로 구성된다. 구조체는 배열이나 다른 구조체 등과 같은 C 언어에서 사용 가능한 모든 데이터형을 포함할 수 있다. 즉, 구조체는 배열과는 달리 이질적인(heterogeneous) 자료형으로 원소들을 구성할 수 있는 구조적 자료형으로서, 각 원소들은 배열처럼 기억장소에 순차적으로 저장된다. 구조체를 정의하고 구조체 변수를 선언하는 일반적인 형식 ■ 문법 (1)struct <tag명> {<component_list>}; /*형 정의*/ struct <tag명> <variable_list>; /*변수 선언*/ (2)struct <tag명> {<component_list>} <variable_list>; /*형 정의와 선언*/ (3)struct {<component_list>} <variable_list>; /*형 정의와 선언*/ (4)typedef struct {<component_list>} <identifier>; /* 형 정의 */ <identifier> <variable_list>; /* 변수 선언 */
9.1.1 구조체 정의 및 변수선언(계속) 백화점 고객의 구조체 형태 이 구조체의 이름을 ‘customer‘할 때, 위와 같은 형태의 구조체를 정의하는 방법은 다음과 같다. struct customer{ int id; char name[20]; char address[30]; char telephone[12]; int amount; };
9.1.1 구조체 정의 및 변수선언(계속) 여러 가지 구조체 정의 및 구조체 변수의 선언 (1) 사용예1 (2) 사용예2 struct list{ char *univ; char *class; int count; }; main() { struct list y1, y2, y3; .............. } (2) 사용예2 struct{ } y1={"Hankuk","C Langugage", 40}; (3) 사용예3 } y1, y2, y3; /*구조체 변수 3개 선언*/
9.1.2 구조체의 멤버 접근 특정 구조체 변수에 포함된 멤버 데이터에 접근하기 위해서는 도트연산자를 사용한다. 도트연산자는 ‘구조체_변수명.멤버명’과 같이 구조체 변수명과 멤버명 사이에 기입된다. struct coord{ int x; int y; }; ........... struct coord first, second; first.x=50; first.y=100; second.x=40; second.y=60; 위의 예에는 first와 second가 구조체 변수로 선언되어 있다. 이 구조체 변수의 멤버 데이터에는 정수형의 x, y가 있음을 구조체 정의로부터 알 수 있다. 구조체 변수와 멤버 데이터 사이에 도트연산자가 들어간다는 사실 이외에는 일반적인 변수의 사용과 동일하다.
9.1.2 구조체의 멤버 접근(계속) 예제 9.1 구조체 선언과 도트연산자를 이용한 구조체 멤버 표현. ☑ 프로그램 #include <stdio.h> #include <string.h> struct student { char name[20]; int korean; int english; }; void main() { struct student kdhong; strcpy(kdhong.name, "홍길동"); kdhong.korean=90; kdhong.english=99; printf("이름 : %s \n", kdhong.name); printf("국어 : %d \n", kdhong.korean); printf("영어 : %d \n", kdhong.english); } ꁼ 실행결과 이름 : 홍길동 국어 : 90 영어 : 99
9.1.2 구조체의 멤버 접근(계속) 예제 9.2 구조체 선언과 데이터 입력 및 출력 방법. ☑ 프로그램 #include <stdio.h> struct robot { //구조체 선언하는 방법. struct [데이타 타입] int head; int body; char arm[20]; //char의 경우 배열로 받는다. long leg; }; void main(void) { struct robot tv; //데이타 타입에 따른 변수선언. printf(" input head(int) : "); scanf("%d", &tv.head); printf(" input body(int) : "); scanf("%d", &tv.body); printf(" input arm(char) : "); scanf("%s", tv.arm); //string으로 받아서 배열에 저장 printf(" input leg(long) : "); scanf("%ld", &tv.leg); printf("%d %d %s %ld\n", tv.head, tv.body, tv.arm, tv.leg); } ꁾ 입력 input head(int) : 34 input body(int) : 21 input arm(char) : kkk input leg(long) : 495 ꁼ 실행결과 34 21 kkk 495
9.1.2 구조체의 멤버 접근(계속) 예제 9.3 입력된 자료를 구조체 변수의 각각의 멤버에 저장한 후에, 이를 화면에 다시 출력하는 프로그램을 작성하라. ☑ 프로그램 #include <stdio.h> main(void) { struct tel_nr /* 구조체 정의 */ char name[20]; char addr[40]; char tel[20]; }; struct tel_nr one; /* 구조체 변수 선언 */ /* name, addr, tel은 문자형이기 때문에 scanf()에서 &을 사용할 수 없다 */ scanf("%s %s %s", one.name, one.addr, one.tel); printf(" %s\n %s\n %s\n", one.name, one.addr, one.tel); } ꁾ 입력 Hong Seoul (02)123-4567 ꁼ 실행결과
9.1.2 구조체의 멤버 접근(계속) 예제 9.4 멤버를 문자형으로 name을, 정수형으로 age와 income으로 하고 tag를 enployee로 하는 구조체를 선언한 후 구조체 변수 list를 선언하여 name에 "홍길동", age에 35, income에 220을 대입하고 표시하라. ☑ 프로그램1 /* (1) struct <tag명> {<component_list>}; */ /* struct <tag명> <variable_list>; */ #include <stdio.h> void main() { struct employee { char *name; int age, income; }; struct employee list; list.name="홍길동"; list.age = 35; list.income = 220; printf("%10s %3d %4d\n", list.name, list.age, list.income); } ꁼ 실행결과 홍길동 35 220
9.1.2 구조체의 멤버 접근(계속) 예제 9.4(계속) ☑프로그램2 /* (2) struct <tag명> {<component_list>} <variable_list>; */ #include <stdio.h> void main() { struct employee { char *name; int age, income; } list; list.name="홍길동"; list.age = 35; list.income = 220; printf("%10s %3d %4d\n", list.name, list.age, list.income); } ꁼ 실행결과 홍길동 35 220
9.1.2 구조체의 멤버 접근(계속) 예제 9.5 구조체 포인터를 사용한 예제 ☑ 프로그램 #include <stdio.h> #include <string.h> struct student { char name[20]; int korean; int english; }; void main() { struct student kdhong; struct student *sp=&kdhong; /*포인터sp에 lee의 시작주소 배정*/ strcpy(sp->name, "홍길동"); sp->korean=90; (*sp).english=99; /* sp->eng=99 와 같은 의미 */ printf("이름 : %s \n",sp->name); printf("국어 : %d \n",sp->korean); printf("영어 : %d \n",sp->english); } 구조체의 포인터 변수는 구조체의 멤버 데이터에 접근하기 위해 간접 멤버 참조 연산자인 화살표연산자(arrow operator, ->)를 사용함 화살표연산자(->)는 ‘구조체_포인터명->멤버명’과 같이 구조체 포인터명과 멤버명 사이에 기입됨
9.1.2 구조체의 멤버 접근(계속) 예제 9.6 ☑ 프로그램 #include <stdio.h> struct s_type{ int i; char ch; double d; }var1, var2; void struct_swap(struct s_type* a, struct s_type* b); main() { var1.i = 100; var1.ch = 'A'; var1.d = 10.0; var2.i = 200; var2.ch = 'B'; var2.d = 20.0; struct_swap(&var1, &var2); printf("var1: %d, %c, %lf\n", var1.i, var1.ch, var1.d); printf("var2: %d, %c, %lf\n", var2.i, var2.ch, var2.d); return 0; } void struct_swap(struct s_type* a, struct s_type* b) struct s_type tmp; tmp = *a; *a = *b; *b = tmp; ꁼ 실행결과 var1: 200, B, 20.000000 var2: 100, A, 10.000000
9.1.2 구조체의 멤버 접근(계속) 예제 9.7 구조체를 이용한 성적계산 프로그램 ☑ 프로그램 #include <stdio.h> struct level { //구조체 선언하는 방법. struct [데이타 타입] char name[3]; int kor; int eng; int math; int total; float avr; }; void main(void) { struct level first_session[3]; //데이타 타입에 따른 변수선언. int i; for (i=0; i<3; i++) { printf(" 이름을 입력하시오 : "); scanf("%s", first_session[i].name); printf(" 국어 성적을 입력하시오 : "); scanf("%d", &first_session[i].kor); printf(" 영어 성적을 입력하시오 : "); scanf("%d", &first_session[i].eng); //string으로 받아서 배열에 저장 printf(" 수학 성적을 입력하시오 : "); scanf("%d", &first_session[i].math); first_session[i].total = first_session[i].kor + first_session[i].eng + first_session[i].math; first_session[i].avr = (float)first_session[i].total/3; printf("이름 : %s, 국어 : %d\n 영어 : %d, 수학: %d\n“, first_session[i].name, first_session[i].kor, first_session[i].eng, first_session[i].math,); printf("총점 : %d, 평균 : %f\n", first_session[i].total, first_session[i].avr); }
9.1.3 구조체의 초기화 구조체의 초기화 방법은 일반적인 배열의 초기화와 매우 유사하다. 구조체 초기화를 위해 대입연산자 (=)를 사용하며, 만일 구조체의 각 멤버의 수보다 적은 개수의 값이 할당되면 나머지는 ‘0’ 또는 ‘ ’로 간주된다. 방법 : 구조체를 구성하는 각 멤버에 초기화 값을 중괄호({})를 사용하여 정의 (1) 사용예1 struct student{ int student_id; char name[20]; int kor; int eng; }; struct student teamA={1001, "Kim, Su Young", 97, 99}; (2) 사용예2 }teamA={1001, "Kim, Su Young", 97, 99};
9.1.3 구조체의 초기화(계속) (3) 사용예3 struct student{ int hakbun; char name[20]; int kuk; int eng; }; struct student teamA[3]={ { 1001, "Kim, Su Young", 97, 99}, { 1002, "Lee, Gi Chan", 97, 99}, { 1003, "Choi, Hee Sun", 97, 99},
9.1.4 중첩된 구조체 구조체가 멤버 데이터의 형태로 오는 경우, 이와 같은 구조체를 중첩 구조체(nested structure)라고 한다. 구조체의 멤버 데이터는 C 언어에서 사용될 수 있는 모든 데이터 형태가 사용될 수 있다. 중첩 구조체의 일례 struct rectangle { struct coord topleft; struct coord bottomright; }; 이 구조체를 이용해서 사각형을 그리려면 우선 구조체 변수를 선언해 주어야 함. struct rectangle mybox; 두개의 좌표로 이루어진 두 점의 이용 mybox.topleft.x=0; mybox.topleft.y=10; mybox.bottomright.x=100; mybox.bottomright.y=200;
9.1.4 중첩된 구조체(계속) 예제 9.8 다음과 같은 메모리 맵을 갖는 중첩된 구조체의 멤버 변수를 확인하는 프로그램을 작성하라. ☑ 프로그램 struct tagg { /* 구조체 tagg 정의 */ char c[10]; struct subtag { /* 중첩된 구조체 subtag 정의 */ int i; double d; }z; /* 중첩된 구조체 subtag의 변수 선언 */ int j; } x; /* 구조체 tagg의 변수 선언 */ main(void) { x.z.i=10; /* 개별 항목에 대한 접근 */ x.j=100; printf("%d %d\n", x.z.i, x.j); } ꁼ 실행결과 10 100
9.1.5 구조체 배열 구조체 변수가 많아지면 프로그램이 복잡하게 되므로 통상의 변수와 마찬가지로, 이를 배열로 선언하면 편리하다. struct list y1, y2, y3;를 struct list y[3];와 같이 사용할 수 있다. struct list{ char *univ; char *class; int count; }; main() { int i; struct list y[3]; ............ }
9.1.5 구조체 배열(계속) 구조체 배열이란 구조체가 배열의 요소가 되는 경우를 말함 구조체 배열의 선언은 기존의 배열 선언 방법과 유사함. struct book { float value; char title[10]; char author[7]; }; struct book library[100]; 구조체인 book 형태의 변수 100개로 이루어진 library라는 배열이다. 각 배열의 요소가 구조체이기 때문에, 각 구조체에 대해서 멤버 데이터가 존재한다. 그런데 배열의 요소는 그 변수 형태가 모두 동일하듯이 구조체 배열의 요소인 각 구조체 변수의 속성은 모두 같다.
9.1.5 구조체 배열(계속) 구조체 배열 library의 메모리 맵 상태 library.value[2]; /* 틀림 */
9.1.5 구조체 배열(계속) 구조체 배열의 대입 구조체 배열 변수의 선언 형식 예 배열의 요소인 각 구조체의 기본적인 형태가 같기 때문에 대입(assignment)도 가능하다. 구조체는 같은 구조를 가진 구조체인 경우에는 구조체끼리의 연산이 가능하기 때문이다. library[3] = library[5] strcpy(library[3].value, library[5].value) 구조체 배열 변수의 선언 형식 예 (1)형식1 : struct employee { char *name; int age, income; }list[5]; (2)형식2 : }; struct employee list[5];
9.1.5 구조체 배열(계속) 예제 9.9 가족의 이름과 나이 및 성별을 출력하는 프로그램을 다음과 같은 member형 구조체 변수를 이용하여 작성하라. struct member { char *name; char *sex; int age; } ☑ 프로그램 #include <stdio.h> main() int i; }; struct member a[4]={"Hong, Kil-dong","male",50, "Choi, Soon-Hee","female",46, "Hong, Heon-Jeong","female",3, "Hong, Yoo-Shin","male",2}; for(i=0;i<4;i++) printf("%s %s %d\n",a[i].name,a[i].sex,a[i].age); return 0;
9.1.5 구조체 배열(계속) 예제 9.10 1에서 20까지의 수의 제곱과 세제곱을 저장하기 위해 구조체 배열을 사용하는 프로그램을 작성하여라. 배열의 내용도 출력하여라. ☑ 프로그램 #include <stdio.h> struct power{ int i; int square; int cube; }nums[20]; main() { for(i=1; i<=20; i++) nums[i].i=i; nums[i].square=i*i; nums[i].cube=i*i*i; } printf("nums[%2d].square=%3d, nums[%2d].cube=%4d\n", i, nums[i].square, i, nums[i].cube); return 0;
9.1.5 구조체 배열(계속) 예제 9.11 고용자 이름, 전화번호, 작업시간 그리고 시간당 임금을 저장하는데 구조체 배열을 사용하는 프로그램을 작성하여라. 10명의 고용자를 저장할 수 있게 하여라. ☑ 프로그램 #include <stdio.h> #include <stdlib.h> struct s_type{ char name[40]; char phone[14]; int hours; double wage; }emp[10]; void main(void) { int i; char temp[80]; for(i=0; i<2; i++) printf("Enter name: "); gets(emp[i].name); printf("Enter telephone number: "); gets(emp[i].phone); printf("Enter hours worked: "); gets(temp); emp[i].hours = atoi(temp); printf("Enter hourly wage: "); emp[i].wage = atof(temp); } printf("name=%s, phone=%s, hour=%d, wage=%lf\n", emp[i].name, emp[i].phone, emp[i].hours, emp[i].wage);
9.1.5 구조체 배열(계속) 예제 9.12 20세 이상의 남자직원, 및 이름이 "ziny"인 사람 찾아서 출력하기 ☑ 프로그램 #include <stdio.h> #include <string.h> struct member { //구조체 선언하는 방법. struct [데이타 타입] char name[10]; //이름 char sex; //성별 int age; //나이 char level[10]; //직위 }; void main(void) { struct member member_session[5]= { {"ziny", 'M', 29, "사장"}, {"이말단", 'M', 25, "사원"}, {"임부장", 'M', 39, "부장"}, {"심대리", 'F', 22, "대리"}, {"김이사", 'M', 43, "이사"}}; //데이타 타입에 따른 변수선언. int i; for (i=0; i<5; i++) { if(member_session[i].sex == 'M' && member_session[i].age > 20) printf("이름 : %s \n직위 : %s\n", member_session[i].name, member_session[i].level); } printf("\n\n"); if (strspn(member_session[i].name,"ziny")!=0) //이름이 ziny인 사람만 검색
9.1.6 구조체 포인터 구조체와 포인터의 관계 포인터변수가 구조체 멤버가 되는 경우 구조체 포인터의 경우 구조체 포인터의 예 struct member { int number; char name[5]; }; struct member *ptr; 구조체와 구조체 간에, 또는 구조체 포인터와 구조체 간에 어떤 관계를 가지기 위해서는 서로 구조체 구조가 같아야 한다. struct member student; ptr = &sutdent; /* 포인터변수 ptr의 초기화 */
9.1.6 구조체 포인터(계속) 구조체에 대한 포인터를 사용하여 구조체 멤버를 참조하는 방법 도트연산자(.) (*ptr).number = 13; 간접연산자(*)는 도트연산자(.)보다 우선순위가 낮기 때문에 다음과 같이 괄호를 같이 써 주어야 한다. 화살표연산자(->) ptr->number = 17;
9.1.6 구조체 포인터(계속) 예제 9.13 malloc() 함수를 이용한 배열의 영역을 확보하고 데이터를 저장하는 방법 ☑ 프로그램 #include <stdio.h> void main() { struct employee char *name; int age, income; } *list; list=malloc(sizeof(list)); /*메모리 확보(크기는 list)*/ list->name="김철수"; list->age=38; list->income=562; printf("%s %d %d만원\n", list -> name, list -> age, list -> income); } ꁼ 실행결과 김철수 38 562만원
9.1.7 구조체와 함수 함수에서 매개 변수로 구조체를 주고받는 두 가지 방법 구조체는 다른 데이터형과 마찬가지로 함수의 인수로 구조체를 전달할 수도 있다. 함수에서 매개 변수로 구조체를 주고받는 두 가지 방법 구조체를 매개 변수로 사용하는 경우 struct student {........} std, p; main() { p=sub(std); } struct student sub(struct student std_sub) return std_sub; 구조체 포인터를 매개 변수로 사용하는 경우 struct student {........} std; void main() sub(&std); void sub(struct student *std_sub) (*std_sub).id=1004;
9.1.7 구조체와 함수(계속) 예제 9.14 구조체의 내용을 표시해 주는 함수를 두 가지 방식으로 구조체에 전달 ☑ 프로그램 #include <stdio.h> struct student{ char name[20]; int korean; int english; }; void disp1(struct student aa) { printf("%s %d %d\n", aa.name, aa.korean, aa.english); } void disp2(struct student *bb) printf("%s %d %d\n", bb->name, bb->korean, bb->english); void main() struct student lee={"Hong, Gil Dong", 90, 80}; disp1(lee); disp2(&lee); ꁼ 실행결과 Hong, Gil Dong 90 80
9.1.7 구조체와 함수(계속) 예제 9.15 구조체 자체가 함수의 인수로 사용된 또 다른 예 ☑ 프로그램 #include <stdio.h> struct data{ /* 구조체의 선언 */ int x, y; }; int total(struct data tot); /* 함수의 원형 */ void main() { struct data value = {1, 3}; /* 구조체의 초기화 */ int sum = 0; sum = total ( value); /* 함수의 호출 */ printf("Sum = %d\n", sum); } int total(struct data tot) /* 함수의 정의 */ return (tot.x + tot.y); ꁼ 실행결과 Sum = 4
9.2 공용체 공용체(union) 여러 자료형의 원소들이 공통으로 사용할 수 있는 기억장소를 정의하고, 한 번에 하나의 멤버만이 특정한 자료형 기억장소로 사용할 수 있도록 메모리를 관리하는 자료형 공용체(union)는 구조체와 유사하며, 구조체와 같은 방법으로 선언되고 사용된다. 공용체는 한 번에 하나의 멤버만이 사용될 수 있다는 점에서 구조체와 다르다. 공용체의 모든 멤버는 메모리에서 같은 영역을 차지하고 있다. 즉, 모든 멤버는 겹쳐져 있는 셈이다. 공용체는 구조체와 거의 같기 때문에 멤버에 접근하기 위해서 사용되는 구조체연산자가 모두 사용될 수 있다. 구조체와 달리 데이터를 초기화시킬 수 없다. ■ 문법 union <tag 명> {<component_list>} <variable_list>; 구조체에서 <component_list>의 항목들은 각각 별도의 기억장소를 배정 받는데 반해, 공용체에서는 항목들 중에서 가장 큰 기억장소를 요하는 자료형의 크기만큼 확보하여 모든 항목들이 공통으로 사용한다. 공용체 변수는 함수의 매개변수로 사용될 수 없다는 것이 또 하나의 특징이다.
9.2 공용체(계속) union shared { char c; int i; }; union shared generic_variable; generic_variable.c = 'a'; 공용체는 한 번에 하나의 멤버만 사용될 수 있기 때문에 초기화도 하나의 멤버에 대해서만 해 줄 수 있다. 공용체의 다른 멤버를 초기화 해주면 메모리 내에서는 그 위에 덮여 씌우기 때문에 처음에 초기화 해준 내용은 사라진다. union{ date married, widowed; /* 결혼과 과부의 경우 */ struct { date ddate; boolean firstd; } divorced; /* 이혼한 경우 */ boolean single; /* 독신의 경우 */ } status;
9.2 공용체(계속) 예제 9.16 공용체 tagg의 변수 v1은 정수 n과 실수 i로 선언된 두 멤버 중에서 최근에 결정된 멤버 i에 대한 변수로만 사용되는 것을 보여 준다. ☑ 프로그램 #include <stdio.h> union tagg{ /* 공용체 정의 */ int n; float i; } v1, *pt; void main() { float k; pt=&v1; v1.n=10; v1.i=20.0; k=pt->i; /* pt->n으로 사용할 수 없다 */ printf("%f", k); } ꁼ 실행결과 20.000000
9.2 공용체(계속) 예제 9.17 short int를 int로 변경하기 위해 공용체를 사용하는 프로그램을 작성하여라. ☑ 프로그램 #include <stdio.h> void main() { union u_type{ int i; short int s; }uvar; uvar.i=500; uvar.s=1000; printf("%d\n", uvar.i); } ꁼ 실행결과 1000
9.2 공용체(계속) 예제 9.18 short int의 상위 바이트와 하위 바이트의 값을 개별적으로 출력하는 프로그램을 작성하여라. 이때, 하나의 정수와 2바이트 문자 배열의 두 원소로 구성된 공용체를 사용하여라. ☑ 프로그램 #include <stdio.h> void main(void) { union u_type { short int i; unsigned char c[2]; } uvar; uvar.i = 511; printf("High order byte: %u\n", uvar.c[1]); printf("Low order byte: %u\n", uvar.c[0]); } ꁼ 실행결과 High order byte: 1 Low order byte: 255
9.2 공용체(계속) 예제 9.19 사용자가 입력한 정수를 포함하는 개개의 바이트를 문자로 출력하기 위해 공용체(union)를 사용하는 프로그램을 작성하여라. ☑ 프로그램 #include <stdio.h> union i_to_c{ char c[4]; int i; } ic; void main(void) { printf("Enter an integer: "); scanf("%x", &ic.i); printf("character represention of each byte: %c %c %c %c\n", ic.c[0], ic.c[1], ic.c[2], ic.c[3]); } ꁼ 실행결과 Enter an integer: 41424344 character represention of each byte: D C B A
9.2 공용체(계속) 예제 9.20 하나의 double과 8바이트 문자 배열로 구성된 공용체를 사용하여, 한 번은 하나의 double을 쓰고 다음에는 하나의 문자(char)를 쓰는 함수를 작성하여라. ☑ 프로그램 #include <stdio.h> #include <stdlib.h> union u_type{ double d; unsigned char c[8]; }; uread(union u_type* pvar); main() { int i; union u_type var; uread(&var); printf("%lf\n", var.d); for(i=0; i<8; i++) printf("var.c[%d]=%c\n", i, var.c[i]); } uread(union u_type* pvar) printf("Enter a double number: "); scanf("%lf", &pvar->d); getchar(); printf("Enter 8 charaters: "); scanf("%c", &pvar->c[i]);
9.3 열거형 C 언어는 사용자가 자료의 값을 임의로 정하고 이를 열거하여 새로운 자료형을 정의할 수 있는데, 이러한 자료형을 열거형(enum)이라고 한다. 열거형은 상수의 성질을 갖는 데이터형으로서, 열거형의 정의 부분을 제외한 프로그램 문장 부분에서 열거형 상수에 어떤 값을 배정하는 행위는 불가능하다. 열거형 상수를 사용하여 프로그램을 기호화(symbolic programming)하는 것은 프로그램의 수정을 용이하게 하고, 프로그램의 판독성(readability)을 향상시킨다. ■ 문법 enum <identifier> enum { <identifier >, … } enum { <identifier > = <constant-expression>, … } enum <identifier> { <identifier>, … } enum <identifier> { <identifier> = <constant-expression>, … } 열거형에 나열된 값들은 번역기에 의하여 나열된 순서에 따라 0부터 1씩 증가되는 값을 할당받아 참조 시에 이를 열거된 값에 일치시킨다. 예를 들면, 컴파일러는 enum day {sun, tues, wed, thur, fri, sat} weekday를 enum day {0, 1, 2, 3, 4, 5, 6}으로 해석하여 번호로 값을 일치시킨다. 이때 weekday=sun과 같은 배정문에서 weekday 값은 0으로 해석되나 사용자는 코드값 대신에 요일 이름을 사용함으로써 프로그램의 이해를 향상시킬 수 있다. enum num{sun=2, mon=0, tue=5, wed, thu, fri, sat, someday}day; 이 경우, tue=5의 다음부터는 tue에 1씩 더하여 wed=6, thu=7, fri=8, sat=9, someday=10이 된다.
9.3 열거형(계속) 예제 9.21 열거형을 이용하여 요일을 표시하였을 때 사용 방법. ☑ 프로그램 #include <stdio.h> void main() { enum day{ Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }d; d=Monday; printf("%d\n", d); } ꁼ 실행결과 1
9.3 열거형(계속) 예제 9.22 열거형의 처음데이터만 초기값을 부여했을 경우. ☑ 프로그램 #include <stdio.h> void main() { enum day{ Sunday=3 Monday,Tuesday,Wednesday Thursday,Friday,Saturday }d; d=Monday; printf("%d\n", d); } ꁼ 실행결과 4
9.3 열거형(계속) 예제 9.23 열거형의 초기값을 순서에 관계없이 부여했을 경우. ☑ 프로그램 #include <stdio.h> void main() { enum num{ sum=2, mon=0, tue=5, wed, thu, fri, sat, someday}d; d=someday; printf("%d\n", d); } ꁼ 실행결과 10
9.3 열거형(계속) 예제 9.24 초기값이 부여되지 않은 열거형. ☑ 프로그램 #include <stdio.h> enum day {sun, mon, tue, wed, thu, fri, sat}; //초기값이 없기때문에 0~6까지 변수값이 대입된다. typedef enum day day; day find_next_day(day d) { return ((day)(((int)d+1)%7)); } void main(void) { day cur_day=tue; char* d_name[] = {"일", "월", "화", "수", "목", "금", "토"}; printf("%s요일\n", d_name[find_next_day(cur_day)]); ꁼ 실행결과 수요일
9.3 열거형(계속) 예제 9.25 열거형을 이용한 계산(전월 나타내기) ☑ 프로그램 #include <stdio.h> enum month {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; typedef enum month mon; mon find_prev_mon(mon m) { return (mon)((m+11)%12); } void main(void) { mon cur_mon=Jan; char* m_name[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; printf("%s\n", m_name[find_prev_mon(cur_mon)]); ꁼ 실행결과 December
9.4 형 정의 예제 9.26 형 정의(typedef)는 프로그램 작성자가 데이터형을 자신이 만든 이름으로 바꾸어 준다. 복잡한 선언을 간단한 이름으로 바꾸고자 할 때 많이 쓰이며, 소문자를 사용해도 무방하지만, 대문자를 사용하여 다른 데이터형과 구별하는 것이 일반적이다. ■ 문법 typedef [기존의 데이터형] [새로운 데이터형] 예제 9.26 일반적인 사용예 ☑ 프로그램 typedef float REAL typedef unsigned char BYTE void main() { REAL t; // = float t BYTE ch; // = unsigned char ch }
9.4 형 정의(계속) 예제 9.27 문자형 typedef 선언의 예 ☑ 프로그램 #include <stdio.h> typedef char string[80]; void main() { string a, b; strcpy(a, "typedef의 시험용"); strcpy(b, "문자열이다."); printf("이것은 %s %s \n", a, b); } ꁼ 실행결과 이것은 typedef의 시험용 문자열이다.
9.4 형 정의(계속) 예제 9.28 변수의 대입이 잘못된 예 ☑ 프로그램 #include <stdio.h> #include <string.h> typedef char string[80]; void main() { string a, b; strcpy(a, "이것은 시험용"); b=a; /*변수 a와 b는 배열*/ printf("이것은 %s %s \n", a, b); }
9.4 형 정의(계속) 예제 9.29 형 정의(typedef)와 구조체 ☑ 프로그램 #include <stdio.h> typedef struct person { char name[10], street[20]; int id; } person; void read_info(struct person *a_person) { printf("이름을 입력하시오 : "); scanf("%s", a_person ->name); printf("%s가 살고 있는 거리를 입력하시오 : ", a_person->name); scanf("%s", a_person ->street); printf("%s의 id를 숫자로 입력하시오 : ", a_person->name); scanf("%d",&(a_person->id)); } void main() person people[5]; int i; for(i=0; i<5;i++) read_info(&people[i]); printf("people[1]의 이름은 %s, 사는 곳은 %s, id는 %d.\n", people[1].name, people[1].street,people[1].id);
9.4 형 정의(계속) 예제 9.30 형 정의(typedef)와 열거형 ☑ 프로그램 #include <stdio.h> typedef enum { false, true } boolean; /* 열거형 boolean 정의 */ void main() { /* 열거형 color 정의와 변수선언 */ enum color{ white, red, blue, green, black } farbe; int a[5], i; boolean yesno; yesno=true; if (yesno) { for (farbe=white; farbe<=black; farbe++) scanf("%d", &a[farbe]); /*열거형 변수를 배열의 첨자로 사용*/ } printf("%d, %d ", a[farbe], farbe); printf("\n"); for (i=0; i<5; i++) /* 정수형 변수를 첨자로 사용 */ printf("%d ", a[i]); ꁾ 입력 1 2 3 4 5 ꁼ 실행결과 1, 0 2, 1 3, 2 4, 3 5, 4 1 2 3 4 5
9.5 비트-필드 비트-필드(bit-field)는 새로운 데이터 구조라기보다는 구조체와 공용체의 조합에서 약간의 내용이 추가된 것이다. 각 구조체 멤버를 비트 단위로 나눌 수 있어 더욱 더 세밀한 데이터 조정이 가능하다. ■ 문법 struct 구조체-tag { <데이터 형><비트필드 멤버 이름> : 비트수 .. .. .. } 구조체 변수; 다음은 구조체 정의에서 다른 원소들과 비트-필드를 혼합할 수 있음을 보여주는 예이다. struct product { char name[30]; unsigned department : 3; unsigned instock : 1; unsigned ordered : 1; unsigned load_time : 3; } item[10] ; 비트-필드를 사용하는 주된 이유는 메모리를 절약하는데 있다. 비트-필드는 가능한 작은 공간에 정보를 압축해 놓을 때 매우 유용하다.
9.5 비트-필드(계속) 예제 9.32 a, b, c라는 3개의 비트-필드를 포함하는 구조체를 생성하는 프로그램을 작성하여라. a와 b는 3비트 크기로, c는 2비트 크기로 하여라. 3가지 모두 signed 변수를 만들어라. 그 다음, 각각에 값을 대입하고, 그 값을 출력하여라. ☑ 프로그램 #include <stdio.h> int main(void) { struct bit_type{ int a: 3; int b: 3; int c: 2; }bitvar; bitvar.a=-4; bitvar.b=10; bitvar.c=1; printf("%d %d %d\n", bitvar.a, bitvar.b, bitvar.c); return 0; } ꁼ 실행결과 -4 2 1
9.6 구조체 응용 프로그램 예제들 예제 9.33 예제 9.34 예제 9.35 예제 9.36 예제 9.37 예제 9.38 선형 연계 리스트(linear linked list)를 이용하는 프로그램 예제 9.34 선형 연계 리스트를 이용하여 생성한 큐(queue)를 이용하는 프로그램 예제 9.35 트리(tree) 방문 프로그램 예제 9.36 이중 연계 리스트(doubly linked list)를 이용하는 프로그램 예제 9.37 데이터를 입력받아 트리에 저장한 후 출력한다. 단, 값이 입력될 때, root 보다 작으면 왼쪽 노드에, 크면 오른쪽 노드에 저장한다. 이렇게 저장한 후 중위순운행(inorder traversal)을 하면 오름차순으로 정렬된 결과가 출력된다. 예제 9.38 리스트 구조에서 지우고 싶은 값 입력해서 지우기 예제 9.39 이진 트리를 생성한 후, inorder 순으로 방문하는 프로그램을 작성하라.