처음으로 배우는 C 프로그래밍 제4부 복합 데이터 형 제 10 장 구조체
구조체 소개 구조체란 ? 구조체는 복잡한 데이터를 간단히 처리할 수 있도록 지원 하나의 이름으로 불려질 수 있는, 이질적인 자료형 변수들의 모임 예. 배열은 동일한 자료형을 가지는 변수들의 모임 Pascal에서는 이를 레코드(record)라고 부름 구조체는 복잡한 데이터를 간단히 처리할 수 있도록 지원 예 ) 책에 대한 정보를 관리하는 경우 구조체 책제목 (문자열 형) 저자 이름 (문자열 형) 출판사 ( 문자열 형 ) 책의 가격( 부동소수 형)
구조체 소개 구조체에 포함된 변수들을 그 구조체의 멤버(member)라고 부름 각 멤버는 자신의 이름과 자료형을 가지며, 개별적으로 참조 가능함 (각 멤버는 변수나 배열의 원소와 동격임) C++ 에서는 구조체를 확장하여 클래스(class)를 생성함 구조체는 사용자 정의 타입으로 볼 수 있음 구조체의 형태: 각 자료 항목의 기호명과 자료형의 배치로 구성 책제목(문자열 형) 저자이름(문자열 형 ) 출판사(문자열 형) 책의 가격( 부동소수 형) 구조체의 내용: 변수에 저장된 실 자료를 의미 처음으로 배우는 C프로그래밍 영한 출판사 유재수, 서영훈 18000
단일 구조체 구조체의 선언 자료형, 자료 명, 자료 항목 배치를 작성 구조체 정의 예제: 년-월-일을 저장하는 구조체 struct { int month; /* 월 */ int day; /* 일*/ int year; /* 년*/ } birth; 구조체 멤버 접근 방법 (.) birth.month (birth 구조체 멤버 month 접근) birth.year (birth 구조체 멤버 year 접근) 자료 항목, 구조체 멤버 구조체 변수
단일 구조체 #include <stdio.h> void main(void) { struct { int month; int day; int year; } birth; birth.month = 6; birth.day = 11; birth.year = 1999; printf("My birth date is %d/%d/%d.", birth.month, birth.day, birth.year); } 출력 결과 My birth date is 6/11/1999.
구조체 정의 변수 명을 갖는 구조체 정의 단일 변수 struct { int month; int day; int year; } birth; 여러 변수 } birth, current; /* birth.month, birth.day, birth.year */ /* current.month, current.day, current.year */
구조체 정의 (계속) 변수명이 없는 정의 구조체 템플릿을 이용한 변수 선언 멤버 접근 struct Date { /* Date : 구조체 태그(tag) 명, 구조체 이름 */ int month; int day; int year; }; 구조체 템플릿을 이용한 변수 선언 struct Date birth, current; 멤버 접근 birth.month, birth.day, birth.year current.month, current.day, current.year 구조체 템플릿(template)
구조체 정의 (계속) #include <stdio.h> struct Date { int month; int day; int year; }; void main(void) { struct Date birth; birth.month = 6; birth.day = 11; birth.year = 1999; printf("My birth date is %d/%d/%d", birth.month, birth.day, birth.year); } 구조체 템플릿 Date 선언 또는 struct Date birth = {6, 11, 1999}; 구조체 멤버의 초기화
구조체 선언 예 회사원 정보 구조체 정의와 초기화 구조체 템플릿 선언 struct Pay_rec { char name[20]; int id_num; float reg_rate; float ot_rate; } ; 회사원 정보 Name Identification Number Regular Pay Rate Overtime Pay Rate 구조체 정의와 초기화 struct Pay_rec employee = {"H. Price", 12345, 1000.0, 50.0};
구조체 선언 예 사람의 이름과 생년월일을 위한 구조체 멤버 접근 방법 Date 구조체를 이용하여 선언 struct { char name[20]; /* 이름을 저장하는 변수 */ struct Date birth; /* 생년월일을 저장하는 변수 */ } person; 멤버 접근 방법 person.name person.birth.month person.birth.day person.birth.year
구조체 메모리 할당 x-y 좌표 상에서 “하나의 점과 그 이름을 표시하는 구조체”인 경우 … … … struct aPoint { int x; int y; char name[10]; } pt1; … … … pt1 x y Name[0] Name[9]
구조체 템플릿 정의와 변수선언 struct tag_name { 예) 구조체 템플릿 정의와 구조체 변수 선언을 한 번에 할 수 있음 struct tag_name { type1 member1; type2 member2; : typen membern; } struct_variables, ... ; 예) struct aPoint { int x; int y; char name[5]; } pt1, pt2, pt3;
구조체 배열 사원에 대한 자료 사원번호 사원이름 사원급여지급비율 사원번호 사원이름 사원급여지급비율 ================================================= 32479 Abrams, B. 6.72 <= 첫 번째 레코드 33623 Bohm, P. 7.54 <= 두 번째 레코드 34145 Donaldson, S. 5.56 <= 세 번째 레코드 35987 Ernst, T. 5.43 <= 네 번째 레코드 36203 Gwodz, K. 8.72 <= 다섯 번째 레코드 36417 Hanson, H. 7.64 <= 여섯 번째 레코드 37634 Monroe, G. 5.29 <= 일곱 번째 레코드 38321 Price, S. 9.67 <= 여덟 번째 레코드 39435 Robbins, L. 8.50 <= 아홉 번째 레코드 39567 Willians, B. 7.20 <= 열 번째 레코드 ================================================== 정수형 배열 문자형 배열 실수형
구조체 배열 (계속) 사원을 위한 구조체 사원들의 정보를 저장하기 위한 구조체 배열 구조체 배열의 접근 struct Pay_rec { long idnum; char name[20]; float rate; }; 사원들의 정보를 저장하기 위한 구조체 배열 struct Pay_rec empolyee[10]; 구조체 배열의 접근 employee[0].rate : 첫번째 사원의 급여 지급 비율 employee[4].idnum : 다섯번째 사원의 사원 번호
구조체 배열 (계속) #include <stdio.h> struct Pay_rec { long id; char name[20]; float rate; }; void main(void) { int i; struct Pay_rec employee[10] = { 32479, "Abrams, B.", 6.72, 33623, "Bohm, P.", 7.54, 34145, "Donaldson, S.", 5.56, 35987, "Ernst, T.", 5.43, 36203, "Gwodz, K.", 8.72, 36417, "Hanson, H.", 7.64, 37634, "Monroe, G.", 5.29, 38321, "Price, S.", 9.67, 39435, "Robbins, L.", 8.50, 39567, "Willians, B.", 7.20 for (i=0; i<5; i++) printf(“\n%ld %-20s %4.2f", employee[i].id, employee[i].name, employee[i].rate); } 출력결과 32479 Abrams, B. 6.72 33623 Bohm, P. 7.54 34145 Donaldson, S. 5.56 35987 Ernst, T. 5.43 36203 Gwodz, K. 8.72
구조체 포인터 구조체 타입의 포인터 변수 예) struct aPoint *pt1, *pt2, *pt3; 포인터 변수로부터 구조체의 멤버를 참조하는 방법 포인터의 성질을 이용한 방법 : (*pt1).x ‘->’연산자를 이용한 방식 : pt1 -> x ‘->’연산 ‘->’연산자의 왼쪽은 구조체의 주소, 오른쪽은 그의 멤버이름을 넣어야 함 구조체 연산자와 -> 는 함수의 ( )와 배열 첨자의 [ ]와 함께 연산 순위가 가장 높음 *point.x는 *(point.x)와 같은 효과를 지니고 ++pt->x는 ++(pt->x)와 같은 효과를 지닌다.
구조체 전달 스칼라(scalar) 변수와 같은 방법으로 전달 구조체 전달(값에 의해) struct { int id_num; double pay_rate; double hours; } emp; 스칼라(scalar) 변수와 같은 방법으로 전달 display(emp.id_num); calc_pay(emp.pay_rate, emp.hours); 구조체 전달(값에 의해) calc_net(emp);
구조체 전달 출력결과 The net pay for employee 6782 is $361.66 #include <stdio.h> struct Employee { int id_num; double pay_rate; double hours; }; void main(void) { struct Employee emp = {6782, 8.93, 40.5}; double net_pay; double calc_net(struct Employee); net_pay = calc_net(emp); printf("The net pay for employee %d is $%6.2f", emp.id_num, net_pay); } double calc_net(struct Employee temp) return (temp.pay_rate * temp.hours); 출력결과 The net pay for employee 6782 is $361.66
구조체 전달 (계속) 구조체 전달(주소에 의한) 피호출문 호출문 void calc_net(struct Employee *pt) } 호출문 calc_net(&emp);
구조체 전달 (계속) #include <stdio.h> struct Employee { int id_num; double pay_rate; double hours; }; void main(void) { struct Employee emp = {6782, 8.93, 40.5}; double net_pay; double calc_net(struct Employee *); net_pay = calc_net(&emp); printf("The net pay for employee %d is $%6.2f", emp.id_num, net_pay); } double calc_net(struct Employee *temp) return (temp->pay_rate * temp->hours);
구조체 반환 함수의 반환 값으로 구조체를 받기를 원하는 경우 스칼라(scalar) 값을 반환할 때와 같은 방법으로 구조체를 반환 #include <stdio.h> struct Employee { int id_num; double pay_rate; double hours; }; struct Employee get_vals(void) { struct Employee em; …. return em; } 구조체반환 void main() { struct Employee emp; ... emp = get_vals(); /*함수 호출*/ } emp.id_num = em.id_num; emp.pay_rate = em.pay_rate; emp.hours = em.hours
구조체 반환 #include <stdio.h> struct Employee get_vals(void) { int id_num; double pay_rate; double hours; }; void main(void) struct Employee emp; struct Employee get_vals(void); emp = get_vals(); printf("\f2 nThe employee id number is %d", emp.id_num); printf("The employee pay rate is $%5.2f", emp.pay_rate); printf("The employee hours are %5.2f", emp.hours); } struct Employee get_vals(void) { struct Employee new_emp; new_emp.id_num = 6789; new_emp.pay_rate = 16.25; new_emp.hours = 38.0; return (new_emp); } 출력결과 The employee id number is 6789 The employee pay rate is $16.25 The employee hours are 38.00
동적 메모리 할당 프로그램에서 정의된 모든 변수는 그 변수의 값을 저장하기에 충분한 기억장소를 컴퓨터 메모리로부터 할당 받음 특정 메모리 위치가 변수를 위해 확보되면, 변수의 유효 범위(life time)내에서는 그 위치가 사용되든 그렇지 않든 그 위치는 변하지 않는다 예: 500 개의 정수를 저장하는 배열 사용하는 정수: 10개, 490개의 기억 공간 낭비 => 효율적인 기억 장소 필요성 필요할 때 필요한 만큼 기억장소를 확보 불필요한 기억장소는 해제
동적 메모리 할당 함수 동적 메모리 할당을 위한 include 함수명: stdlib.h 메모리 할당 함수 - 함수명: malloc(int ) - 기능: 요구된 바이트 수() 만큼 기억장소를 확보한다. 성공적으로 기억장소를 확보하면 기억장소의 시작 주소를 반환하고 충분한 메모리가 없는 경우 NULL을 반환한다. -예: int *pt; pt = malloc(200 * sizeof(int)); 메모리 해제 함수 -함수명: free() -기능: 미리 확보된 바이트의 블록을 해제한다. 해제될 기억장소의 시작 주소가 이 함수의 인자로 사용된다. -예: free(pt);
동적 메모리 할당 함수 배열의 크기를 입력 받아 그 만큼의 배열을 위한 기억 장소 할당 int numgrades; 배열의 크기를 입력 받아 그 만큼의 배열을 위한 기억 장소 할당 int numgrades; int *grades; /* 정수형 포인터 변수 정의 */ printf("Enter the number of grades to be processed: "); scanf("%d", &numgrades); /* 요구된 만큼의 정수형 배열을 위한 기억장소 할당 */ grades = (int *) malloc(numgrades * sizeof(int));
동적 메모리 할당 함수 #include <stdio.h> #include <stdlib.h> void main(void) { int numgrades; int *grades; /* 정수형 포인터 변수 정의 */ printf("Enter the number of grades to be processed: "); scanf("%d", &numgrades); /* 요구된 만큼의 정수형 배열을 위한 기억장 소 할당 */ grades = (int *) malloc(numgrades * sizeof(int)); /* 동적기억장소할당이 정상적으로 이루어졌는지를 검사 */ if (grades == (int *) NULL) { printf("Failed to allocate grades array "); exit(1); } for (i=0; i < numgrades; i++) { printf(" Enter a grade: "); scanf("%d", &grades[i]); } printf("\f2 nAn array was created for %d integers", numgrades); printf("\f2 nThe vales stored in the array are:"); printf(" %d", grades[i]); free(grades);
구조체 동적 기억장소 할당 struct Office_info { 자료 멤버들; }; struct Office_info *off; /*할당된 주소를 저장하기 위한 포인터 변수 */ /* 구조체를 저장하기 위한 공간 확보 */ off = (struct Office_info *) malloc(sizeof(struct Office_info)); /* 공간이 할당되었는지를 점검 */ if (off == (struct Office_info *) NULL) { printf("\f2 nAllocation of Office info record failed"); exit(1) }
공용체(Union) 공용체는 사용할 때마다 이질적인 멤버의 자료형과 다른 크기를 가질 수 있도록 하는 구조체임 비교) 파스칼의 가변 레코드와 동일함 하나의 메모리 장소에 여러 데이터 형의 자료를 저장 가능하도록 지원 즉, 여러 자료형의 변수가 하나의 주소를 공유하게 함 여러 값이 동시에 저장될 수는 없음. 즉, 한 시점에 하나의 자료만 저장됨 공용체의 선언은 구조체와 동일함 union u_tag { int ival; float fval; char *sval; } u, *uptr, uarray[10]; 공용체 u_tag의 크기는 int, float, char 중에서 가장 큰 것으로 할당됨 비교) 구조체의 크기는 모든 멤버들의 크기의 합과 같음
공용체 (계속) 구조체에서 정의된 . 과 -> 연산자도 공용체에서 동일한 의미로 사용 u.fval uptr->ival 공용체 u에는 세 가지 자료형 (int, float, char) 중 어느 것으로도 할당 가능 그러나, 할당된 값의 참조는 가장 최근에 할당한 자료형으로만 가능함 (이는 전적으로 프로그래머 책임임 )
공용체 (계속) union u_tag { int ival; float fval; char *sval; } u, *uptr, uarray[10]; u.fval = 2.0; /* 10이 지워지고 2.0이 저장; 4byte사용 */ u.sval = “I am a boy,”; /* 2.0이 지워지고 주소가 저장; 4byte사용 */ uptr = &u; x = uptr -> fval; /* Error!! 가장 최근에 문자 포인터로 사용했기 때문에 */ u.ival = 10; /* 10이 저장; 2byte사용 */
공용체 (계속) 구조체 안에 공용체을, 반대로 공용체 안에 구조체를 선언할 수도 있음 struct { char *name; int flags; int utype; union { int ival; float fval; char *sval; } u; } symtab[NSYM]; if ( symtab[n].utype == INT) printf(“%d\n”, symtab[n].u.ival); else if (symtab[n].utype == FLOAT) printf(“%f\n”, symtab[n].u.fval); else if (symtab[n].utype == STRING) printf(“%s\n”, symtab[n].u.sval);