C 언어에서는 서로 다른 데이터 타입을 하나의 단위로 묶어서 관리할 수 있도록 구조체(struct)를 제공합니다.
구조체 선언 및 초기화
구조체는 여러 개의 멤버 변수를 포함할 수 있으며, 각각 다른 타입을 가질 수 있습니다. 구조체를 정의한 후에는 이를 기반으로 변수를 생성하고 값을 할당할 수 있습니다.
#include <stdio.h>
struct StudentInfo {
int id;
char name[20];
char gender;
int age;
float grade;
char address[30];
};
int main() {
struct StudentInfo student = {1001, "Alice", 'F', 21, 92.5, "Seoul"};
struct StudentInfo classList[3];
printf("ID: %d, Name: %s, Gender: %c, Age: %d, Grade: %.1f, Address: %s\n",
student.id, student.name, student.gender, student.age, student.grade, student.address);
for (int i = 0; i < 3; i++) {
scanf("%d %s %c %d %f %s",
&classList[i].id, classList[i].name, &classList[i].gender,
&classList[i].age, &classList[i].grade, classList[i].address);
}
for (int i = 0; i < 3; i++) {
printf("Student %d - ID: %d, Name: %s, Gender: %c, Age: %d, Grade: %.1f, Address: %s\n",
i+1, classList[i].id, classList[i].name, classList[i].gender,
classList[i].age, classList[i].grade, classList[i].address);
}
return 0;
}
구조체의 멤버에 접근할 때는 점(.) 연산자를 사용합니다. 예를 들어, student.id와 같이 특정 멤버에 접근할 수 있습니다. 출력 시에는 각 멤버의 데이터 타입에 맞는 형식 지정자를 사용해야 합니다.
입력 함수인 scanf를 사용할 때는 주소 연산자(&)를 통해 각 멤버의 메모리 주소를 전달해야 하며, 문자열은 배열 이름 자체가 주소이므로 &를 붙이지 않습니다. 또한, %c 형식으로 문자를 입력받을 때는 공백 문자도 인식하므로 입력 포맷에 주의해야 합니다.
메모리 정렬 규칙
컴퓨터 메모리에서 구조체는 효율적인 접근을 위해 특정 규칙에 따라 정렬됩니다. 일반적으로 구조체 전체 크기는 가장 큰 멤버의 크기의 배수가 되도록 패딩(padding)이 추가됩니다.
#include <stdio.h>
struct TypeA {
double points; // 8 bytes
short years; // 2 bytes
};
struct TypeB {
double points; // 8 bytes
int height; // 4 bytes
short years; // 2 bytes
};
struct TypeC {
int height; // 4 bytes
char gender; // 1 byte
short years; // 2 bytes
};
int main() {
struct TypeA a;
struct TypeB b;
struct TypeC c;
printf("Size of TypeA: %zu bytes\n", sizeof(a));
printf("Size of TypeB: %zu bytes\n", sizeof(b));
printf("Size of TypeC: %zu bytes\n", sizeof(c));
return 0;
}
위 코드에서 각 구조체의 실제 크기는 내부 멤버들의 크기 합보다 클 수 있으며, 이는 메모리 정렬을 위한 패딩 때문입니다. 예를 들어, TypeA는 10바이트(8+2)의 데이터를 포함하지만, 16바이트로 정렬되어 더 많은 공간을 차지하게 됩니다.