CES-10 INTRODUÇÃO À COMPUTAÇÃO Capítulo VII Tipos Enumerativos e Estruturas Capítulo VII – Tipos Enumerativos e Estruturas 7.1 – Tipos enumerativos 7.2 – A necessidade de estruturas 7.3 – Manipulação dos campos de uma estrutura 7.4 – Campos alternativos 7.1 – Tipos Enumerativos 7.1.1 – Conceitos, declarações e expressões Valores manipulados até agora: números inteiros, reais e caracteres Tipos enumerativos: artifício da Linguagem C para se trabalhar com valores diferentes desses; Exemplos: Dias da semana, meses do ano, cores, estados civis de pessoas, naipes de baralho, etc. Exemplo: sejam as declarações enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; enum mes {janeiro, fevereiro, marco, abril, maio, junho, julho, agosto, setembro, outubro, novembro, dezembro}; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; Elas criam os seguintes novos tipos de variáveis: enum diasemana, enum mes e enum cor Os valores dessas variáveis serão respectivamente: {domingo, ..., sabado}, {janeiro, ..., dezembro} e {branca, ..., preta} enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; enum mes {janeiro, fevereiro, marco, abril, maio, junho, julho, agosto, setembro, outubro, novembro, dezembro}; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; Declarações de variáveis: enum diasemana hoje, ontem, amanha; enum mes MesNascimento, MesAtual, MesPassado; enum cor cor1, cor2, cor3; Outra forma de declarar variáveis: enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado} hoje, ontem, amanha; A palavra enum é obrigatória: enum diasemana hoje, ontem, amanha; enum mes MesNascimento, MesAtual, MesPassado; enum cor cor1, cor2, cor3; Mas pode-se dispensá-la mediante o uso de typedef: typedef enum diasemana diasemana; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; typedef enum cor cor; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; diasemana e cor passam a No CodeBlocks, enumaos cor ser tipos equivalentes diasemana hoje, ontem, amanha; pode ser usada num tipos enum diasemana e cor cor1, cor2, cor3; typedef, antes de declarada enum cor typedef enum diasemana diasemana; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; typedef enum cor cor; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; diasemana hoje, ontem, amanha; cor cor1, cor2, cor3; As variáveis e os valores desses tipos podem ser usados em atribuições e expressões: cor1 = azul; if (ontem == segunda) hoje = terca; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; Na realidade, domingo, segunda, ... , sabado, branca, amarela, ... , preta são constantes inteiras como aquelas criadas por uma declaração const Os valores dessas constantes não podem ser alterados por nenhum comando do programa Assim, o comando segunda = 5; não é aceito pelo compilador enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; enum cor {branca, amarela, azul, verde, vermelha, marrom, cinza, preta}; Por default, o compilador estabelece os seguintes valores: Constante Valor Constante Valor domingo 0 branca 0 segunda 1 amarela 1 terca 2 azul 2 quarta 3 verde 3 quinta 4 vermelha 4 sexta 5 marrom 5 sabado 6 cinza 6 preta 7 Pode-se explicitar o valor desejado para as constantes Exemplo: seja a seguinte declaração: enum mes {janeiro, fevereiro = 7, marco, abril, maio, junho = 5, julho, agosto, setembro, outubro = 26, novembro, dezembro}; Os valores das constantes serão: Constante Valor Constante Valor Constante Valor janeiro 0 maio 10 setembro 8 fevereiro 7 junho 5 outubro 26 marco 8 julho 6 novembro 27 abril 9 agosto 7 dezembro 28 Exemplo: variáveis lógicas simuladas por tipo enumerativo: typedef enum logic logic; enum logic {False, True}; logic L1, L2, L3; Nestas declarações, as constantes False e True têm respectivamente os valores 0 e 1 7.1.2 – Entrada e saída amigável para tipos enumerativos Sejam novamente as declarações: typedef enum diasemana diasemana; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; diasemana hoje, ontem, amanha; A constante inteira quarta não tem nada a ver com a cadeia de caracteres “quarta” Isso dificulta a entrada e saída amigável para esses tipos typedef enum diasemana diasemana; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; diasemana hoje, ontem, amanha; Por exemplo, numa leitura para a variável hoje, deve ser usado um formato inteiro: printf ("Entre com o dia de hoje: "); scanf ("%d", &hoje); Então, caso o operador queira que o valor de hoje seja quarta, ele deverá digitar 3 e não a cadeia quarta É necessário mais trabalho para tornar a entrada amigável (ver programa a seguir) Para o operador digitar uma cadeia e não um número #include <stdio.h> #include <stdlib.h> #include <string.h> /* Declaracoes de tipos NomeDia 0 “domingo” 1 “segunda” 2 “terca” */ 3 “quarta” cadhoje 4 “quinta” 5 “sexta” typedef char nome[10]; 6 “sabado” typedef enum diasemana diasemana; enum diasemana {domingo, segunda, terca, quarta, quinta, sexta, sabado}; /* Cabecalho e declaracoes de variaveis */ int main( ){ diasemana hoje, ontem, amanha; char c, achou; nome cadhoje, NomeDia[7] = {"domingo", "segunda", "terca", "quarta", "quinta", "sexta", "sabado"}; /* Desejo de execucao NomeDia */ 0 “domingo” printf ("Conhecer dia de ontem e de amanhan? (s/n): "); scanf ("%c", &c); cadhoje /* Leitura do dia de hoje */ 1 “segunda” 2 “terca” 3 “quarta” 4 “quinta” 5 “sexta” 6 “sabado” while (c == 's' || c == 'S') { printf ("\n\tDigite o dia de hoje: "); scanf ("%s", cadhoje); achou = 0; /* Conversao da cadeia digitada para o tipo diasemana */ hoje = domingo; while (hoje <= sabado && achou == 0) if (strcmp (cadhoje, NomeDia[hoje]) == 0) achou = 1; else hoje++; /* Caso de erro de digitacao NomeDia */ if (hoje > sabado) printf("\n\thoje: erro de digitacao\n\n"); /* Determinacao dos dias de ontem e amanhan else { */ 0 “domingo” 1 “segunda” 2 “terca” 3 “quarta” 4 “quinta” 5 “sexta” ontem = (hoje+6) % 7; amanha = (hoje+1) % 7; 6 “sabado” printf("\n\thoje = %s; ontem = %s; amanhan = %s;\n\n", NomeDia[hoje], NomeDia[ontem], NomeDia[amanha]); } /* Desejo de nova execucao */ printf ("Conhecer dia de ontem e de amanhan? (s/n): "); scanf (“ %c", &c); } printf ("\n\n"); system ("pause"); return 0; } Capítulo VII – Tipos Enumerativos e Estruturas 7.1 – Tipos enumerativos 7.2 – A necessidade de estruturas 7.3 – Manipulação dos campos de uma estrutura 7.4 – Campos alternativos 7.2 – A Necessidade de Estruturas Em muitas aplicações, é útil poder tratar todas as informações de uma entidade ou de uma pessoa como sendo uma única unidade Por exemplo, é muito melhor dizer: Levar o carro para casa do que dizer Levar as rodas do carro para casa Levar o motor do carro para casa Levar os bancos do carro para casa Levar a lataria do carro para casa Levar o painel do carro para casa Etc. Carro: entidade composta de rodas, motor, lataria, etc. No entanto, nessas mesmas aplicações, pode ser importante também a capacidade de se tratar cada uma dessas informações em separado Por exemplo: Consertar um pneu do carro Ligar o motor do carro Ajustar o banco do motorista Lavar a lataria do carro Acender o painel do carro Etc. Exemplo: declarações para cadastrar os empregados de uma empresa Nome Endereço Telefone Sexo Informações sobre um empregado Logradouro Número Complementos Bairro Cidade Estado Dia País Mês Estado civil Data de nascimento Data de admissão Cargo Setor de trabalho Salário Ano Dia Mês Ano Ao mudar ser demitido, admitido, de endereço todas as ou informações de salário ou do de empregado estado civil, são deletadas nem inseridas todas as no informações do cadastro cadastro do empregado são manipuladas Estruturas de dados para o cadastro dos empregados O vetor de empregados é composto de elementos de mesmo tipo Mas cada empregado guarda informações de diversos tipos Um endereço também guarda informações de diversos tipos Variáveis do tipo empregado e do tipo endereço são estruturadas heterogêneas Também são genericamente denominadas estruturas Em C, usa-se a declaração struct Struct para endereço: struct endereco { char logradouro[15]; int numero; char complemento[6], bairro[10], cidade[10], estado[3], pais[10]; }; Esta declaração cria o novo tipo de variáveis: struct endereco Campos das variáveis desse tipo: logradouro, numero, complemento, bairro, cidade, estado, pais struct endereco { char logradouro[15]; int numero; char complemento[6], bairro[10], cidade[10], estado[3], pais[10]; }; Declaração de variáveis desse tipo: struct endereco ender1, ender2, ender3; Outra forma de declarar variáveis: struct endereco { char logradouro[15]; int numero; char complemento[6], bairro[10], cidade[10], estado[3], pais[10]; } ender1, ender2, ender3; A palavra struct é obrigatória: struct endereco ender1, ender2, ender3; Mas pode-se dispensá-la mediante o uso de typedef: typedef struct endereco endereco; struct endereco { char logradouro[15]; int numero; char complemento[6], bairro[10], cidade[10], estado[3], pais[10]; endereco passa a ser um }; endereco ender1, ender2, ender3; tipo equivalente ao tipo struct endereco No CodeBlocks, struct endereco pode ser usada num typedef, antes de declarada Struct para empregado: struct empregado { char nome[20], cargo[10], setor[10]; endereco ender; int tel; typedef int data[3]; sexo sex; civil estciv; data nasc, adm; sexo e civil são tipos float salario; enumerativos (ver declarações }; a seguir) typedef int data[3]; Declaração do cadastro: typedef enum sexo sexo; empregado Cadastro [1000]; typedef enum estcivil civil; typedef struct endereco endereco; sizeof (Cadastro) = typedef struct empregado empregado; 138000 bytes enum sexo {masc, fem}; enum estcivil {solt,cas,viuvo,desq,divorc}; struct endereco { char lograd[15], compl[6], bairro[10], cidade[10], estado[3], pais[10]; int numero; }; struct empregado { char nome[20], cargo[10], setor[10]; endereco ender; int tel; Obs.: um campo de sexo sex; civil estciv; uma struct pode ser data nasc, adm; outra struct float salario; }; Capítulo VII – Tipos Enumerativos e Estruturas 7.1 – Tipos enumerativos 7.2 – A necessidade de estruturas 7.3 – Manipulação dos campos de uma estrutura 7.4 – Campos alternativos 7.3 – Manipulação dos Campos de uma Estrutura 7.3.1 – Acesso aos campos de uma estrutura Para acessar individualmente os campos de uma estrutura, usa-se o operador ‘.’ (ponto) Por exemplo, declarando-se empregado E1, E2, E3; pode-se fazer atribuições aos campos tel, estciv e salario: E1.tel = 31874622; E3.salario = 6000,00; E2.estciv = cas; O logradouro do endereço de E1 pode receber um valor, usando-se a função strcpy: strcpy (E1.ender.lograd, “Nove de Julho”); Campos de estruturas também podem receber valores lidos e podem ser escritos no vídeo ou em arquivos: gets (Cadastro[i].ender.lograd); scanf("%d",&Cadastro[i].ender.numero); printf("%s",Cadastro[i].ender.lograd); printf("%5d",Cadastro[i].ender.numero); A seguir, um programa para ler de um arquivo e escrever no vídeo as informações de todos os empregados de um cadastro (reduziu-se as informações a serem guardadas) Exemplo: programa para cadastramento dos empregados de uma empresa Nome Informações sobre um empregado Logradouro Número Endereço Bairro Estado civil Dia Data de admissão Mês Ano Salário #include <stdio.h> #include <stdlib.h> /* Definicao dos tipos */ typedef int data[3]; typedef enum estcivil civil; typedef struct endereco endereco; typedef struct empregado empregado; /* Definicao do tipo enumerativo enum estcivil {solt, cas, viuvo, desq, divorc}; */ /* Definicao das estruturas */ EstadoCivil 0 “solteiro” struct endereco { 1 “casado” 2 “viuvo” char lograd[26], bairro[20]; int numero; 3 “desquitado” }; 4 “divorciado” struct empregado { char nome[31]; endereco ender; civil estciv; data nasc; int salario; Para escrever os estados }; civis em vez de números /* Vetor com os nomes dos estados civis char EstadoCivil[][12] = {"solteiro", "casado", "viuvo", "desquitado", "divorciado"}; */ /* Cabecalho da main e declaracoes locais int main(){ int i, n; char c; empregado Cadastro[10]; FILE *filein; /* Abertura do arquivo de dados */ A título de curiosidade */ filein = fopen ("Empregados.dat", "r"); /* Tamanho da estrutura empregado */ printf ("Tamanho da estrutura empregado: %d bytes", sizeof (empregado)); /* Leitura do cadastro dos empregados */ fscanf (filein, "%d", &n); // Leitura do numero de empregados for(i = 0; i < n; i++) { fscanf (filein, "%c", &c); // Eliminacao de enter do arquivo fgets (Cadastro[i].nome, 31, filein); fgets (Cadastro[i].ender.lograd, 26, filein); fscanf(filein, "%d", &Cadastro[i].ender.numero); fgets (Cadastro[i].ender.bairro, 21, filein); O arquivo de fscanf(filein, "%d", &Cadastro[i].estciv); dados deve ser preparado fscanf(filein, "%d%d%d", cuidadosamente &Cadastro[i].nasc[0], Os espaços entre &Cadastro[i].nasc[1], os dados são &Cadastro[i].nasc[2]); relevantes para fscanf(filein, "%d", &Cadastro[i].salario); evitar erros na leitura } /* Escrita do cadastro dos empregados */ printf ("\n\n\nListagem dos Empregados:"); for(i = 0; i < n; i++) { printf("\n\n%d)\nNome: %s", i+1, Cadastro[i].nome); printf("\nEndereco: %s",Cadastro[i].ender.lograd); printf(", %7d",Cadastro[i].ender.numero); printf(", %s",Cadastro[i].ender.bairro); printf("\nEstado Civil: %s",EstadoCivil[Cadastro[i].estciv]); printf("\nData de Nascimento: %2.2d/%2.2d/%d", Cadastro[i].nasc[0], Cadastro[i].nasc[1], Cadastro[i].nasc[2]); printf("\nSalario: %d",Cadastro[i].salario); EstadoCivil } “solteiro” 0 /* Fechamento da tela */ printf ("\n\n"); system ("pause"); return 0; } 1 “casado” 2 “viuvo” 3 “desquitado” 4 “divorciado” Arquivo de dados “Empregados.dat”: 4 Julio Silva Souza Maria Ramos Leite Adalberto Correia Bianca Rocha Camargo 30 espaços R Direita Av 9 de Julho Pr Jose Silva R Augusta 25 espaços 301 Centro 2091 Aclimacao 14 Butanta 1271 Jardins 3 14 0 15 1 25 2 2 3 9 11 4 20 espaços fgets (Cadastro[i].nome, 31, filein); fgets (Cadastro[i].ender.lograd, 26, filein); fscanf(filein, "%d", &Cadastro[i].ender.numero); fgets (Cadastro[i].ender.bairro, 21, filein); 1987 1993 1968 1975 1300 2000 8200 15000 Resultado no vídeo: 7.3.2 – Inicialização e atribuição de estruturas Estruturas também podem ser inicializadas em suas declarações; exemplo: typedef struct endereco endereco; struct endereco { char lograd[30]; int numero; char bairro[15]; }; O resultado da seguinte declaração está abaixo: endereco ender = {“Av. Nove de Julho”, 1300, “Centro”}; lograd numero Av. Nove de Julho■ ender 1300 \0 bairro Centro■ Exemplo: Inicialização de matriz de estruturas Seja o seguinte trecho de programa: 0 1 2 struct complexo {float real, imag;}; 0 1.0 -0.1 2.0 -0.2 3.0 4.3 typedef struct complexo complexo; 1 4.0 -3.4 5.0 4.1 6.0 -2.6 int i, j; complexo A[3][3] = { 0.0 0.0 0.0 0.0 2 0.0 0.0 {{1.0, -0.1},{2.0, -0.2},{3.0, 4.3}}, A {{4.0, -3.4},{5.0, 4.1},{6.0, -2.6}} }; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf ("(%5.1f) + i(%5.1f) ", A[i][j].real, A[i][j].imag); printf ("\n"); Resultado no vídeo } ( ( ( 1.0) + i( -0.1) 4.0) + i( -3.4) 0.0) + i( 0.0) ( ( ( 2.0) + i( -0.2) 5.0) + i( 4.1) 0.0) + i( 0.0) ( ( ( 3.0) + i( 4.3) 6.0) + i( -2.6) 0.0) + i( 0.0) Diferentemente das variáveis indexadas, uma variável do tipo struct pode receber numa atribuição o valor de outra do mesmo tipo Exemplo: sejam as declarações: typedef struct endereco endereco; struct endereco { char lograd[30]; int numero; char bairro[15]; }; endereco ender1 = {“Av. Nove de Julho”, 1300, “Centro”}, ender2; ender2 = ender1; equivale a strcpy (ender2.lograd, ender1.lograd); ender2.numero = ender1.numero; strcpy (ender2.bairro, ender1.bairro); Exemplo: sejam as declarações: typedef struct matriz matriz; struct matriz {int A[5][3];} int B[5][3], C[5][3]; matriz M1, M2; Tendo M1 e B sido previamente inicializadas, C = B; é proibido M2 = M1; é válido “Se você não pode passar um elefante por debaixo de uma porta, coloque-o dentro de um envelope e passe-o.” “Se não é possível fazer atribuições entre variáveis indexadas, colocando-as em estruturas, isso se torna possível” O uso de estruturas para guardar vetores e matrizes apresenta uma outra vantagem Trabalhando com matrizes, seus elementos são guardados numa variável e seu numero de linhas e colunas ficam em outras variáveis No entanto, todas essas informações dizem respeito a uma mesma entidade, sugerindo que fiquem armazenadas numa mesma variável Em quase todos os exemplos vistos com variáveis indexadas, isso se aplica Com estruturas isso é possível: typedef struct matriz matriz; struct matriz {int Elementos[10][10]; int nlin, ncol;}; matriz A, B, C; Exercícios 7.3: 1.