구조체(Structures) 경일대학교 컴퓨터공학과 김권양 kykim@bear.kyungil.ac.kr
목 차 구조체(structure)의 정의 구조체의 선언방법 구조체의 멤버 참조 방법 구조체의 다양한 표현 방법 목 차 구조체(structure)의 정의 구조체의 선언방법 구조체의 멤버 참조 방법 구조체의 다양한 표현 방법 구조체 변수와 함수 구조체의 여러 형태, 사용법 구조체 사용 예
1. 구조체(structure)의 정의 A structure is a collection of one or more variables, possibly of different types, grouped together under a single name for convenient handling. Structures are called “record” in some language, Pascal. Help to organize complicated data in large program(permit a group of related variables to be treated as a unit instead of as separate entities).
Example of a structure: payroll record : an employee a set of attributes such as name, address, social security number, salary, etc. point : a pair of coordinates rectangle : a pair of points book : 제목, 저자, 출판사, 등 배열과 구조체 차이점: 배열 : 개개의 변수들이 모두 동일한 데이터형을 가진다. 접근 -> index 구조체: 개개의 변수들이 제각기 다른 데이터형을 가질 수 있다. 접근 -> 멤버명
2. 구조체의 선언방법 가. 구조체 형식 선언 방법 (선언 형식) struct 구조체명 { 데이터형 멤버명 1; 데이터형 멤버명 2; ................ 데이터형 멤버명 n; };
구조체는 하나의 구조체명(태그)을 가질 수 있다. 구조체 내의 변수 선언은 멤버라고 한다. 구조체 내의 멤버로 또 다른 구조체를 가질 수 있다. 구조체를 선언하면 구조체의 형식만 선언되고 실제로 데이터는 할당되지 않으므로 구조체 형식 선언 후 구조체 변수를 따로 선언해야 한다.
(사용 예) struct woman { char name[10]; int burst; int waist; double hip; }; 위 예에서 10바이트의 문자 배열과 burst, waist라는 정수형 기억장소, 또 hip이라는 double형 기억 장소들을 구성 요소로 하는 구조체 형은 정의되었지만 실제적인 기억 장소가 확보된 것은 아니다.
나. 구조체형 변수의 선언방법 구조체형을 선언하고 난후에 그 구조체를 갖는 변수를 선언한다. (선언형식) struct 구조체명 변수명; (사용 예) - 구조체형 선언 struct student { char name[20]; int kuke; int sansu; };
- 그 구조체로 변수 선언을 한다. struct student haksang ; (2) 구조체형과 변수 선언을 동시에 한다. (선언형식) struct 구조체명 {멤버1,멤버2,........ } 변수명; (사용 예) struct student { char name[20]; int kuke; int sansu; } haksang;
(3) 구조체명 없이 바로 변수를 선언한다. (선언 형식) struct { 멤버1, 멤버2, ......... } 변수명; (사용 예) char name[20]; int kuke; int sansu; } haksang; ==> 이 형태는 구조체 명을 다시 사용할 수는 없다. 반드시 변수명이 선언되어야 함.
다. 구조체의 초기화 방법 (1) 구조체 변수 선언시 초기화 방법 struct student { char name[20]; int kuke; int sansu; }; struct student haksang = {"나원참", 0, 0}; * 초기화 시에 명시적으로 지정하지 않은 항목은 0, 0.0, ‘\0’로 초기화됨!
(2) 구조체 선언시 초기화 방법 struct student { char name[20]; int kuke; int sansu; } haksang = {"나원참", 0, 0};
(3) 배열에서의 초기화 방법 struct student { char name[20]; int kuke; int sansu; }; struct student haksang[50] = { {"나홀로", 0, 0}, {"나원참", 0, 0}, {"나대로", 0, 0}, {"나신하", 0, 0}
라. 적용 문제 (1) 다음 내용 중에서 구조체의 태그, 멤버, 구조체 변수를 고르시오. struct new_years { char jan[20]; char feb[20]; float mar; int *api; } bod, calo, alice ; (2) 구조체와 배열의 차이점을 간단하게 설명하시오. (표현 자료와 접근 방법)
3. 구조체의 멤버 참조 방법 /* kuke에 95 값 배정 */ 가. 직접 멤버 참조(도트( . ) 연산자) haksang.kuke = 95; /* kuke 값 출력 */ printf("%d",haksang.kuke); /* name 값 배정: error */ haksang.name[]=“정지은”; /* correct */ strcpy(haksang.name, “정지은”) 가. 직접 멤버 참조(도트( . ) 연산자) struct student { char name[20]; int kuke; int sansu; }; struct student haksang;
멤버의 명칭과 변수 명칭이 동일해도 지정 방법이 다르기 때문에 서로 그 이름이 충돌하지는 않는다. 예를 들면 struct student haksang ; int kuke ; haksang.kuke = 90 ; kuke = haksang.kuke ; 라는 예 안에서 kuke와 haksang.kuke는 전혀 다른 것으로 취급된다.
(적용 예문) /* 성적출력 프로그램 */ #include <stdio.h> #include <string.h> void main() { struct student haksang ; strcpy (haksang.name, "나홀로") ; haksang.kuke = 99 ; haksang.sansu = 98 ; printf ("이름 : %s",haksang.name) ; printf ("국어 : %d",haksang.kuke) ; printf ("산수 : %d",haksang.sansu) ; }
나. 포인터를 이용한 구조체 멤버 참조(간접 멤버 참조 :애로우(->)연산자) struct student haksang; struct student *ptr=&haksang; *ptr.kuke = 99; /* Error : *(ptr.kuke) */ (*ptr).kuke = 99; /* Correct */ ptr->kuke = 99; /* Correct */ 구조체포인터변수 멤버명 or (*구조체포인터변수).멤버명
(적용 예문: arrow operator) /* 성적출력 프로그램 */ #include <stdio.h> #include <string.h> void main() { struct student haksang; struct student *ptr = &haksang; strcpy (ptr->name,"나홀로"); ptr->kuke = 99; (*ptr).sansu = 98; printf ("이름 : %s",ptr->name); printf ("국어 : %d",ptr->kuke); printf ("산수 : %d",ptr->sansu); }
4. 구조체의 다양한 표현 방법 가. 구조체의 연산 일반 변수 : if (a>b) /*ok */ 구조체 : struct student haksang1, haksang2 ; ............. if (haksang1 > haksang2) /* Incorrect */ if (haksang.kuke > haksang.sansu ) /* ok */
(1) 구조체간의 복사 (ANSI-C 확장) 구조체를 한꺼번에 복사할 수 있다. 구조체 안에 문자열이 있어도 그대로 복사가 가능하다. (예문) struct person { char name[20], sex; int age; } st1, st2 = {“김문수”,’M’,17}; ................ st1 = st2; 두 구조체가 호환 가능하여야 한다! (person)
(2) 구조체의 주소를 추출 (예문) struct student haksang ; struct student *ptr ; ptr = &haksang; /* haksang의 주소값을 추출 */
(3) 멤버를 참조 멤버참조 연산자를 이용하여 구조체의 멤버를 개별적으로 지정 할 수 있다. (예문) struct student haksang ; struct student *ptr ; ptr = &haksang ; haksang.kuke = 99; ptr->sansu = 98 ;
나. 구조체의 배열과 포인터 표현 방법 struct student haksang[100]; /* 배열로 선언 */ struct student *ptr; /* 포인터로 선언 */ ptr = haksang; /* ptr에 haksang[]의 선두번지값을 대입 */ ptr->kuke = 99; /* 멤버참조 haksang[0].kuke=99와 동일 */ ++ptr; /* 포인터 ptr를 1증가 시키면 */ ptr->kuke=99; /* 배열이 1증가 한것과 동일 즉 haksang[1].kuke=99 ;동일 */
(1) 다음의 자료를 구조체 배열에 대입하고 화면에 출력하는 프로그램을 작성하시오.(제출!) 다. 적용 예제 (1) 다음의 자료를 구조체 배열에 대입하고 화면에 출력하는 프로그램을 작성하시오.(제출!) Name Sex Age Address 홍길동 M 30 서울시 마포구 당상동 나원참 F 35 부산시 영도구 영동 신나라 M 42 대구시 북구 침산동 (2) 학생들의 생년월일이 빠른 순서로 학생들의 관련자료를 출력하는 프로그램을 작성하시오. 원래의 자료는 임의의 작성하되 생년월일과 무관한 순서로 되어 있다고 가정한다.
}; struct person *pptr; pptr = person1; struct person { char name[10]; char sex; int age; char addr[30]; } person1[3] = { {“홍길동”,’M’,30,”서울시 마포구 당상동”}, {“나원참”,’F’,35,”부산시 영도구 영동”}, {“신나라”,’M’,42,”대구시 북구 침산동”} }; struct person *pptr; pptr = person1;
5. 구조체 변수와 함수 가. 구조체를 함수로 전달하는 방법 실인자로 구조체 전체 전달(ANSI-C) 실인자로 구조체 멤버 전달 주소에 의한 전달(포인터) 1), 2) 방식은 call-by-value에 의해 실인자의 값이 함수의 인자로 복사되기 때문에 인수의 독립성이 유지되어 프로그램이 안전해지나 구조 체가 큰 경우 복사본 생성을 위한 overhead로 실행속도를 감소시킨다.
(적용 예문) /* 함수에 구조체를 전달하는 프로그램 */ #include <stdio.h> struct woman { /* 구조체 선언부분을 먼저 */ char name[20]; int burst; int hip; }; /* 함수프로토타입 */ void disp1(struct woman str); void disp2(struct woman *str) ;
void main ( ) { struct woman miin = {"한몸매", 34, 35}; disp1(miin) ; /* 값에 의한 전달 */ disp2(&miin) : /* 주소에 의한 전달 */ disp3(miin.name,miin,burst,miin.hip); /* 멤버 */ } void disp1(struct woman str) { printf("%s %d %d ",str.name, str.burst, str.hip) ; void disp2(struct woman *str) { printf("%s %d %d ",str->name, str->burst, str->hip); void disp3(char *name, int bst, int hp) { printf(“%s %d %d”,name,bst,hp);
나. 함수에서 구조체를 전달 받는 방법 (적용 예문) #include <stdio.h> #include <string.h> struct woman { char name [20] ; int burst ; int hip ; }; struct woman set(char irum[] , int bu , int hi ); void disp (struct woman str) ;
void main( ) { struct woman miin ; miin = set ("한몸매", 36, 38) ; disp (miin) ; } struct woman set(char irum[], int bu, int hi) { struct woman da ; strcpy (da.name ,irum) da.burst = bu; da.hip = hi ; return da ; void disp (struct woman str) { printf("%s %d %d ", str.name, str.burst, str.hip) ;
6. 구조체의 여러 형태, 사용법 가. 중첩된 구조체 struct book { char name[100] ; /* 책이름 */ int o_price; /* 원가 */ int d_price; /* 할인가 */ int r_price; /* 정상 판매가 */ int jeago; /* 재고 수량 */ }; struct book fiction ;
* Nested Structures struct gaguk { int o_price ; int d_price ; int r_price ; }; struct book { char name[100]; struct gaguk price; /* 구조체내에 또 구조체 */ int jeago ; struct book fiction;
사용 예) struct book book1; struct book *str = book1; /* 일반변수일 경우 정가를 참조하는 예문 */ book1.price.r_price = 13000 ; /* 포인터일 경우 정가를 참조하는 예문 */ str->price.r_price = 13000; /* error */ str->price->r_price = 13000;
중첩된 구조체의 초기화 struct person { char name[20], sex, tele[12]; struct birth_date { int day; int month; int year; } } club = {“홍길동”, ‘M’, ‘850-7287’, 8, 5, 1979}; or struct person club = {“홍길동”, ‘M’, ‘850-7287’, {8, 5, 1979}};
나. 자기참조 구조체 : 자기 자신을 가리키는 구조체를 말한다. 구조체는 중첩이 가능하므로 자기자신을 포함시킨 것인데 일반적인 포인터 형으로 선언되어야 하며 자료구조 측면에서 매우 중요한 의미를 갖는다 struct sungjuk { char name [50] ; int aver ; int total ; struct sungjuk kamok ; }; /* Wrong */
struct sungjuk { char name [50] ; int aver ; int total ; struct sungjuk *kamok ; }; * 자기참조 구조체는 "자신 안에 자신을 가리키는 포인터를 포함시킨 것"
struct robot { int head; int arms[2]; int *finger; struct robot *next; } mazinga , teagenboy, robocop[5];
void main( ) { ............... ................ /* 한방향으로 연결고리 만들기 */ mazinga.next = &teagenboy ; teagenboy.next = &robocop[0] ; robocop[0].next = &robocop[4] ; robocop[4].next = 0x00 /* 종료 */
/* teagenboy를 삭제할 경우 */ ............................ mazinga.next = &robocop[0] ; robocop[0].next = &robocop[4] ; /* robocop[1]를 robocop[0]다음에 삽입할 경우 */ ............................... robocop[0].next = &robocop[1] ; robocop[1].next = &robocop[4] ; ..............................
/* 양방향 linked list */ struct robot { int head; int arms[2]; int *finger; struct robot *before; struct robot *next; } mazinga , teagenboy, robocop[5];
(응용 예제: 자기참조 구조체) #include <stdio.h> while(1) { #include <stdlib.h> #include <string.h> struct human { char irum [30] ; int nai ; struct human *next ; }; void main( ) { struct human ingan ; struct human *start=&ingan ; struct human *i_data ; struct human *work ; char irum [30] = " ", buf[10] ; start = &ingan ; start->next=NULL; while(1) { printf("이름 : ") ; gets(irum) ; if(strcmp(irum,"") == 0) break ; printf("나이 : ") ; gets(buf) ; nai=atoi(buf) ; i_data=(struct human *)malloc(sizeof(struct human)) ; /* 구조체 1개분의 메모리를 확보 */ if (i_data==NULL) { printf ("메모리를 줄 수 없습니다") ; exit (1) ; } strcpy(i_data->irum,irum) ; /* 확보한 구조체에 이름과 나이를 설정 */ i_data->nai = nai ;
for(work=start;work->next != NULL; work=work->next) { if(nai < work->next->nai i_data->next=work->next ; work->next=i_data ; break ; } if(work->next==NULL) { i_data->next = NULL ; work->next = i_data ; for (work=start->next; work !=NULL ; work = work->next) printf("%s %d",work->irum,work->nai) ;
Dynamic Allocation All of the variables in every program up to this point have been static variables.(Actually, some of them have been automatic and were dynamically allocated for you by the system. We will study some dynamically allocated variables. They are variables that do not exist when the program is loaded, but are created dynamically as they are needed while the program is running. It is possible, using these techniques, to create as many variables as needed, use them, and deallocate their memory space for reuse by other variables.
#include "stdio.h" #include "string.h“ #include "stdlib.h“ /* malloc */ struct animal { char name[25]; char breed[25]; int age; } *pet1, *pet2, *pet3; void main() { pet1 = (struct animal *)malloc(sizeof(struct animal)); strcpy(pet1->name, "General"); strcpy(pet1->breed, "Mixed Breed"); pet1->age = 1; pet2 = pet1; /* pet2 now points to the above data structure */
pet1 = (struct animal *)malloc(sizeof(struct animal)); strcpy(pet1->name, "Frank"); strcpy(pet1->breed, "Labrador Retriever"); pet1->age = 3; pet3 = (struct animal *)malloc(sizeof(struct animal)); strcpy(pet3->name, "Krystal"); strcpy(pet3->breed, "German Shepherd"); pet3->age = 4; /* now print out the data described above */ printf("%s is a %s, and is %d years old.\n", pet1->name, pet1->breed, pet1->age); printf("%s is a %s, and is %d years old.\n", pet2->name, pet2->breed, pet2->age); printf("%s is a %s, and is %d years old.\n", pet3->name, pet3->breed, pet3->age);
pet1 = pet3; /* pet1 now points to the same structure that */ /* pet3 points to */ free(pet3); /* this frees up one structure */ free(pet2); /* this frees up one more structure */ /* free(pet1); this cannot be done, see explanation in text */ } /* Result of execution Frank is a Laborador Retriever, and is 3 years old. General is a Mixed Breed, and is 1 years old. Krystal is a German Shepherd, and is 4 years old. */
/* 화면에 현재시간을 나타내는 프로그램 */ (참고용 예제) /* 화면에 현재시간을 나타내는 프로그램 */ #include <stdio.h> #include <time.h> void main( ) { time_t t; struct tm *struct_t ; char *string ; time (&t) ; struct_t = localtime(&t); string = asctime(struct_t) ; printf ("%s", string) ; }
다. 비트필드( bit - field) 구조체 (1) 비트필드 구조체란? 프로그램을 작성하다 보면 가끔은 flag레지스터 같은 것을 직접 조작할 필요성이 있을 때가 있다. 그런데 이런 것들은 전부 비트 단위로 조작되기 때문에 지금까지 데이터를 취급하던 int형, char형 등의 데이터 처리 단위가 다양하지 않아도 된다. 이런 필요성 때문에 형식은 구조체를 갖추고 있고 조작 단위는 비트 단위로 되어 있는 것이 비트필드 구조체이다.
(2) 선언 및 참조 방법 데이터형 멤버명 : 비트 폭 ; (선언 예문) struct bitgujo { unsigned int busy : 1; int ready : 2; unsigned int send : 3; } dataflag ;
(3) 메모리 구조 데이터형 (멤버이름없음) : 0 ; struct datemi { int weekday : 3 ; 데이터형 (멤버이름없음) : 0 ; struct datemi { int weekday : 3 ; int year : 7 ; int month : 4 ; int day : 5 ; int kiyum : 1 ; } struct dateji { int : 0 ;
7. 구조체 사용 예 1) A SINGLE COMPOUND VARIABLE #include "stdio.h" struct { char initial; /* last name initial */ int age; /* childs age */ int grade; /* childs grade in school */ } boy, girl; void main() { boy.initial = 'R'; boy.age = 15; boy.grade = 75;
girl.age = boy.age - 1; /* she is one year younger */ girl.grade = 82; girl.initial = 'H'; printf("%c is %d years old and got a grade of %d\n", girl.initial, girl.age, girl.grade); printf("%c is %d years old and got a grade of %d\n", boy.initial, boy.age, boy.grade); } /* Result of execution H is 14 years old and got a grade of 82 R is 15 years old and got a grade of 75 */
ASSIGNING VALUES TO THE VARIABLES
2) AN ARRAY OF STRUCTURES #include "stdio.h“ struct { char initial; int age; int grade; } kids[12]; void main() { int index; for (index = 0 ; index < 12 ; index++) { kids[index].initial = 'A' + index; kids[index].age = 16; kids[index].grade = 84; }
kids[3].age = kids[5].age = 17; kids[2].grade = kids[6].grade = 92; kids[10] = kids[4]; /* Structure assignment */ for (index = 0 ; index < 12 ; index++) printf("%c is %d years old and got a grade of %d\n", kids[index].initial, kids[index].age, kids[index].grade); } /* Result of execution A is 16 years old and got a grade of 84 G is 16 years old and got a grade of 92 B is 16 years old and got a grade of 84 H is 16 years old and got a grade of 84 C is 16 years old and got a grade of 92 I is 16 years old and got a grade of 84 D is 17 years old and got a grade of 84 J is 16 years old and got a grade of 84 E is 16 years old and got a grade of 57 E is 16 years old and got a grade of 57 F is 17 years old and got a grade of 84 L is 16 years old and got a grade of 84 */
3) USING POINTERS AND STRUCTURES TOGETHER #include "stdio.h" struct { char initial; int age; int grade; } kids[12], *point, extra; void main() { int index; for (index = 0 ; index < 12 ; index++) { point = kids + index; point->initial = 'A' + index; point->age = 16; point->grade = 84; }
kids[3].age = kids[5].age = 17; kids[2].grade = kids[6].grade = 92; for (index = 0 ; index < 12 ; index++) { point = kids + index; printf("%c is %d years old and got a grade of %d\n", (*point).initial, kids[index].age, point->grade); } extra = kids[2]; /* Structure assignment */ extra = *point; /* Structure assignment */ /* Result of execution A is 16 years old and got a grade of 84 B is 16 years old and got a grade of 84 C is 16 years old and got a grade of 92 …. */
4) NESTED AND NAMED STRUCTURES #include "stdio.h" #include "string.h“ struct person { char name[25]; int age; char status; /* M = married, S = single */ }; struct alldat { int grade; struct person descrip; char lunch[25];
void main() { struct alldat student[53]; struct alldat teacher, sub; teacher.grade = 94; teacher.descrip.age = 34; teacher.descrip.status = 'M'; strcpy(teacher.descrip.name, "Mary Smith"); strcpy(teacher.lunch, "Baloney sandwich"); sub.descrip.age = 87; sub.descrip.status = 'M'; strcpy(sub.descrip.name, "Old Lady Brown"); sub.grade = 73; strcpy(sub.lunch, "Yogurt and toast"); student[1].descrip.age = 15; student[1].descrip.status = 'S'; strcpy(student[1].descrip.name, "Billy Boston"); strcpy(student[1].lunch, "Peanut Butter"); student[1].grade = 77; student[7].descrip.age = 14; student[12].grade = 87; }
예상문제(구조체) 다음 구조체 자료형 선언에 따른 올바른 구조체 변수 선언 방법은? struct ken { int kkk; float bbb; }; 1) struct ken yoo, soo; 2) yoo, soo ken; 3) ken yoo, soo; 4) struct yoo, soo;
2. 다음 구조체 선언에 대해 멤버 값을 올바르게 입력하는 것은? struct ken { int hakbun; int gwa; int college; } daehak; 1) scanf(“%d”,&daehak->gwa); 2) scanf(“%d”,&daehak.gwa); 3) scanf(“%d”,*daehak.gwa); 4) scanf(“%d”,daehak.gwa); 3. 다음 구조체 선언에서 구조체 변수 ken의 초기값 44.4를 가리키는 것은? struct jemok { char gwa; float ccc; }; struct jemok ken[]={8001,’a’,33.3,8002,’b’,44.4, 8003,’c’,55.5};
1) ken[1]->ccc 2) ken[1].ccc 4. 구조체의 초기화 형식으로 옳게 표현한 것은? (괄호 안) struct pyo { int no; char name[10]; } (…) 1) a={25,안중근}; 2) a=(25,”안중근”); 3) a:=(“25”,”안중근”); 4) a={25,”안중근”}; 5. 다음 구조체 포인터의 멤버 참조 표현으로 올바른 것은? struct man { char *name; int age; } *student;
1) name->student 2) age->student 3) student->name 4) student.age 6. 다음 설명 중 올바른 것은? 1) 구조체의 구성 멤버는 반드시 같은 형(type)이어야 한다. 2) 구조체 구성 멤버의 접근은 배열과 같이 첨자(index)를 사용한다. 3) 구조체 선언시 구조체명 없이 선언할 수 없다. 4) 구조체 내의 멤버로 또 다른 구조체를 가질 수 있다.