구조체와함수 구조체를함수의인수로전달하는경우 구조체의복사본이함수로전달되게된다. 만약구조체의크기가크면그만큼시간과메모리가소요된다. int equal(struct student s1, struct student s2) { if( strcmp(s1.name, s2.name) == 0 ) return 1; else return 0; 8-40
구조체와함수 구조체의포인터를함수의인수로전달하는경우 시간과공간을절약할수있다. 원본훼손의가능성이있다. int equal(struct student const *p1, struct student const *p2) { if( strcmp(p1->name, p2->name) == 0 ) 포인터를통한구조 return 1; 체의변경을막는다. else return 0; 8-41
복사본이반환된다. 구조체를반환하는경우 struct student make_student(void) { struct student s; printf(" 나이 : ); scanf("%d", &s.age); printf(" 이름 : ); scanf("%s", s.name); printf(" 키 : ); scanf("%f", &s.grade); 구조체 s 의복사본이반환된다. return s; 8-42
예제 #include <stdio.h> struct vector { float x; float y; ; struct vector get_vector_sum(struct vector a, struct vector b); int main(void) { struct vector a = { 2.0, 3.0 ; struct vector b = { 5.0, 6.0 ; struct vector sum; sum = get_vector_sum(a, b); printf(" 벡터의합은 (%f, %f) 입니다.\n", sum.x, sum.y); return 0; a a + b b 8-43
예제 struct vector get_vector_sum(struct vector a, struct vector b) { struct vector result; result.x = a.x + b.x; result.y = a.y + b.y; a + b a b return result; 벡터의합은 (7.000000, 9.000000) 입니다. 8-44
공용체 (union) 공용체 (union) 같은메모리영역을여러개의변수가공유 공용체를선언하고사용하는방법은구조체와아주비슷 union example { char c; int i; ; // 같은공간공유 // 같은공간공유 8-45
예제 #include <stdio.h> union example { int i; char c; ; int main(void) { union example v; 공용체선언 공용체변수선언. char 형으로참조. v.c = 'A'; printf("v.c:%c v.i:%i\n", v.c, v.i ); v.i = 10000; printf("v.c:%c v.i:%i\n", v.c, v.i); int 형으로참조. v.c:a v.i:65 v.c: v.i:10000 8-46
ip 주소예제 #include <stdio.h> union ip_address { unsigned long laddr; unsigned char saddr[4]; ; int main(void) { union ip_address addr; addr.saddr[0] = 1; addr.saddr[1] = 0; addr.saddr[2] = 0; addr.saddr[3] = 127; printf("%x\n", addr.laddr); return 0; 7f000001 8-47
공용체에타입필드사용 #include <stdio.h> #include <string.h> #define STU_NUMBER 1 #define REG_NUMBER 2 struct student { int type; union { int stu_number; char reg_number[15]; id; char name[20]; ; // 학번 // 주민등록번호 8-48
공용체에타입필드사용 void print(struct student s) { switch(s.type) { case STU_NUMBER: printf(" 학번 %d\n", s.id.stu_number); printf(" 이름 : %s\n", s.name); break; case REG_NUMBER: printf(" 주민등록번호 : %s\n", s.id.reg_number); printf(" 이름 : %s\n", s.name); break; default: printf(" 타입오류 \n"); break; 8-49
공용체에타입필드사용 int main(void) { struct student s1, s2; 학번 : 20070001 이름 : 홍길동주민등록번호 : 860101-1056076 이름 : 김철수 s1.type = STU_NUMBER; s1.id.stu_number = 20070001; strcpy(s1.name, " 홍길동 "); s2.type = REG_NUMBER; strcpy(s2.id.reg_number, "860101-1056076"); strcpy(s2.name, " 김철수 "); print(s1); print(s2); 8-50
열거형 (Enumeration) 열거형 (enumeration) 이란변수가가질수있는값들을미리열거해놓은자료형 ( 예 ) 요일을저장하고있는변수는 { 일요일, 월요일, 화요일, 수요일, 목요일, 금요일, 토요일 중의하나의값만가질수있다. 8-51
열거형의선언 enum days { SUN, MON, TUE, WED, THU, FRI, SAT ; 태그이름 값들을나열 열거형변수선언 enum days today; today = SUN; // OK! 8-52
열거형이필요한이유 다음과같이프로그램을작성할수있다. int today; today = 0; // 일요일 today = 1; // 월요일 되도록오류를줄이고가독성을높여야된다. 0보다는 SUN라는기호상수가더바람직하다. 의미를쉽게알수있기때문이다. today에 9와같은의미없는값이대입되지않도록미리차단하는것도필요하다. 8-53
열거형초기화 enum days { SUN, MON, TUE, WED, THU, FRI, SAT ; // SUN=0, MON=1,... enum days { SUN=1, MON, TUE, WED, THU, FRI, SAT ; // SUN=1, MON=2,... enum days { SUN=7, MON=1, TUE, WED, THU, FRI, SAT=6 ;// SUN=7, MON=1,... 값을지정하기않으면 0 부터할당 8-54
열거형의예 enum colors { white, red, blue, green, black ; enum boolean { false, true ; enum levels { low, medium, high ; enum car_types { sedan, suv, sports_car, van, pickup, convertible ; 8-55
예제 #include <stdio.h> enum days { SUN, MON, TUE, WED, THU, FRI, SAT ; char *days_name[] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ; int main(void) { enum days d; d = WED; printf("%d번째요일은 %s입니다\n", d, days_name[d]); return 0; 3 번째요일은 wednesday 입니다 8-56
열거형과다른방법과의비교 정수사용기호상수열거형 switch(code) { case 1: printf("lcd TV\n"); break; case 2: printf("pdp TV\n"); break; 컴퓨터는알기쉬우나사람은기억하기어렵다. #define LCD 1 #define PDP 2 switch(code) { case LCD: printf("lcd TV\n"); break; case PDP: printf("pdp TV\n"); break; 기호상수를작성할때오류를저지를수있다. enum tvtype { LCD, PDP ; enum tvtype code; switch(code) { case LCD: printf("lcd TV\n"); break; case PDP: printf("pdp TV\n"); break; 컴파일러가중복이일어나지않도록체크한다. 8-57
typedef 의개념 8-58
typedef typedef은새로운자료형 (type) 을정의 (define) C의기본자료형을확장시키는역할 typedef old_type new_type; 새로운자료형을정의 typedef unsigned char BYTE; 기존의자료형 새로운자료형 8-59
typedef 의예 typedef unsiged char BYTE; BYTE index; // unsigned int index; 와같다. typedef int INT32; typedef unsigned int UINT32; INT32 i; // int i; 와같다. UINT32 k; // unsigned int k; 와같다. 8-60
구조체로새로운타입정의 구조체로새로운타입을정의할수있다. struct point { int x; int y; ; typedef struct point POINT; POINT a, b; 8-61
예제 #include <stdio.h> typedef struct point { int x; int y; POINT; POINT translate(point p, POINT delta); int main(void) { POINT p = { 2, 3 ; POINT delta = { 10, 10 ; POINT result; result = translate(p, delta); printf(" 새로운점의좌표는 (%d, %d) 입니다.\n", result.x, result.y); return 0; 8-62
예제 POINT translate(point p, POINT delta) { POINT new_p; new_p.x = p.x + delta.x; new_p.y = p.y + delta.y; return new_p; 새로운점의좌표는 (12, 13) 입니다. 8-63
이식성을높여준다. typedef 과 #define 비교 코드를컴퓨터하드웨어에독립적으로만들수있다 ( 예 ) int형은 2바이트이기도하고 4바이트, int형대신에 typedef을이용한 INT32나 INT16을사용하게되면확실하게 2바이트인지 4바이트인지를지정할수있다. #define 을이용해도 typedef 과비슷한효과를낼수있다. 즉다음과같이 INT32 를정의할수있다. #define UINT32 unsigned int typedef float VECTOR[2];// #define으로는불가능하다. 문서화의역할도한다. typedef 을사용하게되면주석을붙이는것과같은효과 8-64
실습 : 평점이높은학생찾기 어느학교나학기가끝나면학과내에서가장평점이높은학생을선발하여서장학금을수여한다. 가장평점이높은학생을찾아서학생의이름과학번, 평점을화면에출력하는프로그램을작성하여보자. 평점이가장높은학생은 ( 이름 : 홍길동, 학번 : 20120001, 평점 : 4.200000) 입니다. 8-65
힌트 학생에대한정보는구조체를이용하여서표현한다. 학생들이여러명이므로구조체의배열을사용하는것이좋겠다. struct student { int number; char name[20]; double grade; ; struct student list[] = { { 20120001, 홍길동 ", 4.2, { 20120002, 김철수 ", 3.2, { 20120002, 김영희 ", 3.9 ; 8-66
소스 #include <stdio.h> struct student { int number; char name[20]; double grade; ; struct student list[] = { { 20120001, " 홍길동, 4.2, { 20120002, " 김철수, 3.2, { 20120002, " 김영희, 3.9 ; 8-67
소스 int main(void) { struct student super_stu; int i, size; size = sizeof(list)/sizeof(list[0]); super_stu = list[0]; for(i=1; i< size; i++) { if( list[i].grade > super_stu.grade ) super_stu = list[i]; printf(" 평점이가장높은학생은 ( 이름 %s, 학번 %d, 평점 %f) 입니다 \n", super_stu.name, super_stu.number, super_stu.grade); 8-68
비트단위구조체 (bit-field structure) struct with bit-unit members struct TagName { DataType member_1: numberofbits; DataType member_2: numberofbits;... ; struct product { unsigned style : 3; unsigned size : 2; unsigned color : 1; ; unsigned int 1 2 3 color size style 8-69
bit_field.c 1. // bit-field structure 2. #include <stdio.h> 3. struct product { 4. unsigned char 5. style : 3, 6. size : 2, 7. color : 3; 8. ; 9. int main(void) 10. { 11. struct product p1; 12. p1.style = 5; p1.size = 3; p1.color = 6; 13. printf("sizeof(p1)=%d n", sizeof(p1)); 14. printf("style=%d, size=%d, color=%d n", p1.style, p1.size, p1.color); 15. printf("p1=%x n ", p1); 16. return 0; 17. 8-70
Example of Bit-field mapping Bit-field mapping in Little-Endian and Big-Endian 0x2000 0x2001 0x2002 0x2003 7 Big-Endian Byte Ordering, Bit-field Mapping (Apple Mac) 0 f1 f2 f3 c s1 s2 s3 s4 s5 s6 struct BFU_32 { unsigned char f1:3, f2:3, f3:2; char c; unsigned short s1:3, s2:3, s3:2, s4:3, s5:2, s6:3; ; struct BFU_32 *pu32 = (struct BFU_32 *)0x2000; 0x2003 0x2002 0x2001 0x2000 7 s6 s5 s4 s3 s2 s1 f3 Little-Endian Byte Ordering, Bit-field Mapping (PC Intel CPU) c f2 f1 0 8-71
Homework 8 8.1 복소수계산을위한구조체정의 (Struct MyCmplx) 1) 복소수는실수부와허수부를가지며, c = real ( 실수부 ) + j imaginary( 허수부 ) 로표현된다. 복소수를위한구조체 struct Cmplx를작성하라. 실수부와허수부는보다높은정밀도를위하여 double 데이터유형을사용한다. struct Cmplx { double real; double imaginary; double magnitude; 2) 복소수의 4칙연산을위한함수를정의하라. - Cmplx cmplxadd(cmplx c1, Cmplx c2); - Cmplx cmplxsubtract(cmplx c1, Cmplx c2); - Cmplx cmplxmultiply(cmplx c1, Cmplx c2); - Cmplx cmplxdivide(cmplx c1, Cmplx c2); 3) 복소수배열 ( 예 : Cmplx cmplxs[6]) 을정의하라. 8-72
4) 표준입력장치로부터 4개의 double형데이터를입력받아, 두개의복소수의실수부와허수부의값으로설정하라. 이들두개의복소수는복소수배열의첫번째두개의복소수에해당한다 (cmplxs[0], cmplxs[1]). 입력포멧은 rrr.ddd iii.ddd 를사용하라. 5) 위에서구현한 4개의복소수연산함수를사용하여, 표준입력장치로부터입력을받아설정된두개의복소수 (cmplxs[0], cmplxs[1]) 의 addition, subtraction, multiplication 과 division을계산하고, 그결과를각각 cmplxs[2], cmplxs[3], cmplxs[4], cmplxs[5] 에저장하라. 각복소수의크기 (magnitude) magnitude = sqrt (real^2 + imaginary^2) 공식을사용하여계산할것. 6) 복소수배열에포함된각복소수 (cmplxs[0] ~ cmplxs[5]) 를 rrr.ddd + j iii.ddd (magnitude mmm.ddd) 양식으로한줄에복소수 1개씩을출력하라. 7) 복소수배열의신속한정렬을위하여, 퀵정렬함수 ( sortcmplx(cmplx cmplxs[], int size)) 를작성하라. 이복소수배열의퀵정렬함수는복소수배열을파라메터로전달받으며, 복소수크기 (magnitude) 값의오름차순으로정렬한다. 8) 정렬된복소수배열을 rrr.ddd + j iii.ddd (magnitude mmm.ddd) 양식으로한줄에복소수 1개씩을출력하라. 8-73
8.2 구조체 Time을사용하는 Clock system 1) 시간을나타내기위하여, hour, minute, 및 second를포함하는구조체 Time을작성하라. struct Time { int hour; int min; int sec; ; 2) 표준입력장치로부터 3개의정수를입력받아, 이를각각시, 분, 초의값으로설정하라. 예를들어, 10 5 30 로입력된정수는구조체 Time 변수의 10시 5분 30초 로설정된다. 시간을나타내는값은 0시 ~ 23시의값을가지도록할것. 3) 구조체 Time 변수의값을 hh:mm:ss 양식으로출력하는함수를작성하라. 구조제 Time 변수는 00:00:00 ~ 23:59:59 구간의값을가진다. 4) 구조체 Time 변수값을지정된초단위로증가하는함수 void incrementtime(time *, int) 를작성하라. 표준입력장치로부터정수를입력받아, 위 2) 에서초기화설정된구조체 Time 변수의값을증가시켜라. 분과시는 60초와 60분단위로증가되어야한다. 예를들어, 23:59:59 에 2 초를더하면 00:00:01 이되어야한다. 5) 두개의구조체 Time 변수를비교하는 int timecompare(const Time *tptr1, const Time *tptr2) 함수를작성하라. 이함수는 call-by-pointer로 ( 구조체포인터 ) 로전달되는두개의시간을비교하여, 그차이 ( 초단위 ) 를반환한다. 반환데이터유형은정수이며, 초단위값을나타낸다. 위 2) 에서초기설정된시간값과 4) 에서증가된시간값을비교하여, 그차이를 timecompare() 함수를사용하여계산하고, 그결과를반환하여, 정확한계산이이루어졌는가를확인하라. 8-74