|
| 1 | +# 12 - Tipos abstratos de dados |
| 2 | + |
| 3 | +!!! pdf |
| 4 | +  |
| 5 | + |
| 6 | +<br> |
| 7 | +## A estrutura `Point2D` |
| 8 | + |
| 9 | +Vamos considerar primeiro uma estrutura usada para guardar um ponto 2D. Este tipo de estrutura seria útil ao trabalhar com algoritmos de Geometria Computacional ou mesmo em aplicações de física. |
| 10 | + |
| 11 | +~~~{.C} |
| 12 | +typedef struct { |
| 13 | + double x, y; |
| 14 | +} Point2D; |
| 15 | +~~~ |
| 16 | + |
| 17 | +Vamos listar algumas operações que podem ser feitas com um ponto: |
| 18 | + |
| 19 | +1. Inicialização e finalização - todo ponto deve ser inicializado com algum valor para x e y. |
| 20 | +1. Somar dois pontos (e obter um terceiro); |
| 21 | +1. Calcular o coeficiente angular de uma reta que passe pelos dois pontos; |
| 22 | +1. Multiplicar ambas as coordenadas de um ponto (recebendo um novo em troca) - esta operação equivale a mudanças de escala |
| 23 | +1. Retornar os valores das componentes x e y do ponto; |
| 24 | + |
| 25 | +A ideia de um *Tipo Abstrato de Dados* é formalizar um "contrato" que lista quais operações podem ser feitas com este dado. Estas operações não dependem de nenhuma implementação em particular do tipo. Por exemplo, declarar o ponto com contendo um `double coords[2]` não muda os resultados de nenhuma das operações acima mas mudaria o código de acesso a coordenada `x` (`p.x` vs `p.coords[0]`). Veja um exemplo concreto de como fazer isto abaixo (arquivo *point2d.h*). |
| 26 | + |
| 27 | +```c |
| 28 | +#ifndef __POINT2D__ |
| 29 | +#define __POINT2D__ |
| 30 | + |
| 31 | +typedef struct{ |
| 32 | + double x, y; |
| 33 | +}Point2D; |
| 34 | + |
| 35 | +Point2D *point2D_new(double x, double y); |
| 36 | +void point2D_destroy(Point2D *p); |
| 37 | + |
| 38 | +double point2D_get_x(Point2D *p); |
| 39 | +double point2D_get_y(Point2D *p); |
| 40 | + |
| 41 | +Point2D *point2D_add(Point2D *p1, Point2D *p2); |
| 42 | +double point2D_theta(Point2D *p1, Point2D *p2); |
| 43 | +Point2D *point2D_scale(Point2D *p, double s); |
| 44 | + |
| 45 | +#endif |
| 46 | +``` |
| 47 | + |
| 48 | +!!! Note "Declarando tipos abstratos" |
| 49 | + Em *C* declaramos os **tipos abstratos de dados** e as **funções** que podem ser usadas por outras partes do código em arquivos `.h` e implementamos essas funções em arquivos `.c` (de mesmo nome, muitas vezes). Assim conseguimos organizar nosso código em vários módulos e depois juntá-los no momento da compilação. |
| 50 | + |
| 51 | +Notem que essa lista de operações "toma conta" da alocação e liberação de memória. Ou seja, o usuário de nosso `Point2D` não precisa se preocupar com malloc ou free. Basta que ele chame nossas funções. |
| 52 | + |
| 53 | +!!! Note "Por que todas as funções começam com `point2D_` ?" |
| 54 | + Em *C* não existe o conceito de módulo, namespace ou qualquer outro tipo de mecanismo de importar código. Toda função, a princípio, é declarada no escopo global de nomes. Isso significa que se nomeássemos `point2D_add` simplesmente como `add` nenhuma outra função escrita, por nós ou de nenhuma outra biblioteca usada no nosso programa, poderia ter esse nome. |
| 55 | + |
| 56 | + A estratégia usada nesse caso, é usar um prefixo que indique a qual biblioteca a função pertence. No nosso caso, usamos `point2D_` em todas as funções para evitar colisões de nomes. |
| 57 | + |
| 58 | + |
| 59 | +## Acessando as informações do Tipo Abstrato de Dados |
| 60 | + |
| 61 | +Note que na declaração das funções, algumas retornam um ponteiro para o Tipo Abstrato de Dados `Point2D` ou recebem como parâmetro um ponteiro para esse tipo, em ambos os casos o ponteiro foi **alocado dinamicamente na memória**. Para acessar as variáveis do tipo `Point2D` (`x` ou `y`) devemos usar o operador `->`. Por exemplo se temos uma variável `Point2D *p`, o acesso à `x` deve ser da seguinte forma `p->x`. |
| 62 | + |
| 63 | +!!! example |
| 64 | + Abra o arquivo `test_point2d.c`. Você consegue entender seu conteúdo? Examine o código e entenda como `Point2D` deve ser usado. |
| 65 | + |
| 66 | +!!! exercise text short |
| 67 | + Compile o arquivo `test_point2d.c` usando a seguinte linha de comando. Rode-o logo em seguida. O que significa sua saída? |
| 68 | + |
| 69 | + <div class="termy"> |
| 70 | + |
| 71 | + ```console |
| 72 | + $ gcc -Og -Wall -g test_point2d.c point2d.c -o teste_ponto |
| 73 | + ``` |
| 74 | + |
| 75 | + </div> |
| 76 | + |
| 77 | + |
| 78 | + Responda aqui: |
| 79 | + !!! answer |
| 80 | + São realizadas chamadas de testes automáticos que tentam utilizar as funcionalidade de `Point2D`. Os testes falham porque as implementações não foram realizadas. |
| 81 | + |
| 82 | +!!! example |
| 83 | + Abra o arquivo `point2d.c` e complete as partes faltantes. Verifique se tudo funciona corretamente usando `test_point2d.c`. Você deve aproveitar ao máximo as funções já criadas (ou seja, pode usar `point2d_new` nas outras funções). |
| 84 | + |
| 85 | +!!! example |
| 86 | + Agora que sua implementação do *TAD* `Point2D` está completa, compile o arquivo `test_point2d.c` e execute-o usando o *Valgrind*. Seu programa deverá rodar sem erros. |
| 87 | + |
| 88 | +## Vetores dinâmicos |
| 89 | + |
| 90 | +!!! warning "Atividade para Entrega" |
| 91 | + Os arquivos estão na pasta `09-tad` do repositório de entregas. |
| 92 | + |
| 93 | +!!! tip "Dica!" |
| 94 | + Veja a explicação sobre a atividade no final dos slides dessa aula e não se esqueça de ler o `README.md` dentro da pasta `09-tad`! |
| 95 | + |
| 96 | +Agora que já vimos vetores dinâmicos em aula, vamos implementá-los. Nosso vetor tem a seguinte interface: |
| 97 | + |
| 98 | +```c |
| 99 | +#ifndef __VECINT_H__ |
| 100 | +#define __VECINT_H__ |
| 101 | + |
| 102 | +typedef struct{ |
| 103 | + int *data; |
| 104 | + int size; |
| 105 | + int capacity; |
| 106 | +}vec_int; |
| 107 | + |
| 108 | +vec_int *vec_int_create(); |
| 109 | +void vec_int_destroy(vec_int **v); |
| 110 | + |
| 111 | +int vec_int_size(vec_int *v); |
| 112 | + |
| 113 | +/* As seguinte operações devolvem |
| 114 | + * 1 se pos é uma posição válida e a operação foi bem sucedida |
| 115 | + * 0 caso contrário |
| 116 | + * |
| 117 | + * No caso de at, o valor é retornado na variável apontada por vi. |
| 118 | + */ |
| 119 | +int vec_int_at(vec_int *v, int pos, int *vi); |
| 120 | +int vec_int_insert(vec_int *v, int pos, int val); |
| 121 | +int vec_int_remove(vec_int *v, int pos); |
| 122 | + |
| 123 | +#endif |
| 124 | +``` |
| 125 | + |
| 126 | +!!! example |
| 127 | + **Entrega**: implemente a estrutura *vetor dinâmico* no arquivo *vec_int.c* e compile o programa de forma semelhante como foi feito na parte anterior. Para sua entrega estar 100% seu programa de testes deverá rodar sem erros no *valgrind*. |
| 128 | + |
| 129 | +!!! tip "Dica!" |
| 130 | + Leia os testes para entender as operações realizadas e os resultados esperados! |
0 commit comments