
C 언어 struct는 여러 변수를 한 묶음으로 다루기 위한 기본 도구입니다. 중요한 점은 값의 개수가 아니라, 그 값들이 하나의 의미를 이루는지입니다.
핵심은 따로 흩어진 값을 하나의 이름 있는 개념으로 묶는 것입니다. 이 글은 C 공식 문법 자료와 구조체 선언 규칙을 기준으로 struct 정의, 초기화, 배열, 포인터, 함수 전달 방식을 정리합니다.

C 언어 struct를 먼저 한 줄로 정리하면
struct는 서로 관련 있는 여러 값을 하나의 타입으로 묶습니다. 예를 들어 x와 y가 따로 있으면 단순한 숫자 두 개지만, `Point`로 묶으면 좌표라는 의미가 생깁니다.
struct Point {
int x;
int y;
};이렇게 타입을 만들면 함수 인자, 배열, 반환값에서도 `Point`라는 이름으로 의도를 드러낼 수 있습니다.
언제 struct가 자연스러울까
같은 시점에 함께 읽고 함께 전달되는 값이라면 struct 후보입니다. 반대로 우연히 같은 함수 안에서 쓰인다는 이유만으로 묶으면 타입의 의미가 흐려집니다.
- x, y처럼 좌표를 이루는 값
- name, age, score처럼 학생 한 명을 설명하는 값
- host, port, timeout처럼 설정 하나를 구성하는 값
- start, end처럼 범위를 표현하는 값
typedef는 이름을 짧게 만드는 선택이다
C에서는 `struct Point`처럼 태그 이름을 함께 쓰는 방식이 기본입니다. `typedef`를 쓰면 별칭을 만들어 `Point`만으로 타입을 사용할 수 있습니다.
typedef struct {
int x;
int y;
} Point;
Point p = { .x = 10, .y = 20 };typedef는 편리하지만 타입의 의미를 대신 만들어 주지는 않습니다. 먼저 좋은 구조체 이름과 member 이름을 정하는 것이 더 중요합니다.
배열과 포인터를 함께 쓰는 경우
여러 개의 같은 구조체를 다루면 구조체 배열이 자연스럽습니다. 큰 구조체를 함수에 넘길 때는 복사를 줄이기 위해 포인터를 자주 씁니다.
typedef struct {
char name[32];
int score;
} Student;
void print_student(const Student *student) {
printf("%s %d\n", student->name, student->score);
}읽기만 하는 함수라면 `const Student *`처럼 수정하지 않는다는 뜻을 타입에 드러내는 편이 좋습니다.
padding은 일단 존재만 알아두자
구조체 member 사이에는 정렬을 위해 padding이 들어갈 수 있습니다. 그래서 member 크기를 단순히 더한 값과 `sizeof(struct)` 결과가 다를 수 있습니다.
입문 단계에서는 padding을 최적화하려고 구조를 억지로 바꾸기보다, 바이너리 파일 형식이나 네트워크 패킷처럼 크기가 중요한 코드에서 주의해야 한다고 기억하면 충분합니다.
실무 체크리스트
- 함께 움직이는 값인지 먼저 확인한다
- 구조체 이름이 실제 도메인 의미를 설명하는지 본다
- 초기화는 designated initializer를 우선 고려한다
- 큰 구조체를 함수에 넘길 때는 포인터와 const를 검토한다
- 구조체를 공개 헤더에 둘지 .c 내부에 숨길지 경계를 정한다
정리
C 언어 struct를 이해할 때는 문법 자체보다 코드가 표현하려는 경계를 먼저 보는 편이 좋습니다. 오늘 글의 기준은 ‘읽는 사람이 실수를 줄일 수 있는가’입니다.
함께 보면 좋은 내부 글은 C 점 연산자 화살표 연산자 차이, C 언어 배열과 포인터는 같은 걸까, C 언어 헤더 파일은 왜 나눌까입니다. 외부 기준은 cppreference – Struct declaration, cppreference – Initialization, cppreference – Pointer를 확인했습니다.