C 구조체, 공용체, 메모리 관리 심층 분석

구조체

구조체 정의와 변수 사용

#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    int salary;
    char dept;
} emp3; // 구조체 정의 시 전역 변수 emp3 선언

int main() {
    struct employee emp1, emp2;
    
    strcpy(emp1.name, "Kim");
    emp1.salary = 50000;
    emp1.dept = 'D';
    
    emp2 = emp1;               // 동일 타입 구조체 복사
    strcpy(emp2.name, "Park");
    
    emp3 = emp1;
    strcpy(emp3.name, "Lee");
    
    printf("직원1: %s, %d, %c\n", emp1.name, emp1.salary, emp1.dept);
    printf("직원2: %s, %d, %c\n", emp2.name, emp2.salary, emp2.dept);
    printf("직원3: %s, %d, %c\n", emp3.name, emp3.salary, emp3.dept);
    
    return 0;
}

구조체 변수 초기화

#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    int salary;
    char dept;
} emp2 = {"Choi", 60000, 'M'}; // 구조체 정의와 동시에 초기화

int main() {
    struct employee emp1 = {"Jung", 45000, 'E'}; // 지역 변수 초기화
    
    printf("직원1: %s, %d, %c\n", emp1.name, emp1.salary, emp1.dept);
    printf("직원2: %s, %d, %c\n", emp2.name, emp2.salary, emp2.dept);
    
    return 0;
}

구조체 멤버로 다른 구조체 사용

#include <stdio.h>
#include <string.h>

struct hire_date {
    int year;
    int month;
    int day;
};

struct employee {
    char name[25];
    struct hire_date start;  // 구조체를 멤버로 포함
    char dept;
} emp1 = {"Yoon", {2020, 3, 15}, 'S'};

int main() {
    struct employee emp2;
    emp2 = emp1;
    emp2.start.year = 2022;
    
    printf("원본: %s, %d-%d-%d, %c\n", 
           emp1.name, emp1.start.year, emp1.start.month, emp1.start.day, emp1.dept);
    printf("복사: %s, %d-%d-%d, %c\n", 
           emp2.name, emp2.start.year, emp2.start.month, emp2.start.day, emp2.dept);
    
    return 0;
}

무명 구조체

#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    struct {               // 이름이 없는 내부 구조체
        int year;
        int month;
        int day;
    } start;
    char dept;
} emp1 = {"Seo", {2018, 7, 1}, 'T'};

int main() {
    printf("직원: %s, 입사일: %d-%d-%d, 부서: %c\n", 
           emp1.name, emp1.start.year, emp1.start.month, emp1.start.day, emp1.dept);
    return 0;
}

구조체 배열

#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    int salary;
    char dept;
};

int main() {
    struct employee team[3] = {
        {"Kim", 50000, 'D'},
        {"Park", 60000, 'M'},
        {"Lee", 45000, 'E'}
    };
    
    for (int i = 0; i < 3; ++i) {
        printf("%s, %d, %c\n", team[i].name, team[i].salary, team[i].dept);
    }
    
    return 0;
}

구조체 포인터

#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    int salary;
    char dept;
};

int main() {
    struct employee team[3] = {
        {"Kim", 50000, 'D'},
        {"Park", 60000, 'M'},
        {"Lee", 45000, 'E'}
    };
    struct employee *ptr;
    
    ptr = team;
    
    for (int i = 0; i < 3; ++i) {
        // 화살표 연산자와 역참조로 멤버 접근
        printf("%s, %d, %c\n", (*ptr).name, ptr->salary, ptr->dept);
        ptr++;
    }
    
    return 0;
}

공용체

공용체(union)는 서로 다른 데이터 타입이 같은 메모리 공간을 공유하는 구조체와 유사한 데이터 타입이다. 가장 큰 멤버의 크기만큼 메모리를 할당받으며, 한 번에 하나의 멤버만 유효한 값을 가진다.

#include <stdio.h>
#include <string.h>

union data_packet {
    char buffer[20];
    int code;
    char flag;
};

int main() {
    union data_packet packet;
    
    strcpy(packet.buffer, "init");
    packet.code = 42;
    packet.flag = 'X';
    
    printf("packet.buffer: %s\n", packet.buffer);  // 'X' 문자로 덮어써짐
    printf("packet.code: %d\n", packet.code);      // 'X'의 ASCII 값으로 변경
    printf("packet.flag: %c\n", packet.flag);      // 최종 할당된 값 'X'
    printf("공용체 크기: %lu\n", sizeof(union data_packet)); // 20
    
    return 0;
}

typedef 사용

typedef는 기존 데이터 타입에 새로운 이름을 부여하여 코드를 간결하게 만든다.

#include <stdio.h>
#include <string.h>

typedef struct employee {
    char name[25];
    int salary;
    char dept;
} Employee, *EmployeePtr;  // 구조체 별칭과 포인터 별칭

int main() {
    Employee emp;  // struct employee emp와 동일
    strcpy(emp.name, "Kim");
    emp.salary = 50000;
    emp.dept = 'D';
    
    EmployeePtr p = &emp;  // struct employee *p와 동일
    printf("이름: %s\n", p->name);
    printf("급여: %d\n", p->salary);
    
    return 0;
}
#include <stdio.h>
#include <string.h>

struct employee {
    char name[25];
    int salary;
    char dept;
};

typedef struct employee Employee;  // 별도로 typedef 적용

int main() {
    Employee emp;
    strcpy(emp.name, "Park");
    emp.salary = 60000;
    emp.dept = 'M';
    
    return 0;
}

메모리 관리

C 언어는 네 가지 메모리 영역을 사용한다:

  • 코드 영역: 실행할 명령어가 저장
  • 전역/정적 변수 영역: 프로그램 시작 시 할당, 종료 시 해제
  • 스택 영역: 함수 호출 시 생성되는 지역 변수 저장, 함수 종료 시 자동 해제
  • 힙 영역: 동적 메모리 할당에 사용, malloc/free로 관리

동적 메모리 관리: malloc/free

malloc은 힙에서 연속된 메모리를 할당하고, free는 할당된 메모리를 해제한다.

#include <stdio.h>
#include <stdlib.h>

char* read_name() {
    char *buffer;
    buffer = (char*)malloc(10 * sizeof(char));  // 힙에 10바이트 할당
    
    if (buffer == NULL) {
        printf("메모리 할당 실패!\n");
        exit(1);
    }
    
    scanf("%s", buffer);
    return buffer;
}

int main() {
    char *name;
    name = read_name();
    printf("입력된 이름: %s\n", name);
    
    free(name);    // 할당된 힙 메모리 해제
    name = NULL;   // 댕글링 포인터 방지
    
    return 0;
}

댕글링 포인터 (Wild Pointer)

초기화되지 않았거나, 해제된 메모리를 가리키는 포인터는 심각한 오류를 유발할 수 있다.

#include <stdio.h>
#include <string.h>

int main() {
    char *p;  // 초기화되지 않은 포인터
    
    strcpy(p, "hello");  // 예측 불가능한 메모리에 쓰기 시도 -> 오류
    
    char *q;
    *q = 'A';  // 마찬가지로 위험한 접근
    
    return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
    char source[] = "wel";
    char *ptr;
    
    ptr = source;
    strcpy(ptr, "welcome");  // source 배열 크기(4바이트)를 초과하는 쓰기 -> 버퍼 오버플로우
    
    return 0;
}

태그: C 구조체 C 공용체 typedef C 메모리 관리 Malloc

6월 7일 18:40에 게시됨