HOWTO · C
How to Initialize Array of Structs in C
Initialize an array of structs in C with a brace list, runtime allocation, or a function and loop, with guidance on memory cleanup and safe string copying.
On this page
Use a brace initializer when the array’s values are known where it is declared. If its size or values come from runtime data, allocate storage and assign each element, or pass the array to a function that fills it. In each case, the values in an initializer follow the member declaration order.
In C, a struct groups related fields under one type. Here, each Student has a name, age, and GPA.
Structs and Array Initialization Basics
Declare the type before declaring an array of it. The struct keyword introduces the record type, and a struct initializer lists its fields in declaration order: name, then age, then gpa. Character arrays used for names store a terminating null character, which ordinary string literals include automatically.
Initialize a Fixed-Size Array with an Initializer List
Use nested braces to provide one Student initializer for each array element. This complete example uses values known in the source and prints each initialized record.
Run this example:
#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
Allocate and Initialize an Array at Runtime
When the element count is determined while the program runs, allocate enough storage for that many structs. malloc reserves storage but does not assign meaningful values to the fields, so populate every element before reading it. Check the returned pointer, then release it with free when the array is no longer needed.
This complete example chooses the count at runtime and assigns each record.
#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
The compound literals used for individual assignments require C99 or later. If allocation fails, the program reports the failure and exits before accessing the array.
Initialize Array Elements with a Function and Loop
Move repeated initialization into a function when it makes the calling code clearer. For fixed-size strings, check the source length before copying: strlen(source) < sizeof destination leaves room for the terminating null character. The function below reports a too-long name and does not copy it; the caller stops if that happens.
This complete example initializes each record from a parallel set of names, ages, and GPAs.
#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
The length test uses >= as the rejection condition, which is equivalent to requiring strlen(source) < sizeof destination before copying. memcpy copies the measured characters plus their terminator only after that check.
Choose the Right Initialization Method
- Choose a brace initializer when the array size and values are known in the source. Declare an array with
struct Student students[3];when you want to assign its elements later. - Choose runtime allocation when the element count is obtained while the program runs. Remember that allocation only provides storage: initialize the fields and call
freeonce you are done. - Choose a function and loop when initialization logic should be reused or kept separate from the main flow. Validate incoming strings before copying them into fixed-size members.
An array with automatic storage duration is released when its containing scope ends. An array obtained with malloc remains allocated until it is passed to free; do not access its elements after that. These choices answer the common questions about declaring an array, initializing it at runtime, organizing setup in a function, and freeing allocated storage.