aula 256

Dúvida | Como criar uma estrutura de dados fila com várias structs?

Vamos a mais uma dúvida? E na aula de hoje vamos aprender como criar uma estrutura de dados fila com várias structs e não apenas um número inteiro.

Para este exemplo vamos criar uma fila de Pessoas. Cada pessoa possuirá um nome, uma data de nascimento, um endereço e um contrato de trabalho. Assim, podemos dividir estas informações em várias estruturas separadas. Como o contrato de trabalho também tem uma data de assinatura, a primeira estrutura que vamos criar é a estrutura data que possui apenas três inteiros, um dia, um mês e um ano.

/*
      Estrutura data
*/
typedef struct{
    int dia, mes, ano;
}Data;

A estrutura endereço terá uma sequência de strings para rua, bairro, cidade e país e dois números inteiros, um para o número da residência e outro para o cep.

/*
       Estrutura endereço
*/
typedef struct{
    char rua[50];
    char bairro[50];
    char cidade[50];
    char pais[50];
    int num, cep;
}Endereco;

O contrato possuirá um valor inteiro para o código do contrato, possuirá um tipo data que será a data de assinatura do contrato, uma string para especificar o cargo do funcionário e um campo real para o salário.

/*
     Estrutura contrato
*/
typedef struct{
    int codigo;
    Data dataAss;
    char cargo[50];
    float salario;
}Contrato;

Assim, chegamos à estrutura Pessoa, que possuirá uma string para o nome, uma estrutura data para a data de nascimento, uma estrutura endereço e uma estrutura contrato.

/*
     Estrutura pessoa
*/
typedef struct{
    char nome[50];
    Data dataNas;
    Endereco end;
    Contrato contr;
}Pessoa;

Agora que já temos todas as estruturas que precisamos, podemos criar o nó para a estrutura fila. O nosso nó possuirá apenas dois campos, um campo pessoa e um ponteiro para outro nó. Observe como fomos encapsulando os tipos dentro de outros tipos. O tipo Nó possui em seu interior o tipo Pessoa. O tipo Pessoa possui em seu interior os tipos Data, Endereço e Contrato. Por fim, o tipo Contrato possui em seu interior o tipo Data.

/*
      Estrutura nó da fila
*/
typedef struct no{
    Pessoa p;
    struct no *proximo;
}No;

Como temos diversas estruturas e precisaremos imprimir as informações de cada tipo, podemos desenvolver um procedimento para a impressão de cada tipo de dado, chamando cada um no momento oportuno. Assim, observe que quando imprimirmos as informações de um Contrato, chamamos ali o procedimento para imprimir a data de assinatura do contrato. O mesmo ocorre quando imprimimos as informações de uma pessoa, chamamos os procedimentos de impressão para imprimir a data de nascimento, o endereço e o contrato.

Isso facilita a manutenção do código. Se desejarmos alterar por exemplo a forma como a data é impressa, precisamos alterar apenas o procedimento de impressão da data e não vários trechos do nosso código.

/*
      Procedimento para impressão de cada um dos tipos criados
*/

void imprimirData(Data d){
    printf("%d/%d/%d\n", d.dia, d.mes, d.ano);
}

void imprimirEndereco(Endereco end){
    printf("\tEndereco:\n");
    printf("\t\tRua: %s", end.rua);
    printf("\t\tBairro: %s", end.bairro);
    printf("\t\tCidade: %s", end.cidade);
    printf("\t\tPais: %s", end.pais);
    printf("\t\tNumero: %d\n", end.num);
    printf("\t\tCep: %d\n", end.cep);
}

void imprimirContrato(Contrato c){
    printf("\tContrato %d:\n", c.codigo);
    printf("\t\tCargo: %s", c.cargo);
    printf("\t\tSalario R$%.2f\n", c.salario);
    printf("\t\tData de ad.: ");
    imprimirData(c.dataAss); // chama o procedimento para imprimir a data
}

void imprirPessoa(Pessoa p){
    printf("\n\tNome: %s", p.nome);
    printf("\tData de nas.: ");
    imprimirData(p.dataNas); // chama o procedimento para imprimir a data
    imprimirEndereco(p.end); // chama o procedimento para imprimir o endereço
    imprimirContrato(p.contr); // chama o procedimento para imprimir o contrato
}

Assim como fizemos para a impressão, também será necessário ler as informações para cada umas das estruturas criadas. Aqui também vamos desenvolver uma função de leitura para cada uma das estruturas. Esta função irá ler os dados, preencher os campos e retornar a variável preenchida.

Tomando o tipo Data como exemplo, será solicitado ao usuário que digite a data, os números serão lidos e salvos na variável data e a mesma será retornada para o ponto do programa onde foi feito a chamada da função.

Assim como na impressão, a função para a leitura de uma pessoa por exemplo irá chamar as funções para a leitura de uma data, um contrato e um endereço.

/*
      Funções para a leitura de cada um dos tipos criados
*/
Data lerData(){
    Data d;

    printf("\nDigite a data no formato dd mm aaaa: ");
    scanf("%d%d%d", &d.dia, &d.mes, &d.ano);
    getchar();

    return d;
}

Endereco lerEndereco(){
    Endereco end;

    printf("\nRua: ");
    fgets(end.rua, 49, stdin);
    printf("\nBairro: ");
    fgets(end.bairro, 49, stdin);
    printf("\nCidade: ");
    fgets(end.cidade, 49, stdin);
    printf("\nPais: ");
    fgets(end.pais, 49, stdin);
    printf("\nNumero: ");
    scanf("%d", &end.num);
    printf("\nCep: ");
    scanf("%d", &end.cep);
    getchar();

    return end;
}

Contrato lerContrato(){
    Contrato c;

    printf("\nCodigo do contrato: ");
    scanf("%d", &c.codigo);
    printf("\nData de assinatura: ");
    c.dataAss = lerData(); // usa a função lerData
    printf("\nCargo: ");
    fgets(c.cargo, 49, stdin);
    printf("\nSalario: R$");
    scanf("%f", &c.salario);
    getchar();

    return c;
}

Pessoa lerPessoa(){
    Pessoa p;

    printf("\nNome: ");
    fgets(p.nome, 49, stdin);
    printf("\nData de nascimento: ");
    p.dataNas = lerData(); // usa a função lerData
    p.contr = lerContrato(); // usa a função lerContrato
    p.end = lerEndereco(); // usa a função lerEndereço

    return p;
}

Agora que já temos as estruturas, os procedimentos de impressão e as funções de leitura, basta alterar a inserção, a remoção e a impressão na estrutura fila. A estrutura fila não é mais de números inteiros, mas de pessoas. Assim, o procedimento de inserção receberá como parâmetro uma pessoa a ser inserida. A função de remoção não sofrerá nenhuma alteração uma vez que retorna o ponteiro para um nó. A impressão exige alguma alteração, uma vez que não será impresso um número inteiro, mas as informações de uma pessoa.

/*
      Procedimento para inserir na fila
*/
void inserir_na_fila(No **fila, Pessoa pessoa){
    No *aux, *novo = malloc(sizeof(No));
    if(novo){
        novo->p = pessoa;
        novo->proximo = NULL;
        if(*fila == NULL)
            *fila = novo;
        else{
            aux = *fila;
            while(aux->proximo)
                aux = aux->proximo;
            aux->proximo = novo;
        }
    }
    else
        printf("\nErro ao alocar memoria.\n");
}

// função de remoção
No* remover_da_fila(No **fila){
    No *remover = NULL;

    if(*fila){
        remover = *fila;
        *fila = remover->proximo;
    }
    else
        printf("\tFila vazia\n");
    return remover;
}
// procedimento para impressão
void imprimir(No *fila){
    printf("\t------- FILA --------\n\t");
    while(fila){
        imprirPessoa(fila->p);
        fila = fila->proximo;
        if(fila)
            printf("\t-----------------------\n\t");
    }
    printf("\n\t------- FIM FILA --------\n");
}

Código completo em C para a estrutura de dados Fila de structs

/*
        Código escrito por Wagner Gaspar
        Agosto de 2021

        Aula 256: Como criar uma FILA com vários tipos de dados?
        FIFO - First-In, First-Out - Primeiro a Entrar, Primeiro a Sair
/*

typedef struct{
    int dia, mes, ano;
}Data;

typedef struct{
    char rua[50];
    char bairro[50];
    char cidade[50];
    char pais[50];
    int num, cep;
}Endereco;

typedef struct{
    int codigo;
    Data dataAss;
    char cargo[50];
    float salario;
}Contrato;

typedef struct{
    char nome[50];
    Data dataNas;
    Endereco end;
    Contrato contr;
}Pessoa;

typedef struct no{
    Pessoa p;
    struct no *proximo;
}No;

// -------------- impressão das informações de uma Pessoa ------------------------

void imprimirData(Data d){
    printf("%d/%d/%d\n", d.dia, d.mes, d.ano);
}

void imprimirEndereco(Endereco end){
    printf("\tEndereco:\n");
    printf("\t\tRua: %s", end.rua);
    printf("\t\tBairro: %s", end.bairro);
    printf("\t\tCidade: %s", end.cidade);
    printf("\t\tPais: %s", end.pais);
    printf("\t\tNumero: %d\n", end.num);
    printf("\t\tCep: %d\n", end.cep);
}

void imprimirContrato(Contrato c){
    printf("\tContrato %d:\n", c.codigo);
    printf("\t\tCargo: %s", c.cargo);
    printf("\t\tSalario R$%.2f\n", c.salario);
    printf("\t\tData de ad.: ");
    imprimirData(c.dataAss);
}

void imprirPessoa(Pessoa p){
    printf("\n\tNome: %s", p.nome);
    printf("\tData de nas.: ");
    imprimirData(p.dataNas);
    imprimirEndereco(p.end);
    imprimirContrato(p.contr);
}

// ------------ Leitura dos dados de uma Pessoa -------------------------

Data lerData(){
    Data d;
    printf("\nDigite a data no formato dd mm aaaa: ");
    scanf("%d%d%d", &d.dia, &d.mes, &d.ano);
    getchar();
    return d;
}

Endereco lerEndereco(){
    Endereco end;
    printf("\nRua: ");
    fgets(end.rua, 49, stdin);
    printf("\nBairro: ");
    fgets(end.bairro, 49, stdin);
    printf("\nCidade: ");
    fgets(end.cidade, 49, stdin);
    printf("\nPais: ");
    fgets(end.pais, 49, stdin);
    printf("\nNumero: ");
    scanf("%d", &end.num);
    printf("\nCep: ");
    scanf("%d", &end.cep);
    getchar();
    return end;
}

Contrato lerContrato(){
    Contrato c;
    printf("\nCodigo do contrato: ");
    scanf("%d", &c.codigo);
    printf("\nData de assinatura: ");
    c.dataAss = lerData();
    printf("\nCargo: ");
    fgets(c.cargo, 49, stdin);
    printf("\nSalario: R$");
    scanf("%f", &c.salario);
    getchar();
    return c;
}

Pessoa lerPessoa(){
    Pessoa p;
    printf("\nNome: ");
    fgets(p.nome, 49, stdin);
    printf("\nData de nascimento: ");
    p.dataNas = lerData();
    p.contr = lerContrato();
    p.end = lerEndereco();
    return p;
}


void inserir_na_fila(No **fila, Pessoa pessoa){
    No *aux, *novo = malloc(sizeof(No));
    if(novo){
        novo->p = pessoa;
        novo->proximo = NULL;
        if(*fila == NULL)
            *fila = novo;
        else{
            aux = *fila;
            while(aux->proximo)
                aux = aux->proximo;
            aux->proximo = novo;
        }
    }
    else
        printf("\nErro ao alocar memoria.\n");
}

No* remover_da_fila(No **fila){
    No *remover = NULL;

    if(*fila){
        remover = *fila;
        *fila = remover->proximo;
    }
    else
        printf("\tFila vazia\n");
    return remover;
}

void imprimir(No *fila){
    printf("\t------- FILA --------\n\t");
    while(fila){
        imprirPessoa(fila->p);
        fila = fila->proximo;
        if(fila)
            printf("\t-----------------------\n\t");
    }
    printf("\n\t------- FIM FILA --------\n");
}

int main(){
    No *r, *fila = NULL;
    int opcao;
    Pessoa p;

    do{
        printf("\t0 - Sair\n\t1 - Inserir\n\t2 - Remover\n\t3 - Imprimir\n");
        scanf("%d", &opcao);
        getchar();

        switch(opcao){
        case 1:
            p = lerPessoa();
            inserir_na_fila(&fila, p);
            break;
        case 2:
            r = remover_da_fila(&fila);
            if(r){
                imprirPessoa(r->p);
                free(r);
            }
            break;
        case 3:
            imprimir(fila);
            break;
        default:
            if(opcao != 0)
                printf("\nOpcao invaluda!\n");
        }

    }while(opcao != 0);

    return 0;
}

Deixe um comentário

cinco + dezoito =

Wagner Gaspar

Capixaba de São Gabriel da Palha, Espírito Santo. Bacharel em Ciência da Computação pela Universidade Federal do Amazonas e mestre em informática pela Universidade Federal do Espírito Santo.