중첩 구조체(Nested Structure)란?
C 언어에서 구조체 안에 또 다른 구조체가 포함된 형태를 중첩 구조체(nested structure)라고 합니다. 서로 관련 있는 데이터들을 논리적으로 묶어 관리할 수 있어 코드의 가독성과 유지보수성이 크게 향상됩니다.
예를 들어 직원 정보를 다루는 다음과 같은 구조체가 있다고 가정해 보겠습니다.
struct emp {
int eno; // 직원 번호
char ename[30]; // 직원 이름
float sal; // 기본 급여
float da; // 일반 수당
float hra; // 주택 수당
float ea; // 추가 수당
} e;위 구조체에서 수당(allowance)에 해당하는 항목들은 하나로 그룹화할 수 있습니다. 이때 하위 구조체(sub-structure)를 활용하면 다음과 같이 깔끔하게 정리됩니다.
struct emp {
int eno;
char ename[30];
float sal;
struct allowance { // 내부(중첩) 구조체
float da;
float hra;
float ea;
} a; // 내부 구조체 변수
} e;중첩 구조체 멤버에 접근하는 방법
중첩 구조체의 가장 안쪽 멤버에 접근하려면 점(.) 연산자(dot operator)를 사용해 바깥쪽 구조체 변수부터 안쪽 구조체 변수까지 순서대로 연결해야 합니다.
예를 들어 위 예제에서 주택 수당(hra)에 접근하려면 다음과 같이 작성합니다.
e.a.hra = 5000.0;
이처럼 점 연산자를 여러 번 연결함으로써 외부 구조체 → 내부 구조체 → 멤버 순으로 계층적으로 접근할 수 있습니다.
중첩 구조체 활용 프로그램
다음은 사람(Person)의 기본 정보와 주소(Address) 정보를 중첩 구조체로 관리하는 예제 프로그램입니다.
#include <stdio.h>
// 외부 구조체와 내부 구조체 선언 //
struct Person { // 메인(외부) 구조체
char Name[500];
int Age;
char Gender;
char temp; // 입력 버퍼 비우기용
struct Address { // 중첩 구조체
char Apartment[500];
char Street[500];
char City[100]; // 도시
char State[100]; // 주(州)
int Zipcode; // 우편번호
} a[20]; // 내부 구조체 배열 변수
} p[20]; // 외부 구조체 배열 변수
void main() {
int i;
// 사용자 입력 받기 (2명의 데이터)
for (i = 1; i < 3; i++) {
printf("%d번째 사람의 이름 입력 : ", i);
gets(p[i].Name);
printf("%d번째 사람의 나이 입력 : ", i);
scanf("%d", &p[i].Age);
scanf("%c", &p[i].temp); // 버퍼 비우기
printf("%d번째 사람의 성별 입력 : ", i);
scanf("%c", &p[i].Gender);
scanf("%c", &p[i].temp); // 버퍼 비우기
printf("%d번째 사람의 도시 입력 : ", i);
gets(p[i].a[i].City); // 내부 구조체 멤버 접근
printf("%d번째 사람의 주(州) 입력 : ", i);
gets(p[i].a[i].State);
printf("%d번째 사람의 우편번호 입력 : ", i);
scanf("%d", &p[i].a[i].Zipcode);
scanf("%c", &p[i].temp); // 버퍼 비우기
}
// 결과 출력
for (i = 1; i < 3; i++) {
printf("%d번째 사람의 이름 : %s\n", i, p[i].Name);
printf("%d번째 사람의 나이 : %d\n", i, p[i].Age);
printf("%d번째 사람의 성별 : %c\n", i, p[i].Gender);
printf("%d번째 사람의 도시 : %s\n", i, p[i].a[i].City);
printf("%d번째 사람의 주(州) : %s\n", i, p[i].a[i].State);
printf("%d번째 사람의 우편번호 : %d\n", i, p[i].a[i].Zipcode);
}
}실행 결과 예시
1번째 사람의 이름 : 홍길동 1번째 사람의 나이 : 25 1번째 사람의 성별 : M 1번째 사람의 도시 : 서울 1번째 사람의 주(州) : 강남구 1번째 사람의 우편번호 : 12345 2번째 사람의 이름 : 김철수 2번째 사람의 나이 : 30 2번째 사람의 성별 : M 2번째 사람의 도시 : 부산 2번째 사람의 주(州) : 해운대구 2번째 사람의 우편번호 : 54321
주요 포인트 정리
- 중첩 구조체는 구조체 내부에 다른 구조체를 선언하여 복잡한 데이터를 체계적으로 표현합니다.
- 멤버 접근은 점(.) 연산자를 연속으로 사용합니다. 예:
p[i].a[i].City - 내부 구조체는 배열 형태로도 선언할 수 있어 여러 개의 하위 데이터를 한 번에 관리할 수 있습니다.
- 문자열 입력 시
scanf와gets를 함께 사용할 때는 입력 버퍼에 남은 개행 문자를 제거해야 오류를 방지할 수 있습니다.
참고: 예제에 사용된
gets()함수는 버퍼 오버플로우 위험 때문에 C11 표준에서 제거되었습니다. 실무에서는 안전한fgets()사용을 권장합니다.