HOWTO · C

Inicializar Array de Structs em C

Inicialize um array de structs em C com uma lista entre chaves, alocação em tempo de execução, ou uma função e um loop, com orientações sobre a liberação de memória e a cópia segura de strings.

Nesta página

Use um inicializador entre chaves quando os valores do array são conhecidos no local onde ele é declarado. Se o seu tamanho ou os seus valores provêm de dados em tempo de execução, aloque armazenamento e atribua cada elemento, ou passe o array para uma função que o preencha. Em cada caso, os valores em um inicializador seguem a ordem de declaração dos membros.

Em C, um struct agrupa campos relacionados sob um único tipo. Aqui, cada Student tem um nome, uma idade e um GPA.

Noções básicas de structs e de inicialização de arrays

Declare o tipo antes de declarar um array desse tipo. A palavra-chave struct introduz o tipo de registo, e um inicializador de struct lista os seus campos em ordem de declaração: name, depois age, depois gpa. Os arrays de caracteres usados para nomes armazenam um caractere nulo de terminação, que os literais de string comuns incluem automaticamente.

Inicializar um array de tamanho fixo com uma lista de inicialização

Use chaves aninhadas para fornecer um inicializador Student para cada elemento do array. Este exemplo completo usa valores conhecidos no código-fonte e imprime cada registo inicializado.

Execute este exemplo:

#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

Alocar e inicializar um array em tempo de execução

Quando a contagem de elementos é determinada enquanto o programa é executado, aloque armazenamento suficiente para essa quantidade de structs. malloc reserva armazenamento, mas não atribui valores significativos aos campos, por isso preencha cada elemento antes de o ler. Verifique o ponteiro devolvido e, depois, liberte-o com free quando o array já não for necessário.

Este exemplo completo escolhe a contagem em tempo de execução e atribui cada registo.

#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

Os literais compostos usados nas atribuições individuais requerem C99 ou posterior. Se a alocação falhar, o programa reporta a falha e sai antes de aceder ao array.

Inicializar elementos do array com uma função e um loop

Mova a inicialização repetida para uma função quando isso tornar o código chamador mais claro. Para strings de tamanho fixo, verifique o comprimento da fonte antes de copiar: strlen(source) < sizeof destination deixa espaço para o caractere nulo de terminação. A função abaixo reporta um nome demasiado longo e não o copia; o chamador para se isso acontecer.

Este exemplo completo inicializa cada registo a partir de um conjunto paralelo de nomes, idades e 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

O teste de comprimento usa >= como condição de rejeição, o que equivale a exigir strlen(source) < sizeof destination antes de copiar. memcpy copia os caracteres medidos mais o seu terminador apenas após essa verificação.

Escolher o método de inicialização certo

  • Escolha um inicializador entre chaves quando o tamanho do array e os seus valores são conhecidos no código-fonte. Declare um array com struct Student students[3]; quando quiser atribuir os seus elementos mais tarde.
  • Escolha a alocação em tempo de execução quando a contagem de elementos é obtida enquanto o programa é executado. Lembre-se de que a alocação apenas fornece armazenamento: inicialize os campos e chame free quando terminar.
  • Escolha uma função e um loop quando a lógica de inicialização deve ser reutilizada ou mantida separada do fluxo principal. Valide as strings recebidas antes de as copiar para membros de tamanho fixo.

Um array com duração de armazenamento automática é libertado quando termina o âmbito que o contém. Um array obtido com malloc permanece alocado até ser passado para free; não aceda aos seus elementos depois disso. Estas escolhas respondem às perguntas comuns sobre declarar um array, inicializá-lo em tempo de execução, organizar a configuração numa função e libertar o armazenamento alocado.