구조체는 관련 필드를 하나의 데이터 계약으로 묶을 때 쓰는 도구입니다.
구조체 카드는 문법 카드보다 관련 데이터를 하나의 계약으로 묶을 필요가 있는가를 보는 카드입니다.
- 서로 함께 움직이는 필드가 있다
- 함수 인자가 너무 많아진다
- 데이터 묶음 자체에 이름을 붙이고 싶다
숏컷 코드
typedef struct {
char name[32];
int age;
double score;
} Student;문법
구조체는 관련 필드를 하나의 계약으로 묶는 타입입니다. 이름, 나이, 점수처럼 같이 움직이는 값을 따로 흩어 두는 대신, “이 값들은 한 개체를 이룬다”는 사실을 타입으로 표현합니다.
typedef struct {
char name[32];
int age;
double score;
} Student;
Student s = {"Mina", 20, 97.5};
printf("%s %d %.1f\n", s.name, s.age, s.score);typedef는 구조체를 새로 만드는 기능이 아니라, struct Student처럼 긴 타입 이름을 더 쉽게 쓰게 만드는 도구입니다.
typedef struct {
int x;
int y;
} Point;복사 의미
포인터 필드가 없는 구조체는 =로 복사해도 보통 괜찮습니다.
하지만 포인터 필드가 있으면 주소만 복사되는 얕은 복사가 됩니다.
typedef struct {
int x;
int y;
} Point;
Point a = {10, 20};
Point b = a;이 경우 b.x, b.y를 바꿔도 a는 그대로입니다.
반대로 포인터 필드가 있으면 값 두 개가 같은 메모리를 같이 가리킬 수 있습니다.
typedef struct {
char *name;
} Person;
Person a = {strdup("Mina")};
Person b = a;이 시점부터는 구조체 두 개가 같은 문자열 버퍼를 공유합니다.
전달 방식
값으로 전달하면 전체가 복사됩니다.
읽기 전용이면 const struct T *, 수정이 필요하면 struct T *로 넘기는 쪽이 일반적입니다.
void print_student(const Student *s);
void reset_score(Student *s);읽기만 하면 const Student *, 수정하면 Student *처럼 나누는 편이 의도를 더 잘 보여 줍니다.
연결 리스트나 트리처럼 더 복잡한 자료구조는 구조체 위에 포인터가 얹히면서 만들어집니다. 그 전에 구조체를 “필드 묶음”으로 읽는 감각을 먼저 잡아 두는 편이 좋습니다.
체크포인트
- 관련 필드를 하나로 묶는다:
struct - 타입 이름을 간단히 쓴다:
typedef - 포인터 필드가 없다: 값 복사 가능
- 포인터 필드가 있다: 얕은 복사 주의
- 큰 구조체를 함수에 넘긴다: 포인터 전달 검토
주의할 점
포인터 필드가 있는 구조체를 =로 복사하면 같은 메모리를 공유하는 얕은 복사가 됩니다.
typedef struct {
char *name;
} Person;
Person a = {strdup("Mina")};
Person b = a;이 경우 한쪽을 해제하면 다른 쪽 포인터도 위험해집니다.
참고 링크
1 sources