1 / 54

처음으로 배우는 C 프로그래밍

처음으로 배우는 C 프로그래밍. 제 4 부 복합 데이터 형. 제 10 장 구조체. 구조체. 집단을 구성하는 개개 원소들이 어떻게 배치되어 있는지 혹은 어떻게 조직화되어 있는지를 나타냄 예 : 회사 정보 : 회사원 정보와 부서 정보 정부의 조직 : 조직원 , 조직의 형태 , 조직의 배치 정보 개 개의 자료 항목이 어떻게 배치되어 있는지를 잘 설명하고 있는 단위 (unit) 예 ( 우편물 주소 ) Name: ( 자료 항목 ) - 개체 (entity)

overton
Download Presentation

처음으로 배우는 C 프로그래밍

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 처음으로 배우는 C 프로그래밍 제4부 복합 데이터 형 제 10 장 구조체

  2. 구조체 • 집단을 구성하는 개개 원소들이 어떻게 배치되어 있는지 혹은 어떻게 조직화되어 있는지를 나타냄 • 예: • 회사 정보: 회사원 정보와 부서 정보 • 정부의 조직: 조직원, 조직의 형태, 조직의 배치 정보 • 개 개의 자료 항목이 어떻게 배치되어 있는지를 잘 설명하고 있는 단위(unit) • 예 (우편물 주소) Name: (자료 항목) - 개체(entity) Street Address: (자료 항목) - 개체(entity) City: (자료 항목) - 개체(entity) State: (자료 항목) - 개체(entity) Zip Code: (자료 항목) - 개체(entity) • 레코드(record): 개개의 자료 항목을 모아 형성한 더 큰 집단 => 구조체 • 구조체 형태: 개개의 자료 항목의 기호명, 자료형과 배치로 구성 • 구조체 내용: 기호명에 저장된 실 자료를 의미

  3. 구조체(계속) • 구조체 형태: 개개의 자료 항목의 기호명, 자료형과 배치로 구성 Name Street Address City State Zip Code • 구조체 내용: 기호명에 저장된 실 자료를 의미 Rhona Bronson-Karp 614 Freeman Street Orange NJ 07052

  4. 단일 구조체 • 구조체의 선언 • 자료형, 자료 명, 자료 항목 배치 작성 • 구조체 정의 예 (년월일을 저장하는 구조체) struct { int month; /* 월 */ int day; /* 일*/ int year; /* 년*/ } birth; • 구조체 멤버 접근 방법(연산자 .) • birth.month (birth 구조체 멤버 month 접근) • birth.year (birth 구조체 멤버 year 접근) 자료 항목, 구조체 멤버 구조체 변수

  5. #include <stdio.h> void main(void) { struct { int month; int day; int year; } birth; birth.month = 10; birth.day = 12; birth.year = 63; printf("My birth date is %d/%d/%d.", birth.month, birth.day, birth.year); } 출력 결과 My birth date is 10/12/63.

  6. 구조체 정의 • 변수 명을 갖는 구조체 정의 • 단일 변수 • struct {int month; int day; int year;} birth; • 여러 변수 • struct {int month; int day; int year;} birth, current; birth.month, birth.day, birth.year current.month, current.day, current.year

  7. 구조체 정의 (계속) • 변수명이 없는 정의 struct Date { /* Date <- 구조체 태그(tag) 명, 구조체 이름 */ int month; int day; int year; }; 구조체 템플리트(template) 구조체 템플리트를 이용한 변수 선언 struct Date birth, current; 멤버 접근 birth.month, birth.day, birth.year current.month, current.day, current.year

  8. #include <stdio.h> struct Date { int month; int day; int year; }; void main(void) { (1) struct Date birth; (2) birth.month = 10; (3) birth.day = 12; (4) birth.year = 63; printf("My birth date is %d/%d/%d", birth.month, birth.day, birth.year); } 구조체 템플리트 선언 구조체 멤버의 초기화 struct Date birth = {10, 12, 63};

  9. 구조체 선언 예 회사원 정보 Name Identification Number Regular Pay Rate Overtime Pay Rate 회사원 정보를 위한 구조체 템플리트선언 struct Pay_rec { char name[20]; int id_num; float reg_rate; float ot_rate; } ; 구조체 정의와 초기화 struct Pay_rec employee = {"H. Price", 12387, 15.89, 25.50};

  10. 사람의 생년월일을 위한 구조체 • Date 구조체 사용 struct { char name[20]; /* 이름을 저장하는 변수 */ struct Date birth; /* 생년월일을 저장하는 변수 */ } person; • 멤버 접근 방법 • person.name • person.birth.month • person.birth.day • person.birth.year

  11. 구조체 메모리 할당 • 구조체 템플리트(틀) 정의는 구조체의 모양을 정의하며 그 형식은 다음과 같음 struct tag_name{ type1 member1; type2 member2; : typen membern; }; • x-y 좌표 상에서 “하나의 점과 그 이름을 표시하는 구조체”의 예는 다음과 같음 예) struct aPoint { int x; int y; char name[10]; }; tag_name : 구조체의 이름 type1, … typen : 각 멤버의 자료형 member1, … membern : 각 멤버의 이름 Name[1] aPoint Name[9] Name[0] x y 구조체에 대한 메모리 할당

  12. pt1 (10, 20, 청주) 10 20 청주 (10, 15, 대전) 구조체 템플리트 정의와 변수선언 • 구조체 템플리트 정의와 구조체 변수 선언을 한 번에 할 수 있음 struct tag_name { type1 member1; type2 member2; : typen membern; } struct_variables, ... ; 예) struct aPoint { int x; int y; char name[5]; } pt1, pt2, pt3;

  13. 구조체 배열 • 사원에 대한 자료 사원번호 사원이름 사원급여지급비율 ========================================== 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 <= 열 번째 레코드 정수형 배열 문자형 배열 실수형

  14. 구조체 배열(계속) • 사원을 위한 구조체 • struct Pay_rec { long idnum; char name[20]; float rate;}; • 사원들의 정보를 저장하기 위한 구조체 배열 • struct Pay_rec empolyee[10]; employee[0].rate : 첫번째 사원의 급여 지급 비율 employee[4].idnum : 다섯번째 사원의 사원 번호

  15. #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("\f2 nld %-20s %4.2f", employee[i].id, employee[i].name, employee[i].rate); } /* end of main */ 출력결과 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

  16. 구조체 전달 • 구조체 멤버의 전달 • 스칼라(scalar) 변수와 같은 방법으로 전달 • 구조체 전달(값에 의해) struct { int id_num; double pay_rate; double hours; } emp; display(emp.id_num); calc_pay(emp.pay_rate, emp.hours); calc_net(emp);

  17. #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 c_net(struct Employee); net_pay = calc_net(emp); /* 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

  18. 구조체 전달(계속) 구조체 전달(주소에 의한) 피호출문 void calc_net(struct Employee *pt) { /*pt: 구조체 포인터 변수 */ } 호출문 calc_net(&emp);

  19. 구조체 타입의 포인터 변수 예) struct Employee *pt1, *pt2, *pt3; • 포인터 변수로부터 구조체의 멤버를 참조하는 방법 • 포인터의 성질을 이용한 방법 (*pt1).hours • ‘->’연산자를 이용한 방식 pt1 -> hours • ‘->’연산 • ‘->’연산자의 왼쪽은 구조체의 주소, 오른쪽은 그의 멤버이름을 넣어야 함 • 구조체 연산자 . 와 -> 는 함수의 ( )와 배열 첨자의 [ ]와 함께 연산 순위가 가장 높음 • 그러므로 *point.hours는 *(point.hours)와 같은 효과를 지니고, ++pt->hours는 ++(pt-> hours)와 같은 효과를 지닌다.

  20. *pt.hours = *(pt.hours) <= 프로그램 오류 (*pt) *pt == (*pt).id_num (*pt).id_num == pt->id_num (*pt).pay_rate == pt->pay_rate (*pt).hours == pt->hours (*pointer).member => pointer->member

  21. 주소에 의해 구조체 전달 예 #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 c_net(struct Employee *); net_pay = calc_net(&emp); /* 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); }

  22. 구조체 포인터 연산 pt++; ++pt; pt--; --pt; ++pt->hours;

  23. 구조체 반환 • 함수의 반환 값으로 구조체를 받기를 원하는 경우 스칼라(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

  24. #include <stdio.h> struct Employee { 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

  25. 연결 리스트(Linked List) • 자료 처리 방법 • 특정 순서로 존재하는 레코드(record)에 새로운 레코드를 삽입하거나 기존의 레코드를 삭제할 때 존재하는 레코드가 계속적으로 그 순서를 유지하도록 함 • 예 (알파벳순서로 정렬된 전화번호 목록) Acme, Sam (201) 898-2392 Dolan, Edith (213) 682-3104 Lanfrank, John (415) 718-4581 Mening, Stephanie (914) 382-7070 Zemann, Harold (718) 219-9912

  26. Mening, Stephanie (914) 382-7070 Acme, Sam (201) 898-2392 Lanfrank, John (415) 718-4581 Zemann, Harold (718) 219-9912 Dolan, Edith (213) 682-3104 연결리스트(계속) • 배열 구조를 사용하는 경우 struct person { char name[20]; char telnum[20]; }; 삽입과 삭제의 문제점 발생 struct person hb[10]; hb[0] hb[1] hb[2] hb[3] hb[4]

  27. 연결 리스트(계속) • 연결 리스트는 간단한 구조체 집합으로 각 구조체는 리스트 내에서 논리적으로 순서화된 구조체 주소를 갖는 적어도 하나의 멤버를 포함 • 물리적 측면:물리적으로 적절한 순서로 저장되기보다는 오히려 새로운 레코드가 리스트에 추가될 때 물리적으로 컴퓨터의 저장장소내 사용 가능한 임의의 공간에 추가됨 • 논리적 측면:레코드들은 자기 앞의 레코드가 자신의 주소를 가리키게 함으로써 서로 연결됨 • 프로그래밍 관점: 처리될 현재의 레코드는 다음 레코드가 물리적으로 어디에 저장되어 있든지 무관하게 다음 레코드의 주소를 포함함 구조체 포인터

  28. 연결 리스트(계속) • 연결 리스트 삽입 (June Hagar 자료 삽입)

  29. 연결 리스트(계속) • 연결리스트(삭제)

  30. 연결 리스트(계속) • 구조체에 구조체 포인터 추가 #include <stdio.h> struct Test { int id_num; double *pt_pay; }; void main(void) { struct Test emp; double pay = 456.20; emp.id_num = 12345; emp.pt_pay = &pay; printf("Employee number %d was paid $%6.2f'', emp.id_num, *emp.pt_pay); } 출력결과 Employee number 12345 was paid $456.20

  31. 연결 리스트(계속) • 전화번호 저장을 위한 연결 리스트 구조체 #include <stdio.h> struct Tele_typ { char name[30]; char phone_no[15]; struct Tele_typ *nextaddr; }; 구조체 포인터

  32. void main(void) { struct Tele_typ t1 = ''Acme, Sam'', ''(201) 898-2392''; struct Tele_typ t2 = ''Dolan, Edith'', ''(213) 682-3104''; struct Tele_typ t3 = ''Lanfrank, John'', ''(415) 718-4581''; Tele_typ *first; /* 구조체 포인터 생성 */ first = &t1; /* t1 주소를 first 에 저장 */ t1.nextaddr = &t2; /* t2 주소를 t1.nextaddr에 저장 */ t2.nextaddr = &t3; /* t3 주소를 t2.nextaddr에 저장 */ t3.nextaddr = NULL; /* NULL 를 t3.nextaddr에 저장 */ printf(''%s %s %s'', first->name, t1.nextaddr->name, t2.nextaddr->name); } 출력결과 Acme, Sam Dolan, Edith Lanfrank, John

  33. 구조체를 포인터로 전달 void main(void) { struct Tele_typ t1 = "Acme, Sam", "(201) 898-2392"; struct Tele_typ t2 = "Dolan, Edith", "(213) 682-3104"; struct Tele_typ t3 = "Lanfrank, John", "(415) 718-4581"; Tele_typ *first; /* 구조체 포인터 생성 */ first = &t1; /* t1 주소를 first 에 저장 */ t1.nextaddr = &t2; /* t2 주소를 t1.nextaddr에 저장 */ t2.nextaddr = &t3; /* t3 주소를 t2.nextaddr에 저장 */ t3.nextaddr = NULL; /* NULL 를 t3.nextaddr에 저장 */ display(first); /* 구조체 first의 주소를 전달 */ } #include <stdio.h> struct Tele_typ{ char name[30]; char phone_no[15]; struct Tele_typ *nextaddr; };

  34. void display(struct Tele_typ *contents) /*contents는 Tele_typ 형 구조체의 포인터 변수임 */ { while (contents != NULL) /* 연결 리스트에 저장된 모든 구조체 정보를 출력 */ { printf("%30s %-20s %s", contents->name, contents->phone_no); contents = contents->nextaddr; } return; } 출력결과 Acme, Sam (201) 898-2392 Dolan, Edith (213) 682-3104 Lanfrank, John (415) 718-4581

  35. 동적 메모리 할당 • 프로그램에서 정의된 모든 변수는 그 변수의 값을 저장하기에 충분한 기억장소를 컴퓨터 메모리로부터 할당 받음 • 특정 메모리 위치가 변수를 위해 확보되면, 변수의 유효 범위(life time)내에서는 그 위치가 사용되든 그렇지 않든 그 위치는 변하지 않는다 • 예:500 개의 정수를 저장하는 배열 사용하는 정수: 10개, 490개의 기억 공간 낭비 => 효율적인 기억 장소 필요성 • 필요할 때 필요한 만큼 기억장소를 확보 • 불필요한 기억장소는 해제 • 예: 연결 리스트(삽입 정보, 정보 삭제)

  36. 동적 메모리 할당 함수 동적 메모리 할당을 위한 include 함수명: stdlib.h 메모리 할당 함수 - 함수명: malloc(int ) - 기능: 요구된 바이트 수() 만큼 기억장소를 확보한다. 성공적으로 기억장소를 확보하면 기억장소의 시작 주소를 반환하고 충분한 메모리가 없는 경우 NULL를 반환한다. -예: int *pt; pt = malloc(200 * sizeof(int)); 메모리 해제 함수 -함수명: free() -기능:미리 확보된 바이트의 블록을 해제한다. 해제될 기억장소의 시작 주소가 이 함수의 인자로 사용된다. -예: free(pt);

  37. 배열의 크기를 입력 받아 그 만큼의 배열을 위한 기억 장소 할당 int numgrades; int *grades; /* 정수형 포인터 변수 정의 */ printf("Enter the number of grades to be processed: "); scanf("%d", &numgrades); /* 요구된 만큼의 정수형 배열을 위한 기억장소 할당 */ grades = (int *) malloc(numgrades * sizeof(int));

  38. #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); }

  39. 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:"); for (i=0; i < numgrades; i++) printf(" %d", grades[i]); free(grades); } 실행결과 Enter the number of grades to be processed: 4 Enter a grade: 85 Enter a grade: 96 Enter a grade: 77 Enter a grade: 92 An array was created for 4 integers The value stored in the array are: 85 96 77 92

  40. 구조체 동적 기억장소 할당 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) }

  41. 동적 연결 리스트 초기 리스트

  42. 동적 연결 리스트 삽입 예 Carter 삽입

  43. 동적 연결 리스트 삽입 방법 INSERT (새로운 레코드를 연결 리스트에 추가) { -새로운 레코드를 위한 공간을 동적으로 할당 if 리스트에 임의의 레코드가 존재하지 않음 -새로운 레코드의 주소 필드를 NULL로 지정 -첫 번째 레코드 포인터를 새롭게 생성된 레코드의 주소로 지정 else -새로운 레코드가 리스트의 어느 위치에 놓여져야 할 것인지를 결정 if 레코드가 리스트의 첫 번째 레코드로 존재해야 함 -첫 번째 레코드 포인터의 값을 새롭게 추가된 레코드의 주소 필드에 복사 -첫 번째 레코드 포인터의 주소를 새롭게 추가된 레코드의 주소로 지정 else -추가된 레코드의 바로 앞에 놓일 레코드의 포인터 멤버의 값을 새롭게 추가된 레코드의 주소 필드에 복사 -추가된 레코드의 바로 앞에 놓일 레코드의 포인터 멤버의 값을 새롭게 추가된 레코드의 주소로 지정 /* endif */ /* endif } /* end of INSERT

  44. 동적 연결 리스트 삽입 새로운 레코드의 선형 탐색(LINEAR LOCATION of a NEW RECORD) if 새로운 레코드의 키이 필드가 첫 번째 레코드 키이 필드보다 작으면 - 새로운 레코드가 첫 번째 레코드임 else while (리스트에 레코드가 있음) { - 새로운 레코드의 키이 값과 각 레코드의 키이 값과 비교 - 새로운 레코드 키가 두 개의 레코드사이에 존재하거나 혹은 리스트의 끝에 속하는 경우 비교를 멈춤 } endwhile endif

  45. 레코드 삽입 예 #include <stdio.h> #include <stdlib.h> #define MAXCHARS 30 /* 연결 리스트 레코드의 선언 */ struct Name_rec { char name[MAXCHARS]; struct Name_rec *next_addr; }; /* 첫 번째 레코드 포인터의 정의 */ struct Name_rec *first_rec; void main(void) { void read_insert(void); /* 함수 프로토타입 */ void display(void); first_rec = NULL; /* 리스트 포인터 초기화 */ read_insert(); display(); }

  46. /* 이름을 입력받아 이를 연결 리스트에 삽입 */ void read_insert(void) { char name[MAXCHARS]; void insert(char []); printf("\f2 nEnter as many names as you wish, one per line"); printf("\f2 nTo stop entering names, enter a single x "); while(1) { printf("Enter a name: "); gets(name); if (strcmp(name, "x") == 0) break; insert(name); } }

  47. void insert(char *name) { struct Name_rec *locate(char *); /* 함수 프로토타입 */ struct Name_rec *newaddr, *here; /* Name_rec 형 구조체 포인터 */ newaddr = (struct Name_rec *) malloc(sizeof(struct Name_rec)); if (newaddr == (struct Name_rec *) NULL) { /* 주소를 점검 */ printf("\f2 nCould not allocate the requested space"); exit(1); } /* 새로운 레코드가 어디에 놓여져야 할지를 결정, 모든 포인터 멤버를 갱신 */ if (first_rec == NULL) {/* 현재 리스트에 존재하는 레코드가 없는 경우 */ newaddr->next_addr = NULL; first_rec = newaddr; } else if (strcmp(name, first_rec->name) < 0) { /* 리스트에 첫 번째 레코드로 추가되는경우 */ newaddr->next_addr = first_rec; first_rec = newaddr; } else {/* 레코드가 리스트의 첫 번째 레코드가 아닌 경우 */ here = locate(name); newaddr->next_addr = here->next_addr; here->next_addr = newaddr; } strcpy(newaddr->name, name); }

  48. /* 존재하는 연결 리스트에 새로 추가될 레코드의 삽입될 위치를 결정 */ struct Name_rec *locate(char *name) { struct Name_rec *one, *two; one = first_rec; two = one->next_addr; if (two == NULL) return (one); /* 새로운 레코드는 존재하는 단일 레코드 다음에 삽입될 것임 */ while(1) { if (strcmp(name, two->name) <0) /* 리스트내의 이 위치에 레코드를 삽입한다 */ break; else if (two->next_addr == NULL) { /* 마지막 레코드 다음에 위치 */ one = two; break; } else { /* 계속적으로 삽입될 위치를 찾음 */ one = two; two = one->next_addr; } return (one); }

  49. /* 연결 리스트로부터 name을 출력 */ void display(void) { struct Name_rec *contents; contents = first_rec; printf("\f2 nThe names currently on the list are:"); while (contents != NULL) { printf("%s", contents->name); contents = contents->next_addr; } return; } 출력결과 Enter as many names as you wish, one per line To stop entering names, enter a single x Enter a name: Binstock Enter a name: Arnold Enter a name: Duberry Enter a name: Carter Enter a name: x The names currently on the list are: Arnold Binstock Carter Duberry

More Related