Outline
8.1 형 정의 typedef 8.2 구조형 struct 8.3 구조형과 함수 8.4 공용형 union 8.5 비트 필드
8.6 요약
8.7 예제
• ( 예 8.1) typedef 정의와 선언
( 예 8.1) typedef
/* (1) 정의 */
typedef int BOOL;
typedef unsigned char TEXT;
typedef int INCHES, FEET, YARDS;
typedef int vector[10];
typedef char *string;
/* (2) 선언 */
BOOL flag; /* int flag; 와 같은 의미 */
TEXT buf[100]; /* unsigned char buf[100]; 와 같은 의미 */
INCHES length, width; /* int length, width; 와 같은 의미 */
vector a, b; /* int a[10], b[10]; 과 같은 의미 */
string text, input; /* char *text, *input; 과 같은 의미 */
<typedef 와 #define 의 차이점 >
- typedef 는 자료형에 대해서만 기호 이름을 부여 할 수 있다 .
- typedef 는 전처리기가 아닌 컴파일러에 의해 실행된다 .
• ( 예 8.2) typedef 의 사용 (1)
( 예 8.2)
typedef 의 사용
/* (1) 정의 */
#define N 3 /* 벡터 (vector) 와 행렬 (matrix) 의 크기 */
typedef double scalar;
typedef scalar vector[N];
typedef scalar matrix[N][N];
void add(a, b, c)
vector a, b, c; /* double a[3], b[3], c[3]; 과 같은 의미 */
{
int i;
for (i = 0; i < N; i++) a[i] = b[i] + c[i];
}
- 함수 add() 는 벡터를 연산하는 함수이다 .
- matrix 의 선언은 기 정의된 vector 를 사용하면 다음과 같이도 할 수 있다 .
typedef vector matrix[N];
• ( 예 8.3) typedef 의 사용 (2)
( 예 8.3)
typedef 의 사용
scalar dot_product(a, b) /* 벡터 a 와 벡터 b 의 내적 (dot product) */
vector a, b;
{
int i;
scalar s = 0;
for (i = 0; i < N; i++) s += a[i] * b[i];
return s;
}
void multiply(a, b, c) /* 행렬 곱셈 : a = b*c */
matrix a, b, c;
{
int i, j, k;
for (i = 0; i < N; i++) for (j = 0; j < N; j++)
for (c[i][j] = 0, k = 0; k < N; k++) c[i][j] += a[i][k] * b[k][j];
}
- 벡터의 내적 구하는 dot_product 와 두 행렬의 곱을 계산하는 multiply - scalar, vector 의 정의는 예 8.2 에서 정의
- matrix a, b, c; 는 double a[N][N], b[N][N], c[N][N]; 과 동일 .
• 구조형 struct 의 형식
– (1) 새로운 구조형의 정의
– (2) 이미 정의된 struct 태그명 형의 변수를 선언 – (3) 새로운 구조형을 정의하고 , 해당 변수도 선언함
(1) struct 태그명 { 항목 _ 선언 _ 리스트 };
(2) struct 태그명 식별자명 [, 식별자명 … ];
(3) struct [ 태그명 ] { 항목 _ 선언 _ 리스트 } 식별자명 [, 식별자명 … ];
- 태그명 은 식별자이다 .
- 태그명 은 구조형의 template 명이라고도 한다 .
- [ ] 안의 것은 생략 가능하다는 의미임 .
• ( 예 8.4) 구조형 struct 예 (1)
• 형식 3 을 이용하여 태그명 이 tg 인 struct 를 정의하고 , struct tg 형의 변수 y 를 선언한다 .
• struct tg 에는 4 개의 멤버가 있다 .
( 예 8.4) struct 예
struct tg { short a;
int b;
char c;
char d[4];
} y;
• 형식 2 를 이용하여 struct tg 형의 변수 w, x, z 를 추가로 선언한다 .
struct tg w, x, z;
• ( 예 8.5) 구조형 struct 예 (2)
• (1) 은 3 학생의 레코드를 표현하기 위해 s1, s2, s3 를 구조형 변수로 선언하고 있으나 , 구조체의 태그명 이 없으므로 다른 곳에 서 추가적인 학생 레코드의 선언이 가능하지 않다 .
( 예 8.5) struct 예
/* (1) */
struct {
long student_id; /* 학번 */
char *student_name; /* 학생 이름 */
char grade; /* 성적 */
} s1, s2, s3;
• ( 예 8.5) 구조형 struct 예 (2)
• (2) 에서는 구조체의 태그명 으로 student 를 사용하였으나 , 변 수 선언은 없다 .
• (3) 과 같이 하면 , 비로소 변수들을 위한 기억장소가 할당된다 .
( 예 8.5) struct 예
/* (2) */
struct student {
long student_id; /* 학번 */
char *student_name; /* 학생 이름 */
char grade; /* 성적 */
};
/* (3) */
struct student temp, class[100];
struct student {
long student_id; /* 학번 */
char *student_name; /* 학생 이름 */
char grade; /* 성적 */
} temp, class[100];
• (2)(3) 을 결합시켜 다음과 같이 사용할 수 있다 .
• ( 예 8.6) typedef 로 구조형 선언
• 다음의 변수 c 는 구조형 배열이다 .
• complex 를 struct 구문 대신 사용할 수 있다 .
( 예 8.6) typedef 로 구조형 선언
typedef struct {
float re; /* 실수부 */
float im; /* 허수부 */
} complex;
complex a, b, c[100];
• ( 예 8.6 계속 ) typedef 로 구조형 선언
• [ 기억 장소 할당 형태 ]
( 예 8.6 계속 )
c[0].re c[0].im
re im
float Çü float Çü
re im
a 또는 b
c[0]
c[1].re c[1].im
c[99].re c[99].im
c[1]
c[2]
c[99]
멤버 연산자
• 구조형 원소의 접근
구조형 _ 변수명 . 멤버명
• ( 예 8.7) 구조형 멤버의 접근
• 예 8.4, 8.5, 8.6 의 구조형 멤버에 대한 값 배정
• 구조형 배열의 각 원소의 멤버 접근 법 : c[4].im
• 멤버 자체가 배열형 자료인 경우 : y.d[0]
y.a = 1;
y.b = 623596;
y.c = ‘A’;
y.d[0] = ‘T’;
y.d[1] = ‘A’;
y.d[2] = ‘N’;
y.d[3] = ‘K’;
temp.grade = ‘A’;
temp.student_name = “Chanho Park”;
temp.student_id = 90118;
c[0].re = 12.06;
c[0].im = 3.0;
c[4].re = 18.09;
( 예 8.7)
구조형 멤버의 접근
• ( 예 8.8) 구조형 멤버를 접근하는 프로그램
– class 가 구조형 배열이다 . 즉 class 의 각 원소는 구조형이다 . – 각 구조형 원소의 멤버 grade 가 ‘F’ 면 cnt 를 증가시킨다 .
/* F 학점 받은 학생수를 반환하는 함수 */
int fail_count(struct student class[]) {
int i, cnt = 0;
for (i = 0; i < NOSTUDENTS; i++) cnt += class[i].grade == ‘F’;
return cnt;
}
( 예 8.8)
구조형 멤버를
접근하는 프로그램
• ( 예 8.9) 구조형의 내포와 참조
– 구조형 변수 x 의 멤버 z 가 구조형이므로 x.z.s 같이 참조 ( 즉 접근 ) 한다 .
struct tgy { char cbuf[10];
struct tgz { int i;
short s;
} z;
int t;
} x;
. . . x.z.s = 1;
. . .
( 예 8.9)
구조형의 내포와
참조
• ( 예 8.10) 구조형의 초기화
– 구조형의 멤버보다 작은 수의 값이 할당되면 나머지는 0 으로 간주된다 .
/* (1) */
complex m[3][3] = {
{{1.0, -0.5}, {2.3, 1.0}, {0.7, 0.7} }, /* m[0][] 부분 */
{{7.0, -6.5}, {-0.5, 1.0}, {45.7, 8.0} }, /* m[1][] 부분 */
} /* m[2][] 은 생략되었으므로 0 으로 배정됨 */
/* (2) */
static struct month { char *mname;
int day;
} month_tab[] = {
“January”, 31, “February”, 28,
“March”, 31, “April”, 30,
“May”, 31, “June”, 30,
“July”, 31, “August”, 31,
“September”, 30, “October”, 31, “November”, 30, “December”, 31 };
( 예 8.10)
구조형의 초기화
• ( 예 8.10 계속 ) 구조형의 초기화
– (2) 는 다음과 동일하다 .
/* (2)’ */
static struct month { char *mname;
int day;
} month_tab[] = {
{“January”, 31}, {“February”, 28}, {“March”, 31}, {“April”, 30},
{“May”, 31}, {“June”, 30},
{“July”, 31}, {“August”, 31}, {“September”, 30}, {“October”, 31}, {“November”, 30}, {“December”, 31} };
( 예 8.10 계속 )
구조형의 초기화
• struct 형에 대한 포인터
– 구조형 포인터가 구조형 보다 다루기 편리한 경우 있음 – 구조형 포인터를 인수로 사용
• 구조형을 전달할 수 없는 C 컴파일러도 있다 .
• 포인터를 넘기면 구조형의 복사가 일어나지 않아 메모리를 절약
• 구조형의 멤버로 다른 구조형을 가리키는 포인터를 사용하면 편리하다 .
– ( 예 8.11) struct 형에 대한 포인터 선언
/* ( 예 8.11) */
struct e { int n;
int k;
double s;
};
/* struct e 형의 배열 a[] 를 선언하고 초기화 */
static struct e a[] = { {1, 5, 1.7691}, {2, 6, 3.5512}, {3, 6, 7.1545} };
struct e *p; /* (1) */
p = a;
( 예 8.11)
구조형의 포인터
– ( 예 8.11 계속 ) struct 형에 대한 포인터 선언
• struct e *p;
– p 를 struct e 포인터 변수로 선언한다 .
• p = a;
– 배열 a 의 주소 즉 &a[0] 를 p 에 저장함 – 이제 p -> n 으로 a[0].n 을 접근할 수 있다 .
• p++;
– 이제 p 는 &a[1] 과 같다 .
– 이제 p -> n 은 a[1].n 과 같다 .
( 예 8.11 계속 ) 구조형의 포인터
p - > n
p - > s p - > k p
포인터 변수
p++
p++
a[0].n a[0].k a[0].s
– ( 예 8.12) 간접 멤버 연산자 -> 의 사용 예
• 구조형 포인터 변수 p 에 구조형 변수 temp 의 포인터를 배정하 여 사용하고 있다 .
• p -> grade 는 p 가 가리키는 구조형의 멤버 grade 를 뜻함 .
/* ( 예 8.12) */
struct student temp, *p = &temp;
temp.grade = ‘A’;
temp.student_name = “Chanho Park”;
temp.student_id = 90118;
( 예 8.12) -> 의 사용
수 식 연산 우선 순위 결 과
temp.student_name temp.grade temp.student_id
(*p) ->
student_name+2
*p ->
student_name+2
*(p ->
student_name+2)
p -> student_name p -> grade p -> student_id
*((*p) ->
student_name) + 2
*(p -> student_name) + 2
p -> student_name [2]
Chanho Park A
90118 /* 에러 */
E
a
– ( 예 8.13) 함수에 구조형 멤버 자료 전달
• 구조형 멤버를 인수로 : 인수가 복사되어 call by value 로 동작
• 구조형 멤버의 포인터를 인수로 :
– 앞에 & 를 붙여 주소를 넘김 : call by reference 의 효과 – 주소 연산자 & 는 멤버 앞이 아니라 구조형의 이름 앞에 쓴다 .
• [ 주의 ] 문자열 s 는 자체가 주소를 의미한다 .
/* (1) */
struct fred { char x;
int y;
char s[10];
} mike;
/* (2) */
func1(mike.x); /* x 의 문자값 전달 */
func2(&mike.x); /* 문자형 x 의 주소 전달 */
func3(mike.y); /* y 의 정수값 전달 */
func4(&mike.y); /* 정수형 y 의 주소 전달 */
func5(mike.s); /* 문자열 s 의 주소 전달 */
func6(mike.s[2]); /* s[2] 의 문자값 전달 */
func7(&mike.s[2]); /* 문자형 s[2] 의 주소 전달 */
( 예 8.13) 함수에
구조형 멤버
자료 전달
– ( 예 8.14) 함수에 구조형 전체를 전달 (1)
( 예 8.14) 함수에 구조형 전체를 전달
1 /* File : prog8-14.c
2 함수에 구조형 전체를 전달 (1) */
3 #include <stdio.h>
4 int main(void) 5 {
6 struct { 7 int a, b;
8 char ch;
9 } arg;
10 void f1();
11 arg.a = 1000;
12 f1(arg);
13 } 14
– ( 예 8.14) 함수에 구조형 전체를 전달 (1)
• 실 매개변수 (arg) 와 형식 매개 변수 (parm) 을 같은 구조형으로 선언 .
• 인수 선언시 struct 를 선언하는 방식으로 컴파일러에 따라 Warning 메시지를 주기도 함
( 예 8.14 계속 ) 함수에 구조형
전체를 전달
output
15 void f1(parm) 16 struct {
17 int x, y;
18 char ch;
19 } parm;
20 {
21 printf(“%d\n”, parm.x);
22 }
1000
– ( 예 8.15) 함수에 구조형 전체를 전달 (2)
– ( 예 8.14) 대신 이 방법을 사용하시오 !!
– 동일한 struct 형을 중복 선언하지 않는 버전
( 예 8.15) 함수에 구조형 전체를 전달
1 /* File : prog8-15.c
2 함수에 구조형 전체를 전달 (2) */
3 #include <stdio.h>
4 /* 구조형 형 정의 */
5 struct struct_type { 6 int a, b;
7 char ch;
8 };
9 int main(void) 10 {
11 struct struct_type arg; /* arg 선언 */
12 void f1();
13 arg.a = 1000;
14 f1(arg);
15 }
16 void f1(parm)
17 struct struct_type parm;
18 {
19 printf(“%d\n”, parm.a);
20 }
• 포인터 기반 함수와 구조형 기반 함수
– 다음 구조형을 정의하여 사용하자 .
헤더 file complex.h
1 /* File : complex.h
2 For prog8-16.c & prog8-17.c */
3 typedef struct { 4 float re;
5 float im;
6 } complex;
• ( 예 8.16) 포인터 기반 함수 ( 구조형 전달 ) 의 선언과 호출
– 다음 3 개의 함수를 포인터 인수를 사용하여 구현하자 .
• 복소수에 값을 배정하는 함수
• 두 개의 복소수를 더하는 함수
• 복소수를 출력하는 함수
( 예 8.16) 포인터 기반 함수
1 /* File : prog8-16.c
2 포인터 기반 함수 ( 구조형 전달 ) 의 선언과 호출 */
3 #include <stdio.h>
4 #include “complex.h”
5 void assign(complex *cp, float r, float i) 6 {
7 cp->re = r; /* (2) */
8 cp->im = i;
9 }
10 void add(complex *cp1, complex *cp2, complex *cp3) 11 {
12 cp3->re = cp1->re + cp2->re;
13 cp3->im = cp1->im + cp2->im;
14 } 15 16
17 void prnt(complex *cp) 18 {
19 printf(“%.3f + %.3f i\n”, cp->re, cp->im);
20 } 21
22 int main(void) 23 {
24 complex c1, c2, c3;
25 assign(&c1, 1.0, 2.0); assign(&c2, 3.0, 4.0);
26 add(&c1, &c2, &c3);
27 prnt(&c3);
28 }
• ( 예 8.16 계속 )
( 예 8.16 계속 )
output
4.000 + 6.000 i
• ( 예 8.17) 구조형 자료를 인수 및 반환값으로 사용
– 이것이 가능하지 않은 C 컴파일러도 있음 .
– 구조형이 값 호출 (call by value) 로 복사 (copy) 되어 전달 – 다음은 ( 예 8.16) 의 add2 는 add 를 재 작성한 버젼이다 .
• 계산 결과를 구조체 (res) 에 저장하고 반환값으로 사용하였다 .
• main 에서 호출하는 부분 ( 줄 26) 도 바뀐다 .
( 예 8.17) 구조형 자체를 인수와 반환값으로 사용
호출 부분의 변경
1 /* File : prog8-17.c
2 구조형을 인수와 반환값으로 사용하는 add2 의 작성 */
. . . .
10 complex add2(complex c1, complex c2) 11 {
12 complex res; /* 계산 결과를 저장 */
13 res.re = c1.re + c2.re;
14 res.im = c1.im + c2.im;
15 return res;
16 }
26 c3 = add2(c1, c2);
• ( 예 8.18) 공용형 자료 정의
– n 은 int 형이므로 통상 4 바이트 , x 는 double 형이므로 통상 8 바이트 , c 는 char 형이므로 통상 1 바이트가 필요함 .
– union 의 멤버들 (n, x, c) 은 기억장소를 공유한다 .
– 따라서 멤버 중 가장 큰 메모리를 필요로 하는 멤버 x 가 필요한 공 간 (8 바이트 ) 을 확보한다 .
– 모든 멤버 중 단 한 개만 사용하는 경우 ( 가령 심볼 테이블 등 ) 공 간 절약을 위해 흔히 사용된다 .
( 예 8.18) union
/* ( 예 8.18) */
union ifc { int n;
double x;
char c;
} temp;
temp.c temp.n
temp.x
• ( 예 8.19) 공용형 자료 정의
– union 과 struct 의 차이점은 union 의 멤버들은 모두 같은 주소에 배정된다는 점이다 . union 은 공간을 절약할 수 있다 .
– union ifc 의 3 멤버는 주소가 같으므로 , 가령 temp.n 에 저장 후 , temp.x 에 저장하면 temp.n 의 원래 값은 엉뚱한 값이 됨 . – union 멤버의 접근 방법은 struct 와 동일하다 .
( 예 8.19) union 변수의 선언과 참조
/* ( 예 8.19) */
union ifc fit;
union ifc save[10]; /* 10 개의 공용형 변수 배열 */
union ifc *pu; /* union ifc 형 자료에 대한 포인터 변수
temp.n = 444; /* ( 예 8.18) 에서 정의된 변수 temp 의 멤버값 배정 */
temp.x = 15.9;
temp.c = ‘H’;
fit.n = 23;
fit.x = 2.0;
fit.c = ‘a’;
pu = &fit;
k = pu -> n; /* k = fit.n 과 같음 */
• ( 예 8.20) 구조형과 공용형의 혼용
– union fromwhere 은 foreign_traveller 와 korean_traveller 라는 멤버를 가진다 .
– 이 두 멤버는 동시에 사용되지 않으므로 공용형 멤버로 정의 되었다 .
( 예 8.20) struct 와 union 의 혼용
/* ( 예 8.20) */
struct foreign_traveller { int country_code;
int city_code; *pc;
char passport_id[20];
};
struct korean_traveller { int district_code;
char resident_id[13];
};
union fromwhere {
struct foreign_traveller f_trav;
struct korean_traveller k_trav;
};
• ( 예 8.20 계속 ) 구조형과 공용형의 혼용
– traveller_record 란 구조형의 한 멤버로 union fromwhere 형을 사용하고 있다 .
( 예 8.20 계속 )
/* ( 예 8.20 계속 ) */
typedef struct { int serial_no;
char name[10];
short iskorean;
union fromwhere a;
} traveller_record;
• ( 예 8.21) 비트 필드 (bit field) 의 사용
– 1 또는 0 의 값 만을 갖는 비트 단위로 정의 가능
– (1) (1/0 저장 가능한 ) 1 비트짜리 멤버 3 개로 이루어진 struct – (2) ( 문자 저장 가능한 ) 8 비트짜리 멤버 4 개로 이루어진 struct
( 예 8.21) 비트 필드 선언
비트 필드의 접근
/* ( 예 8.21) 비트 필드의 사용 */
/* (1) */
struct {
unsigned class_a : 1;
unsigned class_b : 1;
unsigned class_a : 1;
} fig;
/* (2) */
struct word_bytes {
unsigned byte0 : 8, byte1 : 8, byte2 : 8, byte3 : 8;
} y;
1 비트 1 비트 1 비트
class_a class_b class_c
fig.class_a = 1;
y.byte3 = ‘w’;
• ( 예 8.22) 마스크 사용 비트 처리
– 시스템에 따라 비트 필드를 사용하면 효율이 떨어질 수 있다 . – 특정 비트의 마스크를 이용한 방법이 일반적인 방법임 .
– 01, 02, 04 와 같이 맨 앞에 0 을 붙이면 8 진법 숫자임 . – (1) 정수 fig 의 0 번째 비트를 1 로 set 시킴 .
– (2) 정수 fig 의 1 번째 비트가 0 인지 테스트 함
(fig & BIT1) 은 fig 의 해당 비트가 1 이면 참 (1), 0 이면 거짓 (0) 임
( 예 8.22) 마스크 사용 비트 처리
/* ( 예 8.22) 마스크 사용 비트 처리 */
#define BIT0 01 #define BIT1 02 #define BIT2 04 int fig;
. . . . .
fig |= BIT0; /* (1) */
if ((fig & BIT1) == 0) /* (2) */
. . . . .
예제 8.1
[ 해 설 ]
/* 예제 8.1 다음 선언들의 의미는 ? */
/* (1) */
typedef int WHOLE;
/* (2) */
typedef struct club { char name[30];
int size, year;
} GROUP;
/* (3) */
typedef GROUP, *PG;
/* (4) */
typedef void DRAW(int, int);
- (1) WHOLE 은 int 형과 동의어로 정의된다 .
- (2) 3 개의 멤버를 가진 struct club 을 선언하고 , GROUP 를 그와 동의어 로 정의한다 .
- (3) PG 는 기 정의된 GROUP 포인터 형라고 정의 된다 .
- (4) 정수 2 개를 인수로 취하고 반환형이 없는 함수에 대한 형 정의이다 .
- DRAW box; 는 void box(int, int); 와 같은 선언이 된다 .
예제 8.2
[ 해 설 ]
/* 예제 8.2 다음 선언들의 의미는 ? */
/* (1) */
struct {
float x, y;
} complex;
/* (2) */
struct { float x, y;
} complex[100];
/* (3) */
struct employee { char name[20]
int id;
long class;
} temp;
- (1) complex 라는 구조형 변수를 정의함 . 그 구조형은 float 형 x, y 를 멤버로 갖으나 , 태그가 없다 .
- (2) 구조형의 배열 선언 . 각 원소는 2 개의 멤버를 가진 구조형이다 .
- (3) temp 라는 구조형 변수 선언 . 구조형의 멤버는 name, id, class 이
다 .
예제 8.2( 계속 )
[ 해 설 ]
/* 예제 8.2( 계속 ) */
/* (4) */
struct employee student, faculty, staff;
/* (5) */
struct sample { char c;
float *pf;
struct sample *next;
} x;
/* (6) */
struct {
unsigned icon : 8;
unsigned color : 4;
unsigned underline : 1;
unsigned blink : 1;
} screen[25][80];
- (4) 변수 student, faculty, staf 를 struct employee 형으로 선언 - (5) 구조형의 3 째 멤버 next 는 동일한 구조형 자료에 대한 포인터이다 . - (6) screen 이라는 이름의 구조형 배열로 원소는 2000 개이다 .
각 원소는 4 개의 멤버로 구성되고 , 각 멤버는 각각 길이가 8 비트 ,
4 비트 , 1 비트 , 1 비트이다 .
예제 8.3
[ 해 설 ]
/* 예제 8.3 다음 문장들의 의미는 ? */
struct rec { int a;
struct rec *sp;
} item, list[5];
/* (1) */
item.a = 10;
/* (2) */
list[0].sp = &list[1];
list[0].sp -> a = 20;
/* (3) */
list[3].a = 30;
- (1) struct rec 형의 변수 item 의 멤버 a 에 10 을 배정한다 .
- (2) 배열 list 의 0 번째 원소의 멤버 sp 의 값으로 list[1] 의 포인터를 저 장 .
이후 그 포인터가 가리키는 구조체 ( 즉 list[1]) 의 멤버 a 에 20 을 저 장 .
- (3) 구조형의 배열로부터 , 각 구조형 원소의 멤버에 접근하는 방법 .
예제 8.4
5 CMPLX {
6 double re;
7 double im;
8 };
9 int main(void) 10 {
11 static CMPLX za = {3.0, 4.0};
12 static CMPLX zb = {5.0, 6.0};
13 CMPLX z, cadd(), cmult(); void cprint();
14 z = cadd(za, zb); cprint(z);
15 z = cmult(za, zb); cprint(z);
16 }
17 /* --- 복소수 덧셈 --- */
18 CMPLX cadd(CMPLX za, CMPLX zb) 19 {
20 CMPLX z;
21 z.re = za.re + zb.re;
22 z.im = za.im + zb.im;
23 return z;
24 }
예제 8.4( 계 속 )
[ 해 설 ]
output
8.000 + 10.000 i -9.000 + 38.000 i
- 줄 4 로 CMPLX 를 struct complex 와 같게 선언함 .
- 복소수를 실수부 re(real) 와 허수부 im(imaginary) 로 구성된 구조형 으로 정의 .
- 두 복소수의 합과 곱을 구하는 프로그램
29 z.re = za.re * zb.re - za.im * zb.im;
30 z.im = za.re * zb.im + za.im + zb.re;
31 return z;
32 }
33 /* --- 복소수 출력 --- */
34 void cprint(CMPLX z) 35 {
36 printf(“%.3f + %.3f i\n”, z.re, z.im);
37 }
예제 8.5
[ 해 설 ] output
5 {
6 static struct s1 { 7 char c[4], *s;
8 } s1 = {“abc”, “def” };
9 static struct s2 { 10 char *cp;
11 struct s1 ss1;
12 } s2 = {“ghi”, { “jkl”, “mno” }};
13 printf(“s1.c[0]=%c\t”, s1.c[0]);
14 printf(“*s1.s=%c\n”, *s1.s);
15 printf(“s1.c=%s\t”, s1.c);
16 printf(“s1.s=%s\n”, s1.s);
17 printf(“s2.cp=%s\t”, s2.cp);
18 printf(“s2.ss1.s=%s\n”, s2.ss1.s);
19 printf(“++s2.cp=%s\t”, ++s2.cp);
20 printf(“++s2.ss1.s=%s\n”, ++s2.ss1.s);
21 }
s1.c[0]=a *s1.s=d s1.c=abc s1.s=def s2.cp=ghi s2.ss1.s=mno ++s2.cp=hi ++s2.ss1.s=no
- struct 의 멤버로 struct 를 사용할 수 있다 .
예제 8.6
struct 의 포인터를 인 수로 사용
5 char name[20];
6 int id;
7 } student = { “Kim”, 73 };
8 int main(void) 9 {
10 int id, match();
11 char *name1 = “Lee”, *name2 = “Kim”;
12
13 if (id = match(&student, name1))
14 printf(“%s’s ID is %d.\n”, name1, id);
15 else
16 printf(“He is not %s.\n”, name1);
17
18 if (id = match(&student, name2))
19 printf(“%s’s ID is %d.\n”, name2, id);
20 else
21 printf(“He is not %s.\n”, name2);
22 }
23 int match(struct student *r, char *n) 24 {
25 if (strcmp(r->name, n) == 0) 26 return r->id;
27 return 0; /* 실패 */
28 }
예제 8.6( 계속 ) [ 해 설 ]
output
He is not Lee.
Kim’s ID is 73.
정의된 자료형을 갖는 변수도 student 로 정의하고 , 그 멤버값을 “ Kim” 과 73 으로 초기화 한다 .
- 줄 13 과 줄 18 에서는 각각 변수 student 에 저장된 name 이 “Lee” 인지 또는 “ Kim” 인지 확인하고 있다 .
확인이되면 해당 학생의 id 가 반환된다 .
- 함수 match 는 첫 인수가 가리키는 구조체의 멤버 name 이 가리키는 이름이 둘째 인수와 같은지 strcmp 함수를 호출하여 알아보고 ,
맞으면 해당 학생의 id 를 반환한다 . 아니면 0 을 반환한다 . - strcmp 함수는 비교하는 두 문자열이 같으면 0 을 반환함에 주의 .
- 줄 26 의 r->id 는 포인터 r 이 가리키는 구조체의 멤버 id 를 의미함 .
예제 8.7
[ 해 설 ]
static int add(int x, int y) {
return (x+y);
}
/* (2) */
typedef struct { char name[20];
int id;
} STUDENT;
/* --- */
STUDENT frontstu (STUDENT a, STUDENT b) {
return ((a.id < b.id) ? a : b);
}
- (1) 함수 add() 는 int 형 자료를 반환하는 함수이다 .
static 지정으로 이 함수는 같은 원시 file 내에서만 호출할 수 있다 . static 을 생략한 일반함수는 외부함수로 다른 file 에서도 호출 가능 . - (2) id 등의 멤버를 갖는 구조체를 STUDENT 라고 정의함 .
함수 frontstu 는 인수로 넘어온 STUDENT 형 두 인수의 id 를 비교 하여
그 값이 작은 인수를 반환한다 .
예제 8.7( 계속 )
[ 해 설 ]
/* 예제 8.7( 계속 ) */
/* (3) */
char *shortername_stu(s1, s2) char s1[], s2[];
{
int i;
i = 0;
while (s1[i] != ‘\0’ && s2[i] != ‘\0’) i++;
if (s1[i] == ‘\0’) return s1;
return s2;
}
- (3) 문자배열에 대한 포인터를 반환하는 함수 .
두 인수가 가리키는 문자열 중 길이가 짧은 문자열의 포인터를 반환 .
예제 8-8
5 int id;
6 char name[10];
7 };
8
9 void st_copy(struct st *s1, struct st *s2) 10 {
11 int j;
12 s1 -> id = s2 -> id;
13 for (j = 0; j < 10; j++)
14 s1 -> name[j] = s2 -> name[j];
15 }
16 void st_print(struct st *s) 17 {
18 printf(“ 번호 = %d, 이름 = %s\n”, s -> id, s -> name);
19 } 20
예제 8-8( 계속 )
output
25 printf(“ 학생 1 : ”); st_print(&std1);
26 printf(“ 학생 2 : ”); st_print(&std2);
27 st_copy(&std1, &std2);
28 printf(“\n 학생 2 의 정보를 학생 1 로 복사한다 .\n\n”);
29 printf(“ 학생 1 : ”); st_print(&std1);
30 printf(“ 학생 2 : ”); st_print(&std2);
31 }
학생 1 : 번호 = 30, 이름 = Kim 학생 2 : 번호 = 70, 이름 = Lee 학생 2 의 정보를 학생 1 로 복사한다 .
학생 1 : 번호 = 70, 이름 = Lee 학생 2 : 번호 = 70, 이름 = Lee
- st_copy(&std1, &std2); 는 std2 가 가리키는 구조체를 std1 이 가 리키는 구조체에 복사한다 .
- main 에서는 구조체 복사 (copy) 전과 후의 모습을 확인한다 .
예제 8-9(1)
[ 해 설 ]
output
5 int i, j, k;
6 float m[2][3];
7 } x = { 1, 2, 3, {4.0, 5.0, 6.0} };
8
9 int main(void) 10 {
11 printf(“%d\t%.3f\t%.3f\n”, x.j, x.m[0][1], x.m[1][1]);
12 }
2 5.000 0.000
- x 의 int 형 멤버 x, y, z 는 1, 2, 3 으로 초기화된다 .
- x 의 float 형 배열 m 의 첫 행의 3 원소들 m[0][0], m[0][1], m[0][2] 는 4.0, 5.0, 6.0 으로 초기화된다 .
- 값이 제공되지 않은 2 째 행의 3 원소들 m[1][0], m[1][1], m[1]
[2] 는 0 으로 초기화 된다 .
예제 8-9(2)
[ 해 설 ]
output
5 char x[2][3];
6 int i, j, k;
7 } y;
8
9 int main(void) 10 {
11 y.i = 0;
12 y.x[1][0] = ‘4’;
13 printf(“%d\t%d\t%d\n”, y.I, y.j, y.k);
14 }
52 52 52
- 공용형의 4 멤버 중 x 는 6 바이트 , 나머지 i, j, k 는 4 바이트 필요 하므로 이 공용형은 총 6 바이트 차지함
- 문자 ‘ 4’ 는 코드값이 52 이다 .
- 정수는 x[0][0], x[0][1], x[0][2],x[1][0] 과 겹친다 .
- 정수 4 바이트 중 가장 작은 수를 저장하는 바이트가 x[1][0] 인 기계의 경 우는 아래와 같이 i 값 , j 값 , k 값이 52 이다 .
- 정수 4 바이트 중 가장 작은 수를 저장하는 바이트가 x[0][0] 인 기계의 경
우는 매우 큰 값 (52 * 2
24= 872415232) 이 출력된다 .
예제 8.10
[ 해 설 ]
/* 예제 8.10 다음 선언들의 의미는 ? */
/* (1) */
union sign { int svar;
unsigned uvar;
double dvar;
} number;
/* (2) */
union { struct { char icon;
unsigned color:4;
} window1, window2, window3, window4;
} screen[25][80];
- (1) int 형 , unsigned 형 및 double 형 멤버 3 개 중 가장 큰 메모리 를 필요로 하는 double 형 ( 통상 8 바이트 ) 크기를 갖는 공용형 sign 을 선언하고 그 변수 number 를 정의함
- (2) 공용형 원소 2000 개를 갖는 2 차원 배열 screen 의 선언이다 . 각 원
소는 4 개의 멤버 window1, … window4 중 한 개를 가진다 .
예제 8-11
5 int n;
6 float x;
7 } number;
8
9 int main(void) 10 {
11 number temp;
12 temp.n = 3;
13 printf(“%d %f\n”, temp.n, temp.x);
14 temp.x = 3.0;
15 printf(“%d %f\n”, temp.n, temp.x);
16 }
3 0.000000
1077936128 3.000000
- 공용형의 두 멤버가 동일한 주소를 갖는다는데 주의하라 .
- 값을 배정한 멤버와 접근하는 멤버가 달라도 에러로 처리되지않음 .
- 올바른 사용은 전적으로 프로그래머의 책임이다 .
예제 8.12
[ 해 설 ]
/* 예제 8.12 다음 선언들의 의미는 ? */
/* (1) */
struct both { int a;
char b;
} (*var[ ]) (struct both, struct both);
/* (2) */
union sign { int x;
unsigned y;
} **var[5][5];
/* (3) */
union sign *(*var[5])[5];
- (1) struct both 형의 2 인수를 받아 struct both 형을 반환하는 함수 의 포인터들의 배열
- (2) union sign 포인터에 대한 포인터들의 배열의 배열
- (3) union sign 포인터들의 배열에 대한 포인터들의 배열
예제 8.13
[ 해 설 ]
/* 예제 8.13 다음 구조형 선언의 기억 형태는 ? */
struct {
unsigned icon:8;
unsigned color:4;
unsigned underline:1;
unsigned blink:1;
} screen[25][80];
- screen 의 2000 개 원소 중 첫 번째 원소의 저장 모습이다 . 14 비트 크기 임 .
screen[0][0]
underline 원소
color 원소
icon 원소 blink 원소
예제 8-14
output
5 {
6 struct {
7 unsigned carry: 2; /* overflow */
8 unsigned parity: 2; /* 1 = 짝수 ; 0 = 홀수 */
9 unsigned acarry: 2; /* 보조 carry */
10 unsigned zero: 1; /* 결과가 0 */
11 unsigned sign: 1; /* 결과가 음수 */
12 } f8080;
13 f8080.carry = f8080.acarry = f8080.sign = 0;
14 f8080.parity = f8080.zero = 1;
15 if (f8080.carry == 0) printf(“carry 없음 \n”);
16 if (f8080.parity == 0) printf(“ 짝수 parity\n”);
17 if (f8080.acarry == 0) printf(“ 보조 carry 없음 \n”);
18 if (f8080.zero == 0) printf(“ 결과가 0 이 아님 \n”);
19 if (f8080.sign == 0) printf(“ 결과가 양수임 \n”);
20 }
carry 없음 보조 carry 없음 결과가 양수임