일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 영단어
- 일본
- 리눅스
- fish
- 라면
- Shimajirou
- TOY
- 코라쿠엔
- 점심
- 스테이크
- 돼지갈비
- 전철
- paypay
- 돈까스
- 여름
- 사이타마
- しまじろう
- youtuber
- 칸칸
- 명령어
- 동경 모터쇼
- 시스템관리
- Sekai Entertainment
- one tab buy
- 원탭바이
- 米沢、팽이
- 토익
- 신쥬쿠
- 자동차
- 시마지로
- Today
- Total
IT Japan
제 7장 - 구조체와 공용체 본문
지난 장까지 배운 자료의 구조는 모두 한 개의 데이터로 구성되는 것이었
다. 이번 장에서는 복수개의 데이터형이 모여 하나의 자료를 구성하는 구
조체와 하나의 데이터를 여러 변수가 함께 사용하는 공용체에 대하여 설명
하겠다.
1. 구 조 체
구조체는 한 개의 자료가 여러 개의 데이터형으로 구성되는 복합 데이터
형이다. 예를 들어, 어느 회사에서 인사 화일을 만든다고 가정할 때 인사
화일들은 아래와 같은 구조를 가질 수 있다.
name addr birth tel
+-----+-----+--------+--------+
|이 름|주 소|생년월일|전화번호| ===> 인사 화일의 각 자료
+-----+-----+--------+--------+
이와 같이 여러 개의 단순 항목(field)이 모여서 하나의 집단 항목(recor
d)을 이룬 것을 구조체라고 한다. 그리고 레코드 자체에 하나의 이름(변수
명)을 부여할 수 있는데, 이러한 구조체의 이름을 구조체 택(tag)이라고
한다. 구조체의 선언은 다음과 같은 형식으로 한다.
<형 식> struct 구조체 이름 {
멤버 1의 선언문;
멤버 2의 선언문;
...........;
멤버 n의 선언문;
};
위의 자료를 이용하여 다음과 같이 구조체를 정의할 수 있다.
struct insa {
char name[8];
char addr[25];
long birth;
char tel[8];
};
이와 같은 선언은 일반적으로 main()함수 앞에서 하는데 이는 구조체의
구조 및 형식을 함수에서 인용할 수 있게 하기 위한 것이다. 구조체를 선
언하면 구조체의 형식만 정의되고 실제 자료는 할당되지 않으므로 구조체
형식의 선언 후에 구조체 변수를 따로 잡아 할당해야 한다.
main()
{
struct insa x,y,z; /* 변수 x,y,z를 insa의 구조를 갖는 */
/* 구조체로 선언 */
x.name="Park";
x.addr="Seoul";
x.birth=560604;
x.tel="123-1234";
y.name="Kin";
.....
z.name="Son";
.....
}
구조체의 항목(멤버)을 참조하거나 구조체 요소에 값을 할당할 때는 구조
체 항목 연산자(.)를 이용한다. 구조체는 개개의 항목(field)이 모여 집단
항목을 이루는 복합 데이터형이나 화일을 관리하는 프로그램 등에서 아주
요긴하게 쓰인다. 위의 구조체 변수에서 다음의 경우를 생각해 보자.
&x : 구조체 변수 x의 시작 주소
x.name[2] : x의 멤버 name의 3번째 문자를 가리킨다.
구조체 변수는 static으로 선언된 경우나 외부 변수로 선언된 경우에 한
하여 변수 전체의 초기화가 가능하다. static으로 선언된 경우에는 다음과
같이 기술한다. 이때 멤버와 멤버 사이, 변수와 변수 사이에는 ,로 구분하
며, 맨 마지막에 ; 를 찍는다.
main()
{
static struct insa x={"Park","Seoul",560604,"123-1234"},
y={"Kim","Pusan", ... },
z={"Son", ..... };
반면 구조체를 외부 변수로 선언할 경우에는 구조체의 선언과 동시에 구
조체 변수를 설정하는 것은 물론, 각각의 멤버에 초기치를 부여할 수도 있
다.
struct insa { ( , 와 ; 가 쓰인 곳을 확인하기 바란다)
char name[8];
char addr[25]; | struct insa {
lond birth; | char *name;
char tel[8]; | char *addr;
} x={"Park", ....... }, | long birth;
y={ ........... }, | char *tel;
z={ ........... }; | };
구조체의 멤버는 포인터형으로 선언할 수 있는데 우리가 다루고 있는 구
조체를 포인터형으로 바꾸면 위의 우측과 같다.
2. 구조체 배열
구조체의 경우에도 다음과 같이 배열을 사용할 수 있다.
struct insa kcom[10];
이 경우에는 요소가 10인 구조체 배열 kcom이 준비되며, kcom에는 구조체
배열의 시작 주소가, 메모리 내부에는 각 멤버가 저장될 공간이 확보된다.
이 구조체는 아래 그림과 같이 기억장소가 할당된다.
name addr birth tel
+----------+-----------+---------+----------+
|9문자 배열|25문자 배열|long 정수|8문자 배열|
+----------+-----------+---------+----------+
kcom[0]| | | | |
+----------+-----------+---------+----------+
......
+----------+-----------+---------+----------+
kcom[9]| | | | |
+----------+-----------+---------+----------+
그리고 구조체 배열에서 각 멤버를 참조할 때는 다음과 같이 기술한다.
buf=kcom[3].addr
즉, 배열 첨자를 먼저 기술한 후, 구조체 항목 연산자(.)를 찍고 항목명
을 기술한다. 구조체 배열의 선언 방법과 사용에 따른 제반 절차는 일반배
열의 경우와 동일하다. 그러면, 예제를 보자.
<예제1> 다음 자료를 구조체 배열에 기억시킨 후 화면에 출력하는 프로그
램 작성.
==================================================
번호 성 명 주 소 생일 전화번호
==================================================
1 김 유신 서울 성동구 560604 123-5432
2 강 감찬 부산 동래구 600430 43-4455
3 이 순신 수원 화서동 661122 2-1234
4 고 바우 성남 상대원동 610530 212-1155
==================================================
<리스트1>
#include
struct insa { /* 구조체의 형식 선언 */
char *name; /* 화일의 전구간서 사용가능 */
char *addr;
long birth;
char *tel;
};
main()
{
struct insa in[]={ /* 구조체 배열의 초기화 */
{"김 유신","서울 성동구",560604,"123-5432"},
{"강 감찬","부산 동래구",600430,"43-4455"},
{"이 순신","수원 화서동",661122,"2-1234"},
{"고 바우","성남 상대원동",610530,"212-1155"}
};
int i;
printf("==================================================\n");
printf("번호 성 명 주 소 생일 전화번호\n");
printf("==================================================\n");
for (i=0;i <= 3;i++)
printf("%2d %-10s%-17s%6ld%10s\n",i+1,in[i].name,
in[i].addr,in[i].birth,in[i].tel);
printf("==================================================\n");
}
3. 중첩된 구조체(nested structure)
종종 한 구조체가 또 다른 구조체를 포함시키는 경우가 있다. 아래의 그
림을 보자.
fellow (구조체명 guy)
+------------------------+-----------+-----+-------+
| handle(구조체명 names) | | | |
+------------+-----------+ favfood | job | income|
| first[LEN] | last[LEN] |즐기는 음식|직 업| 수 입|
+------------+-----------+-----------+-----+-------+
| | | | | |
위의 그림은 구조체 guy중에 구조체 name이 들어있는 경우이다.
<예제2> 중첩된 구조체의 예 (철모르는 어린이의 편지)
<리스트2>
#define LEN 20
struct names {
char first[LEN]; /* 성명 구조체의 이름 항목 */
char last[LEN]; /* 성명 구조체의 성 항목 */
};
struct guy {
struct names handle; /* 구조체 guy의 내부에 다시 구조체 */
/* names를 가지는 구조체 변수 handle선언 */
char favfood[LEN];
char job[LEN];
float income;
};
main()
{
static struct guy fellow={ /*구조체guy의 구조를 가지는 변수 */
/* fellow의 초기화 */
{"태지","서"}, /* 구조체names의 초기화이므로 { }로 싼다 */
"돼지 족발",
"락 가수",
1000000
};
printf("안녕하세요? %s아저씨,\n",fellow.handle.first);
printf("새로나온 노래 정말 괜찮테요?\n\n");
printf("저는 %s%s아저씨가 %s을 좋아한다는 소릴 듣고\n",
fellow.handle.last, fellow.handle.first, fellow.favfood);
printf("너무너무 야만인이라고 생각했거든요? \n");
printf("하지만 아저씨가 이번에 수해돕기 성금으로\n");
printf("%.0f원이나 내셨다는 소리를 듣고",fellow.income);
printf("정말 기분 좋았어요.!\n");
printf("앞으로 열심히 하셔서 멋진 %s가 되세요!!\n\n\n",
fellow.job);
getch();
}
4. 구조체 포인터 변수
구조체에 대해서도 포인터를 사용할 수가 있다. 구조체 포인터 변수가 타
당한 이유를 들면,
1) 구조체에 대한 포인터가 구조체 자체 보다는 처리하기가 용이하다.
2) 구조체는 함수의 인자로서 전달될 수 없지만 구조체에 대한 포인터
는 가능하다.
3) 대다수의 고도의 데이터 표현은 또 다른 구조체에 대한 포인터를 구
성원으로 하는 구조체에 의해 가능하다.
struct insa *p;처럼 p를 구조체 insa를 가리키는 포인터로 선언할 수 있
다. 그러므로 ++p라는 표현을 사용하면 구조체 포인터를 1만큼 증가시켜 i
nsa의 크기 만큼이 실제로 증가된다. 또한 p+n번째 구조체를 참조하는 경
우에는 p+n으로 표현한다.
구조체 포인터 변수에서 구조체의 멤버를 참조할 경우에는 구조체 연산자
'->'를 사용하여 다음과 같이 기술한다.
p -> addr : p가 가리키는 구조체의 항목 addr을 나타낸다.
(p+n) -> name : p+n번째 구조체의 name 항목을 나타낸다.
구조체 연산자 . 와 -> 는 우선순위가 가장 높다. 그러므로 아래 두 식의
결과는 서로 다르게 작용한다.
++p -> addr (++p) -> addr
전자의 경우에는 ++(p->addr)로 해석되어 p의 멤버 addr의 값을 하나 증
가시킨다. 그리고 후자는 다음번 구조체의 addr항목을 가리키게 된다.
함수의 인수를 이용하여 구조체를 함수로 전달할 경우에는 구조체 포인터
를 사용한다. 이 때 주는 측은 구조체의 주소를, 받는 측은 구조체의 포인
터를 이용하여 주고 받게 된다. 이렇게 함수에서 구조체의 입력을 받고,
다른 함수에서는 구조체 포인터에 의해 인수를 전달하는 과정을 예제로 직
접 확인해 보자.
<예제3> <예제1>에서 설계한 구조체에 사원의 자료를 함수에서 입력받아
화면에 출력하는 프로그램 작성.
<리스트3>
#include
#include
struct insa { /* 구조체의 형식 선언 */
char name[12]; /* 화일의 전구간서 사용가능 */
char addr[15];
long birth;
char tel[9];
};
int input(); /* 사용자 함수의 선언 */
void display();
main()
{
struct insa arr[10]; /* 옆의 두 라인을, */
struct insa *p; /* struct insa *p=arr;로도 가능 */
int i;
p=arr;
for (i=0;i <= 10;i++,p++)
if (input(p) == 0) break; /* input()함수에서 0을 돌려주면 */
display(arr,i); /* 루프 탈출 */
} /* 구조체 '배열명'arr은 그 구조체의 첫 주소를 나타내므로 */
/* display(p,i)대신 display(arr,i)도 가능한 표현임 */
/* 사실 p는 p++로 증가되어 버렸으므로 구조체의 첫주소를 가리 */
/* 키지 않는다. */
int input(ptr) /* 이 두라인을, */
struct insa *ptr; /* int input(struct insa *ptr)로도 가능 */
{
char buff[20]; /* 임시 문자열 저장 영역 확보 */
printf("성명:");
gets(ptr->name);
if (ptr->name[0] == '\0') return(0); /* 이름을 입력않고, 그냥*/
printf("주소:"); /* 엔터치면 0을 되돌리고 함수를 종료한다. */
gets(ptr->addr);
printf("생년월일(yymmdd):");
gets(buff); /* 생일을 문자열로 입력받은 후, */
ptr->birth=atol(buff); /* 배정도 정수로 변환시킨다 */
printf("전화번호:");
gets(ptr->tel);
printf("\n");
return(1); /* 정상적으로 입력되면 1을 되돌린다. */
}
void display(s,k) /* 이 세행을 한줄로 표현하면, */
struct insa *s; /* */
int k; /* void display(struct insa *s,int k) */
{
int i;
printf("==================================================\n");
printf("번호 성 명 주 소 생일 전화번호\n");
printf("==================================================\n");
for (i=0;i <= k;i++) {
printf("%2d %-10s%-17s%6ld%10s\n",i+1, s->name,
s->addr, s->birth, s->tel);
s++;
}
printf("==================================================\n");
}
5. 공 용 체 (Union)
공용체는 하나의 데이터를 여러 개의 변수가 공용할 수 있게 해주는 데이
터 형이다. 공용체의 정의 방법과 선언 방법은 구조체와 동일하다. 단, 구
조체는 모든 자료가 별개의 기억장소를 배정받지만 공용체의 경우에는 가
장 긴 것의 자료 형에 맞추어 메모리를 할당받는다. 공용체의 멤버로는 주
로 구조체를 사용하며, 공용체의 정의 형식은 다음과 같다.
union 공용체 택 { 멤버1; 멤버2; ...; };
<예제4> 공용체의 사용 보기
<리스트4> | <리스트4>의 공용체는 아래와 같
union abc { | 은 형태로 기억장소를 배정한다
char a; |
int b; | | |
long c; | +------+ ----+ ---+
}; | | 78 | - a | |
main() | +------+ | b |
{ | | 56 | | |
union abc val; | +------+ ----+ | c
val.c=(long)0x12345678; | | 34 | |
printf("c=%08lx\n", val.c); | +------+ |
printf("b=%08x\n", val.b); | | 12 | |
printf("a=%08x\n",val.a); | +------+ ---+
} | | |
위의 그림과 같이 상위 바이트와 하위 바이트가 바뀌어 저장되는 것을 역
워드 형식이라고 하는데 80x계의 CPU에서는 역워드 형식으로 자료가 저장
된다. <리스트4>내의 프로그램에서는 각각의 바이트를 독립적으로 억세스
할 수 없지만 공용체의 멤버로 구조체를 사용하면 각각의 바이트를 개별적
으로 억세스할 수 있다.
<예제5> 공용체의 사용 보기 (II)
<리스트5>
struct str { | <리스트5>의 공용체는 아래와
char c1; | 같은 형태로 기억장소를 배정
char c2; | 한다.
char c3; |
char c4; | | |
}; | +------+ --+ -----+ --+
union abc { | | 78 | c1| - a | |
struct str chr; | +------+ | |b |
char a; | | 56 | c2| | |
int b; | +------+ | -----+ |c
long c; | | 34 | c3|구조체 |
}; | +------+ | chr |
main() | | 12 | c4| |
{ | +------+ --+ ---------+
union abc val; | | |
val.c=(long)0x12345678; |
printf("a=%8lx\n", val.a); |
printf("b=%8x\n", val.b); | <리스트5>에서 c3를 가리킬 경
printf("c=%8x\n", val.c); |우에는 val.chr.c3로 기술해야
printf("c1=%8x\n",val.chr.c1); |한다. 이것은 '공용체 val에 속
printf("c2=%8x\n",val.chr.c2); |해있는 구조체 chr의 멤버 c3'라
printf("c3=%8x\n",val.chr.c3); |는 의미이다. 구조체의 요소를
printf("c4=%8x\n",val.chr.c4); |공용체로 선언해 두면 자료를 전
} |체적으로 통합하여 다룰 수 있고
개별적으로도 다룰 수 있다.
구조체나 공용체를 함수의 인수로 사용할 때는 구조체나 공용체의 주소를
건내주어야 하며, 받는 측에서는 그것을 포인터로 받아온다. 예를 들어 te
st()라는 함수에 <리스트5>에서 정의한 공용체 val을 전달하려면 다음과
같이 하면 된다.
호출측 : test(&val);
...
피호출측 : void test(union val *abc)
{ ....
test()함수에서는 공용체 val을 abc라는 이름으로 사용한다. 구조체와 공
용체의 활용은 초보자에게는 다소 어려운 개념이므로 보다 깊은 내용은 생
략하겠다.
'IT > Programming' 카테고리의 다른 글
[Python]Python으로 OpenCV를 사용 (0) | 2017.06.07 |
---|---|
제 8장 - 화일 조작 / 기타의 것들 (0) | 2016.03.22 |
제 6장 - 배열과 포인터 (0) | 2016.03.22 |
제 5장 - 함수 / 기억부류 (0) | 2016.03.22 |
제 4장 - 연 산 자 (0) | 2016.03.22 |