Ferramentas do usuário

Ferramentas do site


prog2:estruturas

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

Ambos lados da revisão anterior Revisão anterior
Próxima revisão
Revisão anterior
Próxima revisão Ambos lados da revisão seguinte
prog2:estruturas [2019/04/25 15:19]
maziero [Structs e ponteiros]
prog2:estruturas [2019/06/11 11:20]
maziero
Linha 1: Linha 1:
 +====== Estruturas ======
 +
 +As estruturas (//​structs//​),​ também chamadas registros (//​records//​) são variáveis compostas pelo agrupamento de diversas variáveis e vistas/​tratadas pelo programa como uma única variável. As variáveis que compõem uma estrutura podem ser simples (int, float, pointer) ou compostas (arrays e outras estruturas).
 +
 +Estruturas são geralmente utilizadas para agrupar variáveis correlatas, ou seja, que fazem parte de um mesmo conceito lógico. Por exemplo: Uma estrutura pode representar um paciente em uma aplicação médica e conter todos os dados relativos a ele.
 +
 +Uma estrutura é definida através da palavra reservada ''​struct'',​ da seguinte forma:
 +
 +  struct <nome da estrutura>​
 +  {
 +    type variable ;
 +    type variable ;
 +    ...
 +  } ;
 +
 +<note important>​
 +Uma estrutura define um novo **tipo** de dados, mas não cria/aloca variáveis desse tipo. Variáveis desse tipo devem ser declaradas posteriormente.
 +</​note>​
 +
 +A declaração e manipulação de variáveis desse novo tipo é simples:
 +
 +<code c struct.c>​
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +struct Paciente_t ​    // a extensão "​_t"​ é convenção usual para um novo tipo
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} ;
 +
 +int main ()
 +{
 +  // declaração/​alocação
 +  struct Paciente_t pac1, pac2 ;
 +
 +  // atribuição de valor aos campos
 +  pac1.idade = 53 ;
 +  pac1.quarto = 417 ;
 +
 +  // uso como parâmetro
 +  strcpy (pac1.nome, "Homer Simpson"​) ;
 +
 +  // atribuição de structs (o conteúdo é copiado)
 +  pac2 = pac1 ;
 +
 +  // uso dos valores dos campos
 +  printf ("​Paciente %s, %d anos, quarto %d\n", pac1.nome, pac1.idade, pac1.quarto) ;
 +  printf ("​Paciente %s, %d anos, quarto %d\n", pac2.nome, pac2.idade, pac2.quarto) ;
 +
 +  return (0) ;
 +}
 +</​code>​
 +
 +===== Definição de tipos =====
 +
 +A palavra reservada ''​typedef''​ permite definir (ou redefinir) um tipo de dado. Ela pode ser aplicada a qualquer tipo da linguagem C, mas é particularmente útil com //​structs//,​ pois simplifica a declaração de variáveis e parâmetros de tipo //struct//.
 +
 +Forma geral:
 +
 +  typedef <tipo existente>​ <novo tipo> ;
 +
 +Exemplo com escalares:
 +
 +<code c>
 +typedef unsigned long int uint32_t ; // novo tipo inteiro positivo 32 bits
 +
 +uint32_t a, b ;  // aloca duas variáveis do tipo uint32_t
 +</​code>​
 +
 +Exemplo com //​structs//:​
 +
 +<code c>
 +struct Pac_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} ;
 +
 +typedef struct Pac_t Paciente_t ;  // struct Pac_t -> Paciente_t
 +
 +// declaração e alocação
 +Paciente_t pac1, pac2 ;
 +</​code>​
 +
 +Ou redefinindo o próprio tipo ''​Paciente_t''​ ;
 +
 +<code c>
 +struct Paciente_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} ;
 +
 +typedef struct Paciente_t Paciente_t ;
 +
 +// declaração e alocação
 +Paciente_t pac1, pac2 ;
 +</​code>​
 +
 +Ou ainda mais "​enxuto":​
 +
 +<code c>
 +typedef struct Paciente_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} Paciente_t ;
 +
 +// declaração/​alocação
 +Paciente_t pac1, pac2 ;
 +</​code>​
 +
 +===== Atribuição de structs =====
 +
 +Valores de tipo ''​struct''​ podem ser atribuídos,​ copiados, usados como parâmetros e retornados por funções diretamente,​ sem necessidade de manipular cada elemento individualmente. Em uma atribuição,​ por exemplo, todos os bytes contidos no struct de origem serão copiados no struct de destino.
 +
 +As seguintes operações com structs são perfeitamente válidas (e muito úteis):
 +
 +<code c>
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +typedef struct Paciente_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} Paciente_t ;
 +
 +// imprime na tela os dados do paciente
 +void imprime_paciente (Paciente_t p)
 +{
 +  printf ("​Paciente %s, %d anos, quarto %d\n", p.nome, p.idade, p.quarto) ;
 +}
 +
 +// devolve um paciente "​nulo"​
 +Paciente_t paciente_nulo ()
 +{
 +  Paciente_t p = {"​nulo",​ 0, 0} ;
 +  return (p) ;
 +}
 +
 +int main ()
 +{
 +  // declaração de variável com valor inicial
 +  Paciente_t pac1 = { "Home Simpson",​ 47, 501 } ;
 +
 +  // cópia de struct
 +  Paciente_t pac2 = pac1 ;
 +
 +  // struct como parâmetro de função (passagem por cópia)
 +  imprime_paciente (pac2) ;
 +
 +  // struct como retorno de função
 +  pac2 = paciente_nulo () ;
 +  imprime_paciente (pac2) ;
 +
 +  return (0) ;
 +}
 +</​code>​
 +
 +
 +===== Structs e vetores =====
 +
 +O uso de vetores de //structs// permite criar estruturas de dados sofisticadas,​ com grande poder de expressão. A forma de declaração e acesso é similar ao uso convencional de vetores e //structs// visto até agora:
 +
 +<code c>
 +#define VECSIZE 1000
 +
 +typedef struct Paciente_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} Paciente_t ;
 +
 +// declaração/​alocação
 +Paciente_t paciente[VECSIZE] ; // vetor com VECSIZE pacientes
 +
 +// inicializa vetor
 +for (i=0; i<​VECSIZE;​ i++)
 +{
 +  strcpy (paciente[i].nome,​ ""​) ;
 +  paciente[i].idade ​ = 0 ;
 +  paciente[i].quarto = 0 ;
 +}
 +</​code>​
 +
 +===== Structs e ponteiros =====
 +
 +Uma variável de tipo //struct// é alocada na memória da mesma forma que as demais variáveis, então é possível obter o endereço da variável usando o operador ''&''​ e também criar ponteiros para variáveis //struct//, usando ''​*'':​
 +
 +<code c struct-ptr.c>​
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +typedef struct Paciente_t
 +{
 +  char  nome[100] ;
 +  short idade ;
 +  short quarto ;
 +} Paciente_t ;
 +
 +int main ()
 +{
 +  // declaração/​alocação
 +  Paciente_t pac, *ptr ;
 +
 +  // atribuição de valor aos campos
 +  pac.idade = 53 ;
 +  pac.quarto = 417 ;
 +  strcpy (pac.nome, "Homer Simpson"​) ;
 +
 +  // atribuição do ponteiro
 +  ptr = &pac ;
 +
 +  // acesso pela variável struct
 +  printf ("​Paciente %s, %d anos, quarto %d\n",
 +          pac.nome, pac.idade, pac.quarto) ;
 +
 +  // acesso pelo ponteiro
 +  printf ("​Paciente %s, %d anos, quarto %d\n",
 +          (*ptr).nome,​ (*ptr).idade,​ (*ptr).quarto) ;
 +
 +  return (0) ;
 +}
 +</​code>​
 +
 +<note tip>
 +A especificação de C garante que os campos internos de um //struct// são alocados na ordem em que foram definidos, e na área alocada não há outras informações além dos próprios campos. Assim, o endereço de uma variável de tipo //struct// coincide com o endereço de seu primeiro campo.
 +</​note>​
 + 
 +O acesso ao campo interno do //struct// feito através do desreferenciamento do ponteiro também pode ser feito através do operador //​ponteiro->​campo//​. Assim, as operações abaixo são equivalentes:​
 +
 +<code c>
 +  (*ptr).idade = 45 ;
 +  ptr->​idade = 45 ;
 +</​code>​
 +
 +O uso conjunto de //structs// e ponteiros permite construir estruturas de dados complexas, como filas, pilhas, árvores e grafos. Por exemplo, podemos definir um elemento de uma fila de inteiros da seguinte forma:
 +
 +<code c>
 +// definição do tipo FilaInt_t
 +typedef struct FilaInt_t
 +{
 +  int valor ;
 +  struct FilaInt_t *prox ;
 +} FilaInt_t ;
 +
 +// ponteiro para o início de uma fila
 +FilaInt_t *fila1 ;
 +</​code>​
 +
 +O ponteiro ''​prox''​ dentro do //struct// permite "​apontar"​ para outras variáveis de mesmo tipo, que por sua vez podem apontar para outras variáveis de mesmo tipo e assim sucessivamente. Isso permite criar uma fila de inteiros, com uma estrutura similar à da figura a seguir:
 +
 +{{  fila.png ​ |Fila de inteiros}}
 +
 +O código que constrói essa estrutura é o seguinte (simplificado,​ pois não testa o sucesso do ''​malloc''​):​
 +
 +<code c>
 +fila1 = malloc (sizeof(FilaInt_t)) ;
 +
 +fila1->​valor = 45 ;
 +fila1->​prox ​ = malloc (sizeof(FilaInt_t)) ;
 +
 +fila1->​prox->​valor = 21 ;
 +fila1->​prox->​prox ​ = malloc (sizeof(FilaInt_t)) ;
 +
 +fila1->​prox->​prox->​valor = 4 ;
 +fila1->​prox->​prox->​prox ​ = NULL ;
 +</​code>​
 +
 +===== Exercícios =====
 +
 +  - Escrever um programa em C para gerenciar uma relação de alunos, implementada como um vetor de //structs// de tipo ''​aluno_t''​. O programa deve ter funções para:
 +    - ler os dados de um aluno (nome, idade, GRR, curso), devolvendo os campos lidos como um //struct//;
 +    - imprimir os dados de um aluno a partir de seu //struct//;
 +    - imprimir a relação de alunos;
 +    - imprimir os nomes dos alunos com idade acima de 22 anos;
 +    - ordenar a relação de alunos por idade; ​
 +    - ordenar a relação de alunos por nome.
 +  - escreva um programa em C para manipular datas e horários:
 +    - //structs// do tipo ''​data_t''​ armazenam datas (dia, mês, ano);
 +    - //structs// do tipo ''​hora_t''​ armazenam horários (hora, minuto, segundo);
 +    - //structs// do tipo ''​datahora_t''​ armazenam datas e horários (seus campos internos são //structs// dos tipos acima);
 +    - a função ''​le_data''​ lê um //struct// de tipo ''​data_t'';​
 +    - a função ''​le_hora''​ lê um //struct// de tipo ''​hora_t'';​
 +    - a função ''​le_datahora''​ lê um //struct// de tipo ''​datahora_t'';​
 +    - as funções ''​esc_data'',​ ''​esc_hora''​ e ''​esc_datahora''​ escrevem na tela seus tipos respectivos;​
 +    - a função ''​data_dias''​ retorna (''​int''​) o número de dias em uma data, a partir do início do calendário (1/1/1); para simplificar,​ desconsiderar anos bissextos e outros ajustes de calendário;​
 +    - a função ''​hora_segs''​ retorna (''​int''​) o número de segundos em um horário, a partir do início do dia (00:00:00);
 +    - a função ''​dif_data''​ retorna (''​int''​) o número de dias entre duas datas;
 +    - a função ''​dif_hora''​ retorna (''​int''​) o número de segundos entre dois horários;
 +    - a função ''​dif_datahora''​ retorna (''​datahora_t''​) a diferença entre duas datas e horários.
  
prog2/estruturas.txt · Última modificação: 2019/10/09 15:20 por maziero