Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C 언어 중첩 구조체(Nested Structure) 완벽 정리: 개념부터 실전 예제까지

중첩 구조체(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
  • 내부 구조체는 배열 형태로도 선언할 수 있어 여러 개의 하위 데이터를 한 번에 관리할 수 있습니다.
  • 문자열 입력 시 scanfgets를 함께 사용할 때는 입력 버퍼에 남은 개행 문자를 제거해야 오류를 방지할 수 있습니다.

참고: 예제에 사용된 gets() 함수는 버퍼 오버플로우 위험 때문에 C11 표준에서 제거되었습니다. 실무에서는 안전한 fgets() 사용을 권장합니다.