01 구조체
구조체는 멤버(member)라고 하는 값들의 모임이여, 구조체의 멤버들은 대부분 서로 다른 타입으로 구성될 수 있는 통합 자료형이다.
*구조체 변수 선언 방법
struct 구조체 자료형명(tag_name) { 자료형 멤버1; 자료형 멤버2; .. 자료형 멤버 N; } 구조체 변수명; |
struct 키워드는 컴파일러에게 구조체 자료형에 대한 선언임을 알리는 역할을 한다. 구조체 자료형명은 tag_name이라고도 하며 새로운 구조체 형에 대한 이름으로 사용자가 지정하는 이름이다. { 와 } 사이는 그 구조체를 구성하는 구성 요소, 즉 멤버들에 대한 선언 부분으로 멤버들의 선언은 일반 변수나 배열을 선언하듯이 자료형과 멤버명으로 선언한다. 구조체 자료형 선언이 끝나면 자료형을 이용할 구조체 변수명을 기술한다.
02 간단한 구조체의 개념
*학생들의 성적을 처리하기 위하여 구조체 자료형을 선언한 예
struct score { char name[20]; int kor; int math; int eng; float avg; } st1 = {“까꿍이”, 93, 86, 89, 0.0}; |
구조체 변수의 각 멤버는 변수명/멤버명 형식으로 표현하면 된다. 이때 “ .”을 구조체 멤버 연산자라 하고, 구조체 안의 멤버는 직접 사용될 수 없으며, “ .” 연산자를 사용하여 구조체 변수와 멤버를 연결하여 사용해야 한다. 멤버들에 대한 처리는 멤버들의 자료형에 맞추어 처리한다.
구조체 변수의 자료형의 크기를 알아야 하는 경우에는 sizeof() 함수를 사용한다.
sizeof(struct score); //구조체 자료형 이름으로 크기를 구할 때 sizeof(st1); //구조체 변수명으로 크기를 구할 때 |
예
#include <stdio.h> int main(void) { struct score{ char name[20]; // 학생 이름 int kor; // 국어 시험 점수 int math; // 수학 시험 점수 int eng; // 영어 시험 점수 float avg; // 평균 점수 } st1 = {“까꿍이”, 93, 86, 89, 0.0};
printf(“%d, %d \n”, sizeof(st1), sizeof(struct score)); printf(“&st1 : %p, %p\n”, &st1, st1.name);
st1.avg = {st1.kor + st1.math+st1.eng} / (float)3;
// st1 구조체에 학생정보를 입력 printf(“성명 ?”); gets(st1.name); printf(“국어 ? ”); scanf(“%d”, &st1.kor); printf(“수학 ? ”); scanf(“%d”, &st1.math); printf(“영어 ? ”); scanf(“%d”, &st1.eng);
st1.avg = (st1.kor+st1.math+st1.eng} / (float)3; printf(“%s, %d, %d, %d, %.2f \n“, st1.name, st1.kor, st1.math, st1.eng, st1.avg); return 0; } |
36, 36 &st1 : 7f7f0888, 7f7f0888 까꿍이, 93, 86, 89, 89, 33 성명 ? 진달래 국어 ? 60 수학 ? 80 영어 ? 75 진달래, 60, 80, 75, 71, 67 |
03 구조체의 선언과 정의
구조체 선언한다는 것은 메모리 할당이 이루어지지 않는 것을 말하며, 정의는 메모리 할당이 이루어지는 것을 말한다. 즉 구조체는 선언과 할당을 따로 할 수 있으며, 선언과 할당을 동시에 할 수도 있다.
*구조체 선언
struct EMPLOYEE { char name[20]; char phone[15] int age } |
구조체를 선언하며 score라는 구조체 자료형을 선언함. 이 때 메모리는 할당받지 못했으므로 score 구조체를 사용하기 위해서
는 EMPLOYEE tag_name을 이용하여 구조체 변수를 정의하게 된다.
struct EMPLOYEE st1, st2; // s1과 st2 2개의 구조체 변수 메모리에 할당 |
*구조체의 선언과 정의
struct EMPLOYEE { char name[20]; char phone[15] int age }st1, st2 // 메모리 할당 |
구조체 선언과 동시에 st1, st2라는 구조체 변수로 메모리에 할당 받는다.
키워드 typedef는 이미 존재하는 자료형에 새로운 이름을 붙여 간단한 자료형 이름으로 사용하고자 할 때 이용된다. 구조체에서typedef를 많이 사용하고 있다.
struct EMPLOYEE { char name[20]; char phone[15]; intt age; }; typedef struct EMPLOYEE EMP; //새로운 자료형 명 EMP st1 ; // 구조체 변수 메모리에 할당 |
이제 태그네임인 struct EMPLOYEE 대신에 EMP로 구조체 변수를 선언할 수 있다. 다음은 구조체 정의와 typedef 선언을 동시에 하는 문법이다.
typedef struct EMPLOYEE { char name[20]; char phone[15]; int age; } EMP; EMP st1 ; // 구조체 변수 메모리에 할당 |
04 구조체 저장 공간의 할당
구조체는 실제 메모리상에서 어떻게 저장될까? 구조체 멤버들은 주어진 순서대로 메모리에 할당된다. 그러나 구조체가 경우에 따라서는 많은 빈 공간을 포함할 수 있다는 것을 알아야 하며, 멤버들 사이에 경계 정렬(boundary alignment)이 필요할 때 이러한 현상이 생기게 된다. 이를 얼라인먼트라 하며 cpu 사양에 따라 배치할 수 있는 주소에 한계가 있거나 효율적인 주소 사용을 위해 메모리의 경계를 적절히 조절함(속도향상을 위한 일)을 의미한다.
*구조체 멤버 선언의 위치는 가독성보다는 효율적인 메모리 사용(멤버 간 경계에서 메모리의 소모가 최소화되도록)에 우선순위를 둔다.
#include <stdio.h>
int main(void) { struct S { char a; int b; char c; }st;
printf(“st1 : %d \n”, sizeof(st1)); return 0; } |
st1 : 12 |
a b c
|
|
|
|
|
|
|
|
|
|
|
|
그림 구조체 변수의 메모리 할당
정수 크기가 4바이트이고, 한 바이트가 4로 나누어지는 주소로 시작해야 하는 컴퓨터에서는 구조체의 첫 번째 멤버 a는 4의 배수에 해당하는 주소에서 시작한다. 다음 멤버 b는 정수이므로 3개의 바이트를 건너뛰어 적정한 경계로 이동한다. 정수 다음에 마지막으로 c멤버가 저장되어야 하므로 12바이트를 할당하게 된다. 이 구조체는 12바이트의 메모리가 필요하지만 6바이트만을 사용하게 된다. 따라서 이 선언 구조는 좋은 방법이 아니다. 구조체의 경계 정렬에서 낭비되는 공간은 구조체 선언에서 멤버를 재배치하는 것으로 최소화할 수 있다.
#include <stdio.h> int main(void) { struct S { int b; char a; char c; }st;
printf(“st1 : %d \n”, sizeof(st1)); return 0; } |
st1 : 8 |
위와 같이 구조체의 첫 번째 멤버 b는 4의 배수에 해당하는 주소에서 시작하였고, 2개의 문자는 서로 이웃하여 저장할 수 있기 때문에 낭비되는 공간은 그 구조체 다음에 두 바이트만 건너뛴다. 결과적으로 메모리를 4바이트 절약할 수 있다.
멤버들의 가독성을 위하여 연관성을 가진 구조체 멤버들을 함께 열거하여 메모리 낭비를 방치할지 아니면 메모리를 최소화하기 위해 세밀한 경계가 필요한 멤버들을 선언할 지는 개발자의 선택이나, 한 프로그램에서 수십개의 구조체를 포함하여 사용하는 경우, 경계 정렬로 인한 메모리 낭비가 가독성 문제보다 더 중요하게 된다. 이런 상황에서는 선언 부분의 주석을 추가하는 것이 읽어버린 가독성을 찾는데 도움이 될 수 있다.
05 구조체 배열
구조체 배열은 구조체 변수들을 여러 개의 연속된 공간에 모아 놓은 형태이므로 변수명 대신 배열명과 첨자를 이용한다는 점 이외에는 다를 것이 없다.
struct score st[30]; // st1[30] 구조체에 학생 정보를 입력한다면 다음과 같이 배열 첨자를 추가하면 된다.
for(i=0; i<30; i++) { printf(“%d, 성명 ? ”, i+1); gets(st1[i].name); printf(“ 국어 ?”); scanf(“%d”, “&st1[i].kor); } |
'프로그래밍 > C & C++' 카테고리의 다른 글
[C] 날짜/시간 처리 함수 (0) | 2016.07.07 |
---|---|
[C] 문자 처리 함수 (0) | 2016.07.06 |
[C] 포인터 (0) | 2016.03.31 |
[C] 문자열 처리함수 (0) | 2016.03.22 |
[C] 헤더파일 (0) | 2016.01.12 |