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
prog2:estruturas [2019/10/09 15:19]
maziero [Atribuição de structs]
prog2:estruturas [2019/10/09 15:20] (atual)
maziero [Estruturas]
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:
 +
 +<code c>
 +struct <nome da estrutura>​
 +{
 +  type variable ;
 +  type variable ;
 +  ...
 +} ;
 +</​code>​
 +
 +<note important>​
 +Uma estrutura define um novo **tipo de dado**, 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 struct1.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 ; // "​uint32_t"​ equivale a "​unsigned long int"
 +
 +
 +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 na estrutura de origem serão copiados na estrutura de destino.
 +
 +As seguintes operações com estruturas são perfeitamente válidas (e muito úteis):
 +
 +<code c struct2.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