Skip to content

Commit 0cf9088

Browse files
committed
aula12
1 parent 7456136 commit 0cf9088

13 files changed

Lines changed: 652 additions & 311 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# 12 - Tipos abstratos de dados
2+
3+
!!! pdf
4+
![](slides.pdf)
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!
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdio.h>
2+
3+
typedef int (*test_func)();
4+
5+
typedef struct {
6+
char name[50];
7+
test_func function;
8+
} test_data;
9+
10+
#define test_printf (printf("%s: ", __func__));printf
11+
12+
#define test_assert(expr, str) { if(!(expr)) { printf("%s: [FAIL] %s in %s:%d\n", __func__, str, __FILE__, __LINE__); return -1; } }
13+
14+
#define TEST(f) {.name=#f, .function=f}
15+
16+
#define test_list test_data all_tests[]
17+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
3+
int main() {
4+
int size = sizeof(all_tests)/sizeof(test_data);
5+
printf("Running %d tests:\n", size);
6+
printf("=====================\n\n");
7+
int pass_count = 0;
8+
for (int i = 0; i < size; i++) {
9+
if (all_tests[i].function() >= 0) {
10+
printf("%s: [PASS]\n", all_tests[i].name);
11+
pass_count++;
12+
};
13+
}
14+
15+
printf("\n\n=====================\n");
16+
printf("%d/%d tests passed\n", pass_count, size);
17+
return 0;
18+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <stdlib.h>
2+
#include "point2d.h"
3+
4+
Point2D *point2D_new(double x, double y) {
5+
return NULL;
6+
}
7+
8+
9+
void point2D_destroy(Point2D *p) {
10+
11+
}
12+
13+
double point2D_get_x(Point2D *p) {
14+
return 0;
15+
}
16+
17+
double point2D_get_y(Point2D *p) {
18+
return 0;
19+
}
20+
21+
Point2D *point2D_add(Point2D *p1, Point2D *p2) {
22+
return NULL;
23+
}
24+
25+
double point2D_theta(Point2D *p1, Point2D *p2) {
26+
return 0;
27+
}
28+
29+
Point2D *point2D_scale(Point2D *p, double s) {
30+
return NULL;
31+
}
32+
33+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef __POINT2D__
2+
#define __POINT2D__
3+
4+
typedef struct{
5+
double x, y;
6+
}Point2D;
7+
8+
Point2D *point2D_new(double x, double y);
9+
void point2D_destroy(Point2D *p);
10+
11+
double point2D_get_x(Point2D *p);
12+
double point2D_get_y(Point2D *p);
13+
14+
Point2D *point2D_add(Point2D *p1, Point2D *p2);
15+
double point2D_theta(Point2D *p1, Point2D *p2);
16+
Point2D *point2D_scale(Point2D *p, double s);
17+
18+
19+
#endif
608 KB
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// stack.h
2+
typedef struct {
3+
int capacity; // capacidade máxima
4+
int size; // quantidade de elementos armazenados
5+
int *data; // vetor para armazenar itens do TAD
6+
}stack_int;
7+
8+
stack_int * stack_int_new(int capacity);
9+
void stack_int_delete(stack_int *_s);
10+
int stack_int_empty(stack_int *s);
11+
int stack_int_full(stack_int *s);
12+
void stack_int_push(stack_int *s, int value);
13+
int stack_int_pop(stack_int *s);
14+
3.53 KB
Binary file not shown.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#include "mintest/macros.h"
2+
#include "point2d.h"
3+
4+
int test_new_destroy_get() {
5+
Point2D *p = point2D_new(0, 0);
6+
7+
test_assert(point2D_get_x(p) == 0, "Erro na inicialização da componente x!");
8+
test_assert(point2D_get_y(p) == 0, "Erro na inicialização da componente y!");
9+
10+
point2D_destroy(p);
11+
12+
Point2D *p2 = point2D_new(10, 20);
13+
14+
test_assert(point2D_get_x(p2) == 10, "Erro na inicialização da componente x!");
15+
test_assert(point2D_get_y(p2) == 20, "Erro na inicialização da componente y!");
16+
17+
point2D_destroy(p2);
18+
19+
return 0;
20+
}
21+
22+
int test_add() {
23+
Point2D *a, *b, *c;
24+
a = point2D_new(10.5, 20);
25+
b = point2D_new(30, 40.3);
26+
c = point2D_add(a, b);
27+
28+
test_assert(point2D_get_x(c) == 40.5, "Erro na soma: componente x!");
29+
test_assert(point2D_get_y(c) == 60.3, "Erro na soma: componente x!");
30+
31+
point2D_destroy(a);
32+
point2D_destroy(b);
33+
point2D_destroy(c);
34+
35+
return 0;
36+
}
37+
38+
int test_scale() {
39+
Point2D *a, *b, *c;
40+
a = point2D_new(10.5, 20);
41+
b = point2D_scale(a, 2.5);
42+
43+
test_assert(point2D_get_x(b) == 26.25, "Erro na escala: componente x!");
44+
test_assert(point2D_get_y(b) == 50, "Erro na escala: componente y!");
45+
46+
c = point2D_scale(a, 0);
47+
48+
test_assert(point2D_get_x(c) == 0, "Erro na escala: componente x!");
49+
test_assert(point2D_get_y(c) == 0, "Erro na escala: componente y!");
50+
51+
point2D_destroy(a);
52+
point2D_destroy(b);
53+
point2D_destroy(c);
54+
55+
return 0;
56+
}
57+
58+
int test_theta() {
59+
Point2D *a, *b;
60+
a = point2D_new(20, 30);
61+
b = point2D_new(40, 50);
62+
63+
test_assert(point2D_theta(a, b) == 1, "Erro na inclinação da reta!");
64+
65+
point2D_destroy(a);
66+
point2D_destroy(b);
67+
68+
a = point2D_new(20, 30);
69+
b = point2D_new(40, 40);
70+
71+
test_assert(point2D_theta(a, b) == 0.5, "Erro na inclinação da reta!");
72+
73+
point2D_destroy(a);
74+
point2D_destroy(b);
75+
76+
return 0;
77+
}
78+
79+
test_list = { TEST(test_new_destroy_get), TEST(test_add), TEST(test_scale), TEST(test_theta) };
80+
81+
#include "mintest/runner.h"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// test_stack.c
2+
// gcc -Og -Wall -g test_stack.c stack.o -o teste_stack
3+
#include <stdio.h>
4+
#include "stack.h"
5+
6+
int main() {
7+
// Cria um stack com capacidade para 5 elementos
8+
stack_int *s = stack_int_new(5);
9+
10+
stack_int_push(s, 10);
11+
stack_int_push(s, 20);
12+
stack_int_push(s, 30);
13+
// Remove o topo: 30
14+
printf("Valor removido: %d\n", stack_int_pop(s));
15+
// Remove o topo: 20
16+
printf("Valor removido: %d\n", stack_int_pop(s));
17+
stack_int_delete(s); // Libera a memória
18+
19+
return 0;
20+
}

0 commit comments

Comments
 (0)