53.2 구조체 포인터 배열 선언하기
구조체 요소가 한꺼번에 뭉쳐져 있는 배열이 아닌 요소마다 메모리를 할당하고 싶을 수도 있습니다. 이때는 구조체 포인터 배열을 만들고 malloc 함수로 각 요소에 메모리를 할당하면 됩니다.
구조체 포인터 배열은 포인터 변수 이름 뒤에 [ ] (대괄호)를 붙인 뒤 크기를 설정합니다.
- struct 구조체이름 *포인터이름[크기];
다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.
struct_pointer_array.c
#include <stdio.h> #include <stdlib.h> // malloc, free 함수가 선언된 헤더 파일 struct Point2D { int x; int y; }; int main() { struct Point2D *p[3]; // 크기가 3인 구조체 포인터 배열 선언 // 구조체 포인터 배열 전체 크기에서 요소(구조체 포인터)의 크기로 나눠서 요소 개수를 구함 for (int i = 0; i < sizeof(p) / sizeof(struct Point2D *); i++) // 요소 개수만큼 반복 { p[i] = malloc(sizeof(struct Point2D)); // 각 요소에 구조체 크기만큼 메모리 할당 } p[0]->x = 10; // 인덱스로 요소에 접근한 뒤 화살표 연산자로 멤버에 접근 p[0]->y = 20; p[1]->x = 30; p[1]->y = 40; p[2]->x = 50; p[2]->y = 60; printf("%d %d\n", p[0]->x, p[0]->y); // 10 20 printf("%d %d\n", p[1]->x, p[1]->y); // 30 40 printf("%d %d\n", p[2]->x, p[2]->y); // 50 60 for (int i = 0; i < sizeof(p) / sizeof(struct Point2D *); i++) // 요소 개수만큼 반복 { free(p[i]); // 각 요소의 동적 메모리 해제 } return 0; }
실행 결과
10 20 30 40 50 60
struct Point2D *p[3];과 같이 구조체 포인터를 선언하면서 [ ](대괄호)안에 크기를 넣어주면 배열로 선언할 수 있습니다. 하지만 구조체 포인터 배열만 선언하고 메모리를 할당하지 않았으므로 사용을 할 수가 없겠죠?
그러므로 다음과 같이 배열 크기(요소 개수)만큼 반복하면서 각 요소에 구조체 크기만큼 메모리를 할당해줍니다. 이때 구조체 포인터 배열에는 포인터가 들어 있으므로 요소 개수를 구하려면 구조체 포인터 배열의 전체 크기에서 구조체 포인터의 크기로 나눠주면 됩니다.
// 구조체 포인터 배열 전체 크기에서 요소(구조체 포인터)의 크기로 나눠서 요소 개수를 구함 for (int i = 0; i < sizeof(p) / sizeof(struct Point2D *); i++) // 요소 개수만큼 반복 { p[i] = malloc(sizeof(struct Point2D)); / }
sizeof(struct Point2D)는 구조체가 차지하는 크기, sizeof(struct Point2D *)는 구조체 포인터의 크기입니다. 꼭 기억하세요.
구조체 포인터 배열에서 각 요소에 접근하려면 배열 뒤에 [ ] (대괄호)를 사용하며 대괄호 안에 인덱스를 지정해주면 됩니다. 단, 배열 안에 들어있는 요소가 포인터이므로 -> (화살표 연산자)를 사용하여 멤버에 접근해야 합니다. 그래서 p[0]->x와 같은 모양이 되겠죠?
- 배열[인덱스]->멤버
구조체 포인터 배열의 사용이 끝났다면 메모리를 해제해야 합니다. 다음과 같이 배열 크기만큼 반복하면서 각 요소에 할당된 동적 메모리를 해제합니다.
for (int i = 0; i < sizeof(p) / sizeof(struct Point2D *); i++) // 요소 개수만큼 반복 { free(p[i]); // 각 요소의 동적 메모리 해제 }
지금까지 구조체 배열과 구조체 포인터 배열에 대해 알아보았는데 문법이 조금 헷갈릴 수 있습니다. 여기서는 배열에 일반 구조체가 들어있으면 점으로 접근하고, 포인터가 들어있으면 화살표로 접근한다는 점만 기억하면 됩니다.