1. 구조체 변수도 구조체의 멤버가 될 수 있다.
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 31 32 33 34 | #include <stdio.h> #define PI 3.14 typedef struct __point { double xPos; double yPos; } point; typedef struct __circle { point center; // 원의 중심 double rad; // 반지름 } circle; void ShowCircleInfo(const circle * ptr) { printf("원의 중심: [%g, %g] \n", (ptr->center).xPos, (ptr->center).yPos); printf("원의 넓이: %g \n", (ptr->rad)*(ptr->rad)*PI); } int main(void) { circle cl={ {1.1, 2.2}, // center 초기화 2.5 // 반지름 초기화 }; ShowCircleInfo(&cl); return 0; } | cs |
1 2 | 원의 중심: [1.1, 2.2] 원의 넓이: 19.625 | cs |
• 12행 : 구조체 point의 변수를 구조체 circle의 멤버로 정의하고 있다. 이처럼 구조체의 멤버로 다른 구조체의 변수가 정의될 수 있다.
• 16행 : circle 구조체의 주소 값을 인자로 전달받을 수 있도록 함수가 정의되었다.
• 26~29행 : 구조체 변수를 멤버로 두고 있는 구조체 변수의 초기화 방법을 보여준다. 제일 먼저 초기화할 대상이 구조체 변수이기 때문에 중괄호가 등장하였고, 이어서 초기화할 대상이 실수이기 때문에 실수 값이 등장하였다.
위 예제의 26행에서 생성되는 구조체 변수는 다음과 같은 형태로 할당 및 초기화된다.
그리고 이 구조체 변수의 주소값이 31행에서 ShowCirclelnfo 함수의 인자로 전달이 되므로, 16행
에 정의되어 있는 매개변수 ptr과의 관계는 다음과 같다.
따라서 원의 중심 좌표를 출력하기 위해서 19행과 같은 연산식이 만들어졌으며, 원의 넓이를 계산
하기 위해서 21행과 같은 연산식이 만들어졌다.
2. 구조체 변수의 포인터도 구조체의 멤버가 될 수 있다.
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 31 32 33 34 35 36 | #include <stdio.h> #include <stdlib.h> #define PI 3.14 typedef struct __point { double xPos; double yPos; } point; typedef struct __circle { point * cntPtr; double rad; } circle; void ShowCircleInfo(const circle * ptr) { printf("원의 중심: [%g, %g] \n", (ptr->cntPtr)->xPos, (ptr->cntPtr)->yPos); printf("원의 넓이: %g \n", (ptr->rad)*(ptr->rad)*PI); } int main(void) { circle cl={NULL, 2.5}; cl.cntPtr=(point*)malloc(sizeof(point)); cl.cntPtr->xPos=1.1; cl.cntPtr->yPos=2.2; ShowCircleInfo(&cl); free(cl.cntPtr); return 0; } | cs |
1 2 | 원의 중심: [1.1, 2.2] 원의 넓이: 19.625 | cs |
• 13행 : point 구조체 변수를 가리킬 수 있도록 포인터가 멤버로 정의되었다.
• 27행 : circle 구조체 변수를 초기화하고 있다. 첫 번째 멤버인 포인터 cntPtr은 NULL로 초기화하고,두번째 멤버인 rad는 2.5로 초기화 하였다.
• 28행 : 구조체 point의 크기만큼을 힙 영역에 할당하고, 반환되는 주소 값을 저장하고 있다. 이렇게 구조체 변수도 힙 영역에 얼마든지 동적으로 할당할 수 있으며, 할당의 방법은 기본 자료형 변수의 동적 할당방법과 동일하다.
• 33행 : 함수가 호출되었을 때, 구조체 변수 cl과 매개변수 ptr의 메모리 관계를 그림으로 정리해 보겠다.
구조체 변수 cl은 main 함수 내에서 선언되었지만, cl의 멤버 cntPtr이 가리키는 변수는 malloc 함
수에 의해서 할당되었으므로, 위 그림처럼 각각이 존재하는 메모리 영역이 구분된다.
3. 어떤 모델이 더좋을까?
하나의 구조체가 다른 하나의 구조체를 포함하는 방식에는 두 가지가 있음을 설명하였다.
그 중 하나는 1번의 멤버 변수의 형태로 정의하는 방식이고, 다른 하나는 2번의 포인터를 이용해서 참조만 하는 방식이다.
왼쪽은 1번에서 구현한 모델이다. 이 모델은 구조체 변수 center를 내부에 포함하는 모델이다.
오른쪽은 2번에서 구현한 모델이다. 이 모델은 외부에 선언된 구조체 변수 center를 참조하는 모
델이다. 구현방식과 모델의 형태는 다르지만, 물리적 관점이 아닌 논리적인 관점에서 포함의 형
태를 취한다는 데에는 차이가 없다. 두 모델 모두 합리적이고 유용하게 사용이 되는 모델이기 때
문에 둘 다 기억할 필요가 있다.
4. 구조체 변수의 주소 값은 첫 번째 멤버의 주소 값이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> typedef struct __point { double xPos; double yPos; } point; int main(void) { point pnt={1.1, 2.2}; printf("구조체 pnt의 주소: %#x \n", &pnt); printf("구조체 pnt의 첫 번째 멤버의 주소: %#x \n", &(pnt.xPos)); return 0; } | cs |
1 2 | 구조체 pnt의 주소: 0x62fe40 구조체 pnt의 첫 번째 멤버의 주소: 0x62fe40 | cs |
5. 자기 참조 구조체
자기자신과 동일한 자료형의 구조체 변수를 참조할 수 있도록 정의된 구조체
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 31 32 33 | #include <stdio.h> typedef struct box { int data; struct box * boxRef; } box; int main(void) { int i; box * bxPtr; box b1={1, NULL}; box b2={11, NULL}; b1.boxRef=&b2; b2.boxRef=&b1; bxPtr=&b1; for(i=1; i<=10; i++) { printf("%3d", bxPtr->data); (bxPtr->data)++; bxPtr=bxPtr->boxRef; if(!(i%2)) printf("\t"); } return 0; } | cs |
1 | 1 11 2 12 3 13 4 14 5 15 | cs |
• 3행에 정의되어 있는 구조체를 먼저 관찰해 보자.
box형 구조체 변수는 둘 이상 선언될 수 있다. 그래서 하나의 box형 구조체 변수가 다른 box형 구
조체 변수의 주소 값을 저장할 수 있는 형태로 정의 되었다.
• 18행이 실행되면 구조체 변수의 관계는 다음과 같이 형성된다.
• 19행이 실행되면 구조체 변수의 관계는 다음과 같이 변경된다.
간단히 말해서 구조 체 변수 b1과 b2가 서로를 참조하는 형태로 변경이 된다.
결론적으로 구조체 box의 멤버로는 구조체 box의 포인터 변수가 올 수 있다.
6. 구조체 변수는 정렬되어 할당된다.
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 | #include <stdio.h> typedef struct box1 { int AAA; short BBB; short CCC; } box1; typedef struct box2 { short BBB; int AAA; short CCC; } box2; int main(void) { box1 bx1; box2 bx2; printf("구조체 box1의 변수 크기: %d \n", sizeof(bx1)); printf("구조체 box2의 변수 크기: %d \n", sizeof(bx2)); return 0; } | cs |
1 2 | 구조체 box1의 변수 크기: 8 구조체 box2의 변수 크기: 12 | cs |
위의 출력결과에서는 구조체 boxl의 크기를 8바이트,box2의 크기를 12바이트라고 말하고 있다.
구조체 box1과 box2의 유일한 차이점은 구조체 멤버를 배치한 순서 인데,이러한 차이를 보이는 이
유는 메모리 공간에 구조체 변수를 할당할 때, 멤버의 접근 용이성을 위해서 특정 바이트 크기 단
위로 정렬을 하기 때문이다. 예를 들어서 구조체 변수를 4바이트 단위로 정렬해서 할당하는 컴파일
러가 있다고 가정해보자. 그렇다면 이 컴파일러는 메모리 공간을 다음과 같은 방식으로 나눈다.
이로써 구조체를 정의할 때, 구조체 멤버의 배치 순서를 어떻게 가져가는 것이 좋을지에 대한 기준
도 나름대로 세워졌을것이다.
'BackEnd > C' 카테고리의 다른 글
C 모아보기 (0) | 2021.01.09 |
---|---|
I/O 인풋, 아웃풋에 대한 이해 (0) | 2019.10.07 |
구조체 배열 (0) | 2019.03.23 |
구조체의 정의에 포함되는 typedef 선언 (0) | 2019.03.23 |
구조체 변수로 가능한것과 불가능한 것 (0) | 2019.03.22 |