Chapter 16 유도자료형 struct, union, enum 한국항공대학교항공우주기계공학부 1 구조체 (struct) 구조체의필요성 책에대한정보를살펴보면매우다양 책정보제목, 저자, 출판사, 페이지수, 가격, ISBN 등 struct 서로다른자료형의변수들을묶어서만든하나의새로운자료형을구조체 (struct) 구조체는연관된멤버로구성되는통합자료형으로대표적인유도자료형 구조체정의 중괄호사이에원하는여러개의변수를선언 중괄호다음마지막에세미콜론 (;) 을반드시기술 2
구조체정의와변수선언 구조체정의 구조체멤버 ( 구성요소, member) 구조체정의구문에서는각구성요소의초기값을대입할수없음 한구조체내부에서선언되는구조체멤버의이름은모두유일 구조체의정의는구조체 struct book 을새로운자료형으로정의하는구문 구조체정의는구조체변수를선언하는구문이아님 변수선언 구조체정의구문은변수의범위와비슷 구조체정의구문의위치에따라구조체선언시자료형이용의범위가정해짐 3 구조체정의와변수선언 구조체변수를선언하는다른방법은다음과같이구조체정의와변수선언을함께하는방법 위구문에서변수 yourbook 과 mybook 은모두같은구조체 struct book 자료형 위구조체정의구문에서구조체태그이름 book 을생략해도구조체변수선언이가능 4
자료형이다른구조체 다음구문에서구조체변수 mybook과 yourbook은자료형이다른변수 즉동일한구조체태그이름으로선언된변수만이동일한자료형의구조체가됨 자료형이다르면대입연산자를사용불가능 가능한구조체의표준형을사용할것! 5 typedef 를이용한형선언 typedef를이용한형선언 구조체 struct book이정의된상태에서구조체 struct book 좀더간단하게선언 typedef로구조체정의 구조체정의자체를typedef와함께하는방법 아래 typedef 구문에서새로운자료형으로정의되는키워드는 software로서, 이구문이후에는구조체를선언할때 software 를이용하여형의선언이가능 struct book { char title[50]; // 제목 char author[50]; // 저자 char publish[50]; // 출판사 int pages; // 페이지수 int price; // 가격 }; typedef struct book book ; book yourbook; book mybook; 6
구조체멤버변수의초기값지정 구조체 struct book 정의 구조체정의에서는구조체멤버에초기값을지정불가능 구조체변수 mybook 를선언할때초기값을대입 구조체변수도배열과같이중괄호를이용하여초기값을대입 멤버참조 구조체멤버를접근하기위해서는멤버접근연산자인마침표 (.) 를 이용 struct book { int pages = 200; int price = 30000; }; typedef struct book book; 구조체정의에서멤버의초기값을저장하는것은허용되지않는다. book mybook = {"C@PL.com", " 강환수 ", " 학술정보 ", 530, 20000}; 구조체변수. 구조체멤버 mybook.author 7 예제소스 structbook.c 구조체정의, 변수선언, 구조체이용프로그램 8
복소수구조체 복소수를표현하는구조체 complex 를정의 복소수는 a+bi 로표현되며, 실수부 a 와허수부 b 는실수값 구조체 struct complex 는다음과같이정의 struct complex { double real; // 실수 double img; // 허수 }; typedef struct complex complex; 9 구조체주의 메인함수상단전역부분에서 struct complex 를정의 메인함수내부에서다시같은이름으로 struct complex 를정의하면서변수 comp 를하나선언 comp = comp3; 와같은대입문은에러 두변수comp1과 comp2는다시 complex 유형으로선언 10
구조체포인터 구조체변수를가리키는주소값을저장하려면구조체포인터변수를이용 struct univ { char title[50]; // 이름 char address[50]; // 주소 int students; // 학생수 }; struct univ ku = {" 한국대학교 ", " 서울시서초구 ", 5000}; struct univ *ptr = &ku; 변수 ku 는구조체변수이고, 변수 ptr 은구조체를가리키는포인터 11 구조체포인터이용 연산자 -> 구조체포인터변수 ptr 을이용하여구조체의멤버를참조하려면연산자 -> 를이용 연산자 -> 는구조체멤버참조연산자로서연산자우선순위가가장높음 printf(" 학교 : %s, 주소 : %s, 학생수 : %d\n", ptr->title, ptr->address, ptr->students); 간접연산자 * 변수 ptr 을이용하여구조체의멤버 member 를참조하는다른방법은 (*ptr).member 를이용하는방법 printf(" 학교 : %s, 주소 : %s, 학생수 : %d\n", (*ptr).title, (*ptr).address, (*ptr).students); 위구문에서 (*ptr).title은 *ptr.title과는다른의미이므로반드시괄호를사용 * ptr.title 은 *(ptr.title) 을의미하므로 ptr이포인터변수이면에러가발생 구조체의멤버를참조하는연산자 -> 와. 의연산자우선순위가가장높기때문 12
포인터변수 구조체변수및포인터변수를이용하는다음 4 가지구문을잘구별하도록 13 구조체배열 구조체변수를여러개선언하기위해서구조체배열을이용 구조체 book 으로배열 clang[3] 을선언하여구조체원소 3 개를선언하는구문 struct book { char author[50]; char title[50]; int pages; }; struct book clang[3] = { {"Deitel", "C How To Program", 600}, {"Al Kelly", "A Book On C", 700}, {"Stephen Prata", "C Primer Plus", 800} }; 다른배열과같이구조체배열도첨자를이용하여각원소를참조하며, 첨자는 0부터 ( 배열크기-1) 까지가능 첫구조체원소의멤버를출력하는구문 printf(" 저자 : %s, 제목 : %s, 페이지수 : %d n", clang[0].author, clang[0].title, clang[0].pages); 14
함수에서의구조체 : 구조체인자, 값전달 (call by value) 복소수연산에이용되는함수를구현 함수 paircomplex1() 는전달인자복소수의켤레복소수를구하여반환하는함수 그러므로변수 pcomp 에는 {3.4, -4.8} 이저장 complex comp = {3.4, 4.8}; complex pcomp; pcomp = paircomplex1(comp); 구현 complex paircomplex1(complex com) { com.img = -com.img; return com; } 위와같이구조체는함수의전달인자와반환값으로이용이가능 위함수는구조체인자를값에의한호출 (call by value) 방식으로이용 즉함수 paircomplex1() 내부에서지역구조체변수 com 을하나만들어실인자의구조체값을모두복사하는방식으로구조체값을전달 15 함수에서의구조체 : 구조체인자, 주소전달 (call by address) 인자를 call by address 로 이전함수를주소에의한호출 (call by address) 방식으로변환 다음함수 paircomplex2() 는인자를주소값으로저장하여, 실인자의변수 comp 의값을직접수정하는방식 void paircomplex2(complex *com) { com->img = -com->img; } 위함수를호출하기위해서는 comp 의주소값을이용해야하므로다음과같이호출 paircomplex2( &comp ) 구조체가많은멤버를가지거나, 큰배열을멤버로가지는경우, 구조체자체를인자로전달하는것은매우비효율 이러한경우는주소값으로전달하는방식인주소에의한호출방식이효율적임. 16
예제소스 complexfunction.c 함수 paircomplex1() 과 paircomplex2() 를구하는프로그램 17 공용체 (union) 정의 공용체는서로다른자료형을동일한저장공간에이용하는자료형 공용체 union data 를정의하는구문 구조체정의에서키워드 struct 를 union 으로사용한것과비슷 union data { char ch; int cnt; double real; }; 공용체의멤버는모든멤버가동일한저장공간을사용하므로동시에여러멤버의값을저장하여이용할수없으며, 마지막에저장한하나의멤버의자료값만을저장 공용체 union data 정의와함께변수 data1과포인터변수 pdata를선언하는구문 union data { char ch; int cnt; double real; } data1, *pdata ; 18
공용체메모리내부 메모리 공용체 union data 자료형의변수 data1 은 멤버의유형이 char, int, double이므로 멤버중가장큰크기인 double 형의 8바이트를공용체의저장공간으로확보하여세개의멤버가함께이용 동일한저장장소를함께이용 union data { char ch; int cnt; double real; } data1, *pdata ; 멤버가 char인경우는 8바이트중에서첫 1바이트만이용하고, int인경우는전체공간의첫 4바이트만이용하며, double인경우는 8바이트공간을모두사용 19 공용체이용 구조체와같이 typedef 를이용하여새로운자료형으로정의가능 typedef union data uniondata; 공용체의초기값은첫멤버의초기값으로만저장이가능하고 다른동일한변수의값으로초기화가능 //uniondata data1 = {10}; // 에러발생 uniondata data2 = {'A'}; // 첫멤버인 char 유형으로만초기화가능 uniondata data3 = data2; // 다른변수로초기화가능 공용체변수로멤버를접근하기위해서는 구조체와같이접근연산자. 을이용하며, 포인터인경우는연산자 -> 를이용 pdata = &data2; printf("%2c %2c n", pdata->ch, (*pdata).ch); printf("%2c %2c n", data2.ch, data3.ch); 공용체변수 data1 의멤버 ch 에문자 a 를저장하는구문 이문장이후에멤버 cnt 나 real 을출력하는것은의미가없음 data1.ch = 'a'; printf("%c, %d, %6.2f\n", data1.ch, data1.cnt, data1.real); 20
열거형 (skip!) 키워드 enum 을이용하여열거형을정의 열거형구문은관련있는정수형상수목록집합을정의하는구문 위문장은변수 col을열거형 enum color로선언하는구문 열거형 enum color는색상을나타내는 5개의상수 yellow, red, blue, magenta, green을표현하는의미 color는열거형태그이름으로다음과같이생략가능 정수상수에대응 enum color {yellow, red, blue, magenta, green} col; enum {yellow, red, blue, magenta, green} col; 5 개의상수 yellow, red, blue, magenta, green 은 각각 0 에서부터 4 까지의정수상수에대응 정수상수는변수 col 에대입할수있고, 상수 0 에해당하는값을표현 col = yellow; 21 열거형이용 (skip!) enum day7 을정의하고, typedef 를이용하여새로이열거형자료형 day 를정의하는구문 enum day7 {sun, mon, tue, wed, thu, fri, sat}; typedef enum day7 day; 새로운자료형 day 는 enum day7 로변수선언에다음과같이이용할수있고, 변수를선언하면서초기값으로상수 fri 를대입하는문장 day today = fri; 열거형 day 는 7 개의상수 sun, mon, tue, wed, thu, fri, sat 를가지며, 각각 0 에서부터 6 까지의정수상수에대응 열거형 enum pl 정의에서는필요한경우, 상수값을각상수에지정가능 enum pl {c=1972, cpp=1983, java=1995, cs=2000}; typedef enum pl plang; 다음은 circle 상수는 0, tri 는 3, rect 는 4, star 는 7, dia 는 8 로정의 즉상수값을지정한상수는그값으로, 지정되지않은상수는그이후로 1 씩증가한상수값으로정의 enum shape {circle, tri=3, rect=4, star=7, dia}; typedef enum shape shape; 22
프로그래밍실습 프로그램목적 이장에서배운구조체와열거형을이용하여카드게임을할수있는여러자료형을만들어보고, n명에게 7장의카드를나눠주는프로그램을작성 카드게임 카드는 52 장이고, 모양은 4 가지 hearts, diamonds, clubs, spades이며, 번호는 ace(1) 부터 10까지그리고 jack(11), queen(12), king(13) 의종류 출력 23 구현 프로그램에필요한구조체정의나열거형정의는모두파일 card.h 헤더파일에코딩 파일 card.c에는다음함수네개를구현 int main() { card deck[52]; return 0; } void filldeck(card *deck) // 모든카드에모양과번호를부여 { } void shuffle(card *deck) // 카드를섞는과정 { } void deal(card *deck, int cnt) //cnt 에게 7 장을나누어줌 { } 24
헤더파일 card.h 카드의모양과번호를열거형 enumsuit와 enumface로정의하고, 구조체 card의멤버로번호와모양을저장하는 suit, face를정의 구조체자료형 card를 typedef를이용하여정의 문자열배열은번호나모양의출력을위하여전역변수로선언 함수세개의함수원형 25 메인함수 메인함수에서는카드의수만큼배열 deck[52] 를선언하여이배열을함수 filldeck(), shuffle(), deal() 의인자로이용 card deck[52]; int cnt = 2; filldeck(deck); shuffle(deck); printf(" 카드게임에몇사람이참가합니까? >> "); scanf("%d", &cnt); printf("\n"); deal(deck, cnt); return 0; 26
함수 deal() 함수 deal() 의두번째인자는게임에참가하는인원수로표준입력으로받은값을실인자로호출 void deal(card *deck, int cnt) { for ( i = 0; i < total; i++ ) printf( "%5s of %-8s%c", strface[deck[i].face], strsuit[deck[i].suit], (i+1) % cnt? ' ' : '\n'); } 출력될문자열은문자포인터배열 strface[13] 과 strsuit[4] 에정의 카드 deck[i] 에는멤버인 face 와 suit 가있으며, 이값은카드모양의열거형정수상수값으로정의되어있으므로출력될문자열로 strface[deck[i].face] 와 strsuit[deck[i].suit] 를이용하면쉽게원하는문자열출력가능 27 28
Chapter 17 파일처리 한국항공대학교항공우주기계공학부 29 함수 fopen() 파일을만들어데이터를입출력하기위해서는함수 fopen() 을이용 함수 fopen() 의함수원형은다음과같으며헤더파일 stdio.h 파일에정의 struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE; 함수 fopen() 은두개의문자열전달인자를이용, 반환값은포인터값인 FILE * 30
파일열기 함수 fopen() 에서첫번째문자열은처리하려는파일이름이고, 두번째문자열은파일처리종류 ( 모드 ) 다음소스는파일 basic.txt 을여는모듈로서, 파일에자료를쓰기위해파일을열므로모드값을 w 로기술 FILE *f; char fname[] = "basic.txt"; if ( (f = fopen(fname, "w") ) == NULL) { printf( " 파일이열리지않습니다.\n" ); }; fclose(f); FILE *fr, *fw; int a; double b; fr = fopen( 1.dat, r") // 입력파일열기 fw = fopen( 2.out, "w") // 출력파일열기 fscanf(fr, %d, %lf, &a, &b); // 입력데이터읽기 fprintf(fw, %d, %lf, a, b); // 출력데이터쓰기 조건문 if를위와같이함수fopen() 과함께이용하면파일열기에실패할경우문장 " 파일이열리지않습니다.\n" 을출력 파일처리가모두끝났으면파일포인터f를인자로함수 fclose(f) 를호출하여반드시파일을닫도록 함수 fopen() 의두번째인자는파일처리종류 ( 모드 ) r, w, a, r+, w+, a+ 의종류 31 파일처리모드 파일처리모드종류의미 32
함수 fprint, fscanf 파일에자료를쓰거나읽기위하여함수 fprintf() 와 fscanf() 를이용 이함수를이용하기위해서는헤더파일 stdio.h 파일을포함 함수 fprintf() 와 fscanf() 의함수원형 int fprintf(file *, const char *,...); int fscanf(file *, const char *,...); 위함수의첫번째인자는입출력에이용될파일이고, 두번째인자는입출력되는문자열이며, 다음인자들은입출력될변수목록 함수원형에서기호 은여러인자가계속됨을의미 함수 fprintf() 와 fscanf() 를표준입출력에도이용가능 (But, 되도록표준입출력은 printf() 와 scanf 를사용할것!) 즉함수 fprintf() 와 fscanf() 의첫번째인자에각각 stdin 또는 stdout 를이용하면표준입력, 표준출력으로이용이가능 기호상수 stdin, stdout 은 stderr 과함께헤더파일 stdio.h 에정의되어있는값으로각각표준입력, 표준출력, 표준에러를의미 #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2]) 표준파일 키워드 장치 (device) 표준입력 stdin 키보드 표준출력 stdout 모니터화면 표준에러 stderr 모니터화면 33 함수 fgets() 와 fputs() 함수 fgets() 와 fputs() 파일에문자열을입출력하는함수로 fgets() 와 fputs() 이함수도헤더파일 stdio.h 파일에다음과같은함수원형으로정의 함수 fgets() 는문자열을개행문자 ( n) 까지읽어개행문자도함께입력문자열에저장 마찬가지로함수 fputs() 는문자열을그대로출력 함수 fgets() 인자 첫번째인자는문자열이저장될문자포인터이고, 두번째인자는입력할문자의최대수이며, 세번째인자는입력문자열이저장될파일 함수 fputs() 인자 첫번째인자는출력될문자열이저장된문자포인터이고, 두번째인자는문자열이출력되는파일 char * fgets(char *, int, FILE *); int fputs(char *, FILE *); 34
함수 fgetc() 와 fputc() 문자하나를파일에입출력하는함수로 fgetc() 와 fputc() 를제공 이함수의원형은헤더파일 stdio.h 에정의 이함수들은문자하나의입출력의대상인파일포인터를인자로이용 int fgetc(file *); int fputc(int, FILE *); 이함수와같은함수로 getc() 와 putc() 도이용가능 int getc(file *); int putc(int, FILE *); 문자의표준입출력에이용되는 getchar() 와 putchar() 는다음과같이함수 getc() 와 putc() 를이용한매크로 #define getchar() #define putchar(_c) getc(stdin) putc((_c),stdout) 함수 fgetc() 와 fputc() 는 getc() 와 putc() 와그기능은동일하며, fgetc() 와 fputc() 는함수이고, getc() 와 putc() 는매크로 35 함수 feof() 와 ferror(): skip! 함수 feof() 파일의내부포인터위치가파일의끝 (EOF) 인지를검사하는데필요한함수 이함수는헤더파일 stdio.h 에다음함수원형으로정의 int feof(file *); 파일의위치가파일의마지막 (end of file) 인지를검사하여, 파일의마지막이면 0 이아닌값을, 파일의마지막이아니면 0 을반환 그러므로표준입력에서계속적으로입력을받는구문으로다음을이용가능 while (!feof(stdin)) { } 함수 ferror() 파일처리에서오류가발생했는지검사하는함수 함수의원형은헤더파일 stdio.h 에정의 int ferror(file *); 이전파일처리에서오류가발생하면 0 이아닌값을발생하고, 오류가발생하지않으면 0 을반환 36
예제소스 목적 list filename 을입력 파일 filename 의내용을표준출력으로출력하는프로그램 조건 명령어줄인자를활용, 두번째인자가파일이름에해당 이파일이름에해당하는인자를기술하지않으면간단한사용법을알리고프로그램은종료 파일내용의출력은한줄마다맨앞에줄번호를출력 첫실행에서는파일이름을입력하지않았고, 두번째에는이프로그램의소스를파일이름으로기술 37 17.4 절이후 skip! 17 장숙제는 17.3 절까지의중간점검문제 38