HOWTO · C
C에서 구조체 배열 초기화
C에서 구조체 배열을 중괄호 목록, 런타임 할당, 또는 함수와 루프로 초기화하며, 메모리 해제와 안전한 문자열 복사에 대한 안내를 함께 제공합니다.
이 페이지의 내용
배열의 값이 선언되는 위치에서 알려지는 경우에는 중괄호 초기화자를 사용합니다. 크기나 값이 런타임 데이터에서 비롯되는 경우에는 저장 공간을 할당하고 각 요소를 대입하거나, 배열을 채우는 함수에 배열을 전달합니다. 어느 경우든 초기화자의 값은 멤버 선언 순서를 따릅니다.
C에서 struct는 관련된 필드를 하나의 타입 아래에 묶습니다. 여기서 각 Student는 이름, 나이, GPA를 가집니다.
구조체와 배열 초기화의 기초
배열을 선언하기 전에 그 타입을 선언합니다. 키워드 struct는 레코드 타입을 도입하고, 구조체 초기화자는 필드를 선언 순서대로 나열합니다: name, 그다음 age, 그다음 gpa. 이름에 사용되는 문자 배열은 종료 널 문자를 저장하며, 일반적인 문자열 리터럴은 이를 자동으로 포함합니다.
고정 크기 배열을 초기화자 목록으로 초기화하기
중첩된 중괄호를 사용하여 배열의 각 요소마다 Student 초기화자를 하나씩 제공합니다. 이 완전한 예제는 소스에서 알려진 값을 사용하고, 초기화된 각 레코드를 출력합니다.
이 예제를 실행하세요:
#include <stdio.h>
struct Student {
char name[50];
int age;
float gpa;
};
int main(void) {
struct Student students[3] = {
{"Alice", 20, 3.5f},
{"Bob", 22, 3.8f},
{"Charlie", 19, 3.2f}
};
for (int i = 0; i < 3; ++i) {
printf("%s: age %d, GPA %.2f\n",
students[i].name, students[i].age, students[i].gpa);
}
return 0;
}
Alice: age 20, GPA 3.50
Bob: age 22, GPA 3.80
Charlie: age 19, GPA 3.20
런타임에 배열 할당 및 초기화하기
요소 개수가 프로그램이 실행되는 동안 결정되는 경우, 그만큼의 구조체를 담을 수 있는 저장 공간을 할당합니다. malloc은 저장 공간을 예약하지만 필드에 의미 있는 값을 대입하지는 않으므로, 읽기 전에 모든 요소를 채우세요. 반환된 포인터를 확인한 뒤, 배열이 더 이상 필요 없을 때 free로 해제합니다.
이 완전한 예제는 런타임에 개수를 선택하고 각 레코드를 대입합니다.
#include <stdio.h>
#include <stdlib.h>
struct Student {
char name[50];
int age;
float gpa;
};
int main(void) {
size_t count = 3;
struct Student *students = malloc(count * sizeof *students);
if (students == NULL) {
fputs("Memory allocation failed\n", stderr);
return 1;
}
students[0] = (struct Student){"Alice", 20, 3.5f};
students[1] = (struct Student){"Bob", 22, 3.8f};
students[2] = (struct Student){"Charlie", 19, 3.2f};
for (size_t i = 0; i < count; ++i) {
printf("%s: age %d, GPA %.2f\n",
students[i].name, students[i].age, students[i].gpa);
}
free(students);
return 0;
}
Alice: age 20, GPA 3.50
Bob: age 22, GPA 3.80
Charlie: age 19, GPA 3.20
개별 대입에 사용되는 복합 리터럴은 C99 이상이 필요합니다. 할당이 실패하면 프로그램은 실패를 보고하고 배열에 접근하기 전에 종료합니다.
함수와 루프로 배열 요소 초기화하기
반복되는 초기화를 함수로 옮기면 호출 코드가 더 명확해집니다. 고정 크기 문자열의 경우 복사 전에 소스의 길이를 확인합니다: strlen(source) < sizeof destination이면 종료 널 문자가 들어갈 공간이 남습니다. 아래 함수는 너무 긴 이름을 보고하고 복사하지 않으며, 그런 경우 호출자는 중단합니다.
이 완전한 예제는 이름, 나이, GPA의 병렬 집합으로부터 각 레코드를 초기화합니다.
#include <stdio.h>
#include <string.h>
struct Student {
char name[50];
int age;
float gpa;
};
static int initialize_student(struct Student *student,
const char *source,
int age,
float gpa) {
char destination[50];
size_t length = strlen(source);
if (length >= sizeof destination) {
fputs("Name is too long\n", stderr);
return 0;
}
memcpy(destination, source, length + 1);
strcpy(student->name, destination);
student->age = age;
student->gpa = gpa;
return 1;
}
int main(void) {
const char *names[] = {"Alice", "Bob", "Charlie"};
const int ages[] = {20, 22, 19};
const float gpas[] = {3.5f, 3.8f, 3.2f};
struct Student students[3];
for (size_t i = 0; i < 3; ++i) {
if (!initialize_student(&students[i], names[i], ages[i], gpas[i])) {
return 1;
}
}
for (size_t i = 0; i < 3; ++i) {
printf("%s: age %d, GPA %.2f\n",
students[i].name, students[i].age, students[i].gpa);
}
return 0;
}
Alice: age 20, GPA 3.50
Bob: age 22, GPA 3.80
Charlie: age 19, GPA 3.20
길이 검사는 거부 조건으로 >=를 사용하며, 이는 복사 전에 strlen(source) < sizeof destination을 요구하는 것과 동일합니다. memcpy는 이 확인을 거친 뒤에만 측정된 문자와 그 종료 문자를 복사합니다.
올바른 초기화 방법 선택하기
- 배열 크기와 값이 소스에서 알려지는 경우에는 중괄호 초기화자를 선택합니다. 요소를 나중에 대입하고 싶을 때는
struct Student students[3];로 배열을 선언합니다. - 요소 개수가 프로그램 실행 중에 얻어지는 경우에는 런타임 할당을 선택합니다. 할당은 저장 공간만 제공한다는 것을 기억하세요: 필드를 초기화하고, 끝나면
free를 호출합니다. - 초기화 로직을 재사용하거나 주 흐름과 분리하여 유지해야 하는 경우에는 함수와 루프를 선택합니다. 들어오는 문자열은 고정 크기 멤버에 복사하기 전에 검증합니다.
자동 저장 기간을 가진 배열은 그것을 포함하는 스코프가 끝나면 해제됩니다. malloc으로 얻은 배열은 free에 전달될 때까지 할당된 상태를 유지하며, 그 이후에는 그 요소에 접근하지 마세요. 이러한 선택은 배열 선언, 런타임 초기화, 함수에서의 설정 구성, 할당된 저장 공간 해제와 관련된 흔한 질문에 답합니다.