29.01.2014 Views

Pré-texto Livro de Introdução a Programação com C

Pré-texto Livro de Introdução a Programação com C

Pré-texto Livro de Introdução a Programação com C

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Sumário<br />

1 Introdução 5<br />

1.1 Histórico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.2 Arquitetura <strong>de</strong> Computadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

1.2.1 Memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

1.2.2 Processador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

1.3 Algoritmos e Programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

1.4 Técnica <strong>de</strong> Desenvolvimento <strong>de</strong> Programas . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.5 Partes <strong>de</strong> um Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.6 Tradução <strong>de</strong> Programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

1.6.1 Compilação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

1.6.2 Interpretação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

1.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

1.8 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2 Conceitos Básicos 14<br />

2.1 Variáveis e Células <strong>de</strong> Memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.2 I<strong>de</strong>ntificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.3 Comando <strong>de</strong> Atribuição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

2.4 Tipos <strong>de</strong> Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

2.4.1 Declaração <strong>de</strong> Variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

2.4.2 Tipo Inteiro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

2.4.3 Tipo Ponto Flutuante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

2.4.4 Tipo Booleano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

2.4.5 Tipo Caractere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

2.4.6 Conversão <strong>de</strong> Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

2.5 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

2.6 Expressões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

2.6.1 Expressões Aritméticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

2.6.2 Expressões Relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

2.6.3 Expressões Lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

2.7 Comando <strong>de</strong> Entrada <strong>de</strong> Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

2.8 Comando <strong>de</strong> Saída <strong>de</strong> Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

2.9 Comandos <strong>de</strong> Seleção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

2.9.1 Comando <strong>de</strong> seleção simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

2.9.2 Comando <strong>de</strong> seleção dupla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

2.9.3 Comando <strong>de</strong> seleção múltipla . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

2.10 Comandos <strong>de</strong> Repetição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

2.10.1 Comando <strong>de</strong> repetição <strong>com</strong> pré-condição . . . . . . . . . . . . . . . . . . . . . . 39<br />

2.10.2 Comando <strong>de</strong> repetição <strong>com</strong> pós-condição . . . . . . . . . . . . . . . . . . . . . . 45<br />

2.10.3 Comando <strong>de</strong> repetição con<strong>de</strong>nsado . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

2.11 Problema dos Lotes Encaixantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

2.12 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />

2.13 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

DRAFT<br />

1


2 SUMÁRIO<br />

2.14 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

2.15 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

3 Modularização 64<br />

3.1 Resolvendo por Partes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

3.2 Subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />

3.3 Partes <strong>de</strong> um Subprograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

3.3.1 Cabeçalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

3.3.2 Dicionário <strong>de</strong> dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />

3.3.3 Corpo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />

3.3.4 Comentários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />

3.4 Chamada <strong>de</strong> subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

3.5 Passagem <strong>de</strong> parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

3.6 Retorno <strong>de</strong> dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72<br />

3.6.1 Encerramento antecipado <strong>de</strong> execução . . . . . . . . . . . . . . . . . . . . . . . 74<br />

3.7 Funções sem lista <strong>de</strong> parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />

3.8 Funções sem retorno <strong>de</strong> dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

3.9 Recursivida<strong>de</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

3.9.1 Implementação não recursiva equivalente . . . . . . . . . . . . . . . . . . . . . 79<br />

3.10 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

3.11 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />

3.12 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

3.13 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />

4 Tipos Abstratos <strong>de</strong> Dados 94<br />

4.1 Técnicas <strong>de</strong> Programação Top-down e Bottom-up . . . . . . . . . . . . . . . . . . . . . 94<br />

4.2 Tipos Compostos Heterogêneos (Estruturas) . . . . . . . . . . . . . . . . . . . . . . . . 95<br />

4.2.1 Definição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />

4.2.2 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

4.2.3 O Comando Type<strong>de</strong>f . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />

4.2.4 Simplificação na Passagem <strong>de</strong> Parâmetros e Retorno <strong>de</strong> Função . . . . . . . . . 98<br />

4.3 Tipos Abstratos <strong>de</strong> Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

4.3.1 Definição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

4.3.2 Definição <strong>de</strong> Atributos <strong>de</strong> um TAD . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

4.3.3 Definição <strong>de</strong> Operações <strong>de</strong> um TAD . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

4.3.4 Uso do TAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

4.3.5 Tipos <strong>de</strong> TADs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

4.4 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

4.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113<br />

4.6 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114<br />

4.7 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />

DRAFT<br />

5 Vetores 117<br />

5.1 Vetores e sua importância . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<br />

5.2 Representação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

5.3 Definição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

5.4 Operações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122<br />

5.5 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

5.6 O TAD Implementacional Lista Vetorial <strong>de</strong> Inteiros . . . . . . . . . . . . . . . . . . . . 127<br />

5.6.1 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

5.6.2 Operações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />

5.7 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

5.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149<br />

5.9 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149


SUMÁRIO 3<br />

5.10 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />

6 Matrizes 155<br />

6.1 Matrizes e sua importância . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155<br />

6.2 Definição e Acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

6.2.1 Definição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

6.2.2 Acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

6.2.3 Definição dinâmica <strong>de</strong> uma matriz . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

6.3 O TAD Implementacional Matriz <strong>de</strong> Inteiros . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

6.3.1 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158<br />

6.3.2 Operações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

6.3.3 Exemplo <strong>de</strong> utilização do TAD tMatrizInt . . . . . . . . . . . . . . . . . . . . . 163<br />

6.4 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

6.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171<br />

6.6 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171<br />

6.7 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173<br />

7 Apontadores 175<br />

7.1 Variáveis Apontadoras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />

7.2 A Sintaxe dos Apontadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177<br />

7.2.1 Operador En<strong>de</strong>reço <strong>de</strong> Memória . . . . . . . . . . . . . . . . . . . . . . . . . . 177<br />

7.2.2 Acesso a Variável por Meio <strong>de</strong> Apontadores . . . . . . . . . . . . . . . . . . . . 178<br />

7.2.3 O Operador Seta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179<br />

7.3 Uso <strong>de</strong> Apontadores nas Passagens <strong>de</strong> Parâmetros . . . . . . . . . . . . . . . . . . . . 180<br />

7.4 Alocação Dinâmica <strong>de</strong> Memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181<br />

7.5 Problemas Gerados por Apontadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

7.5.1 Apontadores Não Inicializados . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

7.5.2 Objetos Pen<strong>de</strong>ntes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

7.5.3 Referência Pen<strong>de</strong>nte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186<br />

7.5.4 Programação Macarrônica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

7.6 TAD Implementacional Lista Enca<strong>de</strong>ada <strong>de</strong> Inteiros . . . . . . . . . . . . . . . . . . . 187<br />

7.6.1 Definição do Tipo tNo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

7.6.2 Atributos <strong>de</strong> tLista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />

7.6.3 Operações <strong>de</strong> tLista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />

7.6.4 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />

7.7 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />

7.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203<br />

7.9 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204<br />

7.10 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205<br />

DRAFT<br />

8 Arquivos 211<br />

8.1 Variáveis Transientes X Variáveis Persistentes . . . . . . . . . . . . . . . . . . . . . . . 211<br />

8.2 Tipos <strong>de</strong> Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212<br />

8.2.1 Tipos <strong>de</strong> Arquivos - Arquivos Texto . . . . . . . . . . . . . . . . . . . . . . . . 212<br />

8.2.2 Tipos <strong>de</strong> Arquivos - Arquivos Binários . . . . . . . . . . . . . . . . . . . . . . . 212<br />

8.3 Definição <strong>de</strong> arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213<br />

8.4 Operações sobre arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214<br />

8.4.1 Abertura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214<br />

8.4.2 Fechamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215<br />

8.5 Operações sobre arquivos <strong>texto</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

8.5.1 Leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

8.5.2 Escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217<br />

8.6 Operações sobre arquivos binários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218<br />

8.6.1 Leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218


4 SUMÁRIO<br />

8.6.2 Escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219<br />

8.7 Outras funções úteis para arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220<br />

8.7.1 feof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220<br />

8.7.2 fseek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222<br />

8.8 Exercícios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222<br />

8.9 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229<br />

8.10 Exercícios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229<br />

8.11 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230<br />

DRAFT


Capítulo 1<br />

Introdução<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Apresentar um breve histórico da Computação;<br />

Coautores:<br />

André Boechat<br />

Ivan Nunes<br />

Marcos Couto<br />

Apresentar noções sobre arquitetura <strong>de</strong> <strong>com</strong>putadores, <strong>com</strong>o funcionam o processador e a memória;<br />

Definir o que são algoritmos e programas, além <strong>de</strong> apresentar algumas técnicas para <strong>de</strong>senvolvêlos;<br />

Definir as partes <strong>de</strong> um programa e a importância da documentação;<br />

Introduzir o conceito <strong>de</strong> tradução <strong>de</strong> programas.<br />

Este capítulo visa <strong>de</strong>screver um pouco da história da evolução dos <strong>com</strong>putadores e apresentar<br />

alguns conceitos fundamentais para o entendimento <strong>de</strong> programas e algoritmos.<br />

1.1 Histórico<br />

Dado o alto grau tecnológico dos <strong>com</strong>putadores atuais, po<strong>de</strong> ser difícil imaginar que os primeiros<br />

<strong>com</strong>putadores eram totalmente mecânicos. Diversos tipos foram projetados e construídos ao longo da<br />

evolução, chegando aos mo<strong>de</strong>rnos <strong>com</strong>putadores digitais; porém, alguns se <strong>de</strong>stacam pela inovação e<br />

<strong>com</strong>plexida<strong>de</strong> que marcaram suas épocas.<br />

A primeira máquina programável que se tem notícia foi construída pelo professor <strong>de</strong> matemática<br />

da Universida<strong>de</strong> <strong>de</strong> Cambridge, Charles Babbage (1792-1871). A “máquina analítica”, <strong>com</strong>o ficou<br />

conhecida, era totalmente mecânica, <strong>com</strong>posta basicamente por engrenagens que formavam quatro<br />

<strong>com</strong>ponentes: a memória, a unida<strong>de</strong> <strong>de</strong> cálculo ou <strong>com</strong>putação, a unida<strong>de</strong> <strong>de</strong> entrada e a <strong>de</strong> saída. A<br />

unida<strong>de</strong> <strong>de</strong> <strong>com</strong>putação recebia operandos da memória para realizar sobre eles as operações <strong>de</strong> soma,<br />

subtração, multiplicação ou divisão, e <strong>de</strong>pois armazenar o resultado na memória.<br />

Como a máquina analítica executava as instruções lidas pela unida<strong>de</strong> <strong>de</strong> entrada, era possível executar<br />

diferentes seqüências <strong>de</strong> cálculos, bastando para isso que um programa diferente fosse utilizado.<br />

Assim, a primeira pessoa no mundo a programar um <strong>com</strong>putador foi a jovem Ada Augusta Lovelace,<br />

contratada pelo próprio Babbage a fim <strong>de</strong> produzir o software necessário para o funcionamento da<br />

máquina.<br />

A procura por máquinas calculadoras cresceu <strong>com</strong> a Segunda Guerra Mundial, estimulando o surgimento<br />

dos primeiros <strong>com</strong>putadores eletrônicos. O professor <strong>de</strong> física da Universida<strong>de</strong> da Pensilvânia,<br />

John Mauchley, junto <strong>com</strong> seu aluno <strong>de</strong> mestrado, J. Presper Eckert, construiu um <strong>com</strong>putador chamado<br />

ENIAC (Electronic Numerical Integrator And Computer)[1], o qual <strong>de</strong>tinava-se ao cômputo <strong>de</strong><br />

trajetórias táticas que exigissem conhecimento substancial em matemática. O ENIAC tinha 18.000<br />

DRAFT<br />

5


6<br />

CAPÍTULO 1. INTRODUÇÃO<br />

válvulas e 1.500 relés, pesava 30 toneladas e consumia 140 quilowatts <strong>de</strong> energia elétrica. Para programar<br />

o ENIAC, era necessário ajustar a posição <strong>de</strong> 6.000 chaves <strong>de</strong> várias posições e conectar um<br />

número imenso <strong>de</strong> soquetes por meio <strong>de</strong> uma verda<strong>de</strong>ira floresta <strong>de</strong> cabos. Este gigantesco <strong>com</strong>putador<br />

só ficou pronto em 1946, após o término da guerra.<br />

Um dos pesquisadores envolvidos no projeto do ENIAC, John von Neumann, construiu para o<br />

Instituto <strong>de</strong> Estudos Avançado <strong>de</strong> Princeton (Princeton Institute of Advanced Studies — IAS) a<br />

máquina IAS[2], a qual ainda é a base <strong>de</strong> praticamente todas as máquina atuais. Ele imaginou que os<br />

programas po<strong>de</strong>riam ser representados em formato digital na memória, junto <strong>com</strong> os dados.<br />

A invenção do transístor e o <strong>de</strong>senvolvimento <strong>de</strong> circuitos integrados revolucionaram os projetos<br />

<strong>de</strong> <strong>com</strong>putadores do final da década <strong>de</strong> 1950, tornando obsoletos os <strong>com</strong>putadores valvulados. Nas<br />

décadas <strong>de</strong> 1960 e 1970, as famílias <strong>de</strong> <strong>com</strong>putadores da IBM 1 (International Business Machines),<br />

System/360, e da DEC 2 (Digital Equipament Corporation), PDP-11, dominavam o mercado.<br />

Nesse período surgiu uma das linguagens <strong>de</strong> programação mais usadas para o <strong>de</strong>senvolvimento <strong>de</strong><br />

softwares e também adotada neste livro, a linguagem C[3]. Ela é, ainda hoje, muito utilizada para a<br />

criação <strong>de</strong> programas diversos, <strong>com</strong>o processadores <strong>de</strong> <strong>texto</strong>, planilhas eletrônicas, programas para a<br />

solução <strong>de</strong> problemas <strong>de</strong> engenharia, e muitos outros.<br />

Diversos fatores, <strong>com</strong>o a criação <strong>de</strong> linguagens <strong>de</strong> programação mais semelhantes à linguagem<br />

humana, o que facilitava a vida dos programadores, e a integração <strong>de</strong> circuitos em escala muito alta, o<br />

que aumentou o <strong>de</strong>sempenho e diminuiu o tamanho das máquinas, <strong>de</strong>ram início a era dos <strong>com</strong>putadores<br />

pessoais. E foi nesse con<strong>texto</strong>, na década <strong>de</strong> 80, que a IBM construiu o <strong>com</strong>putador mais vendido <strong>de</strong><br />

toda a história, o Personal Computer — o famoso PC. Des<strong>de</strong> então, a evolução dos <strong>com</strong>putadores tem<br />

se baseado principalmente no <strong>de</strong>senvolvimento <strong>de</strong> softwares <strong>de</strong> melhor qualida<strong>de</strong> e seguido a tendência<br />

<strong>de</strong> miniaturização <strong>de</strong> <strong>com</strong>ponentes, aumentando continuamente o po<strong>de</strong>r <strong>de</strong> processamento e espaço <strong>de</strong><br />

memória disponíveis, a custos cada vez menores.<br />

1.2 Arquitetura <strong>de</strong> Computadores<br />

Para melhor <strong>com</strong>preen<strong>de</strong>r a programação, é necessário conhecer um pouco mais sobre o funcionamento<br />

dos <strong>com</strong>putadores. Nesta Seção é apresentada uma noção básica sobre processadores e memórias.<br />

1.2.1 Memória<br />

A memória é a parte do <strong>com</strong>putador on<strong>de</strong> as operações a serem executadas pelo <strong>com</strong>putador (instruções)<br />

e as informações a serem processadas pelo mesmo (dados) são armazenadas.<br />

Na memória, o processador lê e escreve informações ao executar as instruções <strong>de</strong> um programa.<br />

Existem dois tipos <strong>de</strong> memória: a principal e a secundária. A principal, conhecida também <strong>com</strong>o<br />

RAM (Random Access Memory), possui as seguintes características:<br />

ˆ<br />

ˆ<br />

ˆ<br />

DRAFT<br />

Armazena dados e instruções do programa em execução;<br />

Proporciona ao <strong>com</strong>putador acesso rápido aos dados e instruções armazenados por ela;<br />

Só mantem as informações armazenadas enquanto o <strong>com</strong>putador estiver ligado.<br />

A memória secundária geralmente possui maior capacida<strong>de</strong> <strong>de</strong> armazenamento <strong>de</strong> dados e instruções,<br />

porém o tempo necessário para acessá-los é bem maior quando <strong>com</strong>parado ao da memória<br />

principal. As informações permanecem armazenadas mesmo após o <strong>de</strong>sligamento do <strong>com</strong>putador.<br />

Discos rígidos e CD-ROMs são exemplos <strong>de</strong> memórias secundárias.<br />

A unida<strong>de</strong> básica da memória é o dígito binário, conhecido <strong>com</strong>o “bit”. Um bit po<strong>de</strong> assumir<br />

apenas dois valores, normalmente 0 ou 1.<br />

A memória é formada por um conjunto <strong>de</strong> células, ou posições, sendo que cada uma po<strong>de</strong> guardar<br />

uma informação e possui um número <strong>de</strong> reconhecimento, conhecido <strong>com</strong>o “en<strong>de</strong>reço <strong>de</strong> memória”. É<br />

por meio <strong>de</strong>sse en<strong>de</strong>reço que os programas po<strong>de</strong>m acessar uma <strong>de</strong>terminada célula. Se uma célula<br />

1 http://www.ibm.<strong>com</strong><br />

2 http://www.hp.<strong>com</strong>


1.3. ALGORITMOS E PROGRAMAS 7<br />

possuir k bits, ela po<strong>de</strong>rá armazenar qualquer uma das 2 k <strong>com</strong>binações possíveis para os bits. A<br />

Figura 1.1 mostra um exemplo <strong>de</strong> memória <strong>com</strong> seis células en<strong>de</strong>reçáveis, on<strong>de</strong> cada célula possui<br />

<strong>de</strong>zesseis bits.<br />

1.2.2 Processador<br />

Figura 1.1: Exemplo <strong>de</strong> uma memória <strong>de</strong> 16 bits e 6 en<strong>de</strong>reços.<br />

O processador é o “cérebro” do <strong>com</strong>putador. Basicamente, o processador é responsável por buscar<br />

instruções na memória, <strong>de</strong>codificá-las para <strong>de</strong>terminar seus operandos (dados que serão usados ao<br />

processar a instrução) e quais operações <strong>de</strong>vem ser realizadas <strong>com</strong> os mesmos, e executar tais operações.<br />

Essas tarefas <strong>com</strong>põem o processo <strong>de</strong> execução <strong>de</strong> um programa.<br />

1.3 Algoritmos e Programas<br />

Apesar do nome pouco <strong>com</strong>um, diversos algoritmos são executados por pessoas <strong>com</strong>uns todos os dias.<br />

Ao escovar os <strong>de</strong>ntes, fazer um bolo ou trocar o pneu <strong>de</strong> um carro, diversos procedimentos são feitos<br />

em seqüência, seguindo uma certa or<strong>de</strong>m lógica.<br />

Para exemplificar a execução <strong>de</strong> um algoritmo, <strong>de</strong>screve-se a seguir alguns passos necessários para<br />

fazer algo simples, cotidiano, <strong>com</strong>o o ato <strong>de</strong> escovar os <strong>de</strong>ntes.<br />

1. Pegar a escova e a pasta <strong>de</strong> <strong>de</strong>ntes;<br />

2. Colocar um pouco <strong>de</strong> pasta sobre as cerdas da escova;<br />

3. Escovar os <strong>de</strong>ntes do maxilar inferior;<br />

4. Escovar os <strong>de</strong>ntes do maxilar superior;<br />

DRAFT<br />

5. Expelir da boca o excesso <strong>de</strong> espuma;<br />

6. Bochechar <strong>com</strong> um pouco <strong>de</strong> água;<br />

7. Lavar a escova e guardá-la;<br />

8. Enxugar o rosto.<br />

Após conhecer um exemplo <strong>com</strong>um <strong>de</strong> algoritmo, torna-se mais fácil <strong>com</strong>preen<strong>de</strong>r a sua <strong>de</strong>finição:<br />

Algoritmo é uma seqüência <strong>de</strong> operações que <strong>de</strong>ve ser executada em uma or<strong>de</strong>m<br />

<strong>de</strong>finida e não-ambígua, <strong>com</strong> o propósito <strong>de</strong> solucionar um <strong>de</strong>terminado<br />

problema.<br />

Apesar <strong>de</strong> conseguirem executar operações muito <strong>com</strong>plexas, os <strong>com</strong>putadores não são dotados da<br />

mesma capacida<strong>de</strong> <strong>de</strong> <strong>com</strong>preensão que os humanos. Uma seqüência <strong>de</strong> tarefas consi<strong>de</strong>rada simples e<br />

óbvia para uma pessoa qualquer po<strong>de</strong> ser in<strong>com</strong>preensível e pouco <strong>de</strong>talhada para um <strong>com</strong>putador.<br />

Voltando ao exemplo da escovação, um <strong>com</strong>putador po<strong>de</strong>ria consi<strong>de</strong>rá-lo in<strong>com</strong>pleto, pois há diversas<br />

questões sobre <strong>com</strong>o algum passo po<strong>de</strong> ser executado, por exemplo:


8<br />

CAPÍTULO 1. INTRODUÇÃO<br />

1. On<strong>de</strong> está a escova a ser usada?<br />

2. Quanto, exatamente, se <strong>de</strong>ve colocar <strong>de</strong> pasta sobre as cerdas?<br />

3. O que fazer se não houver pasta? Escovar mesmo sem a pasta ou interromper o processo <strong>de</strong><br />

escovação?<br />

Questões <strong>com</strong>o essas são facilmente contornadas por um humano, <strong>de</strong>cididas instantâneamente <strong>de</strong><br />

acordo <strong>com</strong> o ambiente que o cerca. Então, para que uma máquina também possa “<strong>de</strong>cidir” o que fazer<br />

em situações semelhantes, é necessário que se estabeleçam as condições iniciais (condições <strong>de</strong> entrada)<br />

e as finais (condições <strong>de</strong> saída) do problema. Dessa forma, ela saberá quais ferramentas po<strong>de</strong>rão ser<br />

usadas para atingir a condição <strong>de</strong> saída <strong>de</strong>sejada.<br />

Assim, o problema da escovação seria mais bem <strong>de</strong>finido da seguinte maneira:<br />

Condições <strong>de</strong> Entrada: Dentes sujos <strong>com</strong> restos <strong>de</strong> alimentos, uma escova <strong>de</strong>ntal em condições <strong>de</strong><br />

uso, 90 gramas <strong>de</strong> creme <strong>de</strong>ntal e 300 mililitros <strong>de</strong> água tratada.<br />

Condições <strong>de</strong> Saída: Dentes limpos (sem restos <strong>de</strong> alimentos visíveis), uma escova <strong>de</strong>ntal em condições<br />

<strong>de</strong> uso e 85 gramas <strong>de</strong> creme <strong>de</strong>ntal. Toda a quantida<strong>de</strong> <strong>de</strong> água <strong>de</strong>ve ser utilizada.<br />

Portanto, para um <strong>com</strong>putador, os algoritmos <strong>de</strong>finem o conjunto <strong>de</strong> ativida<strong>de</strong>s que ele <strong>de</strong>ve<br />

<strong>de</strong>sempenhar para solucionar um problema.<br />

Contudo, tão importante quanto saber “o que” escrever para a máquina é saber “<strong>com</strong>o” escrever.<br />

Para que um <strong>com</strong>putador possa executar um algoritmo, é necessário que esse algoritmo seja<br />

traduzido para uma linguagem <strong>de</strong> programação. Ao se traduzir um algoritmo para uma linguagem <strong>de</strong><br />

programação, obtém-se um programa.<br />

1.4 Técnica <strong>de</strong> Desenvolvimento <strong>de</strong> Programas<br />

Na maioria das vezes, o ato <strong>de</strong> programar não é uma tarefa simples. A sintaxe das linguagens <strong>de</strong><br />

programação é bem rígida e <strong>de</strong>ve ser respeitada fielmente para que o <strong>com</strong>putador a <strong>com</strong>preenda. Esquecer<br />

<strong>de</strong> um “;” no lugar on<strong>de</strong> é necessário, por exemplo, significa <strong>com</strong>prometer a execução <strong>de</strong> todo o<br />

programa (na verda<strong>de</strong>, o <strong>com</strong>putador po<strong>de</strong> nem <strong>com</strong>eçar a executá-lo). Ou pior, um programa teoricamente<br />

correto, que não apresente erros <strong>de</strong> sintaxe, po<strong>de</strong> fornecer um resultado incorreto. Encontrar<br />

o erro torna-se um enorme problema à medida que o programa cresce em tamanho e <strong>com</strong>plexida<strong>de</strong>.<br />

Para contornar a <strong>com</strong>plexida<strong>de</strong> dos programas, os construtores <strong>de</strong> software costumam fazer uso <strong>de</strong><br />

uma po<strong>de</strong>rosa técnica <strong>de</strong> programação, conhecida <strong>com</strong>o “técnica dos refinamentos sucessivos” 3 . Ela<br />

consiste basicamente em dividir um processo <strong>com</strong>plexo em processos-<strong>com</strong>ponentes menores, especificando<br />

apenas a entrada e a saída <strong>de</strong> cada um <strong>de</strong>les. E se, mesmo assim, alguns processos menores<br />

continuarem <strong>com</strong>plexos, repete-se a divisão no interior dos processos-<strong>com</strong>ponentes, gerando processos<br />

cada vez mais simplificados.<br />

Um exemplo prático do uso dos refinamentos sucessivos segue abaixo:<br />

=⇒ Algoritmo “Escovação <strong>de</strong>ntária”:<br />

DRAFT<br />

1. Pegar a escova e a pasta <strong>de</strong> <strong>de</strong>ntes;<br />

2. Colocar um pouco <strong>de</strong> pasta sobre as cerdas da escova;<br />

3. Escovar os <strong>de</strong>ntes do maxilar inferior;<br />

4. Escovar os <strong>de</strong>ntes do maxilar superior;<br />

5. Expelir da boca o excesso <strong>de</strong> espuma;<br />

6. Bochechar <strong>com</strong> um pouco <strong>de</strong> água;<br />

3 Também conhecida <strong>com</strong>o “dividir para conquistar”.


1.5. PARTES DE UM PROGRAMA 9<br />

7. Lavar a escova e guardá-la;<br />

8. Enxugar o rosto.<br />

=⇒ Processo-<strong>com</strong>ponente “Pegar a escova e a pasta <strong>de</strong> <strong>de</strong>ntes”:<br />

1. Enquanto não encontrar a escova e o tubo <strong>de</strong> pasta, continuar procurando por cada gaveta do<br />

armário;<br />

2. Caso tenham acabado as gavetas e não tenha encontrado a escova e o tubo, interromper a tarefa.<br />

=⇒ Processo-<strong>com</strong>ponente “Escovar os <strong>de</strong>ntes do maxilar inferior”:<br />

1. Com as cerdas da escova na posição vertical, fazer movimentos <strong>de</strong> vai-e-vem na região superior<br />

dos <strong>de</strong>ntes;<br />

2. Com as cerdas na posição horizontal, escovar a região frontal dos <strong>de</strong>ntes;<br />

3. Com as cerdas na posição horizontal, escovar a região <strong>de</strong>trás dos <strong>de</strong>ntes.<br />

=⇒ Processo-<strong>com</strong>ponente “escovar a região <strong>de</strong>trás dos <strong>de</strong>ntes”:<br />

1. Abrir bem a boca;<br />

2. Afastar a língua da região a ser escovada;<br />

3. Esfregar as cerdas da escova atrás dos <strong>de</strong>ntes.<br />

O exemplo anterior mostra apenas parte do processo <strong>de</strong> refinamentos, que <strong>de</strong>ve prosseguir até<br />

que cada ativida<strong>de</strong> esteja suficientemente <strong>de</strong>talhada, possibilitando que o <strong>com</strong>putador as reconheça e<br />

execute.<br />

1.5 Partes <strong>de</strong> um Programa<br />

Como dito anteriormente, os programas po<strong>de</strong>m ser <strong>com</strong>parados a diversas ativida<strong>de</strong>s do dia-a-dia <strong>de</strong><br />

qualquer pessoa. Um exemplo é o <strong>de</strong> receitas culinárias. Geralmente, essas seguem uma <strong>de</strong>terminada<br />

estrutura, <strong>com</strong>o abaixo:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Nome da receita;<br />

DRAFT<br />

Ingredientes: <strong>de</strong>screve todo o material necessário para o preparo da receita;<br />

Modo <strong>de</strong> preparo: <strong>de</strong>screve a forma <strong>de</strong> trabalhar <strong>com</strong> os ingredientes para que se obtenha o<br />

resultado esperado;<br />

Comentários sobre certos procedimentos ou ingredientes a fim <strong>de</strong> <strong>de</strong>talhar alguma peculiarida<strong>de</strong><br />

que o cozinheiro po<strong>de</strong>ria não conhecer previamente.<br />

A estrutura <strong>de</strong> um bom programa segue um mo<strong>de</strong>lo semelhante. Basicamente, um programa <strong>de</strong>ve<br />

conter quatro partes:<br />

ˆ<br />

ˆ<br />

Cabeçalho: contém informações sobre o programa, <strong>com</strong>o o seu nome;<br />

Dicionário <strong>de</strong> dados: <strong>de</strong>fine quais são os dados manipulados pelo programa;<br />

ˆ<br />

Corpo: <strong>de</strong>fine os procedimentos que o programa <strong>de</strong>ve executar;


10<br />

CAPÍTULO 1. INTRODUÇÃO<br />

ˆ<br />

Documentação: explica certos aspectos não muito claros do programa, tanto no corpo do programa<br />

quanto no cabeçalho ou no dicionário <strong>de</strong> dados.<br />

Um dos principais objetivos <strong>de</strong>ste tipo <strong>de</strong> estrutura é aumentar a legibilida<strong>de</strong> do programa, ou seja,<br />

facilitar o entendimento dos diversos processos que o programa executa. Um programa <strong>de</strong>ve valorizar<br />

a formatação, disposição física das linhas <strong>de</strong> código, para facilitar seu entendimento. Colocar cada<br />

<strong>com</strong>ando em uma linha e inserir uma linha em branco entre blocos <strong>de</strong> <strong>com</strong>andos <strong>de</strong> finalida<strong>de</strong> <strong>com</strong>um<br />

são regras básicas para uma boa formatação. Os programas <strong>de</strong>vem ser lidos e entendidos por quem os<br />

escreveu e por outras pessoas, uma vez que po<strong>de</strong>m necessitar <strong>de</strong> correção, manutenção, modificação<br />

ou apenas <strong>de</strong> serem <strong>com</strong>preendidos por um simples usuário.<br />

Para ilustrar essa estrutura, apresenta-se a seguir um programa, Pseudocódigo 1.1, que efetua o<br />

cálculo das raízes reais <strong>de</strong> uma equação <strong>de</strong> segundo grau. Os dados <strong>de</strong> entrada do programa são os<br />

três coeficientes da equação e ele <strong>de</strong>verá apresentar ao usuário as raízes reais da mesma, caso existam.<br />

Pseudocódigo 1.1 Cálculo das raízes reais <strong>de</strong> uma equação <strong>de</strong> segundo grau.<br />

Descrição: Calcula as raízes reais <strong>de</strong> uma equação <strong>de</strong> segundo grau.<br />

Dados <strong>de</strong> Entrada: Os três coeficientes da equação.<br />

Saída do Programa: Raízes reais da equação.<br />

Obter os coeficientes da equaç~ao;<br />

Calcular o discriminante ( <strong>de</strong>lta );<br />

Calcular as raízes pelo processo <strong>com</strong>ponente "Cálculo das Raízes ";<br />

Utilizando a técnica dos refinamentos sucessivos, na última linha do Pseudocódigo 1.1 ocorre<br />

a execução do processo <strong>com</strong>ponente Cálculo das Raízes, que, a partir dos valores dos coeficientes<br />

lidos e do discriminante calculado, encontra os valores das raízes reais da equação. No geral, o processo<br />

<strong>com</strong>ponente Cálculo das Raízes <strong>de</strong>ve conter os passos <strong>de</strong>scritos no Pseudocódigo 1.2.<br />

Pseudocódigo 1.2 Processo <strong>com</strong>ponente para o cálculo das raízes.<br />

Processo - <strong>com</strong>ponente "Cálculo das Raízes ":<br />

Verificar a exist^encia <strong>de</strong> raízes reais ;<br />

SE possuir raízes reais :<br />

Calcular as raízes ;<br />

Apresentar na tela os valores das raízes ;<br />

SEN~AO:<br />

Apresentar na tela a mensagem : "N~ao existem raízes reais !";<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente "Cálculo das Raízes "<br />

DRAFT<br />

No Exemplo 1.1, o programa para o cálculo das raízes está transcrito para a linguagem <strong>de</strong> programação<br />

C. Deve-se <strong>de</strong>stacar que o <strong>texto</strong> escrito entre os símbolos “/*” e “*/” é sempre ignorado<br />

pelo <strong>com</strong>putador, não alterando em nada o funcionamento do programa. Porém, esse <strong>texto</strong> serve para<br />

<strong>com</strong>entar o código e <strong>de</strong>ixá-lo mais claro. Po<strong>de</strong>-se fazê-los também utilizando o símbolo “//”, que<br />

transforma em <strong>com</strong>entário tudo aquilo que estiver a sua direita, até o final da linha.<br />

1 /*<br />

2 Programa para calculo das raizes <strong>de</strong> segundo grau .<br />

3 Dados <strong>de</strong> entrada : Os coeficientes a, b e c <strong>de</strong> uma equacao<br />

4 da forma ax ^2 + bx + c = 0<br />

5 Dados <strong>de</strong> saida : Imprime na tela as raizes reais da equacao , caso existam .<br />

6 Restricao : Nao se consi<strong>de</strong>ra o zero <strong>com</strong>o um possivel valor <strong>de</strong> a.<br />

7 */<br />

8<br />

9 # inclu<strong>de</strong> <br />

10 # inclu<strong>de</strong> // Biblioteca <strong>de</strong> funcoes primitivas <strong>com</strong>o scanf e printf


1.6.<br />

TRADUÇÃO DE PROGRAMAS 11<br />

11<br />

12 int main (){<br />

13 float a; // Coeficiente angular .<br />

14 float b; // Coeficiente linear .<br />

15 float c; // Termo in<strong>de</strong>pen<strong>de</strong>nte .<br />

16 float <strong>de</strong>lta ; // Discriminante .<br />

17 float raiz1 ; // A primeira raiz .<br />

18 float raiz2 ; // A segunda raiz .<br />

19<br />

20 // Obtencao dos coeficientes .<br />

21 scanf ("%f %f %f", &a, &b, &c);<br />

22<br />

23 // Calculo do discriminante ( <strong>de</strong>lta ).<br />

24 <strong>de</strong>lta = b * b - 4 * a * c;<br />

25<br />

26 // Calculo das raizes .<br />

27 if( <strong>de</strong>lta < 0){<br />

28 printf ("A equacao nao possui raizes reais ");<br />

29 } else {<br />

30 raiz1 = (-b + sqrt ( <strong>de</strong>lta )) / (2 * a);<br />

31 raiz2 = (-b - sqrt ( <strong>de</strong>lta )) / (2 * a);<br />

32 printf ("As raizes da equacao sao : %f e %f", raiz1 , raiz2 );<br />

33 }<br />

34<br />

35 return 0;<br />

36 }<br />

Exemplo 1.1: Programa para o cálculo das raízes reais <strong>de</strong> uma equação <strong>de</strong> segundo grau.<br />

Na linguagem C, o cabeçalho dos programas sempre correspon<strong>de</strong> à frase int main() e o início do<br />

corpo do programa é marcado pela primeira chave “{”, assim <strong>com</strong>o o final é marcado pela última chave<br />

“}”. As linhas 9 e 10 permitem o uso dos <strong>com</strong>andos sqrt e printf (o significado <strong>de</strong>sses <strong>com</strong>andos é<br />

explicado no próximo capítulo). O final do programa return 0 é o retorno da função e será explicado<br />

<strong>de</strong>talhadamente na seção 3.6. De acordo <strong>com</strong> a estrutura <strong>de</strong> programa apresentada no início <strong>de</strong>sta<br />

seção, as linhas 13 a 18 <strong>com</strong>põem o dicionário <strong>de</strong> dados e o restante <strong>com</strong>põe o corpo do programa. A<br />

documentação está inserida no programa em forma <strong>de</strong> <strong>com</strong>entários, <strong>com</strong>o as linhas 1 a 7, 20, 23 e 26.<br />

Vale <strong>de</strong>stacar a importância da disposição física das linhas <strong>de</strong> código para o fácil entendimento do<br />

programa. A hierarquização <strong>de</strong> elementos por meio <strong>de</strong> espaços em branco é chamada <strong>de</strong> in<strong>de</strong>ntação.<br />

O trecho <strong>de</strong> programa relacionado ao cálculo das raízes no Exemplo 1.1 <strong>de</strong>monstra <strong>com</strong>o a in<strong>de</strong>ntação<br />

po<strong>de</strong> facilitar a visualização da mudança do fluxo do programa.<br />

Normalmente, linhas <strong>de</strong> código <strong>com</strong> mesma in<strong>de</strong>ntação são executadas <strong>de</strong> maneira contínua, uma<br />

após a outra. Uma mudança na in<strong>de</strong>ntação indica uma mudança nesse fluxo <strong>de</strong> execução do programa.<br />

No próximo capítulo são apresentadas diversas maneiras <strong>de</strong> mudar esse fluxo.<br />

DRAFT<br />

1.6 Tradução <strong>de</strong> Programas<br />

Apesar do que foi dito na seção 1.3, para ser executado pelo <strong>com</strong>putador, um programa ainda precisa<br />

ser traduzido para uma linguagem mais simples que as linguagens <strong>de</strong> programação: a linguagem <strong>de</strong><br />

máquina. Chama-se <strong>de</strong> “código fonte” o arquivo que contém o conjunto <strong>de</strong> instruções escritas em<br />

uma <strong>de</strong>terminada linguagem <strong>de</strong> programação, normalmente familiar ao programador. Já o arquivo<br />

que contém estas instruções traduzidas para linguagem <strong>de</strong> máquina é chamado <strong>de</strong> “código objeto”.<br />

Para efetuar essa tradução, é necessário aplicar um programa, ou conjunto <strong>de</strong> programas, que<br />

receba o código fonte e gere o código objeto. A seguir, <strong>de</strong>screvem-se dois métodos básicos para um<br />

programa tradutor efetuar essa tarefa: a <strong>com</strong>pilação e a interpretação <strong>de</strong> um código fonte.<br />

1.6.1 Compilação<br />

O processo <strong>de</strong> <strong>com</strong>pilação efetua a tradução integral do programa fonte para o código <strong>de</strong> máquina.<br />

Uma vez traduzido, o programa em linguagem <strong>de</strong> máquina po<strong>de</strong> ser executado diretamente. A Figura


12<br />

CAPÍTULO 1. INTRODUÇÃO<br />

1.2 ilustra esse processo.<br />

A gran<strong>de</strong> vantagem <strong>de</strong>sse método <strong>de</strong> tradução é a rapi<strong>de</strong>z na execução dos programas, pois não é<br />

necessário fazer qualquer tradução durante a execução. Porém, o código objeto gerado pela <strong>com</strong>pilação<br />

é, geralmente, específico para um <strong>de</strong>terminado tipo <strong>de</strong> arquitetura <strong>de</strong> <strong>com</strong>putador. Assim, é necessário<br />

uma nova <strong>com</strong>pilação do programa para cada tipo diferente <strong>de</strong> arquitetura.<br />

A linguagem C, adotada neste livro, é um exemplo <strong>de</strong> linguagem <strong>de</strong> programação <strong>com</strong>pilada.<br />

1.6.2 Interpretação<br />

No processo <strong>de</strong> interpretação, cada instrução do código fonte é traduzida no instante imediatamente<br />

anterior à execução <strong>de</strong>la. Desse modo, em contraste <strong>com</strong> a <strong>com</strong>pilação, a tradução e execução <strong>de</strong><br />

programas interpretados po<strong>de</strong>m ser vistas <strong>com</strong>o um processo único (veja as Figuras 1.2 e 1.3).<br />

Figura 1.2: Processo <strong>de</strong> <strong>com</strong>pilação.<br />

Figura 1.3: Processo <strong>de</strong> interpretação.<br />

Apesar <strong>de</strong> ser um processo mais lento que a <strong>com</strong>pilação, a interpretação apresenta ocasionalmente<br />

vantagens em relação ao outro método <strong>com</strong>o flexibilida<strong>de</strong> na construção <strong>de</strong> programas e <strong>de</strong>puração <strong>de</strong><br />

códigos.<br />

1.7 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

DRAFT<br />

O processador é o <strong>com</strong>ponente do <strong>com</strong>putador responsável por executar os programas armazenados<br />

na memória.<br />

A memória é responsável por armazenar os programas e os dados. A unida<strong>de</strong> básica da memória<br />

é o bit.<br />

Algoritmo é uma seqüência <strong>de</strong> operações que <strong>de</strong>ve ser executada em uma or<strong>de</strong>m <strong>de</strong>finida e nãoambígua,<br />

<strong>com</strong> o propósito <strong>de</strong> solucionar um <strong>de</strong>terminado problema. Ao traduzir-se um algoritmo<br />

para uma linguagem <strong>de</strong> programação, obtém-se um programa.<br />

ˆ<br />

A Técnica <strong>de</strong> Refinamentos Sucessivos consiste, basicamente, em dividir sucessivamente problemas<br />

<strong>com</strong>plexos em diversos problemas menores e mais simples.<br />

ˆ<br />

Um programa bem estruturado <strong>de</strong>ve conter as seguintes partes bem <strong>de</strong>finidas: cabeçalho, dicionário<br />

<strong>de</strong> dados, corpo e documentação.


1.8.<br />

EXERCÍCIOS PROPOSTOS 13<br />

ˆ<br />

Basicamente, existem dois mecanismos <strong>de</strong> tradução <strong>de</strong> programas para linguagem <strong>de</strong> máquina:<br />

<strong>com</strong>pilação e interpretação. Na <strong>com</strong>pilação, o código fonte é totalmente traduzido antes <strong>de</strong> ser<br />

executado. Já na interpretação, a tradução do código fonte e a execução do programa ocorrem<br />

quase simultaneamente, <strong>com</strong>o um processo único.<br />

1.8 Exercícios Propostos<br />

1. Qual é o papel do processador?<br />

2. Qual é o papel da memória?<br />

3. Consi<strong>de</strong>re uma memória que possua células <strong>de</strong> 8 bits cada uma. Qual o número <strong>de</strong> possíveis<br />

informações diferentes que cada célula po<strong>de</strong> armazenar?<br />

4. Utilizando o conceito <strong>de</strong> algoritmo apresentado no capítulo, <strong>de</strong>screva o ato <strong>de</strong> trocar um pneu<br />

furado <strong>de</strong> um carro. Não se esqueça <strong>de</strong> estabelecer as condições iniciais do problema (por<br />

exemplo, carro <strong>com</strong> um pneu dianteiro furado, se a chave <strong>de</strong> roda está no carro, se o carro está<br />

parado em uma la<strong>de</strong>ira etc) e as condições <strong>de</strong> saída (por exemplo carro parado, freado etc).<br />

5. Use a Técnica <strong>de</strong> Refinamentos Sucessivos para <strong>de</strong>talhar as seguintes ativida<strong>de</strong>s:<br />

(a) Montagem <strong>de</strong> uma barraca <strong>de</strong> camping;<br />

(b) Preparação <strong>de</strong> um bolo <strong>de</strong> aniversário;<br />

(c) Cálculo da distância entre dois pontos no plano cartesiano.<br />

DRAFT


Capítulo 2<br />

Conceitos Básicos<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Coautores:<br />

André Boechat<br />

Bruno Pandolfi(in memoriam)<br />

Juan <strong>de</strong> Souza<br />

Luiz Bueloni<br />

Thales Carvalho<br />

Apresentar o conceito <strong>de</strong> variável: <strong>de</strong>claração, inicialização, atribuição e manipulação;<br />

Estudar os principais tipos <strong>de</strong> dados básicos e expressões válidas;<br />

Mostrar <strong>com</strong>o é feita a <strong>de</strong>finição <strong>de</strong> variáveis e constantes;<br />

Apresentar os <strong>com</strong>andos elementares usados em programas.<br />

A i<strong>de</strong>ia <strong>de</strong> resolver problemas formalizando a solução através do emprego <strong>de</strong> algoritmos é a espinha<br />

dorsal da programação procedural, na qual as tarefas são prescritas ao <strong>com</strong>putador por meio <strong>de</strong> uma<br />

sequência <strong>de</strong> operações básicas.<br />

Este capítulo trata do estudo dos conceitos e operações elementares da programação, fornecendo<br />

uma base sólida que, mais adiante, serve para construir algoritmos progressivamente mais <strong>com</strong>plexos<br />

e resolver problemas cada vez mais elaborados.<br />

2.1 Variáveis e Células <strong>de</strong> Memória<br />

DRAFT<br />

Qualquer algoritmo tem por finalida<strong>de</strong> produzir algum resultado útil para <strong>com</strong>por a solução <strong>de</strong> um<br />

problema. Os algoritmos <strong>com</strong>putacionais, em sua maioria, operam sobre um conjunto <strong>de</strong> dados para<br />

produzir resultados <strong>de</strong> acordo <strong>com</strong> a necessida<strong>de</strong> da tarefa em questão.<br />

Quando corretamente transcritos para uma linguagem <strong>de</strong> programação, os algoritmos são chamados<br />

<strong>de</strong> programas e po<strong>de</strong>m ser executados pelo <strong>com</strong>putador. É necessário, todavia, armazenar as<br />

informações utilizadas pelos programas em um local organizado e seguro, para que as consultas e<br />

alterações sejam efetuadas <strong>de</strong> maneira coerente e livre <strong>de</strong> erros. Os <strong>com</strong>putadores utilizam a memória<br />

para armazenar os dados <strong>de</strong> um programa em execução.<br />

Como dito na Seção 1.2.1, a memória po<strong>de</strong> ser entendida <strong>com</strong>o uma sequência <strong>de</strong> células, cada<br />

célula contém um número pré-<strong>de</strong>finido <strong>de</strong> bits que varia <strong>de</strong> acordo <strong>com</strong> a arquitetura do <strong>com</strong>putador<br />

po<strong>de</strong>ndo armazenar uma porção dos dados <strong>de</strong> um programa. Graças a essa or<strong>de</strong>nação sequencial,<br />

cada célula possui um número i<strong>de</strong>ntificador chamado en<strong>de</strong>reço, que está relacionado <strong>com</strong> a posição<br />

que a célula ocupa na sequência. Por meio dos en<strong>de</strong>reços é possível acessar qualquer célula para ler<br />

ou alterar seu conteúdo. A Figura 2.1 esboça essa i<strong>de</strong>ia, porém, em contraste <strong>com</strong> a Figura 1.1, omite<br />

a representação dos bits.<br />

As seis células <strong>de</strong> memória da Figura 2.1 po<strong>de</strong>m guardar valores em seus interiores. Cada célula é<br />

apontada por um en<strong>de</strong>reço único e sequencial.<br />

14


2.1.<br />

VARIÁVEIS E CÉLULAS DE MEMÓRIA 15<br />

Figura 2.1: Mo<strong>de</strong>lo para a estrutura da memória do <strong>com</strong>putador, mostrando uma fração <strong>de</strong> seis células,<br />

seus en<strong>de</strong>reços e conteúdos.<br />

A estrutura da memória favorece a execução <strong>de</strong> suas duas operações básicas: leitura e escrita. A<br />

leitura é o processo <strong>de</strong> consulta do conteúdo da célula. Essa operação não altera o valor guardado na<br />

célula.<br />

A escrita é o processo <strong>de</strong> armazenamento <strong>de</strong> um novo dado na célula indicada por um en<strong>de</strong>reço<br />

conhecido. Após a execução da escrita, o valor que estava anteriormente armazenado na célula é<br />

perdido.<br />

Um algoritmo para o cálculo do valor da conta mensal <strong>de</strong> energia elétrica é um bom exemplo para<br />

<strong>com</strong>preen<strong>de</strong>r as operações básicas da memória. Os dados <strong>de</strong> entrada <strong>de</strong>sse algoritmo são: a leitura<br />

atual do medidor, a leitura registrada no mês anterior e o preço do quilowatt-hora (kWh) — unida<strong>de</strong><br />

<strong>com</strong>ercial <strong>de</strong> energia elétrica.<br />

Na prática, o que se faz para calcular o valor da conta é encontrar a diferença entre a leitura<br />

atual do medidor e a leitura do mês anterior e multiplicar esse valor pelo preço do quilowatt-hora. O<br />

algoritmo <strong>com</strong>putacional, por sua vez, é <strong>de</strong>scrito no Pseudocódigo 2.1.<br />

Pseudocódigo 2.1 Cálculo da conta <strong>de</strong> energia elétrica utilizando os en<strong>de</strong>reços das células <strong>de</strong><br />

memória.<br />

Descrição: Calcular o valor da conta <strong>de</strong> energia elétrica.<br />

Dados <strong>de</strong> Entrada: Células 43 e 46 contendo, respectivamente, a leitura atual e a anterior; e valor unitário<br />

do kWh na célula 44.<br />

Saída do Programa: Valor da conta, armazenada na célula 42.<br />

Subtrair o conteúdo da célula 43 do conteúdo da 46 e guardar na célula 41;<br />

Multiplicar o conteúdo da célula 41 pelo conteúdo da 44 e guardar na célula 42;<br />

No Pseudocódigo 2.1, o <strong>com</strong>putador lê os conteúdos das células 43 e 46 (que guardam os valores<br />

das leituras atual e anterior, respectivamente), realiza a subtração e o resultado é guardado na célula<br />

41. Posteriormente, essa diferença é lida e seu valor multiplicado pelo conteúdo da célula 44, que<br />

guarda o valor do preço unitário do kWh. Finalmente, o valor da conta é guardado na célula 42.<br />

A<strong>com</strong>panhando a <strong>de</strong>scrição acima é possível chegar à situação encontrada na Figura 2.2.<br />

DRAFT<br />

Figura 2.2: Conteúdo da memória após execução do algoritmo que calcula o valor <strong>de</strong> uma conta <strong>de</strong> energia<br />

elétrica.<br />

No início da história da programação, percebeu-se que acessar a memória por meio <strong>de</strong> en<strong>de</strong>reços<br />

era trabalhoso <strong>de</strong>mais e causa constante <strong>de</strong> erros. Isso porque o programador <strong>de</strong>veria escolher os<br />

en<strong>de</strong>reços das células <strong>com</strong> as quais iria trabalhar, tanto das células que teriam valores a serem lidos<br />

quanto das que seriam usadas para a escrita <strong>de</strong> resultados.<br />

Essa situação confusa é observável no exemplo da conta <strong>de</strong> energia elétrica. Sem o <strong>com</strong>entário no<br />

início do Pseudocódigo 2.1, seria impossível ter a mínima i<strong>de</strong>ia do que o programa faz em cada passo.


16<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Isso torna difícil não só a escrita, mas também a correção dos programas.<br />

Para resolver essa questão, o conceito <strong>de</strong> variável foi criado. Uma variável nada mais é do que<br />

uma abstração para o en<strong>de</strong>reço <strong>de</strong> memória. Com o emprego <strong>de</strong> variáveis, as células <strong>de</strong> memória são<br />

referenciadas nos programas por meio <strong>de</strong> rótulos, <strong>de</strong>finidos <strong>com</strong> ajuda do bom-senso do programador.<br />

O <strong>com</strong>pilador fica encarregado do trabalho <strong>de</strong> transformar rótulos em en<strong>de</strong>reços para que as operações<br />

<strong>de</strong> acesso à memória sejam realizadas.<br />

O Pseudocódigo 2.2 mostra <strong>com</strong>o fica o programa que calcula o valor da conta <strong>de</strong> energia elétrica,<br />

agora escrito utilizando variáveis.<br />

Pseudocódigo 2.2 Cálculo da conta <strong>de</strong> energia elétrica utilizando variáveis.<br />

Descrição: Calcular o valor da conta <strong>de</strong> energia elétrica.<br />

Dados <strong>de</strong> Entrada: A leitura atual, a anterior e o preço unitário do kWh.<br />

Saída do Programa: Valor da conta.<br />

Subtrair o conteúdo da variável " leituraAtual " do conteúdo da variável<br />

" leituraAnterior " e guardar na variável " diferenca ";<br />

Multiplicar o conteúdo da variável " diferenca " pelo conteúdo da variável<br />

" valorUnitario " e guardar na variável " valorConta ";<br />

Figura 2.3: Uma possível tradução para en<strong>de</strong>reços <strong>de</strong> memória, a partir dos rótulos do código que utiliza<br />

variáveis.<br />

A partir do Pseudocódigo 2.2, um <strong>com</strong>pilador po<strong>de</strong> converter os rótulos para posições na memória,<br />

evitando que o programador tenha que se preocupar em manipulá-las. Uma possível tradução é exibida<br />

na Figura 2.3.<br />

Como visto nos exemplos <strong>de</strong>sta seção, o uso <strong>de</strong> variáveis em um algoritmo reduz a quantida<strong>de</strong> <strong>de</strong><br />

<strong>com</strong>entários explicativos, pois sua leitura é mais simples e seu entendimento é mais fácil. Em caso <strong>de</strong><br />

erros, a correção do programa é muito mais rápida e eficiente.<br />

Apresentados os conceitos <strong>de</strong> variável e células <strong>de</strong> memória, é válido abordar um outro significado<br />

<strong>de</strong> programa. Trata-se <strong>de</strong> consi<strong>de</strong>rar os programas <strong>com</strong>o sendo processos <strong>de</strong> mudança <strong>de</strong> estados.<br />

Nessa abordagem, os dados <strong>de</strong> entrada, escritos em suas respectivas variáveis, são consi<strong>de</strong>rados<br />

o estado inicial do programa. A partir daí, realiza-se uma sequência <strong>de</strong> operações para chegar a um<br />

estado final. A cada operação, diz-se que o programa está em um novo estado intermediário. O estado<br />

final é atingido quando a tarefa em questão é consi<strong>de</strong>rada <strong>com</strong>o realizada.<br />

A transição do estado inicial para o estado final po<strong>de</strong> ser efetuada <strong>de</strong> diversas maneiras. Conforme<br />

po<strong>de</strong> ser visto mais adiante neste capítulo, é possível escolher entre duas ou mais sequências <strong>de</strong><br />

<strong>com</strong>andos, bem <strong>com</strong>o repeti-las, <strong>de</strong> acordo <strong>com</strong> o estado intermediário em que o programa se encontra.<br />

2.2 I<strong>de</strong>ntificadores<br />

DRAFT<br />

Em geral, as linguagens <strong>de</strong> alto nível possuem elementos <strong>de</strong>finidos pela própria linguagem — símbolos<br />

para operadores, nome <strong>de</strong> <strong>com</strong>andos, etc — e os elementos <strong>de</strong>finidos pelo programador — i<strong>de</strong>ntificadores,<br />

<strong>com</strong>entários, etc.<br />

Um i<strong>de</strong>ntificador é um símbolo que po<strong>de</strong> representar alguma entida<strong>de</strong> criada pelo programador,<br />

<strong>com</strong>o uma variável, por exemplo. Cada linguagem <strong>de</strong>fine uma regra para formação <strong>de</strong> i<strong>de</strong>ntificadores.<br />

Em geral, sempre é possível utilizar uma sequência <strong>de</strong> caracteres alfanuméricos — letras ou dígitos,


2.3. COMANDO DE ATRIBUIÇÃO 17<br />

sem acentos e sem cedilha — sendo que o primeiro caractere <strong>de</strong>ve ser obrigatoriamente alfabético. Os<br />

Exemplos 2.1 e 2.2 apresentam, respectivamente, nomes corretos e nomes inválidos <strong>de</strong> variáveis na<br />

linguagem C.<br />

Algumas linguagens, <strong>com</strong>o C, fazem diferenciação entre letras maiúsculas e minúsculas. Desta<br />

forma, uma variável <strong>de</strong> nome Saldo é consi<strong>de</strong>rada diferente <strong>de</strong> outra <strong>de</strong> nome saldo, ou, ainda, <strong>de</strong><br />

nome SALDO. É importante ressalvar que não é uma boa prática <strong>de</strong> programação criar i<strong>de</strong>ntificadores<br />

que apenas se diferenciem pelo formato das letras, <strong>com</strong>o no exemplo do saldo, pois isso tem impacto<br />

negativo na legibilida<strong>de</strong> dos programas.<br />

1 abc<br />

2 x1<br />

3 y2<br />

4 letra<br />

5 SOMA_TOTAL<br />

6 B_32<br />

Exemplo 2.1: Nomes válidos <strong>de</strong> variáveis, concordando <strong>com</strong> as regras <strong>de</strong> nomenclatura.<br />

1 fim ? // "?" nao e um caractere alfanumerico<br />

2 % percentual % // "%" nao e um caractere alfanumerico<br />

3 123 quatro // Iniciado por numero<br />

4 ! hola ! // "!" nao e um caractere alfanumerico<br />

5 @ARROBA // "@" nao e um caractere alfanumerico<br />

Exemplo 2.2: Nomes inválidos <strong>de</strong> variáveis.<br />

Normalmente, em gran<strong>de</strong>s projetos <strong>de</strong> software, são adotados padrões para a escrita dos i<strong>de</strong>ntificadores<br />

a fim <strong>de</strong> que os programadores possam trocar seus códigos, entendê-los e alterá-los sem gran<strong>de</strong><br />

dificulda<strong>de</strong>. Neste <strong>texto</strong>, é adotado <strong>com</strong>o regra na escrita:<br />

ˆ<br />

ˆ<br />

Nomes simples: <strong>com</strong>eçados <strong>com</strong> letra minúscula e <strong>de</strong>mais caracteres minúsculos;<br />

Nomes <strong>com</strong>postos: primeira parte é iniciada por letra minúscula e as <strong>de</strong>mais partes iniciadas<br />

por letra maiúscula. Os <strong>de</strong>mais caracteres são minúsculos.<br />

Como dito na Seção 1.5, um bom programa <strong>de</strong>ve necessariamente ser legível e <strong>de</strong> fácil <strong>com</strong>preensão.<br />

A escolha dos nomes dos i<strong>de</strong>ntificadores influenciam diretamente esses dois aspectos. Logo, é muito<br />

importante que os nomes sejam significativos, <strong>de</strong>ixando bem clara a sua referência.<br />

A fim <strong>de</strong> contrastar <strong>com</strong> o que foi proposto no Exemplo 2.1, o Exemplo 2.3 ilustra a convenção<br />

proposta, apresentando nomes significativos para variáveis. Neste, o rótulo das variáveis já é suficiente<br />

para informar a funcionalida<strong>de</strong> das mesmas, tornando rápida a <strong>com</strong>preensão do programa que as utiliza<br />

e dispensando a necessida<strong>de</strong> <strong>de</strong> <strong>com</strong>entários.<br />

1 <strong>de</strong>lta<br />

2 raiz1<br />

3 ida<strong>de</strong><br />

4 letra<br />

5 percentualDeLucro<br />

6 primeiraLetra<br />

7 indiceBovespa<br />

DRAFT<br />

Exemplo 2.3: Nomes significativos para variáveis.<br />

2.3 Comando <strong>de</strong> Atribuição<br />

Os pseudocódigos da Seção 2.1 não mostram <strong>com</strong>o os conteúdos das variáveis <strong>de</strong> entrada são alterados<br />

para que o cálculo seja efetuado coerentemente. Em outras palavras, não é mostrado <strong>com</strong>o as variáveis


18<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

leituraAtual, leituraAnterior e valorUnitario são inicializadas. O responsável pela alteração <strong>de</strong>ssas<br />

variáveis, assim <strong>com</strong>o <strong>de</strong> qualquer outra, é o <strong>com</strong>ando <strong>de</strong> atribuição.<br />

O <strong>com</strong>ando <strong>de</strong> atribuição é muito importante e, <strong>com</strong> certeza, é o mais utilizado. É por meio <strong>de</strong>le<br />

que as variáveis po<strong>de</strong>m ter seus valores (conteúdos) alterados. Por isso, o <strong>com</strong>ando <strong>de</strong> atribuição está<br />

diretamente ligado às operações <strong>de</strong> memória.<br />

No Exemplo 2.4 é transcrito o algoritmo do cálculo da conta <strong>de</strong> energia elétrica para um trecho <strong>de</strong><br />

código na linguagem C.<br />

1 leituraAtual = 125;<br />

2 leituraAnterior = 25;<br />

3 valorUnitario = 2;<br />

4 diferenca = leituraAtual - leituraAnterior ;<br />

5 valorConta = diferenca * valorUnitario ;<br />

Exemplo 2.4: Cálculo do valor da conta <strong>de</strong> energia elétrica.<br />

No Exemplo 2.4, o símbolo “=” representa o <strong>com</strong>ando <strong>de</strong> atribuição. Em seu lado esquerdo sempre<br />

haverá a variável <strong>de</strong>stino, na qual será escrito o resultado da expressão do lado direito do <strong>com</strong>ando.<br />

As expressões mais simples são as que contêm valores constantes, tais <strong>com</strong>o as que ocorrem nas linhas<br />

1, 2 e 3 do Exemplo 2.4.<br />

Essas três linhas são omitidas propositalmente do Pseudocódigo 2.2 para torná-lo mais simples.<br />

Entretanto, elas não são difíceis <strong>de</strong> <strong>com</strong>preen<strong>de</strong>r, pois apenas informam ao <strong>com</strong>putador quais valores<br />

ele <strong>de</strong>ve manipular para encontrar o resultado esperado: o valor da conta mensal <strong>de</strong> energia elétrica.<br />

Dessa forma, o <strong>com</strong>ando da linha 2 do Exemplo 2.4 simplesmente realiza a atribuição do valor<br />

125 à variável leituraAtual. A partir da efetivação <strong>de</strong>sse <strong>com</strong>ando, o conteúdo <strong>de</strong>ssa variável po<strong>de</strong> ser<br />

usado para os cálculos. O mesmo vale para as <strong>de</strong>mais variáveis.<br />

As linhas 4 e 5 do Exemplo 2.4 são transcrições diretas dos dois passos do algoritmo da conta<br />

<strong>de</strong> energia. O que ocorre <strong>de</strong> diferente é que o valor a ser atribuído às variáveis do lado esquerdo é<br />

primeiramente calculado na expressão para, em seguida, ser guardado na variável correspon<strong>de</strong>nte. A<br />

Figura 2.4 representa graficamente esse processo.<br />

DRAFT<br />

Figura 2.4: Representação gráfica da linha 4 do Exemplo 2.4.<br />

O <strong>com</strong>ando <strong>de</strong> atribuição é executado sempre da mesma maneira pelo <strong>com</strong>putador. Em primeiro<br />

lugar a expressão que está do lado direito do <strong>com</strong>ando é calculada e, para isso, todas as variáveis que<br />

aparecem têm seus valores lidos e lançados na expressão. Após o fim dos cálculos na expressão, o<br />

<strong>com</strong>putador escreve o resultado na variável <strong>de</strong>stino, no lado esquerdo. Basicamente, a forma geral do<br />

<strong>com</strong>ando <strong>de</strong> atribuição em C é a seguinte:<br />

= ;<br />

É muito importante <strong>com</strong>preen<strong>de</strong>r a diferença significativa existente entre o <strong>com</strong>ando <strong>de</strong> atribuição<br />

e a igualda<strong>de</strong> matemática. Em muitas linguagens <strong>de</strong> programação (C, por exemplo) a atribuição<br />

é representada pelo símbolo “=”, o que po<strong>de</strong> provocar interpretações equivocadas. O Exemplo 2.5<br />

mostra um trecho <strong>de</strong> programa que geralmente causa confusão para os programadores iniciantes.


2.4. TIPOS DE DADOS 19<br />

1 contador = 10;<br />

2 contador = contador + 1;<br />

Exemplo 2.5: Incremento <strong>de</strong> uma variável usando o <strong>com</strong>ando <strong>de</strong> atribuição.<br />

No Exemplo 2.5 ocorrem duas atribuições. A primeira ocorre na linha 1, sendo mais um exemplo<br />

simples <strong>de</strong> inicialização <strong>de</strong> uma variável, <strong>com</strong>o já discutido anteriormente. Na linha 2, a variável<br />

contador aparece em ambos os lados da expressão, o que po<strong>de</strong> parecer um absurdo matemático.<br />

Porém, é necessário lembrar que, nesse con<strong>texto</strong>, o símbolo “=” atribui o valor da expressão da direita<br />

à variável que aparece à esquerda. Ou seja, avalia-se primeiro o resultado da expressão à direita<br />

(10 + 1 = 11) e, posteriormente, atribui-se o valor à variável à esquerda (contador = 11). Isso é<br />

representado graficamente na Figura 2.5.<br />

Figura 2.5: Representação gráfica do incremento <strong>de</strong> uma variável.<br />

Mais uma observação é necessária: O programador <strong>de</strong>ve ficar atento aos tipos <strong>de</strong> dados manipulados<br />

em um <strong>com</strong>ando <strong>de</strong> atribuição, pois o tipo da expressão à direita <strong>de</strong>ve ser <strong>com</strong>patível <strong>com</strong> o tipo da<br />

variável à esquerda. A manipulação dos tipos <strong>de</strong> dados é <strong>de</strong>talhada na Seção 2.4.<br />

2.4 Tipos <strong>de</strong> Dados<br />

Um tipo <strong>de</strong> dados <strong>de</strong>limita o conjunto <strong>de</strong> valores possíveis que uma <strong>de</strong>terminada variável po<strong>de</strong> representar.<br />

Além disso, <strong>de</strong>fine as operações básicas possíveis para suas variáveis.<br />

Sua necessida<strong>de</strong> <strong>de</strong>corre do fato <strong>de</strong> que as células <strong>de</strong> memória, sozinhas, conseguem representar<br />

apenas conjuntos <strong>de</strong> dados muito limitados. Entretanto, a maioria dos valores <strong>de</strong> interesse pertence a<br />

conjuntos extensos, os quais não po<strong>de</strong>m ser representados <strong>com</strong> o uso <strong>de</strong> apenas uma célula <strong>de</strong> memória.<br />

Os programadores, então, passaram a utilizar múltiplas células para representar um único valor.<br />

Essa atitu<strong>de</strong> resolveu a dificulda<strong>de</strong> <strong>de</strong> armazenar dados <strong>com</strong>plexos, mas criou um outra questão: os<br />

processos <strong>de</strong> leitura e escrita para valores <strong>de</strong> múltiplas células, bem <strong>com</strong>o as <strong>de</strong>mais operações sobre<br />

tais valores, exigiam códigos que, além <strong>de</strong> não triviais, fugiam do foco do problema a ser resolvido.<br />

Não <strong>de</strong>morou para que as linguagens <strong>de</strong> programação incorporassem a <strong>de</strong>finição dos tipos <strong>de</strong><br />

dados e suas operações essenciais, poupando os programadores da tarefa <strong>de</strong> <strong>de</strong>fini-los em seu código e<br />

tornando-o mais enxuto e legível.<br />

Tipos <strong>de</strong> dados, portanto, abstraem a forma <strong>de</strong> implementação e disponibilizam operações sobre<br />

os elementos do conjunto para que o programador possa utilizá-las sem ter que implementá-las.<br />

Os tipos básicos mais importantes são o tipo inteiro, o ponto flutuante, o booleano e o tipo<br />

caractere. Cada linguagem <strong>de</strong> programação possui certas particularida<strong>de</strong>s em relação aos tipos <strong>de</strong><br />

dados.<br />

Primeiramente, é preciso abordar um conceito imprescindível da escrita <strong>de</strong> programas em linguagem<br />

C: a <strong>de</strong>claração <strong>de</strong> variáveis. Em seguida, são <strong>de</strong>scritas as características mais <strong>com</strong>uns dos tipos<br />

básicos principais.<br />

DRAFT


20<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

2.4.1 Declaração <strong>de</strong> Variáveis<br />

De acordo <strong>com</strong> o problema abordado, diferentes conjuntos <strong>de</strong> dados são necessários. Conforme visto,<br />

os tipos <strong>de</strong> dados representam os conjuntos <strong>de</strong> valores possíveis para suas variáveis, assim <strong>com</strong>o as<br />

operações válidas sobre elas. Também já foram abordadas a necessida<strong>de</strong> e as vantagens do uso <strong>de</strong><br />

variáveis em um programa. Entretanto, ainda não foi mencionado <strong>com</strong>o as variáveis são criadas, ou<br />

seja, <strong>com</strong>o o programador <strong>de</strong>clara formalmente uma variável em seu código.<br />

Na linguagem C, o ato <strong>de</strong> <strong>de</strong>clarar uma variável é simples e imprescindível. Afinal, sem esse<br />

procedimento, não é possível usá-la. Quando a <strong>de</strong>claração <strong>de</strong> variáveis é esquecida, uma mensagem <strong>de</strong><br />

erro é apresentada ao programador, e a <strong>com</strong>pilação do código é interrompida. Por isso, toda variável<br />

<strong>de</strong>ve ser <strong>de</strong>clarada antes <strong>de</strong> ser utilizada.<br />

A <strong>de</strong>claração <strong>de</strong> variáveis tem uma estrutura simples e algumas regras básicas. Em primeiro lugar,<br />

escreve-se o nome do tipo <strong>de</strong> dados ao qual a variável pertence. Em seguida, separado por um espaço<br />

em branco, escreve-se o i<strong>de</strong>ntificador da variável.<br />

;<br />

É possível <strong>de</strong>clarar mais <strong>de</strong> uma variável em uma mesma linha, <strong>de</strong>s<strong>de</strong> que todas sejam do mesmo tipo,<br />

conforme mostra o Exemplo 2.6.<br />

1 float valorFracionado , saldo , salarioMinimo ;<br />

2 char letra , ultimaLetra ;<br />

3 int entrada1 , entrada2 , entrada3 ;<br />

Exemplo 2.6: Declaração múltipla <strong>de</strong> variáveis em uma mesma linha <strong>de</strong> código.<br />

2.4.2 Tipo Inteiro<br />

O tipo inteiro, <strong>com</strong>o o próprio nome sugere, representa um intervalo finito do conjunto matemático<br />

dos números inteiros.<br />

De fato, uma linguagem <strong>de</strong> programação po<strong>de</strong> <strong>de</strong>finir vários tipos inteiros, cada um <strong>com</strong> intervalo<br />

diferente. Na linguagem C, por exemplo, existem vários tipos inteiros, tais <strong>com</strong>o o int, long int,<br />

unsigned int, short int. Neste livro, para bem da simplicida<strong>de</strong>, usa-se apenas o tipo int.<br />

O intervalo <strong>de</strong> valores para o tipo int <strong>de</strong>pen<strong>de</strong> do <strong>com</strong>pilador que está sendo empregado. Assumimos<br />

aqui que o intervalo do tipo int sempre varia <strong>de</strong> entre −2147483648 a 2147483647.<br />

Em C, <strong>com</strong>o na maioria das linguagens, as operações sobre as variáveis do tipo inteiro já estão<br />

implementadas e à disposição do programador. As operações disponíveis são as <strong>de</strong> soma, subtração,<br />

multiplicação, divisão e resto <strong>de</strong> divisão, conforme o Exemplo 2.7.<br />

O uso <strong>de</strong>ssas funções é bastante simples e intuitivo, pois há até certa relação <strong>com</strong> os símbolos da<br />

escrita matemática. No Exemplo 2.7, as variáveis x e y são relacionadas entre si e os resultados são<br />

armazenados nas variáveis <strong>de</strong> a a f.<br />

Os operadores <strong>de</strong> soma e subtração funcionam tal qual na aritmética. O operador <strong>de</strong> subtração<br />

po<strong>de</strong> ser aplicado para um único valor quando se <strong>de</strong>seja inverter seu sinal. A linha 12 do Exemplo 2.7<br />

mostra essa situação.<br />

Um <strong>de</strong>staque <strong>de</strong>ve ser dado ao operador <strong>de</strong> multiplicação. Seu único símbolo é “*” (não há o<br />

símbolo “×” ou o “·”). Além disso, em oposição ao que ocorre na aritmética, a escrita do “*” não<br />

po<strong>de</strong> ser omitida. Logo, a operação da linha 13 do Exemplo 2.7 geraria erro se não estivesse <strong>com</strong>entada,<br />

pois o <strong>com</strong>pilador trataria xy <strong>com</strong>o uma variável não <strong>de</strong>clarada.<br />

DRAFT<br />

1 int main (){<br />

2 int x, y, a, b, c, d, e, f;<br />

3<br />

4 x = 10;<br />

5 y = 3;<br />

6<br />

7 a = x + y; // a armazena 13


2.4. TIPOS DE DADOS 21<br />

8 b = x - y; // b armazena 7<br />

9 c = x * y; // c armazena 30<br />

10 d = x / y; // d armazena 3<br />

11 e = x % y; // e armazena 1<br />

12 f = -a; // f armazena -13<br />

13 // c = xy;<br />

14<br />

15 return 0;<br />

16 }<br />

Exemplo 2.7: Operações básicas <strong>com</strong> o tipo inteiro int.<br />

Também é importante <strong>de</strong>stacar o resultado da operação <strong>de</strong> divisão. No caso do Exemplo 2.7, o<br />

resultado correto da divisão <strong>de</strong> x — que armazena o valor 10 — por y — cujo valor é 3 — é a dízima<br />

periódica 3, 333 . . . Entretanto, <strong>com</strong>o as variáveis envolvidas na linha 10 são todas do tipo inteiro,<br />

o <strong>com</strong>pilador trata <strong>de</strong> truncar o resultado, <strong>de</strong>sconsi<strong>de</strong>rando a parte <strong>de</strong>cimal e fornecendo 3 <strong>com</strong>o<br />

resultado da operação.<br />

Ainda no Exemplo 2.7, <strong>de</strong>ve-se notar o uso do operador <strong>de</strong> resto <strong>de</strong> divisão inteira. Seu símbolo<br />

— “%” — <strong>de</strong>ve ficar entre os valores do divi<strong>de</strong>ndo e do divisor. A linha 11 mostra a obtenção do resto<br />

da divisão <strong>de</strong> x por y. Após a execução <strong>de</strong>ssa operação, a variável e guardará o valor 1, que é o resto<br />

da divisão <strong>de</strong> 10 por 3.<br />

2.4.3 Tipo Ponto Flutuante<br />

Esse tipo <strong>de</strong> dados representa um intervalo dos números racionais. Assim <strong>com</strong>o o tipo inteiro, há mais<br />

do que um intervalo possível, <strong>de</strong>pen<strong>de</strong>ndo da precisão escolhida.<br />

Na linguagem C, os tipos <strong>de</strong> ponto flutuante são o float e o double. Neste livro, apenas o tipo<br />

float é empregado.<br />

Depen<strong>de</strong>ndo do <strong>com</strong>pilador utilizado, os tipos <strong>de</strong> dados <strong>de</strong> ponto flutuante apresentam diferentes<br />

precisões. Aqui se consi<strong>de</strong>ra que o tipo float provê seis casas <strong>de</strong>cimais <strong>de</strong> precisão.<br />

As operações pré-<strong>de</strong>finidas são as mesmas que as disponíveis para o tipo int, exceto, é claro, pela<br />

inexistência do operador <strong>de</strong> resto <strong>de</strong> divisão. O Exemplo 2.8 mostra o uso <strong>de</strong> variáveis do tipo float<br />

em um programa.<br />

1 int main (){<br />

2 float p, q, x, z;<br />

3 int y;<br />

4<br />

5 x = 10;<br />

6 y = 4;<br />

7<br />

DRAFT<br />

8 p = 50 / 30; // p guardara 1.0<br />

9 q = 10.0 / 4; // q guardara 2.5<br />

10<br />

11 z = x / y; // z guardara 2.5<br />

12<br />

13 return 0;<br />

14 }<br />

Exemplo 2.8: Operações <strong>com</strong> variáveis do tipo float.<br />

As operações entre variáveis do tipo float são escritas <strong>com</strong> os mesmos símbolos das operações do<br />

tipo int. O Exemplo 2.8 mostra particularida<strong>de</strong>s do processo <strong>de</strong> <strong>com</strong>pilação que po<strong>de</strong>m gerar erros<br />

nos programas.<br />

A linha 8 do Exemplo 2.8 possui um <strong>com</strong>entário explicando que a variável p recebe 1.0 <strong>com</strong>o<br />

resultado da operação <strong>de</strong> divisão. A justificativa para essa situação é que, conforme mostrado na<br />

Seção 2.3, o <strong>com</strong>putador primeiro calcula o resultado da expressão do lado direito do <strong>com</strong>ando <strong>de</strong><br />

atribuição para, em seguida, escrever esse valor na correspon<strong>de</strong>nte variável <strong>de</strong> <strong>de</strong>stino.


22<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Durante a <strong>com</strong>pilação, o <strong>com</strong>pilador checa os tipos das variáveis envolvidas nos cálculos para<br />

realizar as operações correspon<strong>de</strong>ntes. Entretanto, quando há apenas valores numéricos envolvidos, o<br />

<strong>com</strong>pilador consi<strong>de</strong>ra os números escritos sem ponto <strong>de</strong>cimal <strong>com</strong>o sendo do tipo inteiro. É por isso<br />

que a divisão realizada na linha 8 do Exemplo 2.8 resulta em 1. O <strong>com</strong>putador enten<strong>de</strong> a operação<br />

50/30 <strong>com</strong>o uma divisão inteira, <strong>de</strong>scartando a parte <strong>de</strong>cimal do resultado. Já na linha 9, o <strong>com</strong>pilador<br />

enxerga o valor 10.0 <strong>com</strong>o sendo do tipo float <strong>de</strong>vido à presença explícita do ponto <strong>de</strong>cimal, e realiza<br />

a divisão real, resultando no valor esperado.<br />

No caso da última linha do Exemplo 2.8, nenhum resultado inesperado ocorre porque o tipo<br />

mais abrangente — tipo float da variável x — encontrado na expressão é consi<strong>de</strong>rado nas operações,<br />

garantindo o resultado esperado. Caso a variável x também fosse do tipo int, então o mesmo efeito<br />

da linha 8 ocorreria.<br />

2.4.4 Tipo Booleano<br />

O tipo booleano é o tipo <strong>de</strong> dados mais simples. Ele contém apenas dois valores possíveis: verda<strong>de</strong>iro<br />

e falso. É usado principalmente quando se precisa verificar condições no programa, em expressões<br />

lógicas (Seção 2.6.3) e relacionais (Seção 2.6.2).<br />

Na linguagem C não há uma representação específica para esse tipo <strong>de</strong> dados e são utilizados<br />

valores inteiros para codificá-lo. Desta forma, todo valor inteiro diferente <strong>de</strong> zero é consi<strong>de</strong>rado valor<br />

“verda<strong>de</strong>iro”e o valor zero é consi<strong>de</strong>rado “falso”.<br />

2.4.5 Tipo Caractere<br />

Como o próprio nome indica, o tipo caractere registra os códigos para letras, números e caracteres<br />

especiais ($, &, #, @ etc). Normalmente, esses códigos e caracteres variam para as diversas regiões<br />

do planeta, conforme suas particularida<strong>de</strong>s linguísticas. Um padrão largamente utilizado é o ASCII<br />

(American Standards Co<strong>de</strong> of Information Interchange — Padrão Americano para Intercâmbio <strong>de</strong><br />

Informações), especificado pelo ANSI (American National Standards Institute — Instituto Americano<br />

Nacional <strong>de</strong> Padrões).<br />

O padrão ASCII é uma tabela. Cada posição da tabela simboliza um caractere. Na linguagem C,<br />

o tipo char é empregado para conter o índice para a posição da tabela que codifica um <strong>de</strong>terminado<br />

caractere.<br />

Originalmente, essa tabela era <strong>com</strong>posta por apenas 128 símbolos, os quais incluíam todos os<br />

caracteres alfanuméricos do Inglês, sinais <strong>de</strong> pontuação e alguns outros símbolos. Os primeiros 32<br />

caracteres eram utilizados para controle <strong>de</strong> fluxo <strong>de</strong> dados (em <strong>com</strong>unicações entre o <strong>com</strong>putador e<br />

seus periféricos) e não imprimíveis. A Tabela 2.1 mostra os 128 caracteres da tabela ASCII original.<br />

Para fazer <strong>com</strong> que uma variável do tipo char armazene um símbolo <strong>de</strong> interesse, o programador<br />

precisa apenas atribuir a essa variável o caractere <strong>de</strong>sejado, colocando-o entre aspas simples. O<br />

Exemplo 2.9 exibe essa situação.<br />

1 int main (){<br />

DRAFT<br />

2 char letraA , letraFMaiuscula , simboloSoma ;<br />

3<br />

4 letraA = ‘a’;<br />

5 letraFMaiuscula = ‘F’;<br />

6 simboloSoma = ‘+’;<br />

7<br />

8 return 0;<br />

9 }<br />

Exemplo 2.9: Uso <strong>de</strong> variáveis do tipo caractere.<br />

2.4.6 Conversão <strong>de</strong> Tipos<br />

Agora, conhecidas algumas informações sobre os tipos <strong>de</strong> dados básicos, torna-se mais simples <strong>com</strong>preen<strong>de</strong>r<br />

o problema existente na atribuição entre tipos diferentes, mencionada na Seção 2.3.


2.4. TIPOS DE DADOS 23<br />

Código Caractere Código Caractere Código Caractere Código Caractere<br />

0 NUL (null) 32 SPACE 64 @ 96 `<br />

1 SOH (start of heading) 33 ! 65 A 97 a<br />

2 STX (start of text) 34 ” 66 B 98 b<br />

3 ETX (end of text) 35 # 67 C 99 c<br />

4 EOT (end of transmission) 36 $ 68 D 100 d<br />

5 ENQ (enquiry) 37 % 69 E 101 e<br />

6 ACK (acknowledge) 38 & 70 F 102 f<br />

7 BEL (bell) 39 ’ 71 G 103 g<br />

8 BS (backspace) 40 ( 72 H 104 h<br />

9 HT (horizontal tab) 41 ) 73 I 105 i<br />

10 LF (NL line feed,new line) 42 * 74 J 106 j<br />

11 VT (vertical tab) 43 + 75 K 107 k<br />

12 FF (NP from feed,new page) 44 , 76 L 108 l<br />

13 CR (carriage return) 45 - 77 M 109 m<br />

14 SO (shift out) 46 . 78 N 110 n<br />

15 SI (shift in) 47 / 79 O 111 o<br />

16 DLE (data link escape) 48 0 80 P 112 p<br />

17 DC1 (<strong>de</strong>vice control 1) 49 1 81 Q 113 q<br />

18 DC2 (<strong>de</strong>vice control 2) 50 2 82 R 114 r<br />

19 DC3 (<strong>de</strong>vice control 3) 51 3 83 S 115 s<br />

20 DC4 (<strong>de</strong>vice control 4) 52 4 84 T 116 t<br />

21 NAK (negative acknowledge) 53 5 85 U 117 u<br />

22 SYN (synchronous idle) 54 6 86 V 118 v<br />

23 ETB (end of trans. block) 55 7 87 W 119 w<br />

24 CAN (cancel) 56 8 88 X 120 x<br />

25 EM (end of medium) 57 9 89 Y 121 y<br />

26 SUB (substitute) 58 : 90 Z 122 z<br />

27 ESC (escape) 59 ; 91 [ 123 {<br />

28 FS (file separator) 60 < 92 \ 124 |<br />

29 GS (group separator) 61 = 93 ] 125 }<br />

30 RS (record separator) 62 > 94 ˆ 126 ˜<br />

31 US (unit separator) 63 ? 95 127 DEL<br />

Tabela 2.1: Os 128 caracteres da tabela ASCII original.<br />

Consi<strong>de</strong>ra-se que os tipos int, float e char ocupam a quantida<strong>de</strong> <strong>de</strong> memória representada na<br />

Figura 2.6.<br />

DRAFT<br />

Figura 2.6: Tamanho da memória utilizada pelos tipos <strong>de</strong> dados básicos.<br />

As diferenças nos tamanhos são justificáveis, uma vez que, quanto maior o conjunto a ser representado,<br />

mais células <strong>de</strong> memória são necessárias para a<strong>com</strong>odar uma variável. Desta forma, sendo<br />

o conjunto dos caracteres o menor, é preciso apenas um byte (uma célula) para representá-lo. Já o<br />

conjunto do tipo float, que é o maior dos três, precisa <strong>de</strong> 4 bytes (4 células) para uma representação<br />

coerente <strong>de</strong> seus valores.<br />

É preciso ter em mente que, <strong>de</strong>vido a essas restrições <strong>de</strong> implementação, não se <strong>de</strong>ve utilizar<br />

operações <strong>de</strong> atribuição entre variáveis sem tomar algum cuidado. Se elas forem <strong>de</strong> tipos diferentes,<br />

problemas po<strong>de</strong>m acontecer.<br />

Não há problemas em atribuir uma variável do tipo int a outra do tipo float. Tal qual ocorre<br />

na matemática, toda variável do tipo int é possível <strong>de</strong> ser representada por outra do tipo float, pois<br />

o conjunto dos números racionais contém o conjunto dos inteiros. Um raciocínio similar po<strong>de</strong> ser


24<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

empregado para justificar as atribuições <strong>de</strong> variáveis char a variáveis <strong>de</strong> tipo int ou float, que também<br />

ocorrem sem problemas.<br />

O problema é quando se tenta atribuir uma variável <strong>de</strong> um conjunto mais amplo a uma <strong>de</strong> um<br />

conjunto mais restrito. Veja o Exemplo 2.10.<br />

Observando o Exemplo 2.10, um programador distraído po<strong>de</strong> pensar que houve uma atribuição<br />

correta. Entretanto, o valor armazenado pela variável teste é 125. Não havendo condições <strong>de</strong> armazenar<br />

corretamente, o <strong>com</strong>pilador simplesmente <strong>de</strong>scarta a parte <strong>de</strong>cimal do número, armazenando<br />

apenas sua parte inteira na variável. Logo, é preciso permanecer atento às atribuições <strong>de</strong>sse tipo para<br />

não se equivocar sobre o valor armazenado por uma variável.<br />

1 int main (){<br />

2 int teste ;<br />

3<br />

4 teste = 125.568;<br />

5<br />

6 return 0;<br />

7 }<br />

2.5 Constantes<br />

Exemplo 2.10: Atribuição entre tipos diferentes <strong>com</strong> perda <strong>de</strong> informação.<br />

Em algumas situações surge a necessida<strong>de</strong> <strong>de</strong> se utilizar um <strong>de</strong>terminado valor constante em diversas<br />

partes do código. Para simplificar a alteração <strong>de</strong>ssas constantes e facilitar a leitura do código, é possível<br />

<strong>de</strong>finir um nome significativo para elas <strong>de</strong> maneira simples, por meio <strong>de</strong> uma estrutura específica.<br />

Essa estrutura é iniciada pela diretiva #<strong>de</strong>fine, seguida pelo i<strong>de</strong>ntificador da constante e pelo seu<br />

respectivo valor, todos separados por um espaço em branco.<br />

#<strong>de</strong>fine <br />

Na linguagem C, a <strong>de</strong>claração <strong>de</strong> constantes <strong>de</strong>ve ser feita no início do código, antes da função main,<br />

que é a parte principal <strong>de</strong> um código pois é o ponto <strong>de</strong> partida do programa.Será datalhada melhor<br />

ao longo do livro. O Exemplo 2.11 apresenta <strong>de</strong>clarações válidas <strong>de</strong> constantes.<br />

1 # <strong>de</strong>fine PI 3.141593<br />

2 # <strong>de</strong>fine FALSO 0<br />

3 # <strong>de</strong>fine VERDADEIRO 1<br />

4 # <strong>de</strong>fine RAIZDEDOIS 1.414214<br />

5<br />

6 int main (){<br />

7 float raio , <strong>com</strong>primento , area ;<br />

8<br />

9 raio = 10;<br />

10 area = PI * raio * raio ;<br />

11 <strong>com</strong>primento = 2 * PI * raio ;<br />

12<br />

13 return 0;<br />

14 }<br />

DRAFT<br />

Exemplo 2.11: Definição <strong>de</strong> constantes.<br />

Na <strong>de</strong>claração <strong>de</strong> constantes, a escolha dos nomes segue as mesmas regras para a escrita dos nomes<br />

<strong>de</strong> variáveis. Geralmente, para diferenciar as constantes no código, opta-se por escrever seus nomes<br />

<strong>com</strong> todas as letras maiúsculas. O Exemplo 2.11 mostra um exemplo simples on<strong>de</strong> diversas constantes<br />

são <strong>de</strong>claradas <strong>de</strong> acordo <strong>com</strong> a convenção proposta.


2.6.<br />

EXPRESSÕES 25<br />

2.6 Expressões<br />

As variáveis e constantes po<strong>de</strong>m ser <strong>com</strong>binadas <strong>com</strong> os operadores associados a cada tipo <strong>de</strong> dados,<br />

gerando expressões.<br />

2.6.1 Expressões Aritméticas<br />

A expressão aritmética é aquela cujos operadores e operandos são <strong>de</strong> tipos numéricos (int ou float,<br />

por exemplo).<br />

Nas expressões aritméticas, é guardada sempre a seguinte relação <strong>de</strong> priorida<strong>de</strong>:<br />

1. Multiplicação, divisão e resto <strong>de</strong> divisão;<br />

2. Adição e subtração.<br />

Para se obter uma sequência diferente <strong>de</strong> cálculos, vários níveis <strong>de</strong> parênteses po<strong>de</strong>m ser usados<br />

para quebrar as priorida<strong>de</strong>s <strong>de</strong>finidas. Não é permitido o uso <strong>de</strong> colchetes e chaves, uma vez que<br />

estes símbolos já são utilizados <strong>com</strong> outras finalida<strong>de</strong>s. O Exemplo 2.12 exibe uma série <strong>de</strong> expressões<br />

aritméticas válidas.<br />

1 int main (){<br />

2 int x, y, z;<br />

3<br />

4 x = 10 * 10 + 25; // x = 125<br />

5 y = 5 * (7 + 3); // y = 50<br />

6 z = 10 * ((x - 25) / y + (x - 25) * 2); // z = 2020<br />

7<br />

8 return 0;<br />

9 }<br />

Exemplo 2.12:<br />

operações.<br />

Expressões aritméticas e o uso <strong>de</strong> parênteses para <strong>de</strong>terminar a precedência das<br />

No Exemplo 2.12, é importante notar que, no <strong>com</strong>ando <strong>de</strong> atribuição à variável x, a multiplicação<br />

10 × 10 é executada primeiro. Na linha seguinte, a soma 7 + 3 é executada primeiro e seu valor é, em<br />

seguida, multiplicado por 5 e atribuído à variável y. A análise da linha 6 é <strong>de</strong>ixada para o leitor.<br />

Além das operações básicas já citadas, é possível usar, nas expressões aritméticas, outras operações<br />

bastante <strong>com</strong>uns na matemática, <strong>de</strong>finidas <strong>de</strong>ntro da linguagem na forma <strong>de</strong> funções. A sintaxe geral<br />

para o uso <strong>de</strong>ssas funções é a seguinte:<br />

()<br />

DRAFT<br />

Algumas funções matemáticas são mostradas na Tabela 2.2.<br />

Nome Descrição Tipo do valor<br />

abs Módulo ou valor absoluto <strong>de</strong> um valor Inteiro<br />

fabs Módulo ou valor absoluto <strong>de</strong> um valor racional Inteiro e Ponto Flutuante<br />

sin Seno <strong>de</strong> um ângulo em radianos Inteiro e Ponto Flutuante<br />

cos Cosseno <strong>de</strong> um ângulo em radianos Inteiro e Ponto Flutuante<br />

sqrt Raiz quadrada <strong>de</strong> um número Inteiro e Ponto Flutuante<br />

pow Potenciação Inteiro e Ponto Flutuante<br />

floor Maior inteiro não maior que o valor Inteiro e Ponto Flutuante<br />

ceil Menor inteiro não menor que o valor Inteiro e Ponto Flutuante<br />

log Logaritmo neperiano Inteiro e Ponto Flutuante<br />

exp Exponencial Inteiro e Ponto Flutuante<br />

Tabela 2.2: Funções matemáticas pré-<strong>de</strong>finidas na linguagem C.<br />

O Exemplo 2.13 exibe vários usos <strong>de</strong> funções matemáticas e expressões aritméticas.


26<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

1 # inclu<strong>de</strong> <br />

2 # <strong>de</strong>fine PI 3.1415<br />

3<br />

4 int main (){<br />

5 float a, b, c, <strong>de</strong>lta , raiz1 , raiz2 ;<br />

6 float x, y, z;<br />

7<br />

8 a = 10;<br />

9 b = 50;<br />

10 c = 30;<br />

11<br />

12 <strong>de</strong>lta = b * b - 4 * a * c;<br />

13 raiz1 = -b + sqrt ( <strong>de</strong>lta ) / (2 * a);<br />

14 raiz2 = -b - sqrt ( <strong>de</strong>lta ) / (2 * a);<br />

15<br />

16 x = sin (-PI / 2);<br />

17 y = fabs (x);<br />

18 z = pow (y ,2) ; // y elevado a potencia 2<br />

19<br />

20 return 0;<br />

21 }<br />

Exemplo 2.13: Uso <strong>de</strong> funções matemáticas pré-<strong>de</strong>finidas.<br />

Para o uso das funções matemáticas apresentadas no Exemplo 2.13 é necessário a inclusão da<br />

biblioteca math.h, <strong>com</strong>o expresso na linha 1. Os mesmos cálculos para a procura das raízes <strong>de</strong> uma<br />

equação <strong>de</strong> segundo grau são executados nas linhas 13 a 15, on<strong>de</strong> a função sqrt calcula a raiz quadrada<br />

do seu operando — a variável <strong>de</strong>lta. Já as linhas 15 a 17 apresentam cálculos avulsos: a linha 17<br />

executa o cálculo do seno <strong>de</strong> −π/2 e armazena o resultado na variável x; a linha 18 armazena, na<br />

variável y, o módulo do valor armazenado em x; e a linha 19 calcula o valor armazenado em y elevado<br />

à potência <strong>de</strong> 2 e armazena o resultado na variável z.<br />

2.6.2 Expressões Relacionais<br />

As expressões relacionais <strong>com</strong>param valores entre si. Tal qual se faz na prática, o operador relacional<br />

trabalha <strong>com</strong> dois valores: o da expressão que está a sua direita e o da expressão que está a sua<br />

esquerda. É importante <strong>de</strong>stacar que uma variável ou uma constante isolada, por si só, po<strong>de</strong> ser<br />

consi<strong>de</strong>rada uma expressão.<br />

DRAFT<br />

A Tabela 2.3 mostra exemplos <strong>de</strong> operadores relacionais da linguagem C e alguns casos <strong>de</strong> uso.<br />

Símbolo Nome Exemplo<br />

< menor que a < 10<br />

0<br />

>= maior ou igual a <strong>de</strong>lta >= 0<br />

!= diferente <strong>de</strong> x != 9+8*8<br />

Tabela 2.3: Operadores relacionais.<br />

As expressões relacionais resultam sempre em 0 (zero) para uma <strong>com</strong>paração falsa ou 1 para uma<br />

<strong>com</strong>paração verda<strong>de</strong>ira.<br />

É importante atentar que, embora sejam escritos <strong>de</strong> maneira parecida, há uma gran<strong>de</strong> diferença<br />

entre o operador <strong>de</strong> <strong>com</strong>paração “==” e o <strong>com</strong>ando <strong>de</strong> atribuição “=”. Essa semelhança é uma fonte<br />

<strong>com</strong>um <strong>de</strong> erros <strong>de</strong> programação, geralmente difíceis <strong>de</strong> <strong>de</strong>tectar.


2.7. COMANDO DE ENTRADA DE DADOS 27<br />

2.6.3 Expressões Lógicas<br />

As expressões lógicas são utilizadas para relacionar os resultados <strong>de</strong> um conjunto <strong>de</strong> expressões relacionais.<br />

Elas realizam as principais operações da lógica booleana e, na linguagem C, têm <strong>com</strong>o<br />

operadores:<br />

ˆ<br />

“&&” (AND): Realiza o “E” lógico;<br />

ˆ<br />

ˆ<br />

“||” (OR): Realiza o “OU” lógico;<br />

“!” (NOT): Realiza a negação.<br />

Os resultados obtidos das expressões lógicas também são valores do tipo inteiro: 0 para falso e 1<br />

para verda<strong>de</strong>iro.<br />

Para melhor enten<strong>de</strong>r o que cada operador realiza, são levados em conta duas variáveis p e q <strong>de</strong><br />

entrada, que po<strong>de</strong>m ser consi<strong>de</strong>radas verda<strong>de</strong>iras (V) ou falsas (F). Veja as tabelas abaixo:<br />

p q p && q<br />

V V V<br />

V F F<br />

F V F<br />

F F F<br />

Tabela 2.4: Tabela verda<strong>de</strong> para o operador “&&”<br />

O operador “&&” analisa se todas as variáveis são verda<strong>de</strong>iras (q ≠ 0 “E” p ≠ 0). Se forem, a<br />

expressão retornará 1 (V). Caso contrário, retornará 0 (F).<br />

p q p || q<br />

V V V<br />

V F V<br />

F V V<br />

F F F<br />

Tabela 2.5: Tabela verda<strong>de</strong> para o operador “||”<br />

O operador “||” analisa se, pelo menos, uma das variáveis são verda<strong>de</strong>iras (q ≠ 0 “OU” p ≠ 0).<br />

Se for, retornará 1 (V). Caso contrário, retornará 0 (F).<br />

p q !p !q<br />

V V F F<br />

V F F V<br />

F V V F<br />

F F V V<br />

DRAFT<br />

Tabela 2.6: Tabela verda<strong>de</strong> para o operador “!”<br />

O operador “!” retorna o oposto do que as variáveis são consi<strong>de</strong>radas. Portanto, se uma variável<br />

for consi<strong>de</strong>rada verda<strong>de</strong>ira (p≠0), a expressão retornará 0 (F). Caso contrário (<strong>com</strong> p igual a 0),<br />

retornará 1 (V).<br />

O uso dos operadores relacionais e lógicos fica bem mais claro adiante, neste capítulo, quando os<br />

<strong>com</strong>andos <strong>de</strong> seleção e repetição são estudados.<br />

2.7 Comando <strong>de</strong> Entrada <strong>de</strong> Dados<br />

O <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados serve para captar do usuário do programa um ou mais valores<br />

necessários para a execução das tarefas. Na verda<strong>de</strong>, o que se faz é ler os dados <strong>de</strong> uma fonte externa,<br />

normalmente do teclado, para <strong>de</strong>pois usá-los <strong>de</strong> alguma maneira <strong>de</strong>ntro do programa.


28<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Por meio <strong>de</strong>sse <strong>com</strong>ando <strong>de</strong> leitura <strong>de</strong> dados, uma ou mais variáveis po<strong>de</strong>m ter seus valores lidos<br />

durante a execução do programa. Essa característica permite criar programas mais flexíveis.<br />

Na linguagem C, a sintaxe para o uso do <strong>com</strong>ando é a seguinte:<br />

scanf(" ... ", &var1, &var2, ..., &varN);<br />

Essa estrutura é dividida em duas partes distintas. A primeira, colocada entre aspas duplas,<br />

contém os formatos, os quais são relacionados diretamente <strong>com</strong> os tipos das variáveis a serem lidas. A<br />

segunda parte é uma lista dos nomes <strong>de</strong>ssas variáveis, <strong>com</strong> uma relação direta entre a posição nessa<br />

lista e o respectivo formato <strong>de</strong>scrito na primeira parte do <strong>com</strong>ando. Conforme mostra a <strong>de</strong>scrição da<br />

sintaxe, os nomes das variáveis <strong>de</strong>vem ser precedidos pelo caractere “&”(O motivo disso será explicado<br />

no capítulo 7 <strong>de</strong>ste livro).<br />

A Tabela 2.7 mostra alguns dos possíveis formatos.<br />

Código Significado<br />

%c Lê um único caracter<br />

%d Lê um inteiro <strong>de</strong>cimal<br />

%f Lê um número em ponto flutuante<br />

Tabela 2.7: Códigos para formatos <strong>de</strong> dados do <strong>com</strong>ando <strong>de</strong> entrada scanf .<br />

Um exemplo claro da utilida<strong>de</strong> do <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados é o cálculo da conta <strong>de</strong> energia<br />

elétrica. O exemplo apresentado até agora tinha os valores <strong>de</strong> consumo e do preço do quilowatt-hora<br />

escritos diretamente no código. Isso é bastante incômodo, pois, quando se quer calcular o valor <strong>de</strong><br />

uma conta diferente, o código <strong>de</strong>ve ser alterado e re<strong>com</strong>pilado.<br />

Uma maneira <strong>de</strong> tornar o programa mais flexível é utilizar o <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados. Com<br />

ele, é possível digitar os valores <strong>de</strong>sejados para as variáveis e efetuar os cálculos para diferentes contas,<br />

bastando, para isso, executar novamente o programa. O código modificado é exibido no Exemplo 2.14.<br />

De acordo <strong>com</strong> o formato <strong>de</strong>scrito no <strong>com</strong>ando <strong>de</strong> leitura, os valores das variáveis leituraAtual,<br />

leituraAnterior e valorUnitario <strong>de</strong>vem ser digitados pelo usuário, nesta or<strong>de</strong>m, separados por espaços<br />

em branco.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int leituraAtual , leituraAnterior , diferenca ;<br />

5 float valorUnitario , valorConta ;<br />

6<br />

7 scanf ("%d %d %f", & leituraAtual , & leituraAnterior , & valorUnitario );<br />

8 diferenca = leituraAtual - leituraAnterior ;<br />

9 valorConta = diferenca * valorUnitario ;<br />

10<br />

11 return 0;<br />

12 }<br />

DRAFT<br />

Exemplo 2.14: Emprego do <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados para o algoritmo do Exemplo 2.4.<br />

Observando o código do Exemplo 2.14, é importante ressaltar que não há mais a parte <strong>de</strong> inicialização<br />

das variáveis. Essa tarefa foi substituída pelo <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados e os valores<br />

são, agora, passados pelo usuário do programa. Esses valores po<strong>de</strong>m ser alterados a cada execução do<br />

programa para que várias contas diferentes possam ser calculadas.Observe também que há necessida<strong>de</strong><br />

<strong>de</strong> inserir a biblioteca stdio.h para utilização da função scanf .<br />

2.8 Comando <strong>de</strong> Saída <strong>de</strong> Dados<br />

Até agora, os exemplos <strong>de</strong> códigos e os conceitos estudados não mostravam <strong>com</strong>o os programas <strong>com</strong>unicavam<br />

seus resultados ao usuário no final do programa, as variaveis armazenavam os resultados,<br />

mas o usuario não tinha <strong>com</strong>o acessá-los. De fato, esse é o papel do <strong>com</strong>ando <strong>de</strong> saída <strong>de</strong> dados.


2.8. COMANDO DE SAÍDA DE DADOS 29<br />

O <strong>com</strong>ando <strong>de</strong> saída <strong>de</strong> dados serve para escrever mensagens e exibir valores <strong>de</strong> expressões, proporcionando<br />

mais informação e legibilida<strong>de</strong> tanto para o usuário quanto para o próprio programador.<br />

Na linguagem C, a sintaxe para o uso do <strong>com</strong>ando <strong>de</strong> saída é mostrada a seguir.<br />

printf(" ... ", exp1, exp2, ..., expN);<br />

A estrutura do <strong>com</strong>ando <strong>de</strong> saída <strong>de</strong> dados é bastante semelhante à do <strong>com</strong>ando <strong>de</strong> entrada. A<br />

principal diferença é que na segunda parte po<strong>de</strong>m ser colocadas expressões. Além disso, no <strong>com</strong>ando<br />

<strong>de</strong> saída, o caractere “&” não <strong>de</strong>ve ser escrito à das expressões. Ressalva-se que a segunda parte do<br />

<strong>com</strong>ando é opcional, conforme será mostrado logo adiante nesta seção.<br />

A Tabela 2.8 mostra alguns dos possíveis formatos a serem usados.<br />

Código Significado<br />

%c Caracter<br />

%d Inteiros <strong>de</strong>cimais <strong>com</strong> sinal<br />

%e Notação científica<br />

%f Ponto flutuante <strong>de</strong>cimal<br />

%% Escreve o símbolo “%”<br />

Tabela 2.8: Códigos para formatos <strong>de</strong> dados para o <strong>com</strong>ando <strong>de</strong> saída printf .<br />

Conforme já mencionado, o <strong>com</strong>ando <strong>de</strong> saída é muito utilizado para exibir mensagens para o<br />

usuário. Não é obrigatório que as mensagens contenham apenas valores ou caracteres armazenados<br />

em variáveis, sendo possível escrever <strong>texto</strong>s <strong>com</strong>o mensagem. O Exemplo 2.15 <strong>de</strong>monstra essa possibilida<strong>de</strong>.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 printf (" Bom dia a todos !");<br />

5 printf (" Outra mensagem ");<br />

6<br />

7 return 0;<br />

8 }<br />

Exemplo 2.15: Escrevendo mensagens para o usuário do programa.<br />

Observe no 2.15 que há necessida<strong>de</strong> <strong>de</strong> inserir a biblioteca stdio.h para uso da função printf . Po<strong>de</strong>se,<br />

ainda, mesclar uma mensagem <strong>de</strong> <strong>texto</strong> <strong>com</strong> valores <strong>de</strong> variáveis. O Exemplo 2.16 ilustra essa i<strong>de</strong>ia.<br />

Nele, é possível notar que, para cada especificador <strong>de</strong> formato na primeira parte do <strong>com</strong>ando, <strong>de</strong>ve<br />

existir uma expressão <strong>de</strong> tipo correspon<strong>de</strong>nte posicionada a<strong>de</strong>quadamente na segunda parte.<br />

DRAFT<br />

1 printf (" Valor do saldo : %f", saldo );<br />

2 printf ("A meta<strong>de</strong> <strong>de</strong> %d vale %d", numero , meta<strong>de</strong> );<br />

3 printf ("O menor numero digitado foi %d", menor );<br />

Exemplo 2.16: Escrevendo mensagens que incluem valores <strong>de</strong> variáveis.<br />

1 printf (" Valor do saldo total : %f", saldo1 + saldo2 );<br />

2 printf ("A meta<strong>de</strong> do saldo vale : %f", ( saldo1 + saldo2 ) / 2);<br />

Exemplo 2.17: Escrevendo mensagens que incluem manipulação <strong>de</strong> expressões<br />

Conforme mostra o 2.17 é permitido o uso <strong>de</strong> expressões ao invés <strong>de</strong> um único valor. Uma versão mais<br />

<strong>com</strong>pleta do código para o cálculo da conta <strong>de</strong> energia elétrica é exibida no Exemplo 2.18. Nele, o<br />

<strong>com</strong>ando <strong>de</strong> saída é usado antes <strong>de</strong> cada <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados (linhas 7, 10 e 13), escrevendo<br />

mensagens para indicar ao usuário do programa qual valor ele <strong>de</strong>verá informar. A última linha <strong>de</strong>


30<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

código utiliza o <strong>com</strong>ando <strong>de</strong> saída para exibir o valor do cálculo da conta. Trata-se <strong>de</strong> uma mensagem<br />

mista, em que o especificador %f será substituído pelo valor da variável valorConta. Supondo que,<br />

após os cálculos, essa variável armazene o valor 187.0, a mensagem apresentada na tela seria:<br />

Valor da conta: R$ 187.000000<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int leituraAtual , leituraAnterior , diferenca ;<br />

5 float valorUnitario , valorConta ;<br />

6<br />

7 printf (" Digite o valor da leitura ATUAL : ");<br />

8 scanf ("%d", & leituraAtual );<br />

9<br />

10 printf (" Digite o valor da leitura ANTERIOR : ");<br />

11 scanf ("%d", & leituraAnterior );<br />

12<br />

13 printf (" Digite o preco do Quilowatt - hora : ");<br />

14 scanf ("%f", & valorUnitario );<br />

15<br />

16 diferenca = leituraAtual - leituraAnterior ;<br />

17 valorConta = diferenca * valorUnitario ;<br />

18<br />

19 printf (" Valor da conta R$: %f", valorConta );<br />

20<br />

21 return 0;<br />

22 }<br />

Exemplo 2.18: Algoritmo mais interativo para o exemplo <strong>de</strong> cálculo da conta <strong>de</strong> energia elétrica.<br />

Quando se usa o <strong>com</strong>ando printf , o caractere especial “\n” é bastante útil. Ele serve para quebrar<br />

a linha exatamente na posição on<strong>de</strong> for inserido no <strong>texto</strong>. A Tabela 2.9 explica melhor o funcionamento<br />

<strong>de</strong>sse caractere.<br />

Código<br />

Resultado<br />

printf("OI.\nComo vai?");<br />

OI.<br />

Como vai?<br />

int x;<br />

O valor <strong>de</strong> x eh:<br />

x = 10; 10<br />

printf("O valor <strong>de</strong> x eh:\n%d", x);<br />

int a;<br />

Primeira linha.<br />

a = 20; Segunda linha (a = 20).<br />

printf("Primeira linha.\nSegunda linha (a = %d). \n\nFIM.", a);<br />

FIM.<br />

DRAFT<br />

Tabela 2.9: Exemplos <strong>de</strong> uso do caractere especial “\n”.<br />

2.9 Comandos <strong>de</strong> Seleção<br />

O <strong>com</strong>ando <strong>de</strong> seleção permite que um programa possa realizar diferentes alternativas <strong>de</strong> sequências<br />

<strong>de</strong> instruções durante sua execução. Depen<strong>de</strong>ndo do valor <strong>de</strong> uma expressão, o programa segue<br />

executando uma ou outra sequência <strong>de</strong> <strong>com</strong>andos.<br />

Existem três categorias distintas: seleção simples, seleção dupla e seleção múltipla, as quais são<br />

abordadas a seguir.


2.9. COMANDOS DE SELEÇÃO 31<br />

2.9.1 Comando <strong>de</strong> seleção simples<br />

É possível imaginar diversas situações cotidianas que se assemelham ao <strong>com</strong>portamento do <strong>com</strong>ando<br />

<strong>de</strong> seleção simples. Uma <strong>com</strong>paração clássica leva em conta a tomada <strong>de</strong> um <strong>de</strong>svio durante uma<br />

viagem.<br />

Quando o carro é utilizado para ir a algum lugar, é normal conhecer uma rota sequenciada <strong>de</strong><br />

lugares intermediários pelos quais se passa antes <strong>de</strong> chegar ao <strong>de</strong>stino. Entretanto, é possível que<br />

ocorra algum imprevisto e seja necessário tomar um <strong>de</strong>svio.<br />

Há tarefas <strong>com</strong>putacionais que também se <strong>de</strong>param <strong>com</strong> tais cenários. Antes <strong>de</strong> exemplificar, é<br />

melhor apresentar a estrutura do <strong>com</strong>ando <strong>de</strong> seleção simplificado. Ela po<strong>de</strong> ser observada a seguir.<br />

1<br />

if(){<br />

<br />

}<br />

Não é difícil entendê-la. Quando o <strong>com</strong>putador executa esse <strong>com</strong>ando, o que é realizado em primeiro<br />

lugar é o teste da expressão lógica. Se ela resultar “verda<strong>de</strong>iro”, então a sequência <strong>de</strong> <strong>com</strong>andos é<br />

executada. Caso contrário, o programa segue executando normalmente as instruções posteriores.<br />

Desta forma, a <strong>de</strong>cisão <strong>de</strong> <strong>de</strong>sviar a execução normal do programa é condicionada ao resultado da<br />

expressão lógica escrita no início do <strong>com</strong>ando.<br />

O uso do <strong>com</strong>ando <strong>de</strong> seleção simples é exibido no Pseudocódigo 2.3, o qual <strong>de</strong>screve um algoritmo<br />

que faz a leitura <strong>de</strong> dois números inteiros e os imprime <strong>com</strong>o foram digitados e, também, em or<strong>de</strong>m<br />

crescente.<br />

Pseudocódigo 2.3 Or<strong>de</strong>na dois números inteiros digitados pelo usuário.<br />

Descrição: Apresentar, em or<strong>de</strong>m crescente, dois números inteiros digitados pelo usuário.<br />

Dados <strong>de</strong> Entrada: Dois números inteiros.<br />

Saída do Programa: Números inteiros impressos na or<strong>de</strong>m em que foram digitados e em or<strong>de</strong>m crescente.<br />

Funç~ao Principal :<br />

Ler dois valores inteiros .<br />

Apresentar os valores coletados .<br />

SE o primeiro número lido for maior que o segundo :<br />

Or<strong>de</strong>nar os valores .<br />

FIM -SE<br />

Apresentar os valores or<strong>de</strong>nados .<br />

FIM - Funç~ao Principal<br />

DRAFT<br />

No Pseudocódigo 2.3, a operação SE é executada tal qual o <strong>com</strong>ando <strong>de</strong> seleção simples if. O<br />

Exemplo 2.19 apresenta um código em linguagem C para o algoritmo do referido pseudocódigo.<br />

2 # inclu<strong>de</strong> <br />

3<br />

4 int main (){<br />

5 int num1 , num2 , aux ;<br />

6<br />

7 printf (" Digite dois numeros inteiros separados por espacos : ");<br />

8 scanf ("%d %d", &num1 , & num2 );<br />

9 printf (" Valores digitados : %d %d.\n", num1 , num2 );<br />

10<br />

11 if( num1 > num2 ){<br />

12 aux = num1 ;<br />

13 num1 = num2 ;<br />

14 num2 = aux ;<br />

15 }<br />

16<br />

17 printf (" Valores or<strong>de</strong>nados : %d %d.\n", num1 , num2 );


32<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

18<br />

19 return 0;<br />

20 }<br />

Exemplo 2.19: Comando <strong>de</strong> seleção simples if<br />

O Exemplo 2.19 inicia exibindo uma mensagem ao usuário (linha 7), solicitando que sejam digitados<br />

dois números. Esses valores são armazenados em variáveis correspon<strong>de</strong>ntes (linha 8) e, em seguida, são<br />

mostrados ao usuário por meio <strong>de</strong> uma mensagem (linha 9). A expressão lógica do <strong>com</strong>ando <strong>de</strong> seleção<br />

da linha 11 <strong>de</strong>termina se há necessida<strong>de</strong> <strong>de</strong> inverter os números antes <strong>de</strong> exibi-los or<strong>de</strong>nadamente. É<br />

importante ressaltar que não há necessida<strong>de</strong> <strong>de</strong> or<strong>de</strong>nar os números caso o usuário já os tenha digitado<br />

na sequência correta. Nesse caso, o programa po<strong>de</strong> seguir normalmente e exibir na tela os valores das<br />

variáveis. Por último, os valores são exibidos em or<strong>de</strong>m crescente (linha 17).<br />

Ainda no Exemplo 2.19, as linhas 12, 13 e 14 são importantes o bastante para serem <strong>de</strong>stacadas.<br />

Elas tratam da operação <strong>de</strong> troca <strong>de</strong> valores entre duas variáveis, a qual é muito utilizada e <strong>de</strong>ve ser<br />

bem entendida.<br />

O <strong>com</strong>ando <strong>de</strong> atribuição é i<strong>de</strong>al para copiar o valor <strong>de</strong> uma variável para outra. A questão é que<br />

a variável <strong>de</strong> <strong>de</strong>stino tem seu valor alterado permanentemente após a realização do <strong>com</strong>ando. Ou seja,<br />

o valor que estava escrito nessa variável antes da execução da atribuição é apagado e o novo valor é<br />

escrito em seu lugar.<br />

No caso da operação <strong>de</strong> troca <strong>de</strong> valores, se fossem usadas apenas as duas variáveis envolvidas,<br />

uma <strong>de</strong>las teria seu valor perdido quando a primeira atribuição fosse realizada. Esse problema ocorre<br />

no Exemplo 2.20, no qual o valor inicial da variável var1 é perdido.<br />

1 int main (){<br />

2 int var1 , var2 ;<br />

3<br />

4 var1 = 100;<br />

5 var2 = 200;<br />

6<br />

7 var1 = var2 ; // var1 guarda 200<br />

8 var2 = var1 ; // var2 guarda 200<br />

9<br />

10 return 0;<br />

11 }<br />

Exemplo 2.20: Tentativa equivocada <strong>de</strong> trocar os valores <strong>de</strong> duas variáveis.<br />

A solução para o problema da perda <strong>de</strong> valores é simples e po<strong>de</strong> ser encontrada nas linhas 12, 13<br />

e 14 do Exemplo 2.19. Basta usar uma variável auxiliar e copiar para ela o valor da primeira variável<br />

<strong>de</strong> <strong>de</strong>stino usada nas atribuições. Naquele exemplo, o valor da variável num1 foi salvo na variável aux<br />

para não ser perdido na atribuição da linha 13. Em seguida, esse valor pô<strong>de</strong> ser copiado corretamente<br />

para a variável num2 na linha 14.<br />

2.9.2 Comando <strong>de</strong> seleção dupla<br />

DRAFT<br />

O <strong>com</strong>ando <strong>de</strong> seleção dupla po<strong>de</strong> ser <strong>com</strong>parado <strong>com</strong> a bifurcação <strong>de</strong> um caminho. É preciso escolher<br />

uma das alternativas e segui-la.<br />

Em programação, o <strong>com</strong>ando <strong>de</strong> seleção dupla serve para executar sempre uma <strong>de</strong> duas alternativas<br />

<strong>de</strong> sequências <strong>de</strong> instruções, <strong>de</strong> acordo <strong>com</strong> a verificação <strong>de</strong> uma condição. A estrutura do <strong>com</strong>ando<br />

na linguagem C é mostrada a seguir.<br />

if (){<br />

<br />

}else{<br />

<br />

}


2.9. COMANDOS DE SELEÇÃO 33<br />

Primeiramente, o <strong>com</strong>putador testa a expressão lógica. Caso resulte “verda<strong>de</strong>iro”, então a sequência<br />

<strong>de</strong> <strong>com</strong>andos 1 é executada. Caso contrário, a sequência <strong>de</strong> <strong>com</strong>andos 2 é realizada. Assim, apenas uma<br />

e sempre uma das sequências <strong>de</strong> <strong>com</strong>andos é executada durante uma mesma realização do <strong>com</strong>ando<br />

<strong>de</strong> seleção dupla.<br />

Após a operação <strong>de</strong> uma das sequências <strong>de</strong> <strong>com</strong>ando, o programa continua sua execução na primeira<br />

linha <strong>de</strong> código após o conjunto <strong>de</strong> instruções do <strong>com</strong>ando <strong>de</strong> seleção.<br />

Para exemplificar o uso do <strong>com</strong>ando <strong>de</strong> seleção dupla, o algoritmo do Pseudocódigo 2.4 mostra<br />

<strong>com</strong>o se faz para <strong>de</strong>cidir se um aluno está aprovado em uma disciplina, <strong>com</strong> base na média <strong>de</strong> suas<br />

notas semestrais.<br />

Pseudocódigo 2.4 Informa se um aluno está aprovado ou não, <strong>de</strong> acordo <strong>com</strong> a média das notas<br />

obtidas no semestre.<br />

Descrição: Decidir se um aluno está aprovado ou não, <strong>com</strong> base na média das notas semestrais.<br />

Dados <strong>de</strong> Entrada: Matrícula do aluno e notas.<br />

Saída do Programa: Mensagem dizendo se o aluno está aprovado ou não.<br />

Funç~ao Principal :<br />

Ler a matrícula e as notas do aluno .<br />

Calcular a média parcial .<br />

SE a média parcial for menor que 7:<br />

Apresentar uma mensagem dizendo que o aluno <strong>de</strong>ve fazer prova final .<br />

SEN~AO<br />

Apresentar uma mensagem dizendo que o aluno está aprovado .<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

O <strong>com</strong>ando SE-SENÃO do Pseudocódigo 2.4 <strong>de</strong>ve ser interpretado da mesma maneira que é<br />

o <strong>com</strong>ando <strong>de</strong> seleção dupla if. No Exemplo 2.21, é listado o código em C para o algoritmo do<br />

pseudocódigo recém-mencionado.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int matricula ;<br />

5 float n1 , n2 , n3 , mediaParcial ;<br />

6<br />

7 printf (" Digite a matricula e as notas parciais do aluno : ");<br />

8 scanf ("%d %f %f %f", & matricula , &n1 , &n2 , &n3);<br />

9 mediaParcial = (n1 + n2 + n3) / 3.0;<br />

10<br />

DRAFT<br />

11 if ( mediaParcial < 7.0) {<br />

12 printf ("\nO aluno %d <strong>de</strong>ve fazer prova final .", matricula );<br />

13 } else {<br />

14 printf ("\nO aluno %d foi aprovado <strong>com</strong> media %f", matricula , media );<br />

15 }<br />

16<br />

17 return 0;<br />

18 }<br />

Exemplo 2.21: Uso do <strong>com</strong>ando <strong>de</strong> seleção if para a verificação da média parcial <strong>de</strong> um aluno.<br />

No Exemplo 2.21, as linhas 4 e 5 correspon<strong>de</strong>m à <strong>de</strong>claração das variáveis; a linha 8, à inicialização<br />

<strong>de</strong>las. Após o cálculo da média parcial das notas (linha 9), o <strong>com</strong>ando <strong>de</strong> seleção verifica se tal média<br />

é menor que 7, 0 e, assim, executa a instrução da linha 12 ou da linha 14.<br />

Como po<strong>de</strong> ser visto no Exemplo 2.22, é possível usar <strong>com</strong>andos <strong>de</strong> seleção <strong>de</strong> forma aninhada,<br />

ou seja, po<strong>de</strong>-se colocar um <strong>com</strong>ando <strong>de</strong> seleção <strong>de</strong>ntro <strong>de</strong> uma das sequências <strong>de</strong> <strong>com</strong>andos <strong>de</strong> outro.<br />

Nesse programa, <strong>com</strong>para-se dois números inteiros digitados pelo usuário, informando se foram<br />

digitados em or<strong>de</strong>m crescente, <strong>de</strong>crescente ou se são iguais. Antes, entretanto, é bom observar o


34<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Pseudocódigo 2.5, que correspon<strong>de</strong> ao código do Exemplo 2.22.<br />

Pseudocódigo 2.5 Compara dois números e informa se foram digitados em or<strong>de</strong>m crescente, <strong>de</strong>crescente<br />

ou se são iguais.<br />

Descrição: Decidir se dois números digitados estão em or<strong>de</strong>m crescente, <strong>de</strong>crescente ou se são iguais.<br />

Dados <strong>de</strong> Entrada: Dois números.<br />

Saída do Programa: Mensagem dizendo se estão em or<strong>de</strong>m crescente, <strong>de</strong>crescente ou se são iguais.<br />

Funç~ao Principal :<br />

Ler dois números inteiros .<br />

SE o primeiros for maior que o segundo :<br />

Apresentar uma mensagem dizendo que é or<strong>de</strong>m crescente .<br />

SEN~AO<br />

SE o segundo for maior que o primeiro :<br />

Apresentar uma mensagem dizendo que é or<strong>de</strong>m <strong>de</strong>crescente .<br />

SEN~AO<br />

Apresentar uma mensagem dizendo que os números s~ao iguais .<br />

FIM -SE<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int num1 , num2 ;<br />

5<br />

6 printf (" Digite dois numeros inteiros quaisquer : ");<br />

7 scanf ("%d %d", &num1 , & num2 );<br />

8<br />

9 if ( num1 > num2 ){<br />

10 printf ("\ nOr<strong>de</strong>m <strong>de</strong>crescente .");<br />

11 } else {<br />

12 if ( num2 > num1 ){<br />

13 printf ("\ nOr<strong>de</strong>m crescente .");<br />

14 } else {<br />

15 printf ("\ nNumeros iguais .");<br />

16 }<br />

17 }<br />

18<br />

19 return 0;<br />

20 }<br />

DRAFT<br />

Exemplo 2.22: Comando <strong>de</strong> seleção if aninhado em outro <strong>com</strong>ando if.<br />

A estrutura dos <strong>com</strong>andos <strong>de</strong> seleção do Exemplo 2.22 permite testar todos os casos. Observe que<br />

não há uma verificação explícita para a igualda<strong>de</strong> dos números. Isso acontece porque todos os <strong>de</strong>mais<br />

casos possíveis são testados antes e, se não se tratar <strong>de</strong> nenhum <strong>de</strong>sses, então os números certamente<br />

são iguais. Nesse caso, basta apenas exibir a mensagem correspon<strong>de</strong>nte.<br />

Em muitos casos, além <strong>de</strong> ser elegante, o uso da estrutura <strong>de</strong> seleção aninhada po<strong>de</strong> ser mais<br />

eficiente. Verifica-se esse fato nos Exemplos 2.23 e 2.24. Ambos os programas leem três números<br />

digitados pelo usuário e i<strong>de</strong>ntificam o maior <strong>de</strong>les, porém, um dos programas faz menos verificações<br />

que o outro, ganhando eficiência.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int n1 , n2 , n3;<br />

5<br />

6 printf (" Entre <strong>com</strong> os tres numeros : ");


2.9. COMANDOS DE SELEÇÃO 35<br />

7 scanf ("%d %d %d", &n1 , &n2 , &n3);<br />

8<br />

9 if (( n1 > n2) && (n1 > n3)){<br />

10 printf ("O maior numero digitado foi : %d.", n1);<br />

11 }<br />

12<br />

13 if (( n2 > n1) && (n2 > n3)){<br />

14 printf ("O maior numero digitado foi : %d.", n2);<br />

15 }<br />

16<br />

17 if (( n3 > n1) && (n3 > n2)){<br />

18 printf ("O maior numero digitado foi : %d.", n3);<br />

19 }<br />

20<br />

21 return 0;<br />

22 }<br />

Exemplo 2.23: Programa que i<strong>de</strong>ntifica o maior <strong>de</strong> três números sem o uso do <strong>com</strong>ando <strong>de</strong> seleção<br />

aninhado.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int n1 , n2 , n3;<br />

5<br />

6 printf (" Entre <strong>com</strong> os tres numeros separados por espacos : ");<br />

7 scanf ("%d %d %d", &n1 , &n2 , &n3);<br />

8<br />

9 if (n1 > n2){<br />

10 if (n1 > n3){<br />

11 printf ("O maior numero digitado foi : %d.", n1);<br />

12 } else {<br />

13 printf ("O maior numero digitado foi : %d.", n3);<br />

14 }<br />

15 } else {<br />

16 if (n2 > n3){<br />

17 printf ("O maior numero digitado foi : %d.", n2);<br />

18 } else {<br />

19 printf ("O maior numero digitado foi : %d.", n3);<br />

20 }<br />

21 }<br />

22<br />

23 return 0;<br />

24 }<br />

Exemplo 2.24:<br />

aninhado.<br />

DRAFT<br />

Programa que i<strong>de</strong>ntifica o maior <strong>de</strong> três números, usando o <strong>com</strong>ando <strong>de</strong> seleção<br />

No caso do Exemplo 2.23, o uso <strong>de</strong> vários <strong>com</strong>andos if isolados acarreta em perda <strong>de</strong> eficiência.<br />

Quando o primeiro número digitado pelo usuário for o maior, o programa realiza dois testes <strong>de</strong>snecessários<br />

(linhas 13 e 17). E quando o segundo número for o maior, o programa realiza um teste<br />

<strong>de</strong>snecessário (linha 17).<br />

No Exemplo 2.24, apenas dois testes são executados (linhas 9 e 10 ou linhas 9 e 16), diminuindo<br />

significativamente o número <strong>de</strong> <strong>com</strong>parações em relação ao Exemplo 2.23.<br />

O programa do Exemplo 2.25 recebe do usuário três números inteiros e verifica se eles po<strong>de</strong>m<br />

ser lados <strong>de</strong> um triângulo. Caso verda<strong>de</strong>iro, o programa ainda indica a classificação do triângulo. O<br />

Pseudocódigo 2.6 lista o algoritmo para esse exemplo.<br />

Pseudocódigo 2.6 Informa se três números po<strong>de</strong>m constituir os lados <strong>de</strong> um triângulo e o tipo do<br />

triângulo que po<strong>de</strong> ser formado.


36<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Descrição: Calcular se três números po<strong>de</strong>m representar os lados <strong>de</strong> um triângulo e, caso seja possível, o tipo<br />

do triângulo.<br />

Dados <strong>de</strong> Entrada: Três valores inteiros.<br />

Saída do Programa: Mensagem dizendo o tipo do triângulo ou se não po<strong>de</strong> ser formado um triângulo.<br />

Funç~ao Principal :<br />

Ler tr^es números inteiros .<br />

SE os tr^es valores forem iguais :<br />

Apresentar uma mensagem dizendo que é tri^angulo equilátero .<br />

SEN~AO<br />

SE cada valor é menor do que a soma dos outros dois :<br />

SE os tr^es valores forem diferentes :<br />

Apresentar uma mensagem dizendo que é tri^angulo escaleno .<br />

SEN~AO<br />

Apresentar uma mensagem dizendo que é tri^angulo isósceles .<br />

FIM -SE<br />

SEN~AO<br />

Apresentar uma mensagem dizendo que os valores n~ao po<strong>de</strong>m ser lados <strong>de</strong><br />

um tri^angulo .<br />

FIM -SE<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int lado1 , lado2 , lado3 , soma1 , soma2 , soma3 ;<br />

5<br />

6 printf (" Entre <strong>com</strong> tres numeros inteiros : ");<br />

7 scanf ("%d %d %d", & lado1 , & lado2 , & lado3 );<br />

8<br />

9 if (( lado1 == lado2 ) && ( lado2 == lado3 )){<br />

10 printf (" Triangulo equilatero \n");<br />

11 } else {<br />

12 soma1 = lado1 + lado2 ;<br />

13 soma2 = lado1 + lado3 ;<br />

14 soma3 = lado2 + lado3 ;<br />

15<br />

16 if (( soma1 > lado3 ) && ( soma2 > lado2 ) && ( soma3 > lado1 )){<br />

17 if (( lado1 != lado2 ) && ( lado1 != lado3 ) && ( lado2 != lado3 )){<br />

18 printf (" Triangulo escaleno \n");<br />

19 } else {<br />

20 printf (" Triangulo isosceles \n");<br />

21 }<br />

22 } else {<br />

DRAFT<br />

23 printf ("Os tres lados nao formam um triangulo \n");<br />

24 }<br />

25 }<br />

26<br />

27 return 0;<br />

28 }<br />

Exemplo 2.25: Programa que indica se três números formam um triângulo.<br />

No Exemplo 2.25, o <strong>com</strong>ando if mais externo (linha 9) confere se os números formam um triângulo<br />

equilátero, verificando se os três números são iguais. Caso não formem um triângulo equilátero, na<br />

linha 16 é verificado se os três números formam realmente um triângulo, <strong>com</strong>parando a soma <strong>de</strong> dois<br />

lados <strong>com</strong> a medida do terceiro (para todas as possibilida<strong>de</strong>s). Caso verda<strong>de</strong>iro, o if mais interno<br />

confere se os três lados são diferentes um do outro, formando um triângulo escaleno; o resultado<br />

“falso”para esse último teste implica necessariamente na formação <strong>de</strong> um triângulo isósceles.


2.9. COMANDOS DE SELEÇÃO 37<br />

2.9.3 Comando <strong>de</strong> seleção múltipla<br />

O <strong>com</strong>ando <strong>de</strong> seleção if é bastante po<strong>de</strong>roso e largamente utilizado. Entretanto, ele não é o único<br />

<strong>com</strong>ando <strong>de</strong> seleção existente. Há um <strong>com</strong>ando que, embora seja menos abrangente que o <strong>com</strong>ando<br />

if, resolve muitas situações <strong>de</strong> forma clara e simples. Trata-se do <strong>com</strong>ando <strong>de</strong> seleção múltipla.<br />

O <strong>com</strong>ando <strong>de</strong> seleção múltipla sempre po<strong>de</strong> ser substituído por um ou mais <strong>com</strong>andos if aninhados,<br />

mas ele torna o código muito mais claro quando se quer executar várias sequências <strong>de</strong> <strong>com</strong>andos<br />

diferentes, sendo que cada sequência <strong>de</strong>va correspon<strong>de</strong>r a um <strong>de</strong>terminado valor <strong>de</strong> uma expressão. A<br />

estrutura seguinte facilita a <strong>com</strong>preensão do <strong>com</strong>ando.<br />

switch (){<br />

case :<br />

<br />

break;<br />

case :<br />

<br />

break;<br />

.<br />

.<br />

.<br />

case :<br />

<br />

break;<br />

<strong>de</strong>fault:<br />

<br />

}<br />

Na estrutura do <strong>com</strong>ando <strong>de</strong> seleção múltipla, a expressão normalmente é uma expressão aritmética<br />

ou uma variável <strong>de</strong> tipo numérica, e associa-se o valor da expressão ao valor <strong>de</strong> um <strong>de</strong>terminado case.<br />

Assim, apenas a sequência <strong>de</strong> <strong>com</strong>andos do bloco case correspon<strong>de</strong>nte será executada. É importante<br />

observar que cada sequência <strong>de</strong> <strong>com</strong>andos é encerrada pelo <strong>com</strong>ando break.<br />

A cláusula <strong>de</strong>fault é opcional. Ela marca a sequência <strong>de</strong> <strong>com</strong>andos padrão, que <strong>de</strong>ve ser executada<br />

quando nenhuma <strong>com</strong>paração obtiver sucesso. Se não estiver presente, nada será executado nesse caso.<br />

Na linguagem C, cada case <strong>de</strong>ve servir para <strong>com</strong>parar o resultado da expressão <strong>com</strong> um valor<br />

específico. Não se permite <strong>com</strong>parações <strong>com</strong> o resultado <strong>de</strong> outras expressões.<br />

No Exemplo 2.26 usa-se o <strong>com</strong>ando switch na construção <strong>de</strong> um programa que simula o funcionamento<br />

<strong>de</strong> uma urna eletrônica. O Pseudocódigo 2.7 exibe o algoritmo <strong>de</strong>sse exemplo.<br />

DRAFT<br />

Pseudocódigo 2.7 Simulação <strong>de</strong> uma urna eletrônica simplificada.<br />

Descrição: Simular uma urna eletrônica simplificada. Não há a opção para voto em branco.<br />

Dados <strong>de</strong> Entrada: Número do candidato.<br />

Saída do Programa: Mensagem dizendo o nome do candidato escolhido ou se o voto foi anulado.<br />

Funç~ao Principal :<br />

Ler o número do candidato .<br />

CASO o número do candidato SEJA :<br />

1, ENT~AO apresentar uma mensagem dizendo que Hort^encia da Silva foi<br />

escolhida .<br />

2, ENT~AO apresentar uma mensagem dizendo que José dos Cravos foi escolhido .<br />

3, ENT~AO apresentar uma mensagem dizendo que Margarida S. Pereira foi<br />

escolhida .<br />

OUTRO VALOR , ENT~AO imprima uma mensagem dizendo que o voto foi anulado .<br />

FIM - CASO<br />

FIM - Funç~ao Principal


38<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

O <strong>com</strong>portamento do <strong>com</strong>ando CASO-SEJA do Pseudocódigo 2.7 <strong>de</strong>ve ser pensado da mesma<br />

maneira que o do <strong>com</strong>ando <strong>de</strong> seleção múltipla switch.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int numero ;<br />

5<br />

6 printf (" URNA ELETR^ONICA - SEU VOTO PARA PREFEITO : ");<br />

7 scanf ("%d", & numero );<br />

8<br />

9 switch ( numero ){<br />

10 case 1:<br />

11 printf (" Candidato escolhido : Hort^encia da Silva ");<br />

12 break ;<br />

13 case 2:<br />

14 printf (" Candidato escolhido : José dos Cravos ");<br />

15 break ;<br />

16 case 3:<br />

17 printf (" Candidato escolhido : Margarida S. Pereira ");<br />

18 break ;<br />

19 <strong>de</strong>fault :<br />

20 printf ("Número digitado inválido . Voto anulado .");<br />

21 }<br />

22<br />

23 return 0;<br />

24 }<br />

Exemplo 2.26: Uso do <strong>com</strong>ando switch para simular uma urna eletrônica <strong>de</strong> eleição.<br />

No programa do Exemplo 2.26, os números <strong>de</strong> 1 a 3 estão associados a <strong>de</strong>terminados candidatos<br />

e, para qualquer outro número, a cláusula <strong>de</strong>fault é associada.<br />

Após a inicialização da variável numero <strong>com</strong> o <strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados (linha 7), o <strong>com</strong>ando<br />

<strong>de</strong> seleção <strong>com</strong>para o número digitado <strong>com</strong> os números dos três candidatos inscritos. Em cada caso,<br />

se o número digitado coinci<strong>de</strong> <strong>com</strong> a constante, a sequência <strong>de</strong> <strong>com</strong>andos correspon<strong>de</strong>nte ao candidato<br />

escolhido é executada. Se nenhuma <strong>com</strong>paração obtiver sucesso, então o usuário digitou um número<br />

<strong>de</strong> candidato que não existe. Nesse caso, o programa exibe uma mensagem <strong>de</strong> alerta para o usuário,<br />

avisando-lhe que o número digitado é inválido para a eleição (linha 20).<br />

Quando o <strong>com</strong>ando break não termina uma sequência <strong>de</strong> <strong>com</strong>andos cuja <strong>com</strong>paração resultou verda<strong>de</strong>ira,<br />

a sequência <strong>de</strong> <strong>com</strong>andos seguinte é executada sem que o teste correspon<strong>de</strong>nte seja efetuado.<br />

Na prática, o que acontece é que quando uma <strong>com</strong>paração do switch resultar em verda<strong>de</strong>iro, todas as<br />

sequências <strong>de</strong> <strong>com</strong>ando seguintes são executadas até que o primeiro <strong>com</strong>ando break seja encontrado.<br />

É preciso, portanto, ficar atento e finalizar cada sequência <strong>de</strong> <strong>com</strong>andos <strong>com</strong> o <strong>com</strong>ando break<br />

evitando, assim, erros <strong>de</strong> programação muitas vezes difíceis <strong>de</strong> <strong>de</strong>tectar.<br />

DRAFT<br />

2.10 Comandos <strong>de</strong> Repetição<br />

A capacida<strong>de</strong> que as máquinas possuem <strong>de</strong> repetir tarefas exaustivamente <strong>com</strong> a mesma qualida<strong>de</strong> é<br />

uma das principais razões do sucesso <strong>de</strong> sua invenção. Os <strong>com</strong>putadores po<strong>de</strong>m repetir uma ou mais<br />

sequências <strong>de</strong> <strong>com</strong>andos quantas vezes forem necessário, e é o programador quem <strong>de</strong>ci<strong>de</strong> o critério <strong>de</strong><br />

parada das repetições.<br />

As aplicações para os <strong>com</strong>andos <strong>de</strong> repetição são praticamente infinitas porque quase todas as<br />

tarefas contêm partes que <strong>de</strong>vem ser executadas mais <strong>de</strong> uma vez.<br />

Na linguagem C, existem três principais estruturas <strong>de</strong> repetição. A opção pelo uso <strong>de</strong> uma ou<br />

outra <strong>de</strong>pen<strong>de</strong> normalmente da preferência do programador e do problema em questão, normalmente<br />

buscando-se o máximo <strong>de</strong> clareza ou facilida<strong>de</strong> <strong>de</strong> escrita do código. Essas três estruturas são abordadas<br />

a seguir.


2.10. COMANDOS DE REPETIÇÃO 39<br />

2.10.1 Comando <strong>de</strong> repetição <strong>com</strong> pré-condição<br />

A estrutura do <strong>com</strong>ando while é a mais simples das três e seu funcionamento é igualmente simples <strong>de</strong><br />

<strong>com</strong>preen<strong>de</strong>r. A estrutura é a seguinte:<br />

while (< express~ao lógica >){<br />

<br />

}<br />

O <strong>com</strong>putador inicia o <strong>com</strong>ando testando a valida<strong>de</strong> da expressão lógica. Se for verda<strong>de</strong>ira, então<br />

ele executa a sequência <strong>de</strong> <strong>com</strong>andos e retorna ao teste <strong>de</strong> validação da expressão lógica, reiniciando<br />

o ciclo. O <strong>com</strong>putador repete esse processo até que o resultado da expressão lógica seja falso.<br />

No caso em que o primeiro teste <strong>de</strong> validação da expressão lógica resulta em falso, a sequência <strong>de</strong><br />

<strong>com</strong>andos não é executada nenhuma vez.<br />

O Pseudocódigo 2.8 representa um algoritmo que recebe um número inteiro positivo n e apresenta<br />

na tela os n primeiros inteiros positivos.<br />

Pseudocódigo 2.8 Apresentar os n primeiros números positivos.<br />

Descrição: Apresentar na tela os n primeiros números positivos.<br />

Dados <strong>de</strong> Entrada: n (quantida<strong>de</strong> <strong>de</strong> inteiros a serem impressos).<br />

Saída do Programa: Números inteiros <strong>de</strong> 1 a n.<br />

Funç~ao Principal :<br />

Ler n.<br />

Valor recebe 1.<br />

ENQUANTO Valor for menor ou igual a n FAÇA:<br />

Apresentar Valor .<br />

Incrementar Valor .<br />

FIM - ENQUANTO<br />

FIM - Funç~ao Principal<br />

O <strong>com</strong>ando ENQUANTO do Pseudocódigo 2.8 funciona da mesma maneira que o <strong>com</strong>ando <strong>de</strong><br />

repetição <strong>com</strong> pré-condição while. O programa do Exemplo 2.27 mostra um código em C que realiza<br />

as operações do referido pseudocódigo.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int n, valor ;<br />

5<br />

DRAFT<br />

6 printf (" Digite um numero inteiro positivo : ");<br />

7 scanf ("%d", &n);<br />

8<br />

10<br />

9 valor = 1;<br />

11 while ( valor


40<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

(linhas 12 e 13) é executado enquanto o número armazenado em valor for menor ou igual ao número<br />

armazenado em n.<br />

A condição <strong>de</strong> parada em qualquer <strong>com</strong>ando <strong>de</strong> repetição é um fator muito importante que se<br />

<strong>de</strong>ve escolher <strong>com</strong> bastante cuidado. É preciso garantir que o <strong>com</strong>putador efetue um número finito <strong>de</strong><br />

repetições para que, em algum momento, o programa possa seguir seu fluxo normal <strong>de</strong> execução. Além<br />

<strong>de</strong> resultados incorretos, uma condição <strong>de</strong> parada errônea po<strong>de</strong> acarretar uma execução <strong>de</strong> programa<br />

sem término (nessa situação, diz-se que o programa está em “loop infinito”).<br />

A Tabela 2.10 apresenta o resultado da execução do programa do Exemplo 2.27, quando o usuário<br />

informa o valor 4 para a variável n.<br />

n valor valor


2.10. COMANDOS DE REPETIÇÃO 41<br />

Saída do Programa: Mensagem indicando o candidato escolhido.<br />

Funç~ao Principal :<br />

Resposta recebe zero .<br />

ENQUANTO resposta for igual a zero FAÇA:<br />

Ler o número do candidato .<br />

Apresentar o nome do candidato escolhido .<br />

Ler a resposta da confirmaç~ao.<br />

FIM - ENQUANTO .<br />

FIM - Funç~ao<br />

Principal<br />

No código do Exemplo 2.29, o usuário tem a possibilida<strong>de</strong> <strong>de</strong> corrigir o seu voto sem que o programa<br />

termine.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int numero , confirma ;<br />

5<br />

6 confirma = 0;<br />

7<br />

8 while ( confirma == 0){<br />

9 printf (" URNA ELETRONICA - SEU VOTO PARA PREFEITO : \n");<br />

10 scanf ("%d", & numero );<br />

11<br />

12 switch ( numero )<br />

13 {<br />

14 case 1:<br />

15 printf (" Candidato escolhido : Hortencia da Silva \n");<br />

16 break ;<br />

17 case 2:<br />

18 printf (" Candidato escolhido : Jose dos Cravos \n");<br />

19 break ;<br />

20 case 3:<br />

21 printf (" Candidato escolhido : Margarida S. Pereira \n");<br />

22 break ;<br />

23 <strong>de</strong>fault :<br />

24 printf (" Numero digitado invalido . Voto NULO .\n");<br />

25 }<br />

26<br />

27 printf ("\ nDigite 1 para CONFIRMAR ou 0 para CORRIGIR ");<br />

28 scanf ("%d", & confirma );<br />

29 }<br />

30<br />

31 return 0;<br />

32 }<br />

DRAFT<br />

Exemplo 2.29: Comando <strong>de</strong> repetição while utilizado para melhorar o código do Exemplo 2.26.<br />

O critério <strong>de</strong> parada escolhido no Exemplo 2.29 é a alteração do valor da variável confirma.<br />

Enquanto essa variável armazena o valor zero, o programa repetirá o processo <strong>de</strong> votação e perguntará<br />

ao usuário se confirma o voto ou se gostaria <strong>de</strong> corrigi-lo. Quando o valor da variável confirma é<br />

alterado, a expressão lógica da linha 8 retorna falso, encerrando o <strong>com</strong>ando <strong>de</strong> repetição.<br />

No Exemplo 2.30, o usuário fornece <strong>com</strong>o entrada números inteiros positivos e o programa retorna<br />

o maior valor <strong>de</strong>ntre os digitados pelo usuário.<br />

Pseudocódigo 2.10 Cálculo do maior número <strong>de</strong>ntre os digitados pelo usuário.<br />

Descrição: Calcular o maior número <strong>de</strong>ntre os digitados pelo usuário


42<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Dados <strong>de</strong> Entrada: Números inteiros positivos<br />

Saída do Programa: Maior número <strong>de</strong>ntre os digitados<br />

Funç~ao Principal :<br />

Ler um número n<br />

Inicializar contador i<br />

ENQUANTO contador i for menor que n FAÇA:<br />

Ler um número inteiro positivo .<br />

SE número é maior que o maior número anterior :<br />

Atualizar o maior número .<br />

FIM -SE<br />

Incrementar o contador i.<br />

FIM - ENQUANTO<br />

Apresentar maior número .<br />

FIM - Funç~ao Principal<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int i = 0, n, numero , maiornumero = 0;<br />

5<br />

6 printf (" Digite o numero ’n’ inteiro positivo :);<br />

7 scanf ("%d", &n);<br />

8<br />

9 while (i < n){<br />

10 printf (" Digite um numero inteiro positivo :");<br />

11 scanf ("%d" ,& numero );<br />

12<br />

13 if ( numero > maiornumero ) maiornumero = numero ;<br />

14 i ++;<br />

15 }<br />

16<br />

17 printf (" Maior numero :%d\n", maiornumero );<br />

18<br />

19 return 0;<br />

20 }<br />

DRAFT<br />

Exemplo 2.30: Comando <strong>de</strong> repetição while utilizado para ler ’n’ números <strong>de</strong> entrada e <strong>com</strong>parar cada um<br />

<strong>com</strong> o maior adquirido até atingir a quantida<strong>de</strong> ’n’.<br />

O critério <strong>de</strong> parada do Exemplo 2.30 é a contagem dos números até atingir o valor ’n’ fornecido<br />

pelo usuário. Portanto, o laço (while) só termina quando a quantida<strong>de</strong> <strong>de</strong> números que o usuário<br />

forneceu for atingida. Enquanto ’i’ < ’n’, a variável ’numero’ é atribuída pelo usuário e <strong>com</strong>parada<br />

<strong>com</strong> o maior número <strong>de</strong>ntre os digitados anteriormente e a variável ’i’ é incrementada <strong>com</strong> o valor 1,<br />

em cada iteração. Enten<strong>de</strong>-se por iteração <strong>com</strong>o a leitura dos <strong>com</strong>andos existentes no laço, portanto,<br />

o <strong>com</strong>ando ’while’ <strong>de</strong>ste exemplo possui ’n’ iterações.<br />

Um outro exemplo simples para o uso do <strong>com</strong>ando while é um algoritmo no qual o usuário informa<br />

uma sequência <strong>de</strong> valores positivos e, em seguida, a média <strong>de</strong>sses valores é apresentada. O usuário<br />

<strong>de</strong>verá digitar zero quando quiser finalizar a sequência e saber a média. O algoritmo <strong>de</strong>sse programa<br />

está listado no Pseudocódigo 2.11.<br />

O Exemplo 2.31 exibe o programa para o Pseudocódigo 2.11.<br />

Pseudocódigo 2.11 Cálculo da média <strong>de</strong> números positivos digitados pelo usuário.<br />

Descrição: Calcular a média <strong>de</strong> números positivos digitados pelo usuário.<br />

Dados <strong>de</strong> Entrada: Números não negativos.<br />

Saída do Programa: Média dos valores digitados.


2.10. COMANDOS DE REPETIÇÃO 43<br />

Funç~ao Principal :<br />

Ler valor .<br />

Inicializar soma .<br />

ENQUANTO valor digitado for positivo FAÇA:<br />

Atualizar a soma dos números digitados .<br />

Incrementar a quantida<strong>de</strong> <strong>de</strong> números digitados .<br />

Ler valor .<br />

FIM - ENQUANTO .<br />

SE a quantida<strong>de</strong> <strong>de</strong> números digitados for maior que zero :<br />

Calcular a média dos valores digitados .<br />

Apresentar a média .<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

No código do Exemplo 2.31, a variável soma precisa ser inicializada <strong>com</strong> zero, pois, caso contrário,<br />

irá receber <strong>com</strong>o atribuição: valor inexistente da soma mais valor fornecido pelo usuário.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 float valor , soma , media ;<br />

5 int quantida<strong>de</strong> ;<br />

6<br />

7 soma = 0;<br />

8 quantida<strong>de</strong> = 0;<br />

9<br />

10 printf (" Informe um valor negtivo ou zero para encerrar o programa : ");<br />

11 scanf ("%f", & valor );<br />

12<br />

13 while ( valor > 0){<br />

14 soma = soma + valor ;<br />

15 quantida<strong>de</strong> = quantida<strong>de</strong> + 1;<br />

16 printf (" Informe um valor negativo ou zero para encerrar o programa : ");<br />

17 scanf ("%f", & valor );<br />

18 }<br />

19<br />

20 if ( quantida<strong>de</strong> > 0){<br />

21 media = soma / quantida<strong>de</strong> ;<br />

22 printf (" Media dos valores digitados : %f\n", media );<br />

23 }<br />

24<br />

25 return 0;<br />

26 }<br />

DRAFT<br />

Exemplo 2.31: Programa que calcula a média dos valores <strong>de</strong> uma sequência digitada pelo usuário.<br />

O funcionamento do programa do Exemplo 2.31 é simples. A variável soma guarda a soma dos<br />

valores digitados pelo usuário e <strong>de</strong>ve ser inicializada <strong>com</strong> zero. A cada novo valor positivo digitado,<br />

seu valor <strong>de</strong>ve ser atualizado. Essa atualização ocorre na linha 14.<br />

A variável valor é a condição <strong>de</strong> parada do <strong>com</strong>ando <strong>de</strong> repetição. Sempre que o usuário digita<br />

zero (ou até mesmo um número negativo), o <strong>com</strong>ando <strong>de</strong> repetição é encerrado.<br />

Para saber quantos números foram digitados, a variável quantida<strong>de</strong> é empregada. Ela é inicializada<br />

<strong>com</strong> zero e, sempre que o usuário digita um número, ela é incrementada (linha 15).<br />

Quando o <strong>com</strong>ando <strong>de</strong> repetição é encerrado, é preciso verificar se o usuário digitou algum valor.<br />

Essa verificação se <strong>de</strong>ve ao fato <strong>de</strong> que o primeiro valor digitado po<strong>de</strong> ser zero, indicando que o<br />

usuário saiu do programa e não quis calcular nada. No caso <strong>de</strong> algum valor válido ter sido informado<br />

(expressão lógica da linha 20), então a média é calculada e uma mensagem <strong>com</strong> o resultado é exibida<br />

ao usuário (linhas 21 e 22).


44<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Há <strong>de</strong>terminados códigos que possuem um padrão ao se utilizar o <strong>com</strong>ando while. Como exemplo,<br />

temos o código do Exemplo 2.31. No Pseudocódigo 2.12, a exemplificação do padrão:<br />

Pseudocódigo 2.12 Padrão <strong>de</strong> código.<br />

Descrição: Padrão <strong>de</strong> código.<br />

Inicializar os dados <strong>de</strong> saída<br />

Ler dado <strong>de</strong> entrada<br />

ENQUANTO n~ao há finalizaç~ao FAÇA:<br />

Atualizar os dados <strong>de</strong> saída.<br />

Ler o próximo dado <strong>de</strong> entrada .<br />

FIM - ENQUANTO<br />

Finalizar os dados <strong>de</strong> saída<br />

Apresentar os dados <strong>de</strong> saída<br />

Ao final <strong>de</strong>ste capítulo, o Problema dos Lotes Encaixantes (Seção 2.11) será <strong>de</strong>talhado utilizando<br />

este padrão.<br />

O Exemplo 2.32 exibe o programa para o Pseudocódigo 2.13.<br />

Pseudocódigo 2.13 Cálculo do maior número, menor e da média <strong>de</strong> números inteiros positivos<br />

digitados pelo usuário.<br />

Descrição: Calcular o maior número, menor e a média <strong>de</strong> números inteiros positivos digitados pelo usuário.<br />

Dados <strong>de</strong> Entrada: Números inteiros não negativos.<br />

Saída do Programa: Maior número, menor e média dos números digitados.<br />

Funç~ao Principal :<br />

Ler número .<br />

Menor número recebe número .<br />

ENQUANTO número digitado for positivo FAÇA:<br />

SE número é maior que o maior número :<br />

Maior número recebe número .<br />

FIM -SE<br />

DRAFT<br />

SE número é menor que o menor número :<br />

Menor n m e r o recebe número .<br />

FIM -SE<br />

Atualizar a soma dos números digitados .<br />

Incrementar a quantida<strong>de</strong> <strong>de</strong> números digitados .<br />

Ler número .<br />

FIM - ENQUANTO .<br />

Média recebe soma dividida pela quantida<strong>de</strong> <strong>de</strong> números digitados .<br />

Apresentar maior número , menor e média .<br />

FIM - Funç~ao Principal<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int numero , maiornumero , menornumero , qtdnumeros , soma , media ;<br />

5<br />

6 maiornumero = 0;<br />

7 qtdnumeros = 0;<br />

8 soma = 0;<br />

9


2.10. COMANDOS DE REPETIÇÃO 45<br />

10 printf (" Digite um numero inteiro positivo (0 para finalizar ):");<br />

11 scanf ("%d", & numero );<br />

12 menornumero = numero ;<br />

13<br />

14 while ( numero > 0){<br />

15 if ( numero > maiornumero )<br />

16 maiornumero = numero ;<br />

17 if ( numero < menornumero )<br />

18 menornumero = numero ;<br />

19<br />

20 soma += numero ;<br />

21 qtdnumeros ++;<br />

22<br />

23 printf (" Digite um numero inteiro positivo (0 para finalizar ):");<br />

24 scanf ("%d", & numero );<br />

25 }<br />

26<br />

27 media = soma / qtdnumeros ;<br />

28 printf (" Maior Numero : %d\n Menor Numero : %d\n Mudia : %d\n", maiornumero ,<br />

menornumero , media );<br />

29<br />

30 return 0;<br />

31 }<br />

Exemplo 2.32: Comando <strong>de</strong> repetição while utilizado para ler números <strong>de</strong> entrada, calcular média e <strong>com</strong>parar<br />

cada um <strong>com</strong> o maior adquirido e menor adquirido.<br />

O programa do Exemplo 2.32 é uma junção dos exemplos 2.30 e 2.31 <strong>com</strong> uma funcionalida<strong>de</strong><br />

adicional que é calcular o menor número <strong>de</strong>ntre os digitados pelo usuário.<br />

2.10.2 Comando <strong>de</strong> repetição <strong>com</strong> pós-condição<br />

Em contraste <strong>com</strong> o <strong>com</strong>ando <strong>de</strong> pré-condição, o <strong>com</strong>ando <strong>de</strong> repetição <strong>com</strong> pós-condição só efetua o<br />

teste da expressão lógica (condição <strong>de</strong> parada) após a primeira execução da sequência <strong>de</strong> <strong>com</strong>andos.<br />

Logo, o bloco <strong>de</strong> <strong>com</strong>andos é executado pelo menos uma vez, in<strong>de</strong>pen<strong>de</strong>nte da expressão lógica. A<br />

própria sintaxe do <strong>com</strong>ando sugere essa diferença:<br />

do{<br />

<br />

} while (< express~ao lógica >);<br />

DRAFT<br />

O Pseudocódigo 2.9 po<strong>de</strong> ser modificado para melhorar sua legibilida<strong>de</strong>.<br />

<strong>com</strong>ando FAÇA-ENQUANTO, o algoritmo fica mais simples.<br />

Pseudocódigo 2.14 Urna eletrônica <strong>com</strong> opção <strong>de</strong> corrigir voto (versão melhorada).<br />

Descrição: Urna eletrônica <strong>com</strong> opção <strong>de</strong> corrigir voto.<br />

Dados <strong>de</strong> Entrada: Número do candidato, resposta da confirmação.<br />

Saída do Programa: Mensagem indicando o candidato escolhido.<br />

Com o emprego do<br />

Funç~ao Principal :<br />

Ler número .<br />

Menor número recebe número .<br />

ENQUANTO número digitado for positivo FAÇA:<br />

SE número é maior que o maior número :<br />

Maior número recebe número .<br />

FIM -SE<br />

SE número é menor que o menor número :


46<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Menor número recebe número .<br />

FIM -SE<br />

Atualizar a soma dos números digitados .<br />

Incrementar a quantida<strong>de</strong> <strong>de</strong> números digitados .<br />

Ler número .<br />

FIM - ENQUANTO .<br />

Média recebe soma dividida pela quantida<strong>de</strong> <strong>de</strong> números digitados .<br />

Apresentar maior número , menor e média .<br />

FIM - Funç~ao Principal<br />

O programa do Exemplo 2.29 po<strong>de</strong> ser reescrito utilizando-se o <strong>com</strong>ando do-while. Nesse caso, o<br />

uso do do-while permite ao programador ter a opção <strong>de</strong> não inicializar a variável confirma antes da<br />

execução da sequência <strong>de</strong> <strong>com</strong>andos, responsabilizando o usuário pela inicialização (conforme se nota<br />

no Exemplo 2.33).<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int numero , confirma ;<br />

5<br />

6 /* A variavel confirma nao e mais inicializada pelo programador */<br />

7 do{<br />

8 printf (" URNA ELETRONICA - SEU VOTO PARA PREFEITO : \n");<br />

9 scanf ("%d", & numero );<br />

10<br />

11 switch ( numero )<br />

12 {<br />

13 case 1:<br />

14 printf (" Candidato escolhido : Hortencia da Silva \n");<br />

15 break ;<br />

16 case 2:<br />

17 printf (" Candidato escolhido : Jose dos Cravos \n");<br />

18 break ;<br />

19 case 3:<br />

20 printf (" Candidato escolhido : Margarida S. Pereira \n");<br />

21 break ;<br />

22 <strong>de</strong>fault :<br />

23 printf (" Numero digitado invalido . Voto NULO .\n");<br />

24 }<br />

25<br />

26 printf ("\ nDigite 1 para CONFIRMAR ou 0 para CORRIGIR ");<br />

27 scanf ("%d", & confirma );<br />

28 } while (! confirma );<br />

29<br />

30 return 0;<br />

31 }<br />

DRAFT<br />

Exemplo 2.33: Aplicação para o <strong>com</strong>ando do-while, modificando o código do Exemplo 2.29.<br />

No Exemplo 2.33, nota-se que não há mais a inicialização explícita da variável confirma. Com<br />

o <strong>com</strong>ando do-while, garante-se que a variável será inicializada pelo usuário antes <strong>de</strong> seu valor ser<br />

testado na expressão lógica da linha 28, utilizada <strong>com</strong>o critério <strong>de</strong> parada.<br />

Po<strong>de</strong> parecer estranho, à primeira vista, <strong>com</strong>o a expressão lógica !confirma funciona. Na verda<strong>de</strong><br />

essa expressão é equivalente ao teste confirma==0.<br />

Para enten<strong>de</strong>r essa equivalência, basta lembrar que o operador lógico <strong>de</strong> negação inverte o valor<br />

lógico da variável ao qual ele é aplicado. É bom recordar também que, para os números inteiros, o<br />

valor zero equivale a falso enquanto que qualquer número diferente <strong>de</strong> zero é tomado <strong>com</strong>o valor lógico<br />

verda<strong>de</strong>iro. Assim sendo, sempre que o programador <strong>de</strong>sejar testar se um valor inteiro é igual a zero,<br />

basta testar o resultado do operador <strong>de</strong> negação, pois o único caso em que ele retornará verda<strong>de</strong>iro<br />

será quando o valor numérico testado for zero.


2.10. COMANDOS DE REPETIÇÃO 47<br />

2.10.3 Comando <strong>de</strong> repetição con<strong>de</strong>nsado<br />

O <strong>com</strong>ando <strong>de</strong> repetição con<strong>de</strong>nsado permite agrupar, em um único <strong>com</strong>ando, a inicialização <strong>de</strong> uma<br />

variável, o incremento <strong>de</strong>sta variável e o teste <strong>de</strong> parada. Seu uso mais <strong>com</strong>um é em situações nas<br />

quais o número <strong>de</strong> repetições da sequência <strong>de</strong> <strong>com</strong>andos é conhecido antes mesmo do início do for.<br />

A estrutura do <strong>com</strong>ando é exibida a seguir:<br />

for (< inicializaç~ao >; < expressao lógica >; ){<br />

<br />

}<br />

Inicialização é um <strong>com</strong>ando <strong>de</strong> atribuição usado para colocar um valor na variável <strong>de</strong> controle<br />

utilizada na expressão lógica. Assim <strong>com</strong>o os <strong>de</strong>mais <strong>com</strong>andos <strong>de</strong> repetição, a expressão lógica<br />

representa a condição <strong>de</strong> parada das iterações. Incremento <strong>de</strong>fine <strong>com</strong>o a variável <strong>de</strong> controle que será<br />

modificada a cada iteração.<br />

Um exemplo <strong>de</strong> <strong>com</strong>o utilizar o <strong>com</strong>ando for está listado no código do Exemplo 2.34. Esse programa<br />

serve para imprimir os n primeiros termos <strong>de</strong> uma PG (progressão geométrica). O usuário <strong>de</strong>ve<br />

informar os valores do primeiro termo, da razão e da quantida<strong>de</strong> <strong>de</strong> termos a serem exibidos.<br />

Pseudocódigo 2.15 Cálculo dos n primeiros termos <strong>de</strong> uma PG (progressão geométrica).<br />

Descrição: Calcular os n primeiros termos <strong>de</strong> uma PG.<br />

Dados <strong>de</strong> Entrada: Primeiro termo da PG, razão da PG e quantida<strong>de</strong> <strong>de</strong> termos da PG a serem impressos.<br />

Saída do Programa: Termos da PG.<br />

Funç~ao Principal :<br />

Ler primeiro termo .<br />

Ler raz~ao da PG.<br />

Ler quantida<strong>de</strong> <strong>de</strong> termos .<br />

ENQUANTO i menor que n FAÇA:<br />

Apresentar termo .<br />

Termo recebe termo multiplicado pela raz~ao.<br />

FIM - ENQUANTO .<br />

FIM - Funç~ao<br />

Principal<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

DRAFT<br />

4 float primeiroTermo , razao , n, i, termo ;<br />

5<br />

6 printf (" Informe o valor do primeiro termo da PG: \n");<br />

7 scanf ("%f", & primeiroTermo );<br />

8<br />

9 printf (" Informe o valor da razao da PG: \n");<br />

10 scanf ("%f", & razao );<br />

11<br />

12 printf (" Informe quantos termos <strong>de</strong>vem ser impressos : \n");<br />

13 scanf ("%f", &n);<br />

14<br />

15 termo = primeiroTermo ;<br />

16<br />

17 for (i = 0; i < n; i = i + 1) {<br />

18 printf ("%f ", termo );<br />

19 termo = termo * razao ;<br />

20 }<br />

21<br />

22 return 0;<br />

23 }


48<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Exemplo 2.34: Programa para exibir os n primeiros termos <strong>de</strong> uma progressão geométrica utilizando o <strong>com</strong>ando<br />

<strong>de</strong> repetição for.<br />

No Exemplo 2.34, as variáveis primeiroTermo, razao e n são inicializadas pelo usuário, usando o<br />

<strong>com</strong>ando <strong>de</strong> entrada <strong>de</strong> dados. A linha 15 trata da inicialização da variável termo, que guarda o valor<br />

do termo da PG a ser impresso a cada repetição (iteração) do <strong>com</strong>ando for.<br />

O <strong>com</strong>ando <strong>de</strong> repetição, em primeiro lugar, inicializa a variável <strong>de</strong> controle i <strong>com</strong> o valor zero.<br />

Em seguida, ocorre a verificação da expressão lógica. Caso o usuário tenha digitado zero, o <strong>com</strong>ando<br />

não executa sua sequência <strong>de</strong> instruções nenhuma vez, pois tanto i quanto n armazenam zero e tornam<br />

falso o resultado da expressão lógica. Nesse caso, nada é impresso na tela.<br />

Mas se o usuário digitou um valor maior que zero, a sequência <strong>de</strong> <strong>com</strong>andos será repetida até que<br />

a quantida<strong>de</strong> solicitada <strong>de</strong> termos seja impressa. Para isso, o <strong>com</strong>ando <strong>de</strong> saída <strong>de</strong> dados é chamado<br />

logo no início da sequência <strong>de</strong> <strong>com</strong>andos (linha 18). No caso em que i é igual a zero (primeira iteração),<br />

o primeiro termo é exibido. A linha 19 conclui a sequência <strong>de</strong> <strong>com</strong>andos atualizando a variável termo<br />

para guardar o próximo termo da sequência.<br />

Um passo implícito é que o <strong>com</strong>ando realiza o incremento da variável i no momento após a<br />

execução da última instrução da sequência <strong>de</strong> <strong>com</strong>andos. Feita essa atualização, a condição <strong>de</strong> parada<br />

é novamente verificada e, caso seja verda<strong>de</strong>ira, uma nova repetição é <strong>com</strong>eçada para imprimir outro<br />

termo da PG.<br />

A Tabela 2.11 mostra passo a passo a execução <strong>com</strong>pleta do <strong>com</strong>ando <strong>de</strong> repetição para o programa<br />

do Exemplo 2.34. Os valores informados são para uma PG <strong>de</strong> razão igual a 2, primeiro termo igual<br />

a 2 e quantida<strong>de</strong> <strong>de</strong> termos a serem impressos igual a 4. As colunas mostram as variáveis principais<br />

do <strong>com</strong>ando <strong>de</strong> repetição (i, termo e n), o resultado da expressão lógica a cada iteração e o que foi<br />

impresso na tela.<br />

i termo n i < n Tela<br />

0 4 4 Verda<strong>de</strong>iro 2<br />

1 8 4 Verda<strong>de</strong>iro 2 4<br />

2 16 4 Verda<strong>de</strong>iro 2 4 8<br />

3 32 4 Verda<strong>de</strong>iro 2 4 8 16<br />

4 32 4 Falso 2 4 8 16<br />

Tabela 2.11: Detalhes da execução do <strong>com</strong>ando for do Exemplo 2.34<br />

.<br />

O programa do Exemplo 2.35 realiza a operação <strong>de</strong> exponenciação <strong>de</strong> um número, utilizando o<br />

<strong>com</strong>ando <strong>de</strong> repetição for.<br />

DRAFT<br />

Pseudocódigo 2.16 Cálculo da exponenciação <strong>de</strong> um número n<br />

Descrição: Calcular a exponenciação <strong>de</strong> um número n usando o <strong>com</strong>ando for.<br />

Dados <strong>de</strong> Entrada: Base e expoente.<br />

Saída do Programa: Resultado da exponenciação.<br />

Funç~ao Principal :<br />

Ler base .<br />

Ler expoente .<br />

Inicializar i.<br />

ENQUANTO i menor que expoente FAÇA:<br />

AtualizaR resultado .<br />

Incrementar i.<br />

FIM - ENQUANTO .<br />

FIM - Funç~ao<br />

Principal


2.11. PROBLEMA DOS LOTES ENCAIXANTES 49<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int base , expoente , resultado , i;<br />

5<br />

6 printf (" Informe os valores para base e expoente : \n");<br />

7 scanf ("%d %d", &base , & expoente );<br />

8<br />

10<br />

9 resultado = 1;<br />

11 for (i = 0; i < expoente ; i = i + 1)<br />

12 resultado = resultado * base ;<br />

13<br />

14 printf ("%d elevado a %d = %d\n", base , expoente , resultado )<br />

15<br />

16 return 0;<br />

17 }<br />

Exemplo 2.35: Programa para realizar a operação <strong>de</strong> exponenciação utilizando o <strong>com</strong>ando <strong>de</strong> repetição for.<br />

No Exemplo 2.35, os valores da base e do expoente são fornecidos pelo usuário via <strong>com</strong>ando <strong>de</strong><br />

entrada <strong>de</strong> dados (linha 7). O valor 1 é atribuído a variável resultado, pois é o elemento neutro da<br />

multiplicação. Caso fosse atribuído o valor zero repare que não iria funcionar. A variável <strong>de</strong> controle i<br />

é inicializada <strong>com</strong> o valor zero <strong>de</strong>ntro do <strong>com</strong>ando for e, a cada iteração, é incrementada <strong>de</strong> 1. Quando<br />

o valor <strong>de</strong> i atinge valor igual ao valor da variável expoente, as iterações são terminadas e o programa<br />

segue para a linha 14, imprimindo os valores da base, do expoente e do resultado da exponenciação.<br />

Assim <strong>com</strong>o o <strong>com</strong>ando while, o <strong>com</strong>ando for efetua primeiramente o teste da condição <strong>de</strong> parada<br />

antes <strong>de</strong> executar a sequência <strong>de</strong> <strong>com</strong>andos pela primeira vez.<br />

2.11 Problema dos Lotes Encaixantes<br />

Nesta seção será discutido o Problema dos Lotes Encaixantes. Este problema correspon<strong>de</strong> a situações<br />

em que se precisa executar uma varredura em uma massa <strong>de</strong> dados e extrair <strong>de</strong>la algumas informações<br />

estatísticas.<br />

O termo lotes encaixantes refere-se ao fato <strong>de</strong> que, na maioria das vezes, problemas <strong>com</strong>o esse<br />

envolvem entida<strong>de</strong>s <strong>com</strong>plexas <strong>com</strong>postas por outras mais simples. As entida<strong>de</strong>s mais simples se<br />

encaixam para formar outras <strong>com</strong> um grau <strong>de</strong> <strong>com</strong>plexida<strong>de</strong> ainda maior. Assim sendo, é possível<br />

visualizar vários níveis que variam <strong>de</strong>s<strong>de</strong> os mais simples e <strong>com</strong> muitos elementos até os mais <strong>com</strong>plexos<br />

e <strong>com</strong> algumas <strong>de</strong>zenas <strong>de</strong> integrantes.<br />

A Figura 2.7 ajuda a explicar a i<strong>de</strong>ia. Nela, os quadrados <strong>de</strong> bordas contínuas e finas representam o<br />

nível mais simples. Eles se agrupam para formar os quadrados <strong>de</strong> bordas pontilhadas, que representam<br />

um nível intermediário <strong>de</strong> <strong>com</strong>plexida<strong>de</strong>. Juntos, os quadrados pontilhados <strong>com</strong>põem o nível mais<br />

<strong>com</strong>plexo, representado pelo gran<strong>de</strong> quadrado <strong>de</strong> borda grossa. Na prática, po<strong>de</strong>m existir não apenas<br />

três, mas quantos níveis forem necessários para caracterizar os dados <strong>de</strong> um programa.<br />

Consi<strong>de</strong>ra-se, <strong>com</strong>o exemplo, o problema <strong>de</strong> um professor que ministra uma disciplina para diversas<br />

turmas. Nesse caso, é interessante saber qual turma obteve melhor aproveitamento, ou seja, qual turma<br />

adquiriu a maior porcentagem <strong>de</strong> aprovações sobre o número total <strong>de</strong> alunos da turma. Também é<br />

interessante obter o aluno que mais se <strong>de</strong>stacou em cada turma e o que menos ren<strong>de</strong>u nos estudos, ou<br />

seja, o que alcançou a maior média <strong>de</strong> suas notas na turma e o que obteve a menor média na turma.<br />

Os dados, nesse caso, po<strong>de</strong>m ser observados em quatro níveis: nível da disciplina, turma, alunos e<br />

notas.<br />

O nível <strong>de</strong> notas é o mais simples. Ele é indivisível e é caracterizado pelas notas dos trabalhos e<br />

provas realizados no período letivo. O nível seguinte é o <strong>de</strong> alunos, nos quais são obtidas as médias das<br />

notas <strong>de</strong> cada aluno. O terceiro agrupamento é o das turmas. Os alunos são reunidos <strong>de</strong> acordo <strong>com</strong><br />

as turmas a que pertencem. Por último, o nível mais <strong>com</strong>plexo, é a própria disciplina. Ela é a entida<strong>de</strong><br />

mais abrangente, que é <strong>com</strong>posta diretamente pelas turmas existentes no <strong>de</strong>terminado semestre.<br />

DRAFT


50<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Figura 2.7: Uma representação gráfica para os lotes encaixantes<br />

Problemas <strong>de</strong> lotes encaixantes, normalmente, são resolvidos por meio do emprego <strong>de</strong> <strong>com</strong>andos <strong>de</strong><br />

repetição aninhados. Quanto mais externo for o <strong>com</strong>ando <strong>de</strong> repetição, maior o nível <strong>de</strong> <strong>com</strong>plexida<strong>de</strong><br />

das entida<strong>de</strong>s que estão sendo examinadas. Normalmente os lotes seguem o padrão apresentado na<br />

seção 2.10.1 A Figura 2.8 exibe essa i<strong>de</strong>ia, usando <strong>com</strong>o exemplo o problema das notas escolares.<br />

DRAFT<br />

Figura 2.8: Comandos <strong>de</strong> repetição aninhados para resolver um problema <strong>de</strong> lotes encaixantes.<br />

A Figura 2.8 será explicada passo a passo:<br />

1. Primeiramente, é inicializado o processamento da disciplina.<br />

2. Inicializa-se o processamento <strong>de</strong> uma turma da disciplina.<br />

3. Começa o processamento <strong>de</strong> um aluno da turma.<br />

4. Cada nota do aluno é lida e <strong>com</strong>putada terminando o processamento <strong>de</strong>ste aluno.<br />

5. O item 3 é repetido para cada aluno, até que todos os alunos <strong>de</strong>sta turma sejam consi<strong>de</strong>rados.<br />

Assim finaliza-se o processamento <strong>de</strong> uma turma.<br />

6. O item 2 é repetido até que todas as turmas em que foi ministrada a disciplina sejam consi<strong>de</strong>ras.<br />

Assim finaliza-se o processamento da disciplina.


2.11. PROBLEMA DOS LOTES ENCAIXANTES 51<br />

O Pseudocódigo 2.17 <strong>de</strong>screve um algoritmo para realizar um levantamento estatístico do <strong>de</strong>sempenho<br />

<strong>de</strong> alunos e turmas <strong>de</strong> uma disciplina hipotética em um <strong>de</strong>terminado semestre.<br />

Pseudocódigo 2.17 Problema dos Lotes Encaixantes aplicado às notas escolares<br />

Descrição: Analisar as notas <strong>de</strong> uma disciplina escolar.<br />

Dados <strong>de</strong> Entrada: Código da turma, matrículas dos alunos, notas dos alunos.<br />

Saída do Programa: Média <strong>de</strong> cada aluno, matrículas dos alunos <strong>de</strong> melhor e <strong>de</strong> pior médias <strong>de</strong> cada turma,<br />

código da turma <strong>com</strong> melhor rendimento.<br />

Funç~ao Principal :<br />

INICIO - PROCESSAMENTO DA DISCIPLINA .<br />

Inicializar as variáveis usadas para <strong>de</strong>terminar a turma <strong>de</strong> melhor<br />

aproveitamento .<br />

Ler a primeira turma .<br />

ENQUANTO há turmas da disciplina FAÇA:<br />

INICIO - PROCESSAMENTO DA TURMA<br />

Inicializar as variáveis usadas para <strong>de</strong>terminar o aluno <strong>de</strong> maior média , o<br />

aluno <strong>de</strong> menor<br />

média da turma e o aproveitamento da turma .<br />

Ler a matrícula do primeiro aluno .<br />

ENQUANTO há alunos na turma FAÇA:<br />

INICIO - PROCESSAMENTO DO ALUNO<br />

Inicializar as variáveis usadas para <strong>de</strong>terminar a média do aluno .<br />

Ler a primeira nota .<br />

ENQUANTO há notas do aluno FAÇA:<br />

Atualizar as variáveis usadas para <strong>de</strong>terminar a média do aluno .<br />

Ler a próxima nota .<br />

FIM - ENQUANTO<br />

Calcular média do aluno .<br />

Apresentaç~ao da média do aluno .<br />

FIM - PROCESSAMENTO DO ALUNO<br />

DRAFT<br />

Atualizaç~ao <strong>de</strong> variáveis usadas para <strong>de</strong>terminar o aproveitamento da<br />

turma e<br />

os alunos <strong>de</strong> menor e maior média da turma .<br />

Ler próximo aluno .<br />

FIM - ENQUANTO<br />

Apresentar os alunos <strong>de</strong> menor e maior média da turma .<br />

FIM - PROCESSAMENTO DA TURMA<br />

Atualizar as variáveis usadas para <strong>de</strong>terminar a turma <strong>de</strong> melhor<br />

aproveitamento .<br />

Ler próxima turma<br />

FIM - ENQUANTO<br />

Apresentar a turma <strong>de</strong> melhor aproveitamento<br />

FIM - PROCESSAMENTO DA DISCIPLINA<br />

FIM - Funç~ao Principal<br />

O Exemplo 2.36 ilustra o código para um programa que lê os dados das notas dos alunos e exibe<br />

a média <strong>de</strong> cada um. Para cada turma, será exibida a melhor e a pior média. Ao final, exibe a turma<br />

<strong>com</strong> maior percentual <strong>de</strong> aprovações da disciplina.<br />

1 # inclu<strong>de</strong> <br />

2 # <strong>de</strong>fine MEDIAMINIMA 7.0<br />

3<br />

4 int main (){


52<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

5 int codTurma , matricula , numNotasAluno , numAlunosTurma , alunoMaiorMedia ,<br />

alunoMenorMedia , melhorTurma ;<br />

6 float nota , mediaAluno , numAprovadosTurma , somaNotasAluno , maiorMediaTurma ,<br />

menorMediaTurma , aproveitamentoTurma , melhorAproveitamento ;<br />

7<br />

8 melhorAproveitamento = -1;<br />

9<br />

10 printf (" Informe o codigo da turma : ");<br />

11 scanf ("%d", & codTurma );<br />

12<br />

13 while ( codTurma != -1){<br />

14 maiorMediaTurma = -1;<br />

15 menorMediaTurma = 11;<br />

16 numAprovadosTurma = 0;<br />

17 numAlunosTurma = 0;<br />

18<br />

19 printf (" Informe o numero <strong>de</strong> matricula do aluno : ");<br />

20 scanf ("%d", & matricula );<br />

21<br />

22 while ( matricula != -1){<br />

23 numNotasAluno = 0;<br />

24 somaNotasAluno = 0;<br />

25 numAlunosTurma = numAlunosTurma + 1;<br />

26<br />

27 printf (" Informe a nota do aluno : ");<br />

28 scanf ("%f", & nota );<br />

29<br />

30 while ( nota != -1){<br />

31 somaNotasAluno = somaNotasAluno + nota ;<br />

32 numNotasAluno = numNotasAluno + 1;<br />

33 printf (" Informe a nota do aluno ou ’-1’ para encerrar : ");<br />

34 scanf ("%f", & nota );<br />

35 }<br />

36<br />

37 if ( numNotasAluno != 0){<br />

38 mediaAluno = somaNotasAluno / numNotasAluno ;<br />

39<br />

40 if ( mediaAluno >= MEDIAMINIMA ){<br />

41 numAprovadosTurma = numAprovadosTurma + 1;<br />

42 }<br />

43<br />

44 if ( mediaAluno >= maiorMediaTurma ) {<br />

45 maiorMediaTurma = mediaAluno ;<br />

46 alunoMaiorMedia = matricula ;<br />

47 }<br />

48<br />

49 if ( mediaAluno


2.11. PROBLEMA DOS LOTES ENCAIXANTES 53<br />

67<br />

68 printf ("O aluno %d obteve a melhor media (%f) da turma %d\n",<br />

alunoMaiorMedia , maiorMediaTurma , codTurma );<br />

69 printf ("O aluno %d obteve a pior media (%f) da turma %d\n",<br />

alunoMenorMedia , menorMediaTurma , codTurma );<br />

70 printf (" Informe o codigo da turma ou ’-1’ para encerrar : ");<br />

71 scanf ("%d", & codTurma );<br />

72 }<br />

73<br />

74 if ( melhorAproveitamento != -1){<br />

75 printf ("A turma %d obteve o melhor aproveitamento (%f %%) ", melhorTurma ,<br />

melhorAproveitamento );<br />

76 }<br />

77 }<br />

78 return 0;<br />

79 }<br />

Exemplo 2.36: Problema dos lotes encaixantes aplicado a notas <strong>de</strong> uma disciplina<br />

Fazendo uma <strong>com</strong>paração <strong>com</strong> a Figura 2.8 e <strong>com</strong> o Pseudocódigo 2.17, não fica <strong>com</strong>plicado<br />

enten<strong>de</strong>r o funcionamento do código do Exemplo 2.36. Após a <strong>de</strong>claração das variáveis, o programa<br />

inicializa a variável melhorAproveitamento (linha 8), que armazenará o percentual <strong>de</strong> aprovações da<br />

turma <strong>de</strong> melhor aproveitamento. O valor ajustado é menor (−1) que o menor valor possível (zero) e<br />

sua escolha será justificada adiante. Em seguida, o programa solicita ao usuário que digite um código<br />

para i<strong>de</strong>ntificar a primeira turma que será analisada (linhas 10 e 11).<br />

O primeiro <strong>com</strong>ando <strong>de</strong> repetição, na linha 13, serve para percorrer todas as turmas, uma a uma.<br />

Sempre que sua expressão lógica resultar verda<strong>de</strong>iro, é sinal que uma nova turma terá seus dados<br />

digitados.<br />

Aqui vale <strong>de</strong>stacar um artifício útil que é empregado nesse código. Todos os <strong>com</strong>andos <strong>de</strong> repetição<br />

fazem a verificação <strong>de</strong> suas variáveis <strong>de</strong> controle <strong>com</strong>parando-as <strong>com</strong> o mesmo valor −1. Ocorre que,<br />

para evitar que o usuário seja obrigado a saber, a priori, da quantida<strong>de</strong> <strong>de</strong> elementos <strong>de</strong> um conjunto<br />

<strong>de</strong> dados que será passado ao programa, utiliza-se um valor absurdo (qualquer valor que não pertença<br />

ao conjunto em questão) para servir <strong>de</strong> sinalização para o programa <strong>de</strong> que o conjunto <strong>de</strong> dados foi<br />

inteiramente percorrido. Esse valor é, <strong>com</strong>umente, chamado <strong>de</strong> flag.<br />

No Exemplo 2.36, consi<strong>de</strong>ra-se que os códigos das turmas e das matrículas são inteiros positivos e<br />

que as notas são valores racionais não negativos. Assim sendo, o valor −1 foi utilizado para indicar<br />

ao programa quando todas as notas <strong>de</strong> um aluno já foram digitadas. Ou que todos os dados dos<br />

alunos <strong>de</strong> uma <strong>de</strong>terminada turma foram digitados. Ou ainda, que todas as turmas tiveram seus<br />

dados informados.<br />

A sequência <strong>de</strong> <strong>com</strong>andos <strong>com</strong>eça, então, <strong>com</strong> a inicialização das variáveis da turma em questão<br />

(linhas 14 a 17). As variáveis maiorMediaTurma e menorMediaTurma guardam, respectivamente, a<br />

melhor e a pior média obtidas na turma. Já numAprovadosTurma e numAlunosTurma armazenam,<br />

respectivamente, a quantida<strong>de</strong> <strong>de</strong> alunos aprovados na turma e a quantida<strong>de</strong> total <strong>de</strong> alunos da turma.<br />

Os valores <strong>de</strong>ssas duas variáveis servem para calcular o aproveitamento da turma.<br />

Nas linhas 19 e 20, o programa solicita ao usuário que informe a matrícula do primeiro aluno da<br />

turma que terá suas notas lidas. Na linha seguinte aparece o segundo <strong>com</strong>ando <strong>de</strong> repetição, o qual<br />

interage <strong>com</strong> os dados dos alunos <strong>de</strong> uma turma.<br />

Assim <strong>com</strong>o no <strong>com</strong>ando <strong>de</strong> repetição mais externo, o <strong>com</strong>ando da linha 22 inicia sua sequência<br />

<strong>de</strong> <strong>com</strong>andos realizando a inicialização das variáveis pertinentes. As variáveis numNotasAluno e<br />

somaNotasAluno servem para calcular a média aritmética simples das notas do aluno em questão<br />

armazenando, respectivamente, a quantida<strong>de</strong> <strong>de</strong> notas do aluno e a soma <strong>de</strong>las. Na linha 25, a<br />

variável numAlunosTurma é incrementada, indicando a adição dos dados <strong>de</strong> mais um aluno.<br />

As linhas 27 e 28 requerem ao usuário que ele digite o valor da primeira nota do aluno em questão.<br />

Em seguida, o programa executa o <strong>com</strong>ando <strong>de</strong> repetição mais interno, que serve para registrar todas<br />

as notas <strong>de</strong> um <strong>de</strong>terminado aluno.<br />

Esse <strong>com</strong>ando coleta os dados das notas, solicitando ao usuário que digite o valor da nota (linhas<br />

31 e 32) e atualizando os valores das variáveis que calculam a média do aluno no semestre.<br />

DRAFT


54<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Encerrada a digitação das notas, o usuário <strong>de</strong>ve digitar −1 para encerrar e, quando o faz, o<br />

programa passa para a rotina <strong>de</strong> cálculo da média (linha 37).<br />

Com o valor da média, algumas verificações são feitas para atualizar as estatísticas da turma em<br />

questão. Em primeiro lugar, é verificado se a média alcançada pelo aluno é suficiente para aprovação.<br />

Em caso afirmativo, a variável numAprovadosTurma é incrementada.<br />

É verificado, em seguida (linha 44), se a média do aluno é maior que a maior média encontrada<br />

até então. Em caso verda<strong>de</strong>iro, a variável maiorMediaTurma é atualizada, assim <strong>com</strong>o a variável<br />

alunoMaiorMediaTurma, que guardará a matrícula <strong>de</strong>sse aluno.<br />

O <strong>com</strong>ando <strong>de</strong> seleção da linha 49 é equivalente ao da linha 40. Desta vez, a intenção é atualizar<br />

os dados do aluno <strong>com</strong> pior rendimento.<br />

Vale um <strong>com</strong>entário sobre os valores <strong>de</strong> inicialização das variáveis maiorMediaTurma e menorMediaTurma.<br />

É preciso ter em mente que, para a primeira verificação <strong>de</strong> melhor e pior aluno <strong>de</strong> cada<br />

turma, os respectivos <strong>com</strong>andos <strong>de</strong> seleção <strong>de</strong>vem <strong>com</strong>parar o valor da média calculada <strong>com</strong> os valores<br />

já armazenados. O problema é que, para o primeiro aluno <strong>de</strong> cada turma, essas variáveis ainda não<br />

contém valores válidos. Sendo assim, para evitar erros, a variável maiorMediaTurma é inicializada<br />

<strong>com</strong> um valor menor que o menor valor nominal possível para a média e a variável menorMediaTurma,<br />

ao contrário, é inicializada <strong>com</strong> o um valor maior que o maior valor possível. Essa inicialização garante<br />

que os dados do primeiro aluno serão corretamente assimilados <strong>com</strong>o o melhor e o pior resultado<br />

encontrado. Essa condição é correta no início, pois os dados do primeiro aluno são os únicos passados<br />

ao sistema até então.<br />

O <strong>com</strong>ando da linha 54 imprime os dados do aluno, informando sua matrícula e a média alcançada.<br />

Em seguida o usuário <strong>de</strong>ve informar o código da matrícula do próximo aluno ou encerrar o cadastro<br />

dos dados da turma em análise, digitando −1.<br />

Caso tenha encerrado as digitações <strong>de</strong> uma turma, o programa executa o cálculo do respectivo<br />

aproveitamento (linha 60).<br />

Feito isso, um <strong>com</strong>ando <strong>de</strong> seleção verifica se o aproveitamento calculado é melhor que o melhor já<br />

encontrado. Em caso afirmativo, as variáveis melhorAproveitamento e melhorTurma são atualizadas<br />

para apontar para a turma recém analisada (linhas 64 e 65, respectivamente).<br />

Terminando a sequência <strong>de</strong> instruções do segundo <strong>com</strong>ando <strong>de</strong> repetição, os dados do melhor e do<br />

pior aluno da turma são exibidos (linhas 68 e 69). Por último, é perguntado ao usuário se ele <strong>de</strong>seja<br />

incluir os dados <strong>de</strong> uma outra turma, bastando, para isso, digitar seu código. Se digitar a flag −1,<br />

o <strong>com</strong>ando <strong>de</strong> repetição é encerrado e o programa exibirá, em sua última linha, os dados da melhor<br />

turma (linha 74).<br />

2.12 Exercícios Resolvidos<br />

DRAFT<br />

Exercício Resolvido 2.1 - Raízes reais <strong>de</strong> uma equação do segundo grau<br />

Faça um programa que calcule as raízes reais da equação do segundo grau ax 2 + bx + c.<br />

Solução Possível:<br />

Para solucionar este problema usaremos a Fórmula <strong>de</strong> Báskara. Esta <strong>de</strong>scrita por: raizes = − b±√ δ<br />

2a .<br />

O discriminante δ é obtido por δ = b 2 − 4ac. No Pseudocódigo 2.18 está <strong>de</strong>talhado o algoritmo.


2.12.<br />

EXERCÍCIOS RESOLVIDOS 55<br />

Pseudocódigo 2.18 Cálculo das raízes da equação do segundo grau ax 2 + bx + c.<br />

Descrição: Calcular as raízes <strong>de</strong> uma equação do segundo grau ax 2 + bx + c.<br />

Dados <strong>de</strong> Entrada: Coeficientes a, b e c.<br />

Saída do Programa: Raízes da equação.<br />

Funç~ao Principal :<br />

Ler os coeficientes discriminante .<br />

Calcular o discriminante .<br />

SE o discriminante for maior ou igual a zero :<br />

SE <strong>de</strong>lta for igual a zero :<br />

Calcular a única raiz .<br />

Apresentar o valor da raiz .<br />

SEN~AO<br />

Calcular a primeira raiz .<br />

Calcular a segunda raiz .<br />

Apresentar os valores das raízes .<br />

FIM -SE<br />

SEN~AO<br />

Apresentar uma mensagem dizendo que n~ao há raízes reais .<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

No Exemplo 2.37 está exemplificado o Pseudocódigo 2.18 .<br />

1 # inclu<strong>de</strong> <br />

2 int main (){<br />

3 float a, b, c, <strong>de</strong>lta , raizDelta , raiz1 , raiz2 ;<br />

4<br />

5 printf (" Informe os valores das constantes ’a ’, ’b’ e ’c’ ( separados por espacos ):<br />

");<br />

6 scanf ("%f %f %f", &a, &b, &c);<br />

7<br />

8 <strong>de</strong>lta = b * b - 4 * a * c;<br />

9<br />

10 if ( <strong>de</strong>lta >= 0){<br />

11 if ( <strong>de</strong>lta == 0){<br />

12 raiz1 = -b / (2 * a);<br />

13 printf ("As duas raizes sao iguais a: %f.\n", raiz1 );<br />

14 } else {<br />

15 raizDelta = sqrt ( <strong>de</strong>lta );<br />

16 raiz1 = (-b + raizDelta ) / (2 * a);<br />

17 raiz2 = (-b - raizDelta ) / (2 * a);<br />

18 printf ("As duas raizes sao : %f e %f.\n", raiz1 , raiz2 );<br />

19 }<br />

20 } else {<br />

DRAFT<br />

21 printf (" Nao existem raizes reais <strong>de</strong>sta equacao !\n");<br />

22 }<br />

23<br />

24 return 0;<br />

25 }<br />

Exemplo 2.37: Programa para calcular as raízes reais <strong>de</strong> uma equação do segundo grau.<br />

Exercício Resolvido 2.2 - Cálculo dos n primeiros termos <strong>de</strong> Fibonacci<br />

Escreva um programa que escreva os n primeiros termos da sequência <strong>de</strong> Fibonacci. Essa sequência<br />

tem zero <strong>com</strong>o primeiro termo e 1 <strong>com</strong>o segundo. Do terceiro termo em diante, a fórmula para obtenção<br />

é a soma dos dois anteriores.<br />

Solução Possível:<br />

A lei <strong>de</strong> formação está <strong>de</strong>scrita no enunciado. Sendo assim, <strong>de</strong>fina dois termos iniciais em 0 e 1 e<br />

calcule o terceiro termo a partir <strong>de</strong>stes dois termos. Em seguida, repita o processo para achar o quarto


56<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

termo a partir do terceiro e segundo termo. Observe que é um laço e constantemente os termos estão<br />

sendo atualizados. Uma forma <strong>de</strong> implementar está <strong>de</strong>talhada no Pseudocódigo 2.19.<br />

Pseudocódigo 2.19 Cálculo dos n primeiros termos da sequencia <strong>de</strong> Fibonacci.<br />

Descrição: Calcular os n primeiros termos da sequência <strong>de</strong> Fibonacci.<br />

Dados <strong>de</strong> Entrada: Valor inteiro n.<br />

Saída do Programa: Exibir os n termos.<br />

Funç~ao Principal :<br />

Ler o número n.<br />

Inicializar termo <strong>com</strong> valor zero .<br />

Inicializar novo <strong>com</strong> valor um.<br />

ENQUANTO i for menor que n FAÇA:<br />

Exibir valor <strong>de</strong> termo .<br />

Anterior recebe o valor <strong>de</strong> termo .<br />

Termo recebe o valor <strong>de</strong> novo .<br />

Novo recebe o valor <strong>de</strong> novo somado <strong>com</strong> anterior .<br />

Incrementar i.<br />

FIM - ENQUANTO<br />

FIM - Funç~ao Principal<br />

Segue no Exemplo 2.38 a implementação em C do Pseudocódigo 2.19.<br />

1 int main (){<br />

2 int n, termo , novo , anterior , i;<br />

3<br />

4 printf (" Informe o numero <strong>de</strong> termos a serem impressos : ");<br />

5 scanf ("%d", &n);<br />

6<br />

7 termo = 0;<br />

8 novo = 1;<br />

9<br />

10 for (i = 0; i < n; i = i + 1) {<br />

11 printf ("%d ", termo );<br />

12 anterior = termo ;<br />

13 termo = novo ;<br />

14 novo = novo + anterior ;<br />

15 }<br />

16<br />

17 return 0;<br />

18 }<br />

DRAFT<br />

Exemplo 2.38: Programa para calcular os n primeiros termos da sequência <strong>de</strong> Fibonacci<br />

Exercício Resolvido 2.3 - Tabuada <strong>de</strong> 1 a 9<br />

Fazer um programa para imprimir a tabuada <strong>de</strong> 1 a 9.<br />

Solução Possível:<br />

A resolução <strong>de</strong>ste exercício é simples. Observe que cada número <strong>de</strong> 1 a 9 é multiplicado por outro<br />

número que também po<strong>de</strong> ser <strong>de</strong> 1 a 9. Uma possível solução são laços aninhados, on<strong>de</strong> um número<br />

é fixo e o outro varia <strong>de</strong> acordo <strong>com</strong> a variável <strong>de</strong> controle do laço. Segue no Pseudocódigo 2.20 uma<br />

possível solução.


2.12.<br />

EXERCÍCIOS RESOLVIDOS 57<br />

Pseudocódigo 2.20 Cálculo da tubuada.<br />

Descrição: Calcular a tabuada <strong>de</strong> 1 a 9.<br />

Dados <strong>de</strong> Entrada: Não possui entrada.<br />

Saída do Programa: Apresentar a tabuada <strong>de</strong> 1 a 9.<br />

Funç~ao Principal :<br />

Inicializar n1 <strong>com</strong> 1.<br />

Inicializar n2 <strong>com</strong> 1.<br />

ENQUANTO n1 for menor que 10 FAÇA:<br />

ENQUANTO n2 for menor que 10 FAÇA:<br />

Exibir o valor da multiplicaç~ao entre n1 e n2.<br />

FIM - ENQUANTO<br />

FIM - ENQUANTO<br />

FIM - Funç~ao Principal<br />

1 int main (){<br />

2 int n1 , n2 , r;<br />

3<br />

4 printf ("\ nTABUADA <strong>de</strong> 1 a 9\n\n");<br />

5<br />

6 for (n1 = 1; n1 < 10;) {<br />

7 for (n2 = 1; n2 < 10) {<br />

8 r = n1 * n2;<br />

9 printf ("%d * %d = %d\n", n2 , n1 , r);<br />

10 }<br />

11 printf ("\n");<br />

12 }<br />

13<br />

14 return 0;<br />

15 }<br />

Exemplo 2.39: Programa para exibir a tabuada <strong>de</strong> 1 a 9.<br />

Exercício Resolvido 2.4 - Cálcular MDC entre dois números<br />

DRAFT<br />

Calcular o Maximo Divisor Comum (MDC) <strong>de</strong> dois números.<br />

Solução Possível: O MDC <strong>de</strong> dois números po<strong>de</strong> ser obtido escolhendo o maior <strong>de</strong>les e subtraindolhe<br />

o valor do menor. Esta operação é repetida até que os dois sejam iguais, cujo valor será o MDC<br />

dos números iniciais:<br />

33 15 45 18<br />

18 15 27 18<br />

03 15 09 18<br />

03 12 09 09<br />

03 09 MDC = 09<br />

03 06<br />

03 03<br />

MDC = 03


58<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

Pseudocódigo 2.21 Cálculo do M.D.C. entre dois números.<br />

Descrição: Calcular o M.D.C. entre dois números.<br />

Dados <strong>de</strong> Entrada: Números inteiros n1 e n2.<br />

Saída do Programa: Apresentar o valor do M.D.C. entre n1 e n2.<br />

Funç~ao Principal :<br />

Ler o número n1.<br />

Ler o número n2.<br />

Auxiliar1 recebe o valor <strong>de</strong> n1.<br />

Auxiliar2 recebe o valor <strong>de</strong> n2.<br />

ENQUANTO Auxiliar1 for diferente <strong>de</strong> Auxiliar2 FAÇA:<br />

SE Auxiliar1 for maior que Auxiliar2 :<br />

Auxiliar1 recebe Auxiliar1 s u b t r a d o <strong>de</strong> Auxiliar2 .<br />

S E N O<br />

Auxiliar2 recebe Auxiliar2 s u b t r a d o <strong>de</strong> Auxiliar1 .<br />

FIM -SE<br />

FIM - ENQUANTO<br />

M.D.C. recebe o valor <strong>de</strong> Auxiliar1 .<br />

Exibir o valor <strong>de</strong> M.D.C.<br />

FIM - Funç~ao Principal<br />

1 int main (){<br />

2 int numero1 , numero2 , auxiliar1 , auxiliar2 ;<br />

3<br />

4 printf (" Digite dois numeros para calcular seu MDC : ");<br />

5 scanf ("%d %d", & numero1 , & numero2 );<br />

6<br />

7 auxiliar1 = numero1 ;<br />

8 auxiliar2 = numero2 ;<br />

9<br />

10 while ( auxiliar1 != auxiliar2 ) {<br />

11 if ( auxiliar1 > auxiliar2 )<br />

12 auxiliar1 = auxiliar1 - auxiliar2 ;<br />

13 } else {<br />

14 auxiliar2 = auxiliar2 - auxiliar1 ;<br />

15 }<br />

16 }<br />

17<br />

18 printf ("O MDC vale %d\n", auxiliar1 );<br />

19<br />

20 return 0;<br />

21 }<br />

DRAFT<br />

Exemplo 2.40: Programa para exibir o MDC <strong>de</strong> dois números.<br />

Exercício Resolvido 2.5 - Conversão <strong>de</strong> base binária para <strong>de</strong>cimal<br />

Faça um programa que converta um valor em base binária para base <strong>de</strong>cimal.<br />

Solução Possível:<br />

Para solucionar este problema <strong>de</strong>ve-se pensar na estrutura <strong>de</strong> um número binário. Por exemplo,<br />

o número 111 equivale a 7 na base <strong>de</strong>z. Pois, 2 2 + 2 1 + 2 0 = 7. Assim <strong>com</strong>o, 1111 equivale a 15<br />

pois 2 3 + 2 2 + 2 1 + 2 0 = 15. Com base nesses exemplos e observando padrões, po<strong>de</strong>mos estabeler o<br />

Pseudocódigo 2.22.


2.13. RESUMO 59<br />

Pseudocódigo 2.22 Conversão <strong>de</strong> um valor <strong>de</strong> base binária para base <strong>de</strong>cimal.<br />

Descrição: Converter um valor <strong>de</strong> base binária para base <strong>de</strong>cimal.<br />

Dados <strong>de</strong> Entrada: Número em binário.<br />

Saída do Programa: Exibir o valor <strong>de</strong> entrada em base <strong>de</strong>cimal.<br />

Funç~ao Principal :<br />

Ler o número n em base binária ;<br />

Inicializar Decimal <strong>com</strong> valor zero ;<br />

Inicializar Auxiliar2 <strong>com</strong> valor 1;<br />

Auxiliar1 recebe o valor <strong>de</strong> n;<br />

ENQUANTO Auxiliar1 for maior que zero FAÇA:<br />

Auxiliar3 recebe o resto da divis~ao <strong>de</strong> Auxiliar1 por 10;<br />

Decimal recebe Decimal somado <strong>com</strong> Auxiliar2 vezes Auxiliar3 ;<br />

Auxiliar2 recebe o dobro <strong>de</strong> Auxiliar2 ;<br />

Auxiliar1 recebe o quociente da divis~ao <strong>de</strong> Auxiliar1 por 10;<br />

FIM - ENQUANTO<br />

Apresentar o valor <strong>de</strong> Decimal ;<br />

FIM - Funç~ao Principal<br />

1 int main (){<br />

2 int binario , aux1 , aux2 , aux3 , <strong>de</strong>cimal ;<br />

3<br />

4 printf (" Digite um valor em base binaria : ");<br />

5 scanf ("%d", & binario );<br />

6<br />

7 aux1 = binario ;<br />

8 aux2 = 1;<br />

9 <strong>de</strong>cimal = 0;<br />

10<br />

11 while ( aux1 > 0) {<br />

12 aux3 = aux1 % 10;<br />

13 <strong>de</strong>cimal = <strong>de</strong>cimal + aux3 * aux2 ;<br />

14 aux2 = aux2 * 2;<br />

15 aux1 = aux1 / 10;<br />

16 }<br />

17<br />

18 printf ("O valor %d em base binaria equivale a %d em base <strong>de</strong>cimal \n", binario ,<br />

<strong>de</strong>cimal );<br />

19<br />

20 return 0;<br />

21 }<br />

2.13 Resumo<br />

ˆ<br />

DRAFT<br />

Exemplo 2.41: Programa para converter números <strong>de</strong> binário para <strong>de</strong>cimal.<br />

O <strong>com</strong>putador guarda as informações dos programas na memória. A memória po<strong>de</strong> ser entendida<br />

<strong>com</strong>o uma sequência <strong>de</strong> células, cada uma i<strong>de</strong>ntificada por um número conhecido <strong>com</strong>o en<strong>de</strong>reço<br />

<strong>de</strong> memória. Nas linguagens <strong>de</strong> programação, as variáveis permitem o acesso às células <strong>de</strong><br />

memória sem a necessida<strong>de</strong> <strong>de</strong> manipular seus en<strong>de</strong>reços diretamente.<br />

ˆ<br />

Na linguagem C, para a <strong>de</strong>claração <strong>de</strong> uma variável, o programador <strong>de</strong>ve informar qual o tipo<br />

<strong>de</strong> dados que ela irá manipular.<br />

ˆ<br />

O <strong>com</strong>ando <strong>de</strong> atribuição permite atribuir uma <strong>de</strong>terminada informação (ou valor) a uma variável<br />

do programa.


60<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

ˆ<br />

ˆ<br />

Os i<strong>de</strong>ntificadores são nomes que i<strong>de</strong>ntificam uma variável ou constante. Eles são formados por<br />

caracteres alfanuméricos, sendo que o primeiro <strong>de</strong>ve ser obrigatoriamente alfabético.<br />

Na programação, os quatro tipos <strong>de</strong> dados mais <strong>com</strong>uns são: tipo inteiro, tipo ponto flutuante,<br />

tipo booleano e tipo caractere.<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Variáveis e constantes po<strong>de</strong>m ser <strong>com</strong>binadas <strong>com</strong> operadores para formarem expressões. No<br />

<strong>com</strong>ando <strong>de</strong> atribuição, o valor da expressão (termos à direita do <strong>com</strong>ando) é atribuído à variável<br />

(à esquerda do <strong>com</strong>ando).<br />

Os principais tipos <strong>de</strong> expressões são aritmética, relacional e lógica.<br />

Na maioria dos problemas <strong>de</strong> <strong>com</strong>putação, os <strong>com</strong>andos <strong>de</strong> entrada <strong>de</strong> dados, saída <strong>de</strong> dados,<br />

seleção e repetição, são imprescindíveis.<br />

Diversos problemas <strong>com</strong>putacionais encaixam-se na mo<strong>de</strong>lagem do Problema dos Lotes Encaixantes.<br />

Essa classe <strong>de</strong> problemas é facilmente resolvida <strong>com</strong> o aninhamento <strong>de</strong> <strong>com</strong>andos <strong>de</strong><br />

repetição, os quais <strong>de</strong>stinam-se a examinar um nível específico da massa <strong>de</strong> dados.<br />

2.14 Exercícios Propostos<br />

1. Faça um programa, em C, que converta valores <strong>de</strong> temperatura <strong>de</strong> Fahrenheit para Celsius. A<br />

proporção utilizada é:<br />

T emperatura Celsius<br />

= (T emperatura F ahrenheit − 32)<br />

5<br />

9<br />

2. Faça um programa que calcule e escreva uma tabela <strong>de</strong> graus centígrados em função <strong>de</strong> graus<br />

farenheit que variam <strong>de</strong> 0 a 150 <strong>de</strong> 1 em 1.<br />

3. Faça um programa que calcule a soma<br />

4. Faça um programa que calcule a soma<br />

S = 1 1 + 3 2 + 5 3 + . . . + 99<br />

50<br />

37 × 38 36 × 37 35 × 36<br />

S = − + − . . . + 1 × 2<br />

1 2 3<br />

37<br />

5. Faça um programa para ler uma seqüência <strong>de</strong> n números inteiros positivos (um por vez), e<br />

verificar se eles são pares ou ímpares.<br />

DRAFT<br />

6. Suponha que a população <strong>de</strong> um país A seja <strong>de</strong> 9.000 habitantes <strong>com</strong> uma taxa anual <strong>de</strong> crescimento<br />

<strong>de</strong> 3% e que a população <strong>de</strong> um país B seja, aproximadamente, <strong>de</strong> 20.000 <strong>de</strong> habitantes<br />

<strong>com</strong> uma taxa anual <strong>de</strong> crescimento <strong>de</strong> 1,5%, fazer um programa que calcule e escreva o número<br />

<strong>de</strong> anos necessários para que a população <strong>de</strong> país A ultrapasse ou se iguale à população do país<br />

B, mantidas estas taxas <strong>de</strong> crescimento.<br />

7. Uma certa firma fez uma pesquisa <strong>de</strong> mercado para saber se as pessoas gostaram ou não <strong>de</strong> um<br />

novo produto lançado no mercado. Para isso, obteve, para cada pessoa entrevistada, informações<br />

a respeito do sexo do entrevistado e sua resposta (S = Sim ou N = Não). Sabe-se que foram<br />

entrevistados 2000 pessoas, fazer um programa que calcule e escreva:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

O número <strong>de</strong> pessoas que respon<strong>de</strong>ram sim<br />

O número <strong>de</strong> pessoas que respon<strong>de</strong>ram não<br />

A porcentagem <strong>de</strong> pessoas do sexo feminino que respon<strong>de</strong>ram sim<br />

A porcentagem <strong>de</strong> pessoas do sexo masculino que respon<strong>de</strong>ram não


2.14.<br />

EXERCÍCIOS PROPOSTOS 61<br />

8. Refazer o Exemplo 2.38 sem utilizar a variável anterior.<br />

9. Faça um programa em C que verifique se o número 26 é o único no intervalo entre 2 e 999999<br />

que se encontra entre um quadrado (52=25) e um cubo (33=27). Dica: para verificar isso basta<br />

elevar ao cubo todo número no intervalo entre 2 e 100 e mostrar que não existe número elevado<br />

ao quadrado cuja diferença para o cubo seja igual a dois, além obviamente do número 26.<br />

10. O gerente <strong>de</strong> uma agência bancária te contratou para fazer um programa em C para extrair<br />

algumas informações das contas dos correntistas <strong>de</strong> sua agência. Para tanto o gerente te forneceu<br />

uma listagem contendo, em cada linha, os dados do número da conta (um valor inteiro) e valor<br />

da operação (um valor ponto flutuante positivo para as operações <strong>de</strong> crédito e negativo para as<br />

operações <strong>de</strong> débito) realizadas no último mês. Seu programa <strong>de</strong>ve usar os dados da listagem<br />

para informar:<br />

(a) As operações suspeitas, isto é, aquelas que movimentaram acima <strong>de</strong> 20.000 reais.<br />

(b) O saldo das operações realizadas em cada conta.<br />

(c) Os dois correntistas que produziram o maior saldo nas suas operações.<br />

(d) O saldo total das operações na agência. Consi<strong>de</strong>re que os dados <strong>de</strong> cada conta são fornecidos<br />

contiguamente, isto é, são fornecidos todos os dados das operações <strong>de</strong> uma conta, <strong>de</strong>pois<br />

todos os dados <strong>de</strong> outra conta e assim sucessivamente. O processamento <strong>de</strong>ve ser encerrado<br />

quando for lido um número <strong>de</strong> conta igual a zero. Um exemplo <strong>de</strong> listagem é apresentado<br />

a seguir:<br />

Número <strong>de</strong> conta Valor <strong>de</strong> Operaç~ao<br />

1 123,02<br />

1 -22,54<br />

2 1000,01<br />

3 22222,22<br />

... ...<br />

0 0.00<br />

11. O <strong>com</strong>itê organizador dos jogos pan-americanos <strong>de</strong> 2007, no Rio <strong>de</strong> Janeiro, <strong>de</strong>seja apresentar os<br />

resultados da <strong>com</strong>petição indicando o total <strong>de</strong> medalhas <strong>de</strong> ouro, prata e bronze <strong>de</strong> cada país,<br />

bem <strong>com</strong>o o país vencedor dos jogos e o país vencedor das <strong>com</strong>petições da modalida<strong>de</strong> natação.<br />

Faça um programa em C para apresentar esses resultados.. Os dados a serem inseridos no<br />

programa <strong>de</strong>vem ser organizados por código <strong>de</strong> país e <strong>de</strong> <strong>com</strong>petição, tal <strong>com</strong>o no<br />

exemplo seguinte:<br />

DRAFT<br />

123 <br />

55123 100 <br />

3412 011 <br />

176665 001 <br />

0 <br />

222 <br />

54321 002 <br />

557 010 <br />

0 <br />

0 <br />

Consi<strong>de</strong>re que as <strong>com</strong>petições <strong>de</strong> natação sempre se iniciam <strong>com</strong> 55. Note, porém, que o número<br />

<strong>de</strong> dígitos do código das <strong>com</strong>petições não é fixo, <strong>com</strong>o po<strong>de</strong> ser observado no exemplo utilizado<br />

(observe que tanto a <strong>com</strong>petição 55123 quanto a 557 são <strong>de</strong> natação). Consi<strong>de</strong>re ainda que a


62<br />

CAPÍTULO 2. CONCEITOS BÁSICOS<br />

classificação dos países é feita primeiramente pelo critério total <strong>de</strong> medalhas <strong>de</strong> ouro, <strong>de</strong>pois<br />

pelo critério total <strong>de</strong> medalhas <strong>de</strong> prata e, por fim, pelo critério total <strong>de</strong> medalhas <strong>de</strong> bronze.<br />

Desconsi<strong>de</strong>re a hipótese <strong>de</strong> haver empate nos três critérios: total <strong>de</strong> medalhas <strong>de</strong> ouro, prata e<br />

bronze.<br />

12. Um banco do país <strong>de</strong>seja conhecer os dados dos maiores correntistas (aqueles <strong>com</strong> maior quantida<strong>de</strong><br />

total <strong>de</strong> recursos aplicados) em cada uma <strong>de</strong> suas agências e também os dados dos três<br />

maiores correntistas do banco. Para isso, o banco possui uma lista <strong>com</strong> o número da conta, o<br />

saldo em conta corrente, o saldo em fundos e o saldo em poupança <strong>de</strong> todos os correntistas <strong>de</strong><br />

cada agência do banco. Faça um programa em C para apresentar esses resultados. Crie um tipo<br />

abstrato <strong>de</strong> dados Correntista que armazene os dados <strong>de</strong> um correntista (agência, conta, saldo<br />

em conta, saldo em fundos, saldo em poupança) e implemente as operações <strong>de</strong> leitura <strong>de</strong> dados <strong>de</strong><br />

um correntista, apresentação dos dados <strong>de</strong> um correntista, cálculo <strong>de</strong> total <strong>de</strong> recursos aplicados<br />

(isto é, a soma dos saldos em conta, em fundos e em poupança). Utilize o tipo Correntista na<br />

implementação do programa. Os dados a serem inseridos no programa <strong>de</strong>vem ser lidos seguindo<br />

uma or<strong>de</strong>m equivalente ao do exemplo seguinte. Desconsi<strong>de</strong>re a hipótese <strong>de</strong> haver correntistas<br />

<strong>com</strong> o mesmo total <strong>de</strong> recursos aplicados no banco.<br />

123 <br />

55123 125.00 2500.00 300.00 <br />

43145 100.00 750.00 3000.00 <br />

17666 10.00 9000.00 5000.00 <br />

0 <br />

222 <br />

54321 900.00 0.00 3000.00 <br />

55711 35.00 95000.00 0.00 <br />

0 <br />

0 <br />

2.15 Trabalhos Sugeridos<br />

1. Registro <strong>de</strong> Médias Finais no Sistema Acadêmico<br />

DRAFT<br />

Ao final <strong>de</strong> cada período letivo em uma universida<strong>de</strong>, o colegiado <strong>de</strong> Ciência da Computação<br />

necessita atualizar o sistema acadêmico <strong>com</strong> a lista das médias finais obtidas pelos alunos em<br />

todas as disciplinas ofertadas naquele período. Consi<strong>de</strong>re que a média mínima <strong>de</strong> aprovação é 5.0<br />

(cinco). Os dados a serem inseridos no sistema <strong>de</strong>vem ser organizados por código <strong>de</strong> disciplina e<br />

<strong>de</strong> turma. Assim, para cada disciplina existem várias turmas. A lista <strong>de</strong> médias finais <strong>de</strong>ve ser<br />

inserida para cada turma.<br />

Exemplo:<br />

2628<br />

1<br />

10.0 9.6 4.5 7.8 8.9 5.0 9.0 6.4 3.7 8.8 -1<br />

2<br />

0.2 3.4 5.6 2.7 8.9 4.5 9.0 8.0 3.0 4.5 6.5 4.5 6.8 9.5 -1<br />

3<br />

2.7 8.9 4.5 9.0 10.0 9.6 4.5 7.0 -1<br />

-1<br />

2777<br />

1<br />

4.0 7.8 5.6 3.6 8.9 0.9 1.2 6.9 5.6 10.0 9.0 -1<br />

2


2.15. TRABALHOS SUGERIDOS 63<br />

8.6 7.8 8.9 5.0 3.4 5.6 -1<br />

-1<br />

3445<br />

1<br />

8.9 5.0 3.4 9.0 10.0 9.6 4.5 7.0 1.2 6.9 2.7 8.9 4.5 -1<br />

-1<br />

-1<br />

Desta forma, o formato <strong>de</strong> entrada dos dados <strong>de</strong>ve ser o seguinte:<br />

<br />

<br />

<br />

<br />

<br />

Códigos e flags são números inteiros. Notas são números em ponto flutuante. Não se sabe a priori<br />

o número <strong>de</strong> disciplinas, o número <strong>de</strong> turmas por disciplina e o número <strong>de</strong> alunos por turma.<br />

Para tanto é preciso utilizar o recurso <strong>de</strong> flags. Consi<strong>de</strong>ramos um flag <strong>com</strong>o uma constante<br />

cujo valor é diferente dos valores fornecidos <strong>com</strong>o entrada e que serve <strong>com</strong>o um <strong>de</strong>limitador <strong>de</strong><br />

interrupção <strong>de</strong> um laço <strong>de</strong> repetição. No exemplo dado, o valor do flag utilizado é −1.<br />

Seu programa <strong>de</strong>ve ler iterativamente cada linha da entrada (obe<strong>de</strong>cendo ao formato <strong>de</strong>scrito<br />

acima) e gerar as seguintes informações:<br />

(a) O índice <strong>de</strong> reprovação <strong>de</strong> cada turma (em percentual). Além do índice <strong>de</strong> reprovação, <strong>de</strong>ve<br />

ser apresentado o código da turma e o código da disciplina.<br />

(b) De cada disciplina, a turma que obteve o menor rendimento, ou seja, menor média das<br />

médias finais. Desconsi<strong>de</strong>re a situação <strong>de</strong> empate. Apresentar o código da disciplina, da<br />

turma e o valor do seu rendimento.<br />

(c) As três disciplinas mais difíceis do curso, ou seja, as três disciplinas <strong>com</strong> maior índice<br />

<strong>de</strong> reprovação. Em caso <strong>de</strong> empate no índice <strong>de</strong> reprovação, consi<strong>de</strong>rar <strong>com</strong>o segundo<br />

critério o rendimento (isto é, consi<strong>de</strong>rar <strong>com</strong>o mais difícil a disciplina <strong>de</strong> menor rendimento).<br />

Desconsi<strong>de</strong>re a situação <strong>de</strong> empate no segundo critério (menor rendimento). Apresente cada<br />

disciplina em or<strong>de</strong>m <strong>de</strong>crescente (da mais difícil para a menos difícil). Para cada disciplina<br />

difícil é preciso mostrar o seu código, seu índice <strong>de</strong> reprovação e seu rendimento.<br />

(d) A melhor nota relativa <strong>de</strong> todo o curso. A nota relativa é obtida através da divisão da nota<br />

pela média da turma. Além da nota relativa <strong>de</strong>ve ser apresentada a nota absoluta, o código<br />

da turma e o código da disciplina nas quais essa nota ocorreu.<br />

DRAFT


Capítulo 3<br />

Modularização<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Definir o que é modularização;<br />

Apresentar as vantagens <strong>de</strong> um programa modularizado;<br />

Apresentar métodos <strong>de</strong> <strong>com</strong>o criar e adaptar programas modularizados;<br />

Introduzir o conceito <strong>de</strong> recursivida<strong>de</strong> e <strong>com</strong>o usá-la;<br />

Coautores:<br />

Gilberto Segundo<br />

Ramon Schiavo<br />

Thaylo <strong>de</strong> Freitas<br />

Os programas são escritos a fim <strong>de</strong> resolverem vários tipos <strong>de</strong> problemas. Alguns <strong>de</strong>sses problemas<br />

exigem mais tempo e maiores esforços do programador. Por isso, é indispensável que o programador<br />

utilize técnicas que visam uma maior organização e consequente entendimento facilitado do programa.<br />

Uma das técnicas mais utilizadas é a modularização.<br />

Este capítulo trata do conceito <strong>de</strong> modularização e da prática <strong>de</strong> construir programas modularizados.<br />

3.1 Resolvendo por Partes<br />

Quando se trabalha em qualquer problema <strong>com</strong>plexo, seja em programação, seja em outra área, o ser<br />

humano sente a necessida<strong>de</strong> <strong>de</strong> dividir esse problema maior em problemas menores. Cada problema<br />

menor é então trabalhado <strong>de</strong> forma a solucionar as questões que lhe cabem e, juntando-se cada uma<br />

<strong>de</strong>ssas soluções, tem-se a solução do problema maior. Esse processo é chamado <strong>de</strong> modularização e<br />

baseia-se na conhecida técnica <strong>de</strong> “dividir para conquistar”e é o fundamento <strong>de</strong> modularização.<br />

Po<strong>de</strong>-se aplicar a modularização em diversas áreas na vida cotidiana. Para a fabricação <strong>de</strong> um<br />

automóvel, por exemplo, são necessários diversos serviços: funilaria, montagem, estofamento, pintura,<br />

soldagem, etc. A princípio, po<strong>de</strong>ria existir apenas um robô que fizesse todas as etapas da fabricação do<br />

carro, mas isso acarretaria em alguns problemas, tais <strong>com</strong>o: <strong>com</strong>plexida<strong>de</strong> do robô, que <strong>de</strong>veria fazer<br />

todos os serviços <strong>de</strong> forma <strong>com</strong>pleta e eficiente; alto prejuízo em eventuais serviços <strong>de</strong> manutenção,<br />

pois teria que parar todo o processo <strong>de</strong> montagem. Uma ótima alternativa para esse problema é<br />

fazer vários robôs, cada um <strong>com</strong> sua função específica. O que se estaria fazendo na verda<strong>de</strong> é uma<br />

modularização.<br />

Po<strong>de</strong>-se facilmente transladar a i<strong>de</strong>ia contida no problema apresentado para a elaboração <strong>de</strong> um<br />

programa. O programa po<strong>de</strong> ser dividido em várias partes, sendo que cada parte trata <strong>de</strong> uma<br />

<strong>de</strong>terminada funcionalida<strong>de</strong>.<br />

Dessa forma, o programa tem a sua legibilida<strong>de</strong> melhorada, uma vez que fica mais fácil enten<strong>de</strong>r o<br />

que o programa faz por <strong>com</strong>pleto ou <strong>com</strong>o o programa faz <strong>de</strong>terminada subtarefa. A modificabilida<strong>de</strong><br />

DRAFT<br />

64


3.2. SUBPROGRAMAS 65<br />

do programa também é melhorada, uma vez que, ao alterar <strong>de</strong>terminada funcionalida<strong>de</strong>, é necessário<br />

apenas mudar uma pequena parte do código, não sendo necessário modificá-lo em vários pontos.<br />

Com as funcionalida<strong>de</strong>s do programa separadas logicamente, o programador tem a oportunida<strong>de</strong><br />

<strong>de</strong> reutilizar uma parte do programa para escrever um outro programa que utilize, em uma <strong>de</strong> suas<br />

tarefas, o mesmo bloco <strong>de</strong> instruções. A confiabilida<strong>de</strong> do programa também é aumentada pelo fato<br />

<strong>de</strong>le ser mais fácil <strong>de</strong> ser entendido e corrigido.<br />

Por fim, a produtivida<strong>de</strong> para a elaboração <strong>de</strong> um programa também é aumentada, uma vez que<br />

cada parte do programa po<strong>de</strong> ser trabalhada por uma equipe diferente, além <strong>de</strong> que cada equipe só<br />

precisa saber o que as partes da outra equipe fazem e não <strong>com</strong>o fazem.<br />

Nas seções seguintes serão mostradas técnicas <strong>de</strong> <strong>com</strong>o fazer um programa modularizado utilizando<br />

a linguagem C.<br />

3.2 Subprogramas<br />

Um subprograma é um trecho <strong>de</strong> um programa que realiza uma operação <strong>com</strong>putacional. Ele efetua<br />

parte <strong>de</strong> uma tarefa que um algoritmo maior <strong>de</strong>veria executar, ou seja, ele é uma parte do programa,<br />

especializado em alguma funcionalida<strong>de</strong>. Subprogramas são uma das principais formas <strong>de</strong> modularização.<br />

Na linguagem C subprogramas existem na forma <strong>de</strong> função.<br />

Uma função matemática f(x) é uma relação que mapeia um dado valor x <strong>de</strong> um domínio em um<br />

único valor y <strong>de</strong> um conjunto imagem. Em programação, a i<strong>de</strong>ia é semelhante: uma função é um<br />

conjunto <strong>de</strong> instruções que recebe alguns valores <strong>com</strong>o dados <strong>de</strong> entrada e, a partir <strong>de</strong>les, produz um<br />

valor <strong>com</strong>o saída. A Figura 3.1 ilustra o funcionamento <strong>de</strong> uma função matemática simples, a função<br />

y = x 2 , para x e y pertencentes aos naturais.<br />

Figura 3.1: Função matemática y = x 2<br />

DRAFT<br />

Em programação, os dados <strong>de</strong> entrada são chamados <strong>de</strong> parâmetros e o valor da saída é chamado<br />

<strong>de</strong> retorno. Durante a execução da função, os dados <strong>de</strong> entrada são manipulados <strong>de</strong> maneira a produzir<br />

o resultado esperado. Durante essa manipulação <strong>de</strong> dados a função po<strong>de</strong> chamar outras funções, que<br />

contêm rotinas que auxiliam na elaboração do resultado final. A Figura 3.2 ilustra esse processo.<br />

Figura 3.2: Função usando outras funções.


66<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

Na fabricação <strong>de</strong> um automóvel, algum processo realizado por um <strong>de</strong>terminado robô po<strong>de</strong> solicitar<br />

serviços <strong>de</strong> outros robôs. Por exemplo, o robô que faz a colocação das peças no carro po<strong>de</strong> solicitar<br />

por diversas vezes o serviço do robô <strong>de</strong> soldagem <strong>de</strong> peças. Após a finalização da soldagem da peça,<br />

o robô <strong>de</strong> montagem po<strong>de</strong>rá colocar outra peça no carro.<br />

3.3 Partes <strong>de</strong> um Subprograma<br />

As partes <strong>de</strong> um subprograma são as mesmas <strong>de</strong> um programa, ou seja: cabeçalho, dicionário <strong>de</strong><br />

dados, corpo e <strong>com</strong>entário. O Exemplo 3.1 mostra um subprograma em C <strong>com</strong> todas essas partes,<br />

que serão <strong>com</strong>entadas a seguir, enfocando sua importância nos subprogramas.<br />

1 float calculaMedia ( float a, float b);<br />

3.3.1 Cabeçalho<br />

Exemplo 3.1: Cabeçalho <strong>de</strong> um subprograma na linguagem C.<br />

O cabeçalho do subprograma é on<strong>de</strong> estão <strong>de</strong>finidos o nome do subprograma, os tipos dos seus<br />

parâmetros <strong>de</strong> entrada e o tipo <strong>de</strong> dado <strong>de</strong> retorno.<br />

Os parâmetros da função são os ingredientes que ela precisa para executar as suas instruções e<br />

seus tipos <strong>de</strong>vem ser respeitados. O tipo dos parâmetros informam qual o tipo <strong>de</strong> ingrediente que<br />

precisa ser fornecido para o subprograma realizar sua tarefa. O tipo <strong>de</strong> retorno da função simboliza<br />

o tipo <strong>de</strong> produto gerado por ela. Se a função diz retornar um número float, quer dizer que o<br />

programador <strong>de</strong>ve esperar receber apenas esse tipo <strong>de</strong> dado e tomar as medidas necessárias para<br />

manipulá-lo posteriormente.<br />

O nome do subprograma serve para i<strong>de</strong>ntificá-lo. O programador <strong>de</strong>ve escolher nomes autoexplicativos<br />

sobre a funcionalida<strong>de</strong> da função, ou seja, nomes que indiquem para que ela serve. Isso torna<br />

o código mais legível e menos susceptível a erros por parte do programador.<br />

O Exemplo 3.1, mostra o cabeçalho da calculaMedia. Ela possui dois parâmetros <strong>de</strong> entrada<br />

do tipo float e retorna um valor também do tipo float. O primeiro parâmetro recebe o nome a e o<br />

segundo recebe o nome b. A função retorna um dado do tipo float, ou seja, retornará um número<br />

que contém casas <strong>de</strong>cimais. Mais <strong>de</strong>talhes sobre passagem <strong>de</strong> parâmetros, assim <strong>com</strong>o o retorno <strong>de</strong><br />

funções serão mostrados posteriormente.<br />

Pseudocódigo 3.1 Processo <strong>com</strong>ponente para o cálculo da distância entre dois pontos.<br />

Descrição: Calcular a distância entre dois pontos.<br />

Dados <strong>de</strong> Entrada: Coor<strong>de</strong>nadas x e y dos dois pontos<br />

Saída do Programa: Distância entre os pontos.<br />

Processo <strong>com</strong>ponente " dist^ancia ":<br />

Usar o teorema <strong>de</strong> Pitágoras para calcular a dist^ancia dos pontos dados<br />

Retornar o valor da dist^ancia<br />

FIM - Processo <strong>com</strong>ponente " dist^ancia "<br />

DRAFT<br />

O Exemplo 3.2 mostra a implementação na linguagem C <strong>de</strong> uma função que calcula a distância<br />

entre dois pontos no plano cartesiano. O corpo é <strong>com</strong>posto <strong>de</strong> atribuição <strong>de</strong> valores às variáveis dx,<br />

dy e dist através <strong>de</strong> cálculos matemáticos e pelo retorno do valor contido em dist. O retorno <strong>de</strong> dados<br />

é estudado na Seção 3.6.<br />

Essa função recebe <strong>com</strong>o parâmetros as coor<strong>de</strong>nadas <strong>de</strong> dois pontos no plano cartesiano e retorna a<br />

distância entre esses pontos. Para fazer o cálculo <strong>de</strong>ssa distância, primeiramente calcula-se a distância


3.3. PARTES DE UM SUBPROGRAMA 67<br />

entre as coor<strong>de</strong>nadas x (armazenando esse valor em dx) e a distância entre as coor<strong>de</strong>nadas y (armazenando<br />

esse valor em dy). Posteriormente, usa-se o teorema <strong>de</strong> Pitágoras para calcular a distância<br />

entre os pontos dados.<br />

1 float distancia ( float x1 , float y1 , float x2 , float y2){<br />

2 float dx , dy , dist ;<br />

3<br />

4 dx = x2 - x1;<br />

5 dy = y2 - y1;<br />

6 dist = sqrt (dx * dx + dy * dy);<br />

7<br />

8 return dist ;<br />

9 }<br />

Exemplo 3.2: O corpo do subprograma são as instruções contidas nele.<br />

Percebe-se que o nome da função já nos dá a i<strong>de</strong>ia do que ela faz: calcula a distância entre dois<br />

pontos. Porém, maiores explicações sobre essa distância, se é por um caminho mínimo ou qualquer<br />

outro arbitrário, <strong>de</strong>vem ser explicadas nos <strong>com</strong>entários da função.<br />

Quando a quantida<strong>de</strong> <strong>de</strong> parâmetros <strong>de</strong> uma função não é respeitada, a função não tem todos<br />

os dados necessários para a realização <strong>de</strong> suas instruções. Na função do Exemplo 3.1, quando o<br />

programador chama a função distancia passando apenas um número, ao invés <strong>de</strong> dois, o <strong>com</strong>pilador<br />

avisa o programador sobre tal erro, não <strong>de</strong>ixando que o programa seja gerado. Assim, evitam-se erros<br />

<strong>de</strong> execução.<br />

Também po<strong>de</strong>m ocorrer erros quando a or<strong>de</strong>m ou tipo dos parâmetros não são respeitadas. No<br />

cotidiano, também ocorrem esses tipos <strong>de</strong> erros. Por exemplo, para que um carro funcione, ele precisa,<br />

entre outras coisas, <strong>de</strong> água e óleo lubrificante. Caso a água seja colocada no lugar do óleo lubrificante,<br />

ou o contrário, é previsível que o carro, em algum momento, apresente falhas na execução <strong>de</strong> suas<br />

operações, não se lo<strong>com</strong>ovendo. Assim, fica fácil perceber que um bom programador <strong>de</strong>ve sempre<br />

verificar se está respeitando os tipos dos parâmetros das funções.<br />

3.3.2 Dicionário <strong>de</strong> dados<br />

DRAFT<br />

O dicionário <strong>de</strong> dados é on<strong>de</strong> se faz a <strong>de</strong>claração <strong>de</strong> variáveis e constantes usadas no subprograma e<br />

não <strong>de</strong>claradas no cabeçalho da função. Normalmente, são <strong>de</strong>claradas após o cabeçalho.<br />

Quando se <strong>de</strong>clara variáveis em subprogramas, estas só po<strong>de</strong>m ser utilizadas naquele subprograma.<br />

Qualquer outro subprograma, mesmo aquele que chamou a função, não tem acesso a essas variáveis.<br />

Assim, por existirem e serem acessíveis apenas naquele subprograma, são chamadas <strong>de</strong> variáveis locais.<br />

Consi<strong>de</strong>re novamente o exemplo do funcionamento da fábrica <strong>de</strong> automóveis. Enquanto o subprograma<br />

“Robô <strong>de</strong> solda” estiver fazendo seu trabalho (soldagem <strong>de</strong> peças), algumas informações usadas<br />

em alguns procedimentos necessitam ser utilizadas, tais <strong>com</strong>o: quantida<strong>de</strong> <strong>de</strong> solda, qualida<strong>de</strong> da solda,<br />

método <strong>de</strong> soldagem, etc. Quando o “Robô <strong>de</strong> solda” termina seu trabalho, essas informações não<br />

são mais necessárias. Note que os outros robôs não precisam saber <strong>de</strong>ssas informações para po<strong>de</strong>rem<br />

executar seus trabalhos.<br />

Para representar em um programa o funcionamento <strong>de</strong> uma fábrica <strong>de</strong> automóveis, cada robô<br />

po<strong>de</strong>ria ser representado por um subprograma. As informações seriam representadas por variáveis<br />

locais. A Figura 3.3 ilustra essa correspondência. O “Robô <strong>de</strong> pintura” tem duas variáveis: quantida<strong>de</strong><br />

<strong>de</strong> tinta e cor da tinta. Essa variáveis não são visíveis para os outros robôs; em particular, para o robô<br />

<strong>de</strong> solda.


68<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

3.3.3 Corpo<br />

Figura 3.3: Dicionário <strong>de</strong> dados.<br />

O corpo do subprograma é on<strong>de</strong> estão contidas as instruções a serem executadas pelo subprograma.<br />

Nele, po<strong>de</strong>m ser realizadas operações, tais <strong>com</strong>o: atribuições <strong>de</strong> valores às variáveis, chamadas <strong>de</strong><br />

outras funções, cálculos <strong>de</strong> expressões, leitura <strong>de</strong> dados e apresentação <strong>de</strong> resultados.<br />

3.3.4 Comentários<br />

Para melhor legibilida<strong>de</strong> e entendimento do código do subprograma, é re<strong>com</strong>endável fazer <strong>com</strong>entários.<br />

Antes <strong>de</strong> cada subprograma <strong>de</strong>ve-se colocar <strong>com</strong>entários <strong>com</strong> as seguintes finalida<strong>de</strong>s: dizer para<br />

quê a função serve, quais os parâmetros que recebe, explicitando <strong>com</strong>o <strong>de</strong>vem ser esses parâmetros<br />

(unida<strong>de</strong> <strong>de</strong> medida, relevância para a função, etc), restrições para aplicações, entre outras.<br />

No dicionário <strong>de</strong> dados, os <strong>com</strong>entários <strong>de</strong>vem ser usados para explicar o significado <strong>de</strong> alguma<br />

variável cujo nome não é suficientemente significativo. No corpo da função, os <strong>com</strong>entários <strong>de</strong>vem ser<br />

usados para explicar o que foi feito em <strong>de</strong>terminado conjunto <strong>de</strong> instruções cujo entendimento não é<br />

fácil.<br />

O Exemplo 3.3 mostra um <strong>com</strong>entário geral da função distancia, explicando os parâmetros da<br />

função e <strong>com</strong>o é feito o cálculo.<br />

1 /*<br />

2 Funcao para calcular a distancia entre dois pontos no plano cartesiano .<br />

3 Dados <strong>de</strong> entrada :<br />

4 float x1: a coor<strong>de</strong>nada x do primeiro ponto .<br />

5 float y1: a coor<strong>de</strong>nada y do primeiro ponto .<br />

6 float x2: a coor<strong>de</strong>nada x do segundo ponto .<br />

7 float y2: a coor<strong>de</strong>nada y do segundo ponto .<br />

8<br />

9 Dados <strong>de</strong> saida :<br />

DRAFT<br />

10 Retorna a distancia entre os pontos passados<br />

11 */<br />

12<br />

13 float distancia ( float x1 , float y1 , float x2 , float y2){<br />

14 float dx , dy , dist ;<br />

15<br />

16 dx = x2 - x1;<br />

17 dy = y2 - y1;<br />

18 dist = sqrt (dx * dx + dy * dy);<br />

19<br />

20 return dist ;<br />

21 }<br />

Exemplo 3.3: Comentários em um subprograma.


3.4. CHAMADA DE SUBPROGRAMAS 69<br />

3.4 Chamada <strong>de</strong> subprogramas<br />

Em programação, quando um subprograma solicita serviços <strong>de</strong> um outro subprograma dizemos que foi<br />

feita uma chamada ao subprograma. Durante a execução <strong>de</strong> um programa, po<strong>de</strong>m ser feitas diversas<br />

chamadas a um mesmo subprograma.<br />

Consi<strong>de</strong>re o exemplo do funcionamento da fábrica <strong>de</strong> automóveis. O “Robô <strong>de</strong> Solda” po<strong>de</strong> ser<br />

chamado diversas vezes durante o processo <strong>de</strong> fabricação <strong>de</strong> um carro e, é claro, em pontos <strong>de</strong> montagem<br />

diferentes. Toda vez que ele é chamado, executa novamente o seu serviço, consi<strong>de</strong>rando as<br />

particularida<strong>de</strong>s <strong>de</strong> cada caso.<br />

Em programação acontece o mesmo. Um mesmo subprograma po<strong>de</strong> ser chamado em diversos<br />

pontos do código. A função distancia, <strong>de</strong>scrita no Exemplo 3.2, po<strong>de</strong> ser usada para fazer vários<br />

cálculos <strong>de</strong> distâncias entre pontos diferentes e em vários lugares diferentes <strong>de</strong> um mesmo programa.<br />

A chamada <strong>de</strong> um subprograma na linguagem C é feita digitando o nome da função e, em seguida,<br />

digitando os dados <strong>de</strong> entrada necessários entre parênteses, para que assim o subprograma execute<br />

suas instruções.<br />

No Exemplo 3.4, a função distancia é chamada duas vezes. Na primeira vez, ela é chamada<br />

para calcular a distância entre duas cida<strong>de</strong>s, sendo fornecidas as coor<strong>de</strong>nadas x e y em quilômetros<br />

<strong>de</strong> distância das cida<strong>de</strong>s. A segunda chamada da função é feita para calcular a distância entre dois<br />

móveis <strong>de</strong> um escritório.<br />

Note que as coor<strong>de</strong>nadas passadas para o subprograma em cada momento po<strong>de</strong>m ser diferentes,<br />

fazendo <strong>com</strong> que o programa calcule distâncias diferentes. A interpretação física das coor<strong>de</strong>nadas<br />

passadas também po<strong>de</strong> ser diferente, não alterando a funcionalida<strong>de</strong> do subprograma.<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> <br />

3<br />

4 // local on<strong>de</strong> <strong>de</strong>ve ser incluido o codigo da funcao distancia .<br />

5 int main (){<br />

6 float xa , xb , ya , yb , dist ;<br />

7<br />

8 printf (" Forneca as coor<strong>de</strong>nadas x e y (em quilometros ) das cida<strong>de</strong>s A e B,<br />

9 respectivamente : ");<br />

10 scanf ("%f%f%f%f", &xa , &ya , &xb , &yb);<br />

11 dist = distancia (xa , ya , xb , yb);<br />

12 printf (" Distancia em quilometros entre as cida<strong>de</strong>s A e B: %f\n", dist );<br />

13 printf (" Forneca as coor<strong>de</strong>nadas x e y (em metros ) da ca<strong>de</strong>ira e da mesa do<br />

14 seu escritorio : ");<br />

15 scanf ("%f%f%f%f", &xa , &ya , &xb , &yb);<br />

16 dist = distancia (xa , ya , xb , yb);<br />

17 printf (" Distancia em metros entre a ca<strong>de</strong>ira e a mesa do seu<br />

18 escritorio : %f\n", dist );<br />

19<br />

20 return 0;<br />

21 }<br />

DRAFT<br />

3.5 Passagem <strong>de</strong> parâmetros<br />

Exemplo 3.4: Chamadas <strong>de</strong> um mesmo subprograma<br />

Os parâmetros <strong>de</strong> uma função são os dados iniciais necessários para que ela possa realizar o seu<br />

trabalho. Por exemplo, a função matemática: y(x) = x 2 calcula o quadrado do número x, que foi<br />

passado <strong>com</strong>o parâmetro para a função. Voltando ao exemplo da fabricação <strong>de</strong> um carro, po<strong>de</strong>-se<br />

dizer que a fábrica é o programa principal. Ao final do processo, ela <strong>de</strong>ve fornecer um carro pronto<br />

para o uso. Mas a fábrica, <strong>com</strong>o já foi dito, não conta apenas <strong>com</strong> um robô para fazer todo o processo<br />

e sim <strong>com</strong> vários robôs, cada um <strong>com</strong> sua função específica.<br />

Cada robô <strong>de</strong>ve receber uma entrada e fornecer uma saída. Para o “Robô <strong>de</strong> Pintura”, as entradas<br />

são: a carroceria do carro, feita por outro robô, e a cor usada para pintá-la. A partir <strong>de</strong>ssas entradas,


70<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

o “Robô <strong>de</strong> Pintura” executa as instruções estabelecidas para pintar a carroceria. Ao final da pintura,<br />

o robô está pronto para fornecer a saída: a carroceria pintada. Essa saída po<strong>de</strong> servir <strong>com</strong>o entrada<br />

para outro robô.<br />

Cada parâmetro <strong>de</strong> uma função possui um tipo, <strong>de</strong>clarado no cabeçalho da função, <strong>com</strong>o mostrado<br />

no Exemplo 3.1, on<strong>de</strong> os parâmetros a e b são do tipo float. Quando é feita uma chamada ao<br />

subprograma, po<strong>de</strong>m ser passados <strong>com</strong>o parâmetro os valores <strong>de</strong> variáveis do programa principal, que<br />

obrigatoriamente <strong>de</strong>vem ser do mesmo tipo dos parâmetros da função chamada.<br />

No Exemplo 3.4, são feitas várias chamadas ao subprograma distancia. Em cada uma <strong>de</strong>ssas<br />

chamadas são passadas entradas distintas, nesse caso, pontos diferentes no plano cartesiano. Consi<strong>de</strong>re<br />

que na primeira chamada os pontos passados são: xa = 10, ya = 30, xb = 20, yb = 60. Já na segunda<br />

chamada foram passados os pontos: xa = 15, ya = 18, xb = 5, yb = 53. A Figura 3.4 ilustra esse<br />

processo.<br />

Figura 3.4: Passagem <strong>de</strong> parâmetros.<br />

Quando o programa principal chama o subprograma distancia, os valores que estão contidos nas<br />

variáveis xa, ya, xb e yb são passados para as variáveis x1, y1, x2 e y2 do subprograma.<br />

É importante perceber que, quando é feita uma passagem <strong>de</strong> parâmetros, apenas os valores das<br />

variáveis são passados para o subprograma chamado e não as variáveis em si.<br />

A primeira implicação <strong>de</strong>ssa regra é a não necessida<strong>de</strong> <strong>de</strong> se usar variáveis <strong>com</strong>o entrada para<br />

outra função, po<strong>de</strong>ndo-se usar diretamente um valor. O Exemplo 3.5 ilustra essa i<strong>de</strong>ia. No programa<br />

principal é feita a chamada ao subprograma distancia passando-se os valores 10, −15, 26 e −23 <strong>com</strong>o<br />

parâmetros. Na função distancia, as variáveis x1, y1, x2 e y2 recebem esses valores, para só então a<br />

função iniciar suas instruções.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int dist ;<br />

5<br />

DRAFT<br />

6 dist = distancia (10 , -15, 26 , -23);<br />

7<br />

8 return 0;<br />

9 }<br />

Exemplo 3.5: Passagem <strong>de</strong> parâmetros.


3.5. PASSAGEM DE PARÂMETROS 71<br />

Outra implicação do fato <strong>de</strong> que apenas valores são passados <strong>com</strong>o parâmetro para uma função é<br />

a impossibilida<strong>de</strong> <strong>de</strong> mudar o conteúdo das variáveis que são usadas <strong>com</strong>o entrada para a função. No<br />

Exemplo 3.6, a variável a, da função dobraValor, recebe apenas o valor da variável x da função principal.<br />

Com isso, a variável x permanece <strong>com</strong> o seu valor anterior à chamada da função dobraValor,<br />

apesar da variável a <strong>de</strong>ssa função ter o seu valor alterado.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 void dobraValor ( int a){<br />

4 printf (" Numero original : %d \n", a);<br />

5 a = 2 * a;<br />

6 printf ("O seu dobro e: %d \n", a);<br />

7 }<br />

8<br />

9 int main (){<br />

10 int x = 10;<br />

11 dobraValor (x);<br />

12 printf ("O valor <strong>de</strong> x e: %d \n", x);<br />

13<br />

14 return 0;<br />

15 }<br />

Exemplo 3.6: Passagem <strong>de</strong> parâmetro na chamada <strong>de</strong> subprogramas.<br />

Note que a função dobraValor é <strong>de</strong> tipo void. Quando uma função apenas manipula informações,<br />

sem retornar nenhum tipo <strong>de</strong> dado, ela é <strong>de</strong>finida <strong>com</strong>o tal.<br />

A saída da execução do programa do Exemplo 3.6 é mostrada no Exemplo 3.7. Note que, <strong>com</strong>o<br />

esperado, a variável x permaneceu <strong>com</strong> o seu valor original.<br />

1 Número original : 10<br />

2 O seu dobro é: 20<br />

3 O valor <strong>de</strong> x é: 10<br />

Exemplo 3.7: Saída da execução do programa do Exemplo 3.6.<br />

Uma outra implicação da passagem <strong>de</strong> parâmetros é a não visibilida<strong>de</strong> das variáveis do programa<br />

principal no subprograma chamado. Isso significa que o subprograma não po<strong>de</strong> utilizar as variáveis do<br />

programa principal ou <strong>de</strong> algum outro subprograma. No Exemplo 3.8, as variáveis x e y não po<strong>de</strong>m ser<br />

acessadas <strong>de</strong>ntro da função alteraValor. Se isso for tentado, o <strong>com</strong>pilador emitirá um erro quando<br />

o programa é <strong>com</strong>pilado, dizendo que as variáveis x e y não foram <strong>de</strong>finidas.<br />

DRAFT<br />

1 void alteraValor ( void ){ // Ocorre erro na <strong>com</strong>pilacao<br />

2 x = 20;<br />

3 y = x * 5;<br />

4 }<br />

5<br />

6 int main (){<br />

7 int x = 10 , y = 15;<br />

8<br />

10<br />

9 alteraValor ();<br />

11 return 0;<br />

12 }<br />

Exemplo 3.8: Erro na visibilida<strong>de</strong> das variáveis.<br />

Note que além da função dobraValor ser do tipo void ela não recebe nenhuma variável <strong>com</strong>o<br />

parâmetro. Portanto este parâmetro po<strong>de</strong> ser <strong>de</strong>scrito <strong>com</strong>o void ou simplesmente ser suprimido.<br />

O que ocorre no Exemplo 3.8 também po<strong>de</strong> ser <strong>com</strong>parado <strong>com</strong> os robôs da fábrica <strong>de</strong> automóveis.<br />

O “Robô <strong>de</strong> Solda” não po<strong>de</strong> usar a variável local cor do automóvel do “Robô <strong>de</strong> Pintura”. O “Robô<br />

<strong>de</strong> Solda” não sabe o que é essa variável, nem que ela existe, assim, não po<strong>de</strong> usá-la.


72<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

3.6 Retorno <strong>de</strong> dados<br />

Esta seção trata da forma <strong>com</strong>o os dados são retornados em cada subprograma, isto é, <strong>com</strong>o se produz<br />

uma saída da função.<br />

Um subprograma produz, no <strong>de</strong>correr das suas instruções, um valor final (uma saída), que <strong>de</strong>verá<br />

ser passado para o programa ou subprograma que o chamou. O valor retornado pelo subprograma<br />

será atribuído a alguma variável do programa que chamou essa função, ou então usado em alguma<br />

expressão.<br />

Na linguagem C, <strong>de</strong>ve-se <strong>de</strong>finir o tipo <strong>de</strong> dado retornado pela função em seu cabeçalho e usa-se<br />

o <strong>com</strong>ando return para especificar o valor que <strong>de</strong>ve ser retornado. Após a execução do <strong>com</strong>ando, a<br />

função corrente termina, mesmo que existam mais instruções após o return. Na implementação da<br />

função distancia, feita no Exemplo 3.2, o valor contido na variável dist é retornado.<br />

Como a main também é uma função, também temos que especificar o tipo <strong>de</strong> dado retornado por<br />

ela. Por padrão, na linguagem C, a função main retorna um valor do tipo int. Quando o programador<br />

não coloca nenhum valor para ser retornado pela main (<strong>com</strong>o no Exemplo 3.9), alguns <strong>com</strong>piladores<br />

fazem <strong>com</strong> que o valor 0 seja retornado por padrão. O valor 0 também é usado para simbolizar que<br />

nada aconteceu <strong>de</strong> errado na execução do programa.<br />

Consi<strong>de</strong>re um programa que calcula a média <strong>de</strong> um aluno e diz se ele foi aprovado ou não. O<br />

Pseudocódigo 3.2 mostra os passos a serem realizados pelo programa.<br />

Pseudocódigo 3.2 Programa para calcular a média <strong>de</strong> um aluno.<br />

Descrição: Calcular a média <strong>de</strong> um aluno.<br />

Dados <strong>de</strong> Entrada: As notas do aluno.<br />

Saída do Programa: A média do aluno.<br />

Funç~ao Principal :<br />

Chamar " calculaMedia " passando as 2 notas <strong>de</strong> provas do aluno <strong>com</strong>o<br />

par^ametros .<br />

SE a média retornada é maior ou igual a sete :<br />

O aluno está aprovado .<br />

SEN~AO:<br />

Chamar " calculaMedia " passando a média anterior<br />

e a nota da prova final do aluno <strong>com</strong>o par^ametros .<br />

SE a nova média retornada é maior ou igual a cinco :<br />

O aluno está aprovado .<br />

SEN~AO:<br />

O aluno está reprovado .<br />

FIM -SE<br />

FIM -SE<br />

FIM - Funç~ao Principal<br />

DRAFT<br />

Processo <strong>com</strong>ponente " calculaMedia ":<br />

Somar os dois números passados <strong>com</strong>o par^ametros e dividir o resultado<br />

por dois .<br />

Retornar o resultado acima .<br />

FIM - Processo <strong>com</strong>ponente " calculaMedia "<br />

Uma possível implementação do Pseudocódigo 3.2 está transcrita no Exemplo 3.9. Primeiramente,<br />

o programa pe<strong>de</strong> que o usuário digite os valores das notas das duas provas realizadas pelo aluno. Essas<br />

notas são armazenadas nas variáveis nota1 e nota2 respectivamente e, logo em seguida, são passadas<br />

<strong>com</strong>o parâmetros para a função calculaMedia. A função calculaMedia recebe dois valores do tipo<br />

float e faz a média aritmética <strong>de</strong>les, retornando, ao final da sua execução, o valor <strong>de</strong>ssa média. O valor<br />

retornado é armazenado na variável resultado da função principal, que por sua vez serve <strong>de</strong> condição<br />

para a aprovação do aluno. Caso o valor armazenado em resultado seja maior ou igual a sete, o aluno<br />

está aprovado; caso contrário, o programa pe<strong>de</strong> a nota da prova final do aluno, que é armazenada na


3.6. RETORNO DE DADOS 73<br />

variável notaFinal. As variáveis notaFinal e resultado são então usadas <strong>com</strong>o parâmetros da função<br />

calculaMedia. Caso o resultado retornado seja maior ou igual a cinco, o aluno está aprovado.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 float calculaMedia ( float a, float b){<br />

4 float media ;<br />

5<br />

6 media = (a + b) / 2;<br />

7<br />

10<br />

8 return media ;<br />

9 }<br />

11 int main (){<br />

12 float nota1 , nota2 , notaFinal , resultado ;<br />

13<br />

14 printf (" Forneca as notas das duas provas do aluno : ");<br />

15 scanf ("%f%f", & nota1 , & nota2 );<br />

16<br />

17 resultado = calculaMedia ( nota1 , nota2 );<br />

18<br />

19 printf ("A media do aluno foi : %f\n", resultado );<br />

20<br />

21 if( resultado >= 7){<br />

22 printf ("O aluno passou <strong>de</strong> semestre .\n");<br />

23 } else {<br />

24 printf ("O aluno teve que fazer prova final . Forneca a nota da prova<br />

25 final do aluno : ");<br />

26 scanf ("%f", & notaFinal );<br />

27<br />

28 if( calculaMedia ( resultado , notaFinal ) >= 5){<br />

29 printf ("O aluno passou <strong>de</strong> semestre .\n");<br />

30 } else {<br />

31 printf ("O aluno nao obteve o rendimento minimo para passar <strong>de</strong><br />

32 semestre .\n");<br />

33 }<br />

34 }<br />

35 return 0;<br />

36 }<br />

Exemplo 3.9: Retorno <strong>de</strong> dados.<br />

Note que, na primeira chamada da função calculaMedia, o valor retornado foi armazenado em<br />

uma variável, pois precisa ser usado posteriormente. Já na segunda chamada da função, o valor<br />

retornado é usado diretamente na condicional <strong>de</strong> aprovação ou não do aluno, não sendo necessário<br />

seu armazenamento em alguma variável. Mas atenção: caso fosse necessário usar esse valor posteriormente,<br />

<strong>de</strong>veríamos guardá-lo em alguma variável, ao invés <strong>de</strong> chamar outra vez a função calculaMedia<br />

usando os mesmos parâmetros. Essa chamada sendo feita novamente acarretaria em perda <strong>de</strong> <strong>de</strong>sempenho<br />

do programa, já que a função teria que recalcular valores, o que levaria um certo tempo para<br />

ser feito.<br />

Em muitos casos é interessante, ou até necessário, que o subprograma altere as variáveis criadas<br />

no programa que o chamou. No exemplo da fábrica <strong>de</strong> automóveis é isso que <strong>de</strong>ve acontecer. A Figura<br />

3.5 ilustra esse processo.<br />

Nesse exemplo, o carro que é passado para o robô <strong>de</strong> solda está <strong>com</strong> várias peças soltas. Então, o<br />

robô solda essas peças e passa o carro para o robô <strong>de</strong> pintura. Nesse caso, percebe-se que <strong>de</strong>ve-se passar<br />

o mesmo carro para o próximo robô e não apenas um cópia das suas características, que simbolizam<br />

os valores das variáveis em programas. Então, o carro recebe a pintura e é passado <strong>com</strong>o parâmetro<br />

para uma próxima função, ou seja, para um outro robô.<br />

Como discutido na Seção 3.5, não é possível para um subprograma que recebe o valor <strong>de</strong> uma<br />

variável <strong>de</strong> um outro subprograma, alterar diretamente o valor da variável do subprograma que o<br />

chamou. Nesse caso, po<strong>de</strong>-se retornar o valor calculado e então armazená-lo na variável <strong>de</strong>sejada. A<br />

DRAFT


74<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

Figura 3.5: Passagem <strong>de</strong> parâmetro por referência.<br />

expressão geral é x = f(x).<br />

Por exemplo, po<strong>de</strong>-se fazer uma variação do uso da função dobraValor usada no Exemplo 3.6<br />

para alterar o valor da variável do programa que a chamou. Essa alteração está <strong>de</strong>scrita no Exemplo<br />

3.10. Nesse exemplo, o valor retornado pela função dobraValor agora é armazenado na variável x.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int dobraValor ( int a){<br />

4 printf (" Numero original : %d \n", a);<br />

5 a = 2 * a;<br />

6 printf ("O seu dobro e: %d \n", a);<br />

7<br />

10<br />

8 return a;<br />

9 }<br />

11 int main (){<br />

12 int x = 10;<br />

13<br />

14 x = dobraValor (x);<br />

15 printf ("O valor <strong>de</strong> x e: %d \n", x);<br />

16<br />

17 return 0;<br />

18 }<br />

Exemplo 3.10: Atualização da variável <strong>de</strong> outra função.<br />

DRAFT<br />

A saída da execução do programa do Exemplo 3.10 é mostrada no Exemplo 3.11.<br />

variável x passou a ter o valor 20.<br />

1 Número original : 10<br />

2 O seu dobro e: 20<br />

3 O valor <strong>de</strong> x e: 20<br />

Exemplo 3.11: Saída da execução do programa do Exemplo 3.6.<br />

Note que a<br />

3.6.1 Encerramento antecipado <strong>de</strong> execução<br />

Observando a <strong>de</strong>finição <strong>de</strong> calculaMedia, implementada no Exemplo 3.9, nota-se que o valor só é<br />

retornado ao final da função, quando todas as outras instruções foram executadas. No entanto, é<br />

possível ocorrer <strong>de</strong> um subprograma ter vários pontos <strong>de</strong> retorno distintos.<br />

No Pseudocódigo 3.3 são mostrados os passos realizados pela função ehDivisor, que verifica se<br />

um número é divisor do outro. Para evitar um erro matemático, é importante verificar se o divisor


3.6. RETORNO DE DADOS 75<br />

é diferente <strong>de</strong> zero. Se for igual a zero, então a execução da função <strong>de</strong>ve ser interrompida e o erro<br />

<strong>de</strong>verá ser indicado <strong>de</strong> alguma forma. Nesse caso, escolheu-se retornar o valor negativo −1.<br />

Pseudocódigo 3.3 Função que <strong>de</strong>termina se um número é divisor do outro.<br />

Descrição: Determinar se um número é divisor <strong>de</strong> outro.<br />

Dados <strong>de</strong> Entrada: Dois números<br />

Saída do Programa: 1, 0 ou -1 <strong>de</strong> acordo <strong>com</strong> o resultado<br />

Processo <strong>com</strong>ponente " eDivisor ":<br />

SE o divisor é igual a zero :<br />

Retornar o valor -1<br />

FIM -SE<br />

SE o resto da divis~ao do divi<strong>de</strong>ndo pelo divisor é igual a zero :<br />

Retornar o valor 1<br />

SEN~AO:<br />

Retornar o valor 0<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " eDivisor "<br />

No Exemplo 3.12 é apresentada a implementação, na linguagem C, do Pseudocódigo 3.3. Note<br />

que a função apresenta três pontos distintos <strong>de</strong> retorno. No primeiro, é verificado se o divisor é zero<br />

e caso isso seja verda<strong>de</strong> é retornado o valor −1, caso contrário, a função continua executando suas<br />

instruções. No segundo, é verificado se o resto da divisão inteira <strong>de</strong> x por y é zero, ou seja, é verificado<br />

se y é divisor <strong>de</strong> x. Caso isso seja verda<strong>de</strong> é retornado o valor 1, caso contrário, é retornado o valor 0,<br />

simbolizando que y não é divisor <strong>de</strong> x. Aqui, o valor 1 foi usado para simbolizar sucesso na verificação.<br />

Note ainda que esse recurso torna a função mais eficiente e legível.<br />

1 int eDivisor ( int x, int y){<br />

2 if (!y){<br />

3 return -1;<br />

4 }<br />

5<br />

6 if(x % y){<br />

7 return 1;<br />

8 } else {<br />

9 return 0;<br />

10 }<br />

11 }<br />

DRAFT<br />

Exemplo 3.12: Encerramento antecipado para evitar erros<br />

No Exemplo 3.12, o encerramento antecipado foi feito para evitar um erro na execução do programa.<br />

Porém, o encerramento antecipado <strong>de</strong> execução po<strong>de</strong> não objetivar evitar erros <strong>de</strong> execução.<br />

Consi<strong>de</strong>re o caso do Exemplo 3.9. O programa principal po<strong>de</strong>ria ser na verda<strong>de</strong> um subprograma<br />

que retorna 1 caso o aluno seja aprovado e 0 caso contrário. Se o aluno obtiver média 7 apenas <strong>com</strong> as<br />

duas primeiras notas, a execução do programa é interrompida e o valor 1 é retornado. Essa alteração<br />

é <strong>de</strong>scrita no Exemplo 3.13.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 float calculaMedia ( float a, float b){<br />

4 float media ;<br />

5<br />

6 media = (a + b) / 2;<br />

7<br />

8 return media ;<br />

9 }


76<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

10<br />

11 int aprovado ( float nota1 , float nota2 , float notaPF ){<br />

12 float resultado ;<br />

13<br />

14 resultado = calculaMedia ( nota1 , nota2 );<br />

15<br />

16 if( resultado >= 7){<br />

17 return 1;<br />

18 }<br />

19<br />

20 if( calculaMedia ( resultado , notaPF ) >= 5){<br />

21 return 1;<br />

22 }<br />

23<br />

24 return 0;<br />

25 }<br />

26 int main (){<br />

27 float nota1 , nota2 , notaPF ;<br />

28<br />

29 printf (" Forneca as notas das duas provas do aluno e a nota da prova final .<br />

30 Caso o aluno nao tenha feito prova final , digite zero : ");<br />

31 scanf ("%f%f%f", & nota1 , & nota2 , & notaPF );<br />

32<br />

33 if( aprovado ( nota1 , nota2 , notaPF )){<br />

34 printf ("O aluno passou <strong>de</strong> semestre .\n");<br />

35<br />

36 } else {<br />

37 printf ("O aluno nao obteve o rendimento minimo para passar<br />

38 <strong>de</strong> semestre .\n");<br />

39 }<br />

40<br />

41 return 0;<br />

42 }<br />

Exemplo 3.13: Encerramento antecipado natural.<br />

3.7 Funções sem lista <strong>de</strong> parâmetros<br />

Até agora as funções mostradas continham dados <strong>de</strong> entrada, ou seja, uma lista <strong>de</strong> parâmetros. Mas<br />

há casos em que isso não é necessário, pois a função executa suas instruções sem precisar <strong>de</strong> dados <strong>de</strong><br />

entrada. Alguns leitores po<strong>de</strong>m achar que isso faz <strong>com</strong> que o subprograma retorne sempre o mesmo<br />

dado, afinal, a ausência <strong>de</strong> dados <strong>de</strong> entrada tornaria a função uma função constante.<br />

Esse pensamento estaria correto se o subprograma não pu<strong>de</strong>sse coletar dados externos, usando por<br />

exemplo a função scanf.<br />

No Exemplo 3.14 a função lerNumeros não tem nenhum parâmetro <strong>de</strong> entrada. Isso foi feito<br />

pois ela sempre executará a mesma rotina: lerá 5 números digitados pelo usuário e fará a soma <strong>de</strong>les.<br />

É fácil perceber que o resultado retornado po<strong>de</strong> variar a cada chamada da função. Isso acontece pois<br />

essa função usa os dados retornados por scanf para <strong>com</strong>pletar suas instruções. Note que usa-se void<br />

na lista <strong>de</strong> parâmetros para simbolizar que a função não possui parâmetros <strong>de</strong> entrada.<br />

1 int lerNumeros ( void ){<br />

2 int x = 0, temp , i;<br />

3<br />

4 for (i = 0; i < 5; i ++) {<br />

5 printf (" digite um numero : ");<br />

6 scanf ("%d", & temp );<br />

7 x += temp ;<br />

8 }<br />

9<br />

10 return x;<br />

11 }<br />

DRAFT


3.8.<br />

FUNÇÕES SEM RETORNO DE DADOS 77<br />

Exemplo 3.14: Lista <strong>de</strong> parâmetros vazia<br />

3.8 Funções sem retorno <strong>de</strong> dados<br />

Assim <strong>com</strong>o há funções que não têm nenhum parâmetro, também há funções que não retornam nenhum<br />

tipo <strong>de</strong> dado. Na linguagem C, para simbolizar essa situação usa-se void <strong>com</strong>o tipo <strong>de</strong> dado retornado.<br />

O Exemplo 3.15 exibe uma função que não retorna dados para a função que a chamou. A função<br />

apresentaMultiplicacao recebe três números e exibe o resultado da multiplicação <strong>de</strong>stes. Nota-se<br />

que nenhum dado é retornado, nem mesmo o valor da multiplicação. O programador po<strong>de</strong> <strong>de</strong>cidir por<br />

este tratamento caso o resultado da multiplicação não seja usado posteriormente.<br />

1 void apresentaMultiplicacao ( float a, float b, float c){<br />

2 printf (" Resultado = %f", a * b * c);<br />

3 }<br />

Exemplo 3.15: Função sem retorno.<br />

Funções sem retorno <strong>de</strong> dados po<strong>de</strong>m guardar os valores gerados em algum arquivo. Caso isso seja<br />

feito, os dados po<strong>de</strong>m ser recuperados lendo-se esses arquivos. A manipulação <strong>de</strong> arquivos, tanto para<br />

leitura, tanto para escrita, é discutida no capítulo 8.<br />

Há também a opção da função não ter nenhum parâmetro <strong>de</strong> entrada e nenhum dado retornado. O<br />

Exemplo 3.16 mostra uma função para exibir uma saudação ao usuário. Note que a função não possui<br />

parâmetros <strong>de</strong> entrada nem valor <strong>de</strong> retorno. O objetivo <strong>de</strong> uma tal função é apenas <strong>de</strong> organização<br />

ou para evitar repetição <strong>de</strong> código, caso seja chamado em diferentes pontos do programa.<br />

1 void saudacao ( void ){<br />

2 printf ("Bem - vindo ao programa Calculo Eletronico , on<strong>de</strong> seus<br />

3 calculos sao resolvidos rapidamente \ nPara mais informacoes e atualizacoes<br />

4 acesse o site : www . programaemc . <strong>com</strong> .br");<br />

5 }<br />

3.9 Recursivida<strong>de</strong><br />

Exemplo 3.16: Função sem parâmetro e sem retorno.<br />

DRAFT<br />

A recursivida<strong>de</strong> ocorre quando algo é <strong>de</strong>finido a partir <strong>de</strong> si mesmo. Uma recursão sempre é <strong>de</strong>finida a<br />

partir <strong>de</strong> uma ou mais relações recursivas (quando o próximo elemento é <strong>de</strong>finido a partir do anterior),<br />

e uma ou mais bases <strong>de</strong> recursão (pontos <strong>de</strong> parada).<br />

Em programação, o método recursivo po<strong>de</strong> ser usado para <strong>de</strong>finir uma função. Por exemplo, o<br />

cálculo do fatorial <strong>de</strong> um número inteiro não negativo po<strong>de</strong> ser implementado através <strong>de</strong> uma função<br />

recursiva. Po<strong>de</strong>-se <strong>de</strong>finir o fatorial <strong>de</strong> um número n <strong>com</strong>o sendo o próprio número n multiplicado<br />

pelo fatorial do número n-1. A <strong>de</strong>finição <strong>de</strong> fatorial po<strong>de</strong> ser representada por:<br />

fatorial (0) = 1 ⇒ base da recursão<br />

fatorial (n) = n * fatorial (n-1) ⇒ relação recursiva<br />

Na <strong>de</strong>finição recursiva anterior é usado critério <strong>de</strong> parada a fim <strong>de</strong> que o processo recursivo tenha<br />

um limite. Se o fatorial <strong>de</strong> um número fosse <strong>de</strong>finido somente <strong>com</strong>o um número multiplicado pelo<br />

fatorial do seu antecessor o fatorial ficaria in<strong>de</strong>finido, pois todo número possui um antecessor. Para<br />

evitar isso usa-se um critério <strong>de</strong> parada, chamado <strong>de</strong> base da recursão. No exemplo do fatorial <strong>de</strong> um<br />

número, a base da recursão po<strong>de</strong> ser o número 0, ou seja, é <strong>com</strong>o seguir o <strong>com</strong>ando: “quando chegar<br />

ao número 0 pare”.


78<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

O Pseudocódigo 3.4 mostra os passos a serem seguidos para o cálculo do fatorial <strong>de</strong> um número<br />

<strong>de</strong> forma recursiva.<br />

Pseudocódigo 3.4 Fatorial <strong>de</strong> um número <strong>de</strong> forma recursiva.<br />

Descrição: Calcular o fatorial <strong>de</strong> um número natural.<br />

Dados <strong>de</strong> Entrada: Número natural.<br />

Saída do Programa: Fatorial do número natural.<br />

Processo <strong>com</strong>ponente " fatorial ":<br />

SE o número passado <strong>com</strong>o par^ametro é igual a zero :<br />

Retornar o valor 1.<br />

SEN~AO:<br />

Retornar o número passado <strong>com</strong>o par^ametro multiplicado<br />

pelo valor do fatorial do seu antecessor .<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " fatorial "<br />

A implementação recursiva do fatorial na linguagem C é mostrada no Exemplo 3.17. O programa<br />

chama ele mesmo quantas vezes forem necessárias até que o parâmetro n seja 0. Quando isso acontece,<br />

a função retorna 1 e a execução prossegue a partir da última chamada da função, multiplicando o valor<br />

retornado (1) pelo valor 1 da chamada anterior da função e assim sucessivamente, até se obter o fatorial<br />

do número n inicial.<br />

1 int fatorial ( int n){<br />

2 if (!n){<br />

3 return 1;<br />

4 } else {<br />

5 return n * fatoria (n - 1);<br />

6 }<br />

7 }<br />

Exemplo 3.17: Implementação recursiva do fatorial.<br />

É importante <strong>com</strong>preen<strong>de</strong>r que a cada chamada do programa fatorial é reservado um novo espaço<br />

<strong>de</strong> memória, ou seja, os dados do programa fatorial anterior são preservados e caso a função recursiva<br />

tivesse variáveis locais, novas instâncias <strong>de</strong>ssas variáveis seriam criadas a cada chamada, sem qualquer<br />

relação <strong>com</strong> as variáveis da outra chamada do subprograma. Por isso, funções recursivas ten<strong>de</strong>m a<br />

necessitar <strong>de</strong> mais memória do <strong>com</strong>putador.<br />

DRAFT<br />

Figura 3.6: Fatorial utilizando recursão.


3.10.<br />

EXERCÍCIOS RESOLVIDOS 79<br />

Chamando a função fatorial passando-se <strong>com</strong>o argumento o número 5, tem-se o esquema ilustrado<br />

na Figura 3.6. As setas direcionadas para baixo significam a chamada do programa apontado, exibindo<br />

o valor passado <strong>com</strong>o parâmetro. As setas direcionadas para cima significam o retorno do dado do<br />

programa chamado, mostrando o valor retornado pela função.<br />

3.9.1 Implementação não recursiva equivalente<br />

Em geral, toda função recursiva po<strong>de</strong> ser implementada sem recursão, através do uso <strong>de</strong> <strong>com</strong>andos <strong>de</strong><br />

repetição. A vantagem da versão não recursiva é a eficiência. Já a vantagem da recursiva é a elegância,<br />

legibilida<strong>de</strong> e redigibilida<strong>de</strong>.<br />

O Exemplo 3.18 mostra uma forma não recursiva da implementação da função fatorial. O <strong>com</strong>ando<br />

for é utilizado para multiplicar o f por i a cada valor <strong>de</strong> i, até que i assuma o valor <strong>de</strong> n, passado <strong>com</strong>o<br />

parâmetro.<br />

1 int fatorial2 ( int n){<br />

2 int i, f;<br />

3<br />

4 f = 1;<br />

5<br />

6 for (i = 2; i


80<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

Pseudocódigo 3.5 Passos a serem realizados pela função soma.<br />

Descrição: Calcular a soma dos n primeiros inteiros.<br />

Dados <strong>de</strong> Entrada: Número inteiro.<br />

Saída do Programa: Somatório dos números.<br />

Processo <strong>com</strong>ponente " soma ":<br />

Inicializar soma <strong>com</strong> o valor zero<br />

Inicializar i <strong>com</strong> o valor 1<br />

ENQUANTO i for menor ou igual a n:<br />

Acumular em soma o valor corrente <strong>de</strong> i<br />

FIM - ENQUANTO<br />

Retornar o valor soma<br />

FIM - Processo <strong>com</strong>ponente " soma ".<br />

O Exemplo 3.19 mostra a implementação <strong>de</strong>sse algoritmo. Note que o pseudocódigo foi seguido<br />

fielmente, acrescentado-se apenas instruções necessárias e específicas da linguagem C.<br />

1 int soma ( int n){<br />

2 int i, soma ;<br />

3<br />

4 soma = 0;<br />

5 for (i = 1; i


3.10.<br />

EXERCÍCIOS RESOLVIDOS 81<br />

Funç~ao Principal :<br />

Ler os valores <strong>de</strong> n, i e j<br />

Chamar o processo <strong>com</strong>ponente multiplos passando <strong>com</strong>o par^ametros n, i e j.<br />

FIM - Funç~ao Principal<br />

Processo <strong>com</strong>ponente " multiplos ":<br />

Inicializar a variável do número atual e a variável indicando o número<br />

<strong>de</strong> múltiplos <strong>com</strong> o valor zero .<br />

ENQUANTO o número <strong>de</strong> múltiplos for menor que n:<br />

SE o número atual é múltiplo <strong>de</strong> i ou <strong>de</strong> j através do processo<br />

<strong>com</strong>ponente Multiplo :<br />

Incrementar a variável contadora <strong>de</strong> múltiplos e<br />

exibir o valor do número atual .<br />

FIM -SE<br />

Incrementar a variável do número atual<br />

FIM - loop<br />

FIM - Processo <strong>com</strong>ponente " multiplos "<br />

Processo <strong>com</strong>ponente " Multiplo ":<br />

SE o resto da divis~ao <strong>de</strong> x por y é zero :<br />

Retornar o valor 1, indicando sucesso .<br />

SEN~AO:<br />

Retornar o valor 0.<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " Multiplo "<br />

Nº Natural Múltiplo <strong>de</strong> b ? Múltiplo <strong>de</strong> a ? Nº <strong>de</strong> múltiplos <strong>de</strong> a ou b<br />

0 sim sim 1<br />

1 não não 1<br />

2 não sim 2<br />

3 sim não 3<br />

4 não sim 4<br />

5 não não 4<br />

6 sim sim 5<br />

7 não não 5<br />

8 não sim 6<br />

DRAFT<br />

Figura 3.8: Solução para n = 6, a = 2 e b = 3.<br />

O Exercício 3.20 mostra a implementação do algoritmo do Pseudocódigo 3.6. Na função eMultiplo<br />

usou-se <strong>com</strong>o convenção o valor 1 para indicar sucesso na verificação <strong>de</strong> x ser múltiplo <strong>de</strong> y e 0 caso<br />

contrário. Note também que no <strong>com</strong>ando <strong>de</strong> repetição for da função múltiplos foi omitido o terceiro<br />

parâmetro. Isso foi necessário pois a variável cont só <strong>de</strong>verá ser incrementada se natural for múltiplo<br />

<strong>de</strong> i ou j, o que nem sempre é verda<strong>de</strong>.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int eMultiplo ( int x, int y){<br />

4<br />

5 if(x % y){<br />

6 return 0;<br />

7 } else {<br />

8 return 1;<br />

9 }<br />

10 }<br />

11<br />

12 void multiplos ( int i, int j, int n){<br />

13 int natural , cont ;


82<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

14<br />

15 natural = 0;<br />

16 cont = 0;<br />

17<br />

18 printf ("Os %d primeiros multiplos <strong>de</strong> %d ou <strong>de</strong> %d sao :", n, i, j);<br />

19<br />

20 while ( cont < n){<br />

21 if( eMultiplo ( natural , i) || eMultiplo ( natural , j) ){<br />

22 printf (" %d", natural );<br />

23 cont = cont + 1;<br />

24 }<br />

25 natural = natural + 1;<br />

26 }<br />

27 printf ("\n");<br />

28 }<br />

29<br />

30 int main (){<br />

31 int n, i, j;<br />

32<br />

33 printf (" Digite 3 numeros naturais ( quantida<strong>de</strong> n <strong>de</strong> multiplos que serao impressos ,<br />

34 e dois geradores )");<br />

35 scanf ("%d%d%d", &n, &i, &j);<br />

36 multiplos (i, j, n);<br />

37<br />

38 return 0;<br />

39 }<br />

Exemplo 3.20: Programa que calcula os n primeiros naturais multiplos <strong>de</strong> dois geradores.<br />

Exercício Resolvido 3.3 - Triângulo Retângulo<br />

Faça uma função que dados três números naturais, verifique se eles formam os lados <strong>de</strong> um triângulo<br />

retângulo. Os números dados simbolizam o <strong>com</strong>primento <strong>de</strong> cada lado do triângulo.<br />

Solução Possível:<br />

Na geometria, o Triângulo Retângulo é um triângulo que possui um ângulo reto e outros dois<br />

ângulos agudos. Sabe-se ainda que o quadrado da hipotenusa (o maior lado do retângulo) é igual a<br />

soma dos quadrados dos catetos.<br />

Sendo assim, para resolver esse exercício, precisamos primeiro saber qual dos três lados dados, a,<br />

b ou c, correspon<strong>de</strong> à hipotenusa. Para tanto, <strong>com</strong>para-se todos os lados, dois a dois, colocando-se o<br />

maior lado na variável a.<br />

Como o maior lado estará guardado em a é certo dizer que os lados dados correspon<strong>de</strong>m a um<br />

triângulo retângulo se, e somente se, a 2 = b 2 + c 2 .<br />

O Pseudocódigo 3.7 mostra um algoritmo que <strong>de</strong>screve os passos a serem realizados pela função.<br />

Pseudocódigo 3.7 Passos a serem realizados pela função.<br />

DRAFT<br />

Descrição: Verificar se 3 valores <strong>de</strong> <strong>com</strong>primento po<strong>de</strong>m <strong>de</strong>screver os lados <strong>de</strong> um triangulo retângulo.<br />

Dados <strong>de</strong> Entrada: Os 3 valores.<br />

Saída do Programa: Retorna 1 caso seja possível, caso contrário retorna 0.<br />

Processo <strong>com</strong>ponente " trianguloRetangulo ":<br />

SE o lado b e maior do que o lado a:<br />

Trocar os valores <strong>de</strong> a e b.<br />

FIM -SE<br />

SE o lado c e maior do que o lado a:<br />

Trocar os valores <strong>de</strong> a e c.<br />

FIM -SE


3.10.<br />

EXERCÍCIOS RESOLVIDOS 83<br />

SE a * a = b * b + c * c:<br />

Retornar o valor 1<br />

SEN~AO:<br />

Retornar o valor 0<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " trianguloRetangulo "<br />

O Exemplo 3.21 mostra a implementação <strong>de</strong>sse algoritmo.<br />

1 int trianguloRetangulo ( int a, int b, int c){<br />

2 int aux ;<br />

3<br />

4 if(b > a){<br />

5 aux = a;<br />

6 a = b;<br />

7 b = aux ;<br />

8 }<br />

9<br />

10 if(c > a){<br />

11 aux = a;<br />

12 a = c;<br />

13 c = aux ;<br />

14 }<br />

15<br />

16 if(a * a == b * b + c * c){<br />

17 return 1;<br />

18 } else {<br />

19 return 0;<br />

20 }<br />

21 }<br />

Exemplo 3.21: Programa que verifica se 3 <strong>com</strong>primentos formam um triangulo retangulo<br />

Exercício Resolvido 3.4 - Tabuada<br />

Faça um programa que dado dois números inteiros, m e n, gere uma tabuada conforme a Figura<br />

3.9, sendo que para esse exemplo os números fornecidos foram: 2 e 3.<br />

0 x 1 = 0<br />

0 x 2 = 0<br />

...<br />

0 x 22 = 0<br />

1 x 1 = 1<br />

...<br />

1 x 22 = 22<br />

2 x 1 = 2<br />

...<br />

2 x 22 = 44<br />

...<br />

37 x 22 = 814<br />

DRAFT<br />

Figura 3.9: Solução para m = 22 e n = 37.<br />

Solução Possível:<br />

Para gerar cada linha da tabuada proposta <strong>de</strong>ve-se imprimir <strong>com</strong>binações <strong>de</strong> a * b = c on<strong>de</strong> a<br />

po<strong>de</strong> assumir valores entre 0 e n e b varia entre 1 e m. Todas as linhas po<strong>de</strong>m ser geradas utilizando<br />

um <strong>com</strong>ando <strong>de</strong> repetição que incrementa o valor <strong>de</strong> a <strong>de</strong>ntro <strong>de</strong> outro <strong>com</strong>ando <strong>de</strong> repetição que<br />

incrementa o valor <strong>de</strong> b imprimindo a linha calculada e fazendo uma quebra <strong>de</strong> linha a cada iteração<br />

interna.


84<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

O Pseudocódigo 3.8 mostra um algoritmo que <strong>de</strong>screve os passos a serem realizados pela função.<br />

Pseudocódigo 3.8 Passos a serem realizados pela função.<br />

Descrição: Gera tabuada consi<strong>de</strong>rando dois multiplicadores máximos.<br />

Dados <strong>de</strong> Entrada: Os dois valores.<br />

Saída do Programa: Gera a tabuada<br />

Processo <strong>com</strong>ponente " geraLinhaTabuada ":<br />

PARA cont variando <strong>de</strong> 1 a n:<br />

Guardar o resultado da multiplicaç~ao <strong>de</strong> x por cont em uma nova variável r e<br />

exibir o resultado<br />

FIM - PARA<br />

FIM - Processo <strong>com</strong>ponente " geraLinhaTabuada "<br />

Funç~ao Principal :<br />

Coletar os valores das duas variáveis (n e m)<br />

PARA cada valor <strong>de</strong> x variando <strong>de</strong> 0 a m:<br />

Chamar processo <strong>com</strong>ponente " geraLinhaTabuada ", passando <strong>com</strong>o par^ametro n e<br />

x<br />

FIM - PARA<br />

FIM - Funç~ao Principal<br />

O Exemplo 3.22 mostra a implementação <strong>de</strong>sse algoritmo. Note que a variável a da função mult<br />

contém o valor da variável n da função main, enquanto a variável b da função mult contém o valor<br />

da variável x da função main.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 void geraLinhaTabuada ( int a, int b){<br />

4 int r, cont ;<br />

5<br />

6 for ( cont = 1; cont


3.10.<br />

EXERCÍCIOS RESOLVIDOS 85<br />

se um dado número x é primo ou não. Por <strong>de</strong>finição: “Número primo é um número natural que é<br />

divisível apenas pelo número 1 (um) e por ele mesmo, <strong>com</strong> exceção do número 1, que não é consi<strong>de</strong>rado<br />

primo”.<br />

Sabe-se também que o único número primo par é o número 2. Logo, qualquer número par que não<br />

seja o dois, não é primo.<br />

Então, o que se tem a fazer para saber se <strong>de</strong>terminado número é primo é verificar se ele não é o<br />

número 1, par (<strong>com</strong> exceção do zero e do dois), ou não tiver um divisor ímpar, então ele é primo.<br />

Após feitas as verificações se o número é 0, 1 ou 2 ou divisível por 2, para encontrar algum outro<br />

divisor do número, basta ir dividindo-o por todos os números ímpares maiores ou iguais a 3 e menores<br />

ou iguais a raiz quadrada do número em questão. Caso não encontremos divisores nesse intervalo,<br />

então não existem outros divisores além do 1 e o próprio número.<br />

O critério <strong>de</strong> parada da raiz quadrada po<strong>de</strong> ser facilmente <strong>de</strong>monstrado. Suponha um número n<br />

que não po<strong>de</strong> ser dividido por nenhum valor entre 3 e r sendo r a raiz quadrada <strong>de</strong> n. Agora suponha<br />

que existe um número m maior que r (exceto n) que é divisor <strong>de</strong> n (provaria que ele não é primo).<br />

Como m >r, m*m >r*r então m*m >n, portanto <strong>de</strong>ve existir algum valor x divisor <strong>de</strong> n menor que<br />

r capaz <strong>de</strong> satisfazer mx = n, o que ja foi <strong>de</strong>scartado pois esse x não existe. Portanto, se nenhum<br />

divisor menor ou igual a r for encontrado, a busca po<strong>de</strong> ser encerrada pois o número é primo. Vale<br />

ressaltar que a função raiz quadrada, é implementada na biblioteca math.h <strong>com</strong> o rótulo sqrt() sendo<br />

necessário importar a biblioteca para utilizá-la.<br />

O Pseudocódigo 3.9 mostra um algoritmo que <strong>de</strong>screve os passos a serem realizados pela função.<br />

O Exemplo 3.23 mostra a implementação <strong>de</strong>sse algoritmo. Note que caso o número passado seja<br />

primo, a função retornará o valor um, caso contrário retornará o valor zero.<br />

Pseudocódigo 3.9 Passos a serem realizados pela função.<br />

Descrição: Verifica se o número passado <strong>com</strong>o parâmetro é primo.<br />

Dados <strong>de</strong> Entrada: Um número inteiro positivo diferente <strong>de</strong> zero.<br />

Saída do Programa: Retorna um quando o número informado for primo e zero caso contrario<br />

Processo <strong>com</strong>ponente " ePrimo ":<br />

SE x é igual a um:<br />

Retornar o valor zero<br />

FIM -SE<br />

SE x é igual a 2:<br />

Retornar o valor um<br />

FIM -SE<br />

SE x é divisível por 2:<br />

Retornar o valor zero<br />

FIM -SE<br />

PARA i variando <strong>de</strong> 3 a raiz quadrada <strong>de</strong> x:<br />

SE x é divisível por i:<br />

Retornar o valor zero<br />

FIM -SE<br />

Incrementar o valor <strong>de</strong> i em 2 unida<strong>de</strong>s<br />

FIM - PARA<br />

Retornar o valor um<br />

FIM - Processo <strong>com</strong>ponente " ePrimo "<br />

DRAFT<br />

Funç~ao Principal :<br />

Coletar o valor da variável quant que representa o número <strong>de</strong> primos a serem<br />

apresentados<br />

Iniciar número <strong>com</strong> valor 0.<br />

PARA cont variando <strong>de</strong> zero a quant :<br />

SE cont for primo :<br />

Apresentar cont na tela


86<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

Incrementar<br />

FIM -SE<br />

FIM - PARA<br />

FIM - Funç~ao Principal<br />

cont<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> <br />

3<br />

4 int ePrimo ( int x){<br />

5 int i;<br />

6<br />

7 if(x == 1){<br />

8 return 0;<br />

10<br />

9 }<br />

11 if(x == 2){<br />

12 return 1;<br />

13 }<br />

14<br />

15 if(x % 2 == 0){<br />

16 return 0;<br />

17 }<br />

18<br />

19 for (i = 3; i


3.10.<br />

EXERCÍCIOS RESOLVIDOS 87<br />

Solução Possível: Para fazer essa função é necessário reconstruir o número <strong>de</strong> trás para frente.<br />

Para ler o último algarismo <strong>de</strong> um número guardado numa variável x basta guardamos numa variável<br />

m o resto da divisão inteira <strong>de</strong>sse número por 10. Após isso, guarda-se em x a parte inteira da divisão<br />

<strong>de</strong> x por 10, excluindo-se assim o último algarismo do número. Nesse momento a variável m possui o<br />

último algarismo original <strong>de</strong> x, enquanto esta possui agora apenas os primeiros algarismos originais,<br />

excluindo-se apenas o último.<br />

Então, multiplicando-se m por 10 e somando-se a esse resultado o resto da divisão inteira do novo<br />

valor <strong>de</strong> x por 10, teremos em m os últimos dois algarismos <strong>de</strong> x na or<strong>de</strong>m inversa.<br />

Po<strong>de</strong>-se perceber que basta fazer os passos acima repetidamente para obter em m o número x<br />

original, mas na or<strong>de</strong>m inversa. Tendo-se esse número, basta <strong>com</strong>pará-lo <strong>com</strong> o valor original, guardado<br />

anteriormente em uma outra variável.<br />

A Figura 3.10 ilustra o <strong>com</strong>portamento das variáveis x e m <strong>com</strong> o <strong>de</strong>correr das iterações para um x<br />

inicial igual a 52325. A coluna x /10 mostra a parte inteira da divisão <strong>de</strong> x por 10, enquanto a coluna<br />

x % 10 mostra o resto <strong>de</strong>ssa divisão. Percebe-se que o processo iterativo <strong>de</strong>ve acabar quando o x final<br />

for igual a zero. Note que no final <strong>de</strong>sse exemplo a variável m contém o número inicial x do processo,<br />

mostrando que 52325 é palíndromo.<br />

x x / 10 x % 10 m<br />

52325 5232 5 5<br />

5232 523 2 52<br />

523 52 3 523<br />

52 5 2 5232<br />

5 0 5 52325<br />

Figura 3.10: Solução para x = 52325.<br />

O Pseudocódigo 3.10 mostra o algoritmo que <strong>de</strong>screve os passos a serem realizados pela função.<br />

Pseudocódigo 3.10 Passos a serem realizados pela função.<br />

Descrição: Verifica se um número<br />

Dados <strong>de</strong> Entrada: Um numero inteiro.<br />

Saída do Programa: Retorna verda<strong>de</strong>iro para palíndromo e falso para não palíndromo<br />

Processo <strong>com</strong>ponente " palíndromo ":<br />

Fazer cópia do número<br />

Iniciar invertido<br />

ENQUANTO número for diferente <strong>de</strong> zero :<br />

Atualizar invertido<br />

Atualizar número<br />

FIM - ENQUANTO<br />

SE número é igual ao invertido :<br />

Retornar verda<strong>de</strong>iro<br />

SEN~AO:<br />

Retornar falso<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " palíndromo "<br />

DRAFT<br />

O Exemplo 3.24 mostra a implementação <strong>de</strong>sse algoritmo. Note que a variável c guarda o valor<br />

inicial <strong>de</strong> x e que esta variável é <strong>com</strong>parada <strong>com</strong> o valor <strong>de</strong> m ao final do processo. Aqui também<br />

usou-se a convenção <strong>de</strong> usar o valor <strong>de</strong> retorno 1 para indicar sucesso na verificação e zero caso<br />

contrário.<br />

1 int palindromo ( int x){


88<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

2 int c, m;<br />

3<br />

4 c = x;<br />

5 m = 0;<br />

6<br />

7 while (x){<br />

8 m = m * 10 + (x % 10) ;<br />

9 x = x / 10;<br />

10 }<br />

11<br />

12 if(m == c){<br />

13 return 1;<br />

14 } else {<br />

15 return 0;<br />

16 }<br />

17 }<br />

Exemplo 3.24: Programa que verifica se um número é palíndromo.<br />

Exercício Resolvido 3.7 - Máximo Divisor Comum<br />

Faça uma função que calcule o máximo divisor <strong>com</strong>um entre dois números naturais. Implemente<br />

a função na forma recursiva e na forma iterativa.<br />

Solução Possível:<br />

A solução adotada po<strong>de</strong> ser é a mesma apresentada no Exemplo 2.40 no capítulo 2.<br />

O Pseudocódigo 3.11 mostra o algoritmo que <strong>de</strong>screve os passos a serem realizados pela função<br />

iterativa.<br />

Pseudocódigo 3.11 Passos a serem realizados pela função.<br />

Descrição: Calcula o mdc <strong>de</strong> dois números <strong>de</strong> forma recursiva.<br />

Dados <strong>de</strong> Entrada: Dois números inteiros.<br />

Saída do Programa: Retorna o mdc<br />

Processo <strong>com</strong>ponente " mdcRecursivo ":<br />

SE iguais :<br />

retornar um <strong>de</strong>les<br />

SEN~AO:<br />

SE distintos :<br />

retornar o mdc entre o menor e a subtraç~ao do maior pelo menor<br />

FIM -SE<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " mdcRecursivo "<br />

DRAFT<br />

O Exemplo 3.25 mostra a implementação <strong>de</strong>sse algoritmo.<br />

1 int mdcRecursivo ( int a, int b){<br />

2 if(a == b){<br />

3 return a;<br />

4 }<br />

5<br />

6 if(a > b){<br />

7 return mdcRecursivo (a - b, a);<br />

8 } else {<br />

9 return mdcRecursivo (a, b - a);<br />

10 }<br />

11 }<br />

Exemplo 3.25: Programa que calcula o M.D.C. <strong>de</strong> dois números (modo recursivo).


3.11. RESUMO 89<br />

O Pseudocódigo 3.12 mostra o algoritmo que <strong>de</strong>screve os passos a serem realizados pela função<br />

iterativa.<br />

Pseudocódigo 3.12 Passos a serem realizados pela função.<br />

Descrição: Calcula o mdc <strong>de</strong> dois números <strong>de</strong> forma iterativa.<br />

Dados <strong>de</strong> Entrada: Dois números inteiros.<br />

Saída do Programa: Retorna o mdc<br />

Processo <strong>com</strong>ponente " mdcIterativo ":<br />

ENQUANTO numeros diferentes<br />

Retirar menor do maior<br />

FIM - ENQUANTO<br />

FIM - Processo <strong>com</strong>ponente " mdcIterativo "<br />

O Exemplo 3.26 mostra a implementação <strong>de</strong>sse algoritmo. Note que nesse caso a implementação<br />

na forma iterativa é obtida facilmente a partir da forma recursiva.<br />

1 int mdcIterativo ( int a, int b){<br />

2<br />

3 while (a != b){<br />

4 if(a > b){<br />

5 a = a - b;<br />

6 } else {<br />

7 b = b - a;<br />

8 }<br />

9 }<br />

10<br />

11 return a;<br />

12 }<br />

Exemplo 3.26: Programa que calcula o M.D.C. <strong>de</strong> dois números (modo iterativo).<br />

3.11 Resumo<br />

ˆ<br />

A modularização baseia-se na conhecida técnica <strong>de</strong> “dividir para conquistar”e po<strong>de</strong> ser <strong>de</strong>finida<br />

<strong>com</strong>o a divisão <strong>de</strong> um problema em várias partes. Cada uma <strong>de</strong>ssas partes po<strong>de</strong> ser resolvida<br />

in<strong>de</strong>pen<strong>de</strong>ntemente das outras.<br />

DRAFT<br />

ˆ As partes principais <strong>de</strong> um subprograma são: cabeçalho, dicionário <strong>de</strong> dados, corpo e <strong>com</strong>entários.<br />

ˆ<br />

ˆ<br />

Os parâmetros <strong>de</strong> um subprograma são os dados iniciais necessários para o subprograma po<strong>de</strong>r<br />

realizar o seu trabalho. O subprograma po<strong>de</strong> também não receber nenhum parâmetro para<br />

realizar suas funções. Na linguagem C, quando a função não têm parâmetros usa-se void na<br />

<strong>de</strong>claração da função, em sua lista <strong>de</strong> parâmetros.<br />

Um subprograma po<strong>de</strong>rá produzir no <strong>de</strong>correr das suas instruções um valor que será retornado,<br />

chamado <strong>de</strong> valor <strong>de</strong> retorno. Na linguagem C, quando o subprograma não produz nenhum valor<br />

<strong>de</strong> retorno usa-se void para simbolizar o tipo <strong>de</strong> dado retornado.<br />

ˆ<br />

ˆ<br />

ˆ<br />

Algumas vezes é interessante antecipar o encerramento da execução <strong>de</strong> programas.<br />

A programação recursiva é uma técnica muito utilizada na implementação <strong>de</strong> funções.<br />

Geralmente é possível criar versões recursivas e não recursivas <strong>de</strong> uma mesma função.<br />

ˆ<br />

As vantagens encontradas em um programa modularizado são:


90<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

1. Legibilida<strong>de</strong>: facilida<strong>de</strong> <strong>de</strong> leitura e entendimento do código fonte;<br />

2. Manutenibilida<strong>de</strong>: facilida<strong>de</strong> <strong>de</strong> modificar o código fonte;<br />

3. Reusabilida<strong>de</strong>: facilida<strong>de</strong> <strong>de</strong> reutilizar total ou parcialmente o código fonte;<br />

4. Confiabilida<strong>de</strong>: <strong>com</strong>o o programa é fácil <strong>de</strong> ser entendido e corrigido, torna-se mais confiável;<br />

5. Produtivida<strong>de</strong>: o programa po<strong>de</strong> ser dividido em módulos e cada módulo po<strong>de</strong> ser trabalhado<br />

por uma equipe diferente. Além disso, uma equipe só precisa saber o que <strong>de</strong>terminado<br />

módulo <strong>de</strong> outra equipe faz e não <strong>com</strong>o faz;<br />

3.12 Exercícios Propostos<br />

1. Faça uma função que receba <strong>com</strong>o entrada dois valores inteiros, a e b, e exiba a sequência <strong>de</strong><br />

números pares do intervalo (a, b), <strong>com</strong> a < b.<br />

2. Faça uma função que receba <strong>com</strong>o argumento os lados <strong>de</strong> um triângulo e calcule o seu perímetro<br />

e em seguida o valor da área.<br />

3. Consi<strong>de</strong>re o valor <strong>de</strong> π = 3.141592. Construa uma função para calcular a área <strong>de</strong> um círculo<br />

tendo <strong>com</strong>o dado <strong>de</strong> entrada, o valor do raio. Em seguida, fazer outra função para calcular o<br />

raio do círculo que possui <strong>com</strong>o área, a meta<strong>de</strong> da área calculada anteriormente.<br />

4. Faça uma função que receba <strong>com</strong>o parâmetro uma quantia em reais (valor inteiro). Calcule<br />

o número <strong>de</strong> cédulas <strong>de</strong> cada tipo (1, 2, 5, 10, 20, 50, 100), necessário para pagar a quantia<br />

(minimizando o número total <strong>de</strong> cédulas a serem entregues). Exiba apenas o número não nulo<br />

<strong>de</strong> cédulas <strong>de</strong> cada tipo.<br />

5. Faça uma função que calcule e retorne o n-ésimo termo <strong>de</strong> uma PA (progressão aritmética) sendo<br />

fornecidos <strong>com</strong>o entrada o número <strong>de</strong> termos, o primeiro termo e a razão.<br />

6. Implemente uma sequencia <strong>de</strong> Fibonacci <strong>de</strong> forma recursiva.<br />

7. Uma loja <strong>de</strong> material <strong>de</strong> construção precisa <strong>de</strong> um programa para saber a quantida<strong>de</strong> <strong>de</strong> metros<br />

quadrados (m2) que <strong>de</strong>vem ser usados para colocar piso nas casas dos clientes. É fornecido o<br />

número <strong>de</strong> cômodos, os lados dos quadriláteros <strong>de</strong> cada cômodo e o preço do piso que o cliente<br />

escolheu. Faça uma função que receba essas informações <strong>com</strong>o dados <strong>de</strong> entrada e apresente a<br />

quantida<strong>de</strong> <strong>de</strong> piso (em m2 ) e o valor da <strong>com</strong>pra. Obs.: Todos os cômodos da casa têm a forma<br />

<strong>de</strong> quadriláteros.<br />

DRAFT<br />

8. Elabore uma função em C que calcule o valor aproximado <strong>de</strong> π <strong>com</strong> precisão <strong>de</strong> cinco décimos<br />

através da série:<br />

π = 1 1 3 − 1 3 3 + 1 5 3 . . .<br />

Consi<strong>de</strong>re que a precisão <strong>de</strong> cinco décimos requer que a soma dos elementos da série só <strong>de</strong>ve ser<br />

interrompida quando o valor do termo é inferior a 0,00001. Para implementar a função, use uma<br />

subfunção que, dados x e y, calcule x y .<br />

9. a) Construa uma função encaixa que, dados dois inteiros positivos a e b, verifica se b correspon<strong>de</strong><br />

aos últimos dígitos <strong>de</strong> a.<br />

Ex.:


3.12.<br />

EXERCÍCIOS PROPOSTOS 91<br />

a b<br />

567890 890 =>encaixa<br />

1243 1243 =>encaixa<br />

2457 245 =>não encaixa<br />

457 2457 =>não encaixa<br />

b) Usando a função do item anterior, faça um programa que lê dois inteiros positivos a e b e<br />

verifica se o menor <strong>de</strong>les é segmento do outro.<br />

Exemplo:<br />

a b<br />

567890 678 => b é segmento <strong>de</strong> a<br />

1243 2212435 => a é segmento <strong>de</strong> b<br />

235 236 => um não é segmento do outro<br />

10. Faça um programa em C que leia vários números inteiros positivos e <strong>de</strong>termine quais são abundantes<br />

(a soma dos seus divisores é superior ao dobro do número), perfeitos (a soma dos seus<br />

divisores é igual ao dobro do número), <strong>de</strong>ficientes (a soma dos seus divisores é inferior ao dobro<br />

do número), levemente imperfeito (a soma dos seus divisores é igual ao dobro do número menos<br />

um) ou não se encaixam em alguma <strong>de</strong>ssas opções. O programa <strong>de</strong>ve ser encerrado quando for<br />

lido o valor zero. Você <strong>de</strong>ve usar uma função para calcular a soma dos divisores <strong>de</strong> um número.<br />

11. Elabore uma função em C que calcule o valor <strong>de</strong> o valor aproximado <strong>de</strong> π <strong>com</strong> precisão <strong>de</strong> cinco<br />

décimos através da série:<br />

π = 1/1 3 - 1/3 3 + 1/5 3 - 1/7 3 ...<br />

Consi<strong>de</strong>re que a precisão <strong>de</strong> cinco décimos requer que a soma dos elementos da série só <strong>de</strong>ve ser<br />

interrompida quando o valor do termo é inferior a 0,00001. Para implementar a função não é<br />

permitido utilizar qualquer função da biblioteca <strong>de</strong> C.<br />

12. Faça um programa em C que:<br />

a) Implemente uma função que calcule o fatorial <strong>de</strong> um número natural.<br />

b) Implemente uma função que calcule a n-ésima potência <strong>de</strong> um número x. Leve em conta<br />

que tanto x quanto n são números inteiros, isto é, po<strong>de</strong>m ser positivos, negativos ou zero. Não<br />

é permitido utilizar a função pow(x,y) da biblioteca math.h.<br />

DRAFT<br />

c) Elabore uma função que calcule o valor <strong>de</strong> e x <strong>com</strong> precisão <strong>de</strong> dois décimos através da<br />

série:<br />

e x = x 0 + x 1 /1! + x 2 /2! + x 3 /3! + ...<br />

Consi<strong>de</strong>re que a precisão <strong>de</strong> dois décimos requer que a soma dos elementos da série só <strong>de</strong>ve<br />

ser interrompida quando o valor do termo é inferior a 0,01. Não é permitido usar as funções<br />

implementadas nos ítens a e b <strong>de</strong>sta questão para calcular os termos da série.<br />

d) Elabore uma função que calcule o valor da seguinte expressão (para n > 0):<br />

n 1! + (n–1) −2! + (n–2) 3! + (n–3) −4! + ... + 1 ±n!<br />

Para fazer esta função você po<strong>de</strong> utilizar as funções implementadas nos ítens a e b <strong>de</strong>sta questão.<br />

e) Faça um programa interativo que permita ao usuário usar todas as funções <strong>de</strong>finidas nos<br />

ítens anteriores. O programa só <strong>de</strong>ve ser encerrado quando o usuário quiser.


92<br />

CAPÍTULO 3. MODULARIZAÇÃO<br />

13. Implemente em C:<br />

a) Uma função que calcule e i . Para isso, consi<strong>de</strong>re que o valor do número neperiano é 2,71828<br />

e que i é um número natural.<br />

b) Uma função que calcule e x , para 0 < x < 1. Para isso, consi<strong>de</strong>re que e x po<strong>de</strong> ser<br />

aproximada pela seguinte série:<br />

e x = x 0 + x 1 /1! + x 3 /3! + x 5 /5! + ...<br />

Consi<strong>de</strong>re ainda que o valor <strong>de</strong> e x <strong>de</strong>ve ser aproximado <strong>com</strong> precisão <strong>de</strong> cinco décimos, isto é,<br />

a soma dos elementos da série só <strong>de</strong>ve ser interrompida quando o valor do termo é inferior a<br />

0,00001. Não é permitido usar as funções <strong>de</strong> fatorial e potência para calcular os termos da série.<br />

c) Uma função que calcule e x , on<strong>de</strong> x é um valor real e maior ou igual a zero. Para tanto,<br />

use as duas funções implementadas nos ítens a e b, consi<strong>de</strong>rando que e x = e i+y = e i .e y , para i<br />

natural e 0 < y < 1.<br />

d) Uma função que calcule e x , on<strong>de</strong> x é um valor real negativo, nulo ou positivo. Para tanto,<br />

use a função do item c e consi<strong>de</strong>re que e −y = 1/e y .<br />

3.13 Trabalhos Sugeridos<br />

1. Aplicando Conhecimentos <strong>de</strong> Cálculo<br />

Um professor <strong>de</strong> Cálculo teve uma simples i<strong>de</strong>ia para facilitar seu trabalho. Percebendo que<br />

vários alunos tinham dúvidas sobre <strong>de</strong>rivadas e integrais <strong>de</strong> polinômios, resolveu pedir a um<br />

programador que implementasse um programa para aplicar sua i<strong>de</strong>ia.<br />

O projetor restringiu o programa a polinômios <strong>de</strong> até grau nove e passou as seguintes especificações<br />

ao programador:<br />

Exemplos <strong>de</strong> Dados <strong>de</strong> Entrada<br />

Uma função seria digitada da seguinte maneira: (Opção 1)<br />

+2x4+0x3-25x2+1x1-5x0=<br />

ou seja, a leitura <strong>de</strong>verá ser pelo teclado e sempre na mesma or<strong>de</strong>m: <br />

. Observação: a leitura do teclado <strong>de</strong>ve ser feita termo a termo, por<br />

exemplo, “+2x4 [enter] +0x3 [enter]”. Apenas o caractere “=” po<strong>de</strong>rá ser lido separadamente.<br />

Uma função f(x) = 2x 4 − 25x 2 + x − 5 seria digitada da seguinte maneira: (Opção 2)<br />

DRAFT<br />

+2x4-25x2+1x-5=<br />

Ou seja, a leitura <strong>de</strong>verá ser pelo teclado, porém <strong>com</strong> algumas diferenças em relação à opção<br />

anterior. Serão omitidos a potência “1”, a variável <strong>com</strong> potência “0” e os termos <strong>com</strong> coeficiente<br />

“0”. Observação: nesse caso a leitura também <strong>de</strong>ve ser feita termo a termo, porém, <strong>de</strong>ve-se<br />

lembrar que alguns termos po<strong>de</strong>m ser menores que outros (“+2x4” e “1x”, por exemplo).<br />

Em ambos os casos, a flag <strong>de</strong> final <strong>de</strong> leitura será o caractere “=” e os coeficientes serão número<br />

reais (float). A i<strong>de</strong>ia é que, se o programador optar pela segunda opção, o algoritmo <strong>de</strong>verá ser<br />

genérico ao ponto <strong>de</strong> receber as duas formas <strong>de</strong> entrada.<br />

Armazenada a função <strong>de</strong> entrada, o programa <strong>de</strong>verá apresentar, no mesmo formato <strong>de</strong> entrada,<br />

a <strong>de</strong>rivada e a integral da função. O professor ainda <strong>de</strong>seja que o programa apresente também<br />

as raízes das funções quando estas forem do primeiro ou do segundo grau.<br />

Exemplos <strong>de</strong> Saída<br />

Usando a função <strong>de</strong> entrada: f(x) = x 2 − 5x + 6


3.13. TRABALHOS SUGERIDOS 93<br />

ˆ Derivada 2.00x1-5.00x0= (Opção 1) 2.00x-5.00= (Opção 2)<br />

ˆ Integral 0.33x3-2.50x2+6.00x1+C= (Opção 1) 0.33x3-2.50x2+6.00x+C= (Opção 2)<br />

ˆ<br />

Raízes (apenas para funções <strong>de</strong> primeiro e segundo grau) x1=2.00 x2=3.00 Os coeficientes<br />

e as raízes <strong>de</strong>verão ser apresentados <strong>com</strong> 2 casas <strong>de</strong>cimais.<br />

DRAFT


Capítulo 4<br />

Tipos Abstratos <strong>de</strong> Dados<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

Introduzir o conceito <strong>de</strong> Tipos Compostos Heterogêneos;<br />

Explicar as vantagens da utilização <strong>de</strong> Tipos Abstratos <strong>de</strong> dados;<br />

Simplificar a confecção <strong>de</strong> aplicações mais <strong>com</strong>plexas.<br />

Coautores:<br />

Bruna Vello Colnago<br />

Glaice Quirino<br />

Matheus Dilem<br />

Rodrigo Lopes Batista<br />

Este capítulo busca esclarecer <strong>com</strong>o a criação e manipulação <strong>de</strong> novos tipos <strong>de</strong> dados permite<br />

facilitar o entendimento, a confecção e o reaproveitamento <strong>de</strong> código.<br />

4.1 Técnicas <strong>de</strong> Programação Top-down e Bottom-up<br />

Para escrever um programa, os programadores po<strong>de</strong>m adotar duas técnicas: a Top-down e a Bottomup.<br />

A técnica Top-down consiste em primeiramente <strong>de</strong>finir a estrutura global do programa e posteriormente<br />

<strong>de</strong>finir cada uma das partes que <strong>de</strong>talham as suas tarefas. Já a técnica Bottom-up consiste em<br />

consi<strong>de</strong>rar o programa <strong>com</strong>o um conjunto <strong>de</strong> módulos correlacionados, implementar cada um <strong>de</strong>sses<br />

módulos e <strong>de</strong>pois juntá-los por meio <strong>de</strong> uma estrutura global.<br />

Analogamente, um projetista <strong>de</strong> automóveis po<strong>de</strong> inicialmente <strong>de</strong>finir <strong>com</strong>o será o carro, velocida<strong>de</strong>,<br />

rapi<strong>de</strong>z, rotações máximas entre outros, e posteriormente confeccionar seus <strong>com</strong>ponentes (motor,<br />

rodas, freios, suspensão...), conforme a necessida<strong>de</strong>, agindo <strong>de</strong> forma Top-down. Ou confeccionar cada<br />

um dos <strong>com</strong>ponentes separadamente, garantir seu funcionamento e <strong>de</strong>pois juntá-los em um carro cujas<br />

metas sejam <strong>com</strong>patíveis <strong>com</strong> as possibilida<strong>de</strong>s dos <strong>com</strong>ponentes, agindo <strong>de</strong> forma Bottom-up.<br />

Na abordagem Bottom-up, cada módulo é implementado segundo suas funcionalida<strong>de</strong>s e objetivos,<br />

in<strong>de</strong>pen<strong>de</strong>ntemente do restante do programa, assim torna-se mais simples redigir o código do programa,<br />

facilitando o trabalho do programador. Além do mais, a separação do programa em módulos permite a<br />

realização <strong>de</strong> testes específicos, facilitando a <strong>de</strong>puração <strong>de</strong> erros. Outra importância <strong>de</strong>ssa abordagem<br />

é a facilida<strong>de</strong> <strong>de</strong> alterar partes do programa, sendo necessário alterar apenas alguns módulos sem se<br />

importar <strong>com</strong> os <strong>de</strong>mais.<br />

Por fim, o programa torna-se muito mais fácil <strong>de</strong> ser entendido, ao passo que o leitor não precisa<br />

ler todo o código do programa, bastando saber as funcionalida<strong>de</strong>s <strong>de</strong> cada módulo. A implementação<br />

dos mesmos importa somente ao programador. Assim, a abordagem Bottom-up é, em muitos casos,<br />

mais vantajosa em relação à Top-down, ao passo que é também mais intuitiva ao programador.<br />

DRAFT<br />

94


4.2. TIPOS COMPOSTOS HETEROGÊNEOS (ESTRUTURAS) 95<br />

4.2 Tipos Compostos Heterogêneos (Estruturas)<br />

As formas <strong>de</strong> representação <strong>de</strong> dados apresentadas até agora neste livro são insuficientes para que o<br />

programador possa representar em sua totalida<strong>de</strong> as possíveis coleções <strong>de</strong> dados existentes. Programadores<br />

há muito tempo reconhecem o valor <strong>de</strong> organizar itens <strong>de</strong> dados correlacionados em uma única<br />

entida<strong>de</strong> <strong>com</strong>putacional. As Estruturas são entida<strong>de</strong>s que representam tipos <strong>de</strong> dados e que permitem<br />

o agrupamento <strong>de</strong> várias variáveis <strong>de</strong> diversos tipos.<br />

Suponha um programa que faça o cadastro <strong>de</strong> estudantes <strong>de</strong> uma universida<strong>de</strong>, cada um possuindo<br />

um conjunto <strong>de</strong> atributos correlacionados, <strong>com</strong>o por exemplo: matrícula, ida<strong>de</strong>, coeficiente<br />

<strong>de</strong> rendimento e período. Utilizando as entida<strong>de</strong>s <strong>de</strong> programação já conhecidas, no cadastro <strong>de</strong> um<br />

único aluno seriam necessárias quatro variáveis para representar todos os seus atributos; para dois<br />

estudantes, seriam necessárias oito variáveis; já para diversos estudantes seria necessário um conjunto<br />

<strong>de</strong> variáveis consi<strong>de</strong>ravelmente gran<strong>de</strong>.<br />

A utilização <strong>de</strong> muitas variáveis aumenta o trabalho do programador e dificulta que outra pessoa<br />

entenda a aplicação. Para solucionar esse problema, muitas linguagens <strong>de</strong> programação, entre elas<br />

a linguagem C, possibilitam ao programador criar tipos <strong>com</strong>postos heterogêneos. Na linguagem C,<br />

os tipos <strong>com</strong>postos heterogêneos são chamados struct (estruturas). As estruturas são conjuntos <strong>de</strong><br />

dados correlacionados, que po<strong>de</strong>m ser representados em sua totalida<strong>de</strong> por uma única variável. No<br />

exemplo mencionado, cada estudante po<strong>de</strong>ria ser representado por uma única variável, <strong>de</strong>ssa forma,<br />

seria necessário adicionar apenas uma variável para cada novo estudante a ser cadastrado.<br />

Dada a impossibilida<strong>de</strong> <strong>de</strong> se antecipar todos os tipos <strong>de</strong> dados utilizados por um programa, uma<br />

linguagem <strong>de</strong> programação apenas implementa tipos <strong>de</strong> dados simples. Desse modo, fica a cargo do<br />

programador usar <strong>de</strong>sses dados para a <strong>de</strong>finição <strong>de</strong> novos tipos <strong>de</strong> dados.<br />

Além <strong>de</strong> facilitar e tornar mais clara a implementação, os tipos <strong>com</strong>postos heterogêneos têm <strong>com</strong>o<br />

finalida<strong>de</strong>s principais a possibilida<strong>de</strong> <strong>de</strong> retorno <strong>de</strong> mais <strong>de</strong> um valor por função e a criação <strong>de</strong> tipos<br />

abstratos <strong>de</strong> dados. Essas características serão discutidas mais adiante neste capítulo.<br />

4.2.1 Definição<br />

Uma estrutura é uma coleção <strong>de</strong> variáveis, que po<strong>de</strong>m ou não ser <strong>de</strong> tipos diferentes, colocadas sob<br />

um único nome para manipulá-las. As estruturas ajudam na organização do código e facilitam a vida<br />

do programador, pois juntam variáveis relacionadas e permitem que elas sejam tratadas <strong>com</strong>o uma<br />

unida<strong>de</strong> maior.<br />

Na prática, uma estrutura é uma “caixa” on<strong>de</strong> po<strong>de</strong>m ser agrupados diversos dados correlacionados.<br />

Essa caixa, na verda<strong>de</strong>, é o conjunto <strong>de</strong> alguns bytes <strong>de</strong> memória correspon<strong>de</strong>nte ao somatório dos<br />

tamanhos dos dados que se preten<strong>de</strong> agrupar.<br />

A Figura 4.1 ilustra uma estrutura que representa um estudante, tEstudante. Note que a estrutura<br />

tEstudante ocupa um espaço equivalente ao espaço necessário para guardar todos os seus atributos.<br />

DRAFT<br />

Figura 4.1: Estrutura tEstudante.<br />

Sintaxe<br />

Para criar uma estrutura <strong>com</strong> n atributos, <strong>de</strong>ve-se obe<strong>de</strong>cer à sintaxe exposta abaixo.


96<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

struct {<br />

;<br />

;<br />

...<br />

;<br />

};<br />

A palavra struct indica que a entida<strong>de</strong> criada é uma estrutura e as chaves <strong>de</strong>limitam o trecho<br />

on<strong>de</strong> os atributos da estrutura são <strong>de</strong>finidos. Cada atributo é <strong>de</strong>finido por seu tipo seguido <strong>de</strong> um<br />

i<strong>de</strong>ntificador.<br />

O Exemplo 4.1 apresenta a sintaxe <strong>de</strong> uma estrutura para o caso do estudante.<br />

1 struct tEstudante {<br />

2 int ida<strong>de</strong> ;<br />

3 int matricula ;<br />

4 float coeficiente ;<br />

5 int periodo ;<br />

6 };<br />

4.2.2 Uso<br />

Exemplo 4.1: Sintaxe da estrutura tEstudante.<br />

Como as estruturas são conjuntos <strong>de</strong> dados, existem duas formas básicas <strong>de</strong> manipulá-las, selecionando<br />

um único elemento <strong>de</strong> dado (modo seletivo), ou manipulando toda a estrutura (modo integral).<br />

Seletivo<br />

Para manipular cada um dos atributos da estrutura se utiliza o mecanismo <strong>de</strong> seleção conforme a<br />

sintaxe apresentada a seguir.<br />

.<br />

O Exemplo 4.2 ilustra o uso seletivo da estrutura tEstudante. Nesse Exemplo, a leitura <strong>de</strong> dados<br />

é feita atribuindo-se cada valor lido a um atributo da estrutura.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 struct tEstudante {<br />

4 int ida<strong>de</strong> ;<br />

5 int matricula ;<br />

6 float coeficiente ;<br />

7 int periodo ;<br />

8 };<br />

9<br />

10 int main (){<br />

11 struct tEstudante aluno ;<br />

12<br />

DRAFT<br />

13 printf (" Digite os dados do estudante \n");<br />

14 scanf ("%d %d %f %d", & aluno . ida<strong>de</strong> , & aluno . matricula , & aluno . coeficiente , & aluno<br />

. periodo );<br />

15<br />

16 return 0;<br />

17 }<br />

Exemplo 4.2: Acesso seletivo a atributos da estrutura tEstudante.<br />

No Exemplo 4.2, primeiramente é feita a <strong>de</strong>finição da estrutura tEstudante antes da função main<br />

(linhas 3 a 8) e em seguida, <strong>de</strong>ntro da função main, é feita a criação da variável aluno (linha 11),<br />

do tipo tEstudante. Na função scanf é feito, então, o acesso seletivo aos atributos da variável aluno<br />

(linha 14).


4.2. TIPOS COMPOSTOS HETEROGÊNEOS (ESTRUTURAS) 97<br />

Integral<br />

Quando se <strong>de</strong>seja manipular a estrutura <strong>com</strong>o um todo, se utiliza simplesmente o nome da variável<br />

on<strong>de</strong> a mesma está armazenada. O uso integral em atribuições é <strong>de</strong>scrito pela sintaxe a seguir.<br />

= ;<br />

O Exemplo 4.3 ilustra o uso integral da estrutura tEstudante.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 struct tEstudante {<br />

4 int ida<strong>de</strong> , matricula , periodo ;<br />

5 float coeficiente ;<br />

6 };<br />

7<br />

10<br />

8 int main (){<br />

9 struct tEstudante aluno , outro ;<br />

11 printf (" Digite os dados do estudante \n");<br />

12 scanf ("%d %d %f %d", & aluno . ida<strong>de</strong> , & aluno . matricula , & aluno . coeficiente , & aluno<br />

. periodo );<br />

13<br />

14 outro = aluno ;<br />

15<br />

16 return 0;<br />

17 }<br />

Exemplo 4.3: Acesso integral à estrutura.<br />

No Exemplo 4.3, os atributos ida<strong>de</strong>, matricula e periodo da estrutura tEstudante foram <strong>de</strong>clarados<br />

na mesma linha (linha 5) por serem do mesmo tipo, tipo int. Do mesmo modo, na função main, as<br />

variáveis aluno e outro foram <strong>de</strong>claradas na mesma linha (linha 10) por serem do mesmo tipo, tipo<br />

tEstudante. No final da função main é feita uma cópia dos valores dos atributos da variável aluno<br />

para a variável outro. Com isso, ao final da execução do programa, os valores dos atributos <strong>de</strong> outro<br />

são iguais aos valores dos atributos <strong>de</strong> aluno.<br />

4.2.3 O Comando Type<strong>de</strong>f<br />

DRAFT<br />

A forma <strong>de</strong> <strong>de</strong>finição <strong>de</strong> uma estrutura apresentada até agora neste livro é inconveniente, pois requer a<br />

repetição da palavra struct sempre que ela for utilizada. O <strong>com</strong>ando type<strong>de</strong>f po<strong>de</strong> ser utilizado para<br />

resolver este problema, renomeando tanto tipos simples <strong>com</strong>o <strong>com</strong>postos. Para utilizar o <strong>com</strong>ando<br />

type<strong>de</strong>f, <strong>de</strong>ve-se obe<strong>de</strong>cer à sintaxe exposta abaixo.<br />

type<strong>de</strong>f ;<br />

Na prática, a renomeação <strong>de</strong> tipos facilita o entendimento e a escrita <strong>de</strong> código.<br />

O Exemplo 4.4 apresenta a utilização do type<strong>de</strong>f.<br />

1 type<strong>de</strong>f struct tEstudante tEstudante ;<br />

2<br />

3 type<strong>de</strong>f float distancia ;<br />

Exemplo 4.4: Uso do <strong>com</strong>ando type<strong>de</strong>f.<br />

O Exemplo 4.5 apresenta a adaptação do Exemplo 4.3 para a utilização do <strong>com</strong>ando type<strong>de</strong>f,<br />

permitindo que o tipo <strong>com</strong>posto heterogêneo struct tEstudante seja utilizado através da palavra<br />

tEstudante.


98<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 struct tEstudante {<br />

4 int ida<strong>de</strong> ;<br />

5 int matricula ;<br />

6 float coeficiente ;<br />

7 int periodo ;<br />

8 };<br />

9<br />

10 type<strong>de</strong>f struct tEstudante tEstudante ;<br />

11<br />

12 int main (){<br />

13 tEstudante aluno , outro ;<br />

14<br />

15 printf (" Digite os dados do estudante \n");<br />

16 scanf ("%d %d %f %d" ,& aluno . ida<strong>de</strong> ,& aluno . matricula ,& aluno . coeficiente ,& aluno .<br />

periodo );<br />

17<br />

18 outro = aluno ;<br />

19<br />

20 return 0;<br />

21 }<br />

Exemplo 4.5: Uso <strong>de</strong> uma estrutura renomeada <strong>com</strong> o <strong>com</strong>ando type<strong>de</strong>f.<br />

4.2.4 Simplificação na Passagem <strong>de</strong> Parâmetros e Retorno <strong>de</strong> Função<br />

Conforme <strong>com</strong>entou-se anteriormente, as estruturas são conjuntos <strong>de</strong> dados inter-relacionados, <strong>de</strong>ssa<br />

forma a passagem <strong>de</strong> parâmetros <strong>de</strong> função é simplificada, pois ao invés <strong>de</strong> cada um dos atributos ser<br />

um parâmetro da função, apenas a estrutura é passada. Note a diferença entre a lista <strong>de</strong> parâmetros<br />

das duas funções representadas no Exemplo 4.6.<br />

1 void funcao1 ( int ida<strong>de</strong> , int matricula , float coeficiente , int periodo ){ ... }<br />

2<br />

3 void funcao2 ( tEstudante aluno ){ ... }<br />

Exemplo 4.6: Passagem <strong>de</strong> estrutura por parâmetro.<br />

DRAFT<br />

A mesma função po<strong>de</strong> ser escrita dos dois modos apresentados no Exemplo 4.6. Na funcao1 ,<br />

quatro variáveis relacionadas ao estudante são passadas <strong>com</strong>o parâmetro. Na funcao2 , o próprio<br />

estudante é passado <strong>com</strong>o parâmetro. A funcao2 é mais <strong>com</strong>preensível que a funcao1 , pois a pessoa<br />

que ler o código da funcao1 terá que inferir que aquelas quatro variáveis referem-se a um mesmo<br />

estudante.<br />

Da mesma forma, o retorno <strong>de</strong> funções po<strong>de</strong> ser simplificado pelo uso <strong>de</strong> estruturas. Suponha que<br />

se <strong>de</strong>seja criar uma função para fazer a leitura <strong>de</strong> dados <strong>de</strong> um estudante. O Exemplo 4.7 mostra<br />

duas maneiras <strong>de</strong> fazer isso: utilizando funções que retornam estruturas ou funções que retornam tipos<br />

simples. Além disso, observa-se uma nova forma <strong>de</strong> <strong>de</strong>clarar estruturas no mesmo Exemplo 4.7: o<br />

type<strong>de</strong>f renomeia a própria estrutura no momento <strong>de</strong> sua <strong>de</strong>claração, ao invés <strong>de</strong> se renomear após a<br />

<strong>de</strong>claração.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 type<strong>de</strong>f struct {<br />

4 int ida<strong>de</strong> ;<br />

5 int matricula ;<br />

6 float coeficiente ;<br />

7 int periodo ;<br />

8 } tEstudante ;<br />

9<br />

10 int leituraPeriodo (){


4.2. TIPOS COMPOSTOS HETEROGÊNEOS (ESTRUTURAS) 99<br />

11 int periodo ;<br />

12<br />

13 scanf ("%d", & periodo );<br />

14<br />

15 return periodo ;<br />

16 }<br />

17<br />

18 int leituraMatricula (){<br />

19 int matricula ;<br />

20<br />

21 scanf ("%d", & matricula );<br />

22<br />

23 return matricula ;<br />

24 }<br />

25<br />

26 float leituraCoeficiente (){<br />

27 float coeficiente ;<br />

28<br />

29 scanf ("%f", & coeficiente );<br />

30<br />

31 return coeficiente ;<br />

32 }<br />

33<br />

34 int leituraIda<strong>de</strong> (){<br />

35 int ida<strong>de</strong> ;<br />

36<br />

37 scanf ("%d", & ida<strong>de</strong> );<br />

38<br />

39 return ida<strong>de</strong> ;<br />

40 }<br />

41<br />

42 tEstudante leituraEstudante (){<br />

43 tEstudante aluno ;<br />

44<br />

45 scanf ("%d %d %f %d", & aluno . ida<strong>de</strong> , & aluno . matricula , & aluno . coeficiente , & aluno<br />

. periodo );<br />

46<br />

47 return aluno ;<br />

48 }<br />

49<br />

50 int main (){<br />

51 tEstudante aluno1 , aluno2 ;<br />

52<br />

53 aluno1 . periodo = leituraPeriodo ();<br />

54 aluno1 . matricula = leituraMatricula ();<br />

55 aluno1 . coeficiente = leituraCoeficiente ();<br />

56 aluno1 . ida<strong>de</strong> = leituraIda<strong>de</strong> ();<br />

57 aluno2 = leituraEstudante ();<br />

58<br />

59 return 0;<br />

60 }<br />

DRAFT<br />

Exemplo 4.7: Estrutura <strong>com</strong>o retorno <strong>de</strong> função.<br />

No Exemplo 4.7 é realizada a leitura <strong>de</strong> dados <strong>de</strong> aluno1 sem utilizar o retorno <strong>de</strong> estruturas, e <strong>de</strong><br />

aluno2, utilizando-o. Para realizar a leitura <strong>de</strong> aluno1 foram necessárias a criação <strong>de</strong> quatro funções<br />

diferentes, uma para cada atributo, e quatro chamadas a estas funções na sub-rotina principal, main.<br />

Para realizar a leitura <strong>de</strong> aluno2 foram necessárias a criação <strong>de</strong> apenas uma função e uma chamada<br />

a esta função função na main. Assim, po<strong>de</strong>-se perceber que o retorno <strong>de</strong> estruturas torna o código<br />

mais coeso, <strong>com</strong>pacto, legível e eficiente, por ter menos chamadas <strong>de</strong> função.


100<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

4.3 Tipos Abstratos <strong>de</strong> Dados<br />

Tipos abstratos <strong>de</strong> dados (TADs) são novos tipos <strong>de</strong> dados implementados pelo programador, nos<br />

quais ele <strong>de</strong>fine tanto as estruturas <strong>de</strong> dados quanto as operações a elas aplicáveis, conforme suas<br />

necessida<strong>de</strong>s para a resolução <strong>de</strong> um <strong>de</strong>terminado problema.<br />

Os TADs po<strong>de</strong>m ser consi<strong>de</strong>rados generalizações <strong>de</strong> tipos primitivos <strong>de</strong> dados, assim <strong>com</strong>o funções<br />

são generalizações <strong>de</strong> operações primitivas, tais <strong>com</strong>o adição, subtração e multiplicação. Da mesma<br />

forma que funções po<strong>de</strong>m ser usadas para encapsular partes <strong>de</strong> algoritmos, o TAD po<strong>de</strong> ser usado<br />

para encapsular tipos <strong>de</strong> dados.<br />

O TAD po<strong>de</strong> ser discutido pela perspectiva do implementador e do usuário do tipo. O implementador<br />

cria as estruturas <strong>de</strong> dados e implementa as funções para manipulá-las. Já o usuário utiliza<br />

esse TAD <strong>com</strong>o se fosse um tipo <strong>de</strong> dados fornecido pela linguagem <strong>de</strong> programação. Deste modo, o<br />

usuário só <strong>de</strong>ve manipular os atributos do TAD através das funções <strong>de</strong>finidas pelo implementador do<br />

tipo.<br />

4.3.1 Definição<br />

Um tipo abstrato <strong>de</strong> dados é um tipo <strong>de</strong> dado <strong>de</strong>finido em termos do seu <strong>com</strong>portamento e não em<br />

termos <strong>de</strong> sua representação. A i<strong>de</strong>ia <strong>de</strong> tipo abstrato <strong>de</strong> dados é <strong>de</strong>svincular o tipo <strong>de</strong> dado (valores<br />

e operações) <strong>de</strong> sua implementação, ou seja, quando <strong>de</strong>finimos um tipo abstrato <strong>de</strong> dados estamos<br />

preocupados <strong>com</strong> o que ele faz e não <strong>com</strong>o ele faz.<br />

Os programas que usam um <strong>de</strong>terminado tipo abstrato <strong>de</strong> dados são chamados clientes; e o programa<br />

que <strong>de</strong>fine sua estrutura e <strong>com</strong>portamento é conhecido <strong>com</strong>o implementação. Um TAD po<strong>de</strong><br />

ser <strong>de</strong>finido <strong>com</strong>o a <strong>com</strong>posição <strong>de</strong> uma estrutura <strong>de</strong> dados e das operações <strong>de</strong>finidas sobre estes dados.<br />

Exemplo da Definição <strong>de</strong> um Tipo Composto <strong>com</strong> Operações Pré-<strong>de</strong>finidas<br />

Suponha que se <strong>de</strong>seja <strong>de</strong>finir um tipo abstrato <strong>de</strong> dados tData, consi<strong>de</strong>rando os atributos dia, mês<br />

e ano. Primeiramente, <strong>de</strong>ve-se <strong>de</strong>cidir as operações a serem <strong>de</strong>finidas para o TAD, que po<strong>de</strong>m ser as<br />

seguintes:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

inicializacaoData: função que inicializa uma data a partir <strong>de</strong> valores passados <strong>com</strong>o parâmetro.<br />

leituraData: função que inicializa uma data a partir <strong>de</strong> valores lidos do teclado.<br />

DRAFT<br />

alteracaoData: função que altera uma data a partir <strong>de</strong> valores passados <strong>com</strong>o parâmetro.<br />

serBissexto: função que indica se um ano é bissexto ou não.<br />

diasNoMes: função que indica a quantida<strong>de</strong> <strong>de</strong> dias do mês em questão.<br />

diaSeguinte: função que altera a data para o dia seguinte.<br />

Po<strong>de</strong>-se então implementar o TAD na linguagem <strong>de</strong>sejada. No Exemplo 4.8, observa-se a implementação<br />

do TAD tData na linguagem C.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 type<strong>de</strong>f struct data {<br />

4 int dia ;<br />

5 int mes ;<br />

6 int ano ;<br />

7 } tData ;<br />

8<br />

9 tData inicializacaoData ( int d, int m, int a){<br />

10 tData dt;<br />

11<br />

12 dt.dia = d;<br />

13 dt.mes = m;


4.3. TIPOS ABSTRATOS DE DADOS 101<br />

14 dt.ano = a;<br />

15<br />

16 return dt;<br />

17 }<br />

18<br />

19 tData leituraData (){<br />

20 tData d;<br />

21<br />

22 printf (" Entre <strong>com</strong> a data \n");<br />

23 scanf ("%d %d %d", &d.dia , &d.mes , &d. ano );<br />

24<br />

25 return d;<br />

26 }<br />

27<br />

28 tData alteracaoData ( int d, int m, int a){<br />

29 tData dt;<br />

30<br />

31 dt.dia = d;<br />

32 dt.mes = m;<br />

33 dt.ano = a;<br />

34<br />

35 return dt;<br />

36 }<br />

37<br />

38 int serBissexto ( tData d){<br />

39 if(d. ano %400 == 0){<br />

40 return 1;<br />

41 }<br />

42<br />

43 if(d. ano %100 == 0){<br />

44 return 0;<br />

45 }<br />

46<br />

47 if(d. ano %4 == 0){<br />

48 return 1;<br />

49 } else {<br />

50 return 0;<br />

51 }<br />

52 }<br />

53<br />

54 int diasNoMes ( tData d){<br />

DRAFT<br />

55 if(d. mes == 4 || d. mes == 6 || d. mes == 9 || d. mes == 11) {<br />

56 return 30;<br />

57 } else {<br />

58 if (d. mes == 2){<br />

59 if( serBissexto (d)){<br />

60 return 29;<br />

61 } else {<br />

62 return 28;<br />

63 }<br />

64 } else {<br />

65 return 31;<br />

66 }<br />

67 }<br />

68 }<br />

69<br />

70 tData diaSeguinte ( tData d){<br />

71 if(d. dia < diasNoMes (d)){<br />

72 d. dia ++;<br />

73 } else {<br />

74 d. dia = 1;<br />

75 if(d. mes < 12) {<br />

76 d. mes ++;<br />

77 } else {<br />

78 d. mes = 1;<br />

79 d. ano ++;


102<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

80 }<br />

81 }<br />

82<br />

83 return d;<br />

84 }<br />

Exemplo 4.8: Definição do TAD tData.<br />

O código do Exemplo 4.8 ilustra a <strong>de</strong>finição <strong>de</strong> um Tipo Composto <strong>com</strong> Operações Pré-<strong>de</strong>finidas. O<br />

tipo tData contém os atributos <strong>de</strong> uma data. Uma variável <strong>de</strong>sse tipo é inicializada através da função<br />

inicializacaoData e essa função permite a inicialização dos atributos sem que estes sejam acessados<br />

pelo usuário, ou seja, o acesso aos atributos ocorre no padrão estipulado <strong>de</strong> <strong>de</strong>ntro da função, não<br />

permitindo, assim, que o usuário inicialize os atributos acessando-os erroneamente. A função <strong>de</strong> leitura<br />

leituraData obtém uma data do teclado e retorna uma variável do tipo tData contendo os valores<br />

lidos. A função alteracaoData apresenta o mesmo código que a função <strong>de</strong> inicialização, contudo sua<br />

utilização <strong>de</strong>stina-se a datas já inicializadas. A função serBissexto verifica se uma dada data está<br />

em um ano bissexto, o algoritmo consi<strong>de</strong>ra a seguinte regra: São bissextos todos os anos múltiplos<br />

<strong>de</strong> 400, não são bissextos todos os múltiplos <strong>de</strong> 100 e não <strong>de</strong> 400, são bissextos todos os múltiplos <strong>de</strong><br />

4 e não múltiplos <strong>de</strong> 100, por fim, não são bissextos todos os <strong>de</strong>mais anos. A função diasNoMes<br />

<strong>de</strong>termina o número <strong>de</strong> dias do mês <strong>de</strong> uma <strong>de</strong>terminada data. Os meses <strong>de</strong> abril, junho, setembro e<br />

novembro possuem 30 dias. Caso a data seja do mês <strong>de</strong> fevereiro, verifica-se se o ano é bissexto, se for<br />

bissexto o mês tem 29 dias, se não for bissexto o mês tem 28 dias. Caso a data não esteja em nenhum<br />

dos meses citados, o mês tem 31 dias.<br />

Importância <strong>de</strong> Definir Tipos <strong>com</strong> Operações Próprias<br />

A criação <strong>de</strong> um conjunto <strong>de</strong> operações próprias <strong>de</strong> um TAD tem <strong>com</strong>o finalida<strong>de</strong> torná-lo, aos olhos<br />

do usuário, um tipo <strong>de</strong> dados da própria linguagem, ou seja, o usuário não <strong>de</strong>ve se preocupar em<br />

<strong>com</strong>o são implementados os TADs. Além do mais, utilizar as operações do TAD torna o código mais<br />

confiável. Suponha uma aplicação que utilize o TAD tData conforme o Exemplo 4.9.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 // A <strong>de</strong>finicao do TAD , bem <strong>com</strong>o suas operacoes , estao no Exemplo 4.6<br />

4<br />

5 int main (){<br />

6 tData d;<br />

7<br />

8 d = leituraData ();<br />

9<br />

10 printf (" Passou um dia !\n");<br />

11<br />

12 d. dia ++;<br />

13<br />

DRAFT<br />

14 printf (" Hoje e %d/%d/%d.\n", d.dia , d.mes , d. ano );<br />

15<br />

16 return 0;<br />

17 }<br />

Exemplo 4.9: Problema <strong>de</strong> Confiabilida<strong>de</strong> no uso do TAD tData.<br />

Observe que, no Exemplo 4.9, a intenção do programador foi adicionar um dia à data lida, entretanto,<br />

ele não utilizou a função do tipo diaSeguinte. Para gran<strong>de</strong> parte dos valores <strong>de</strong> data, o<br />

programa funcionaria corretamente, entretanto, para datas que são o último dia do mês, esse programa<br />

gera inconsistência, pois a data obtida não será uma data válida. No <strong>de</strong>correr da aplicação,<br />

um valor inválido <strong>de</strong> data será repassado para outras partes do programa, acarretando problemas no<br />

código. Sendo assim, é altamente re<strong>com</strong>endável que se utilizem apenas as operações já <strong>de</strong>finidas para<br />

manipular as estruturas do TAD e que não ocorra a manipulação direta <strong>de</strong> atributos.


4.3. TIPOS ABSTRATOS DE DADOS 103<br />

Vantagens <strong>de</strong> Usar TADs<br />

As vantagens <strong>de</strong> utilizar um TAD são:<br />

ˆ<br />

Facilida<strong>de</strong> <strong>de</strong> Manutenção: po<strong>de</strong>-se alterar o tipo usado sem alterar a aplicação. Por exemplo,<br />

po<strong>de</strong>-se incluir novos atributos ou operações sem que o código que utilize o tipo seja alterado.<br />

ˆ<br />

Reutilização: um TAD bem generalizado po<strong>de</strong> ser utilizado em diversas aplicações.<br />

ˆ<br />

Abstração: a abstração <strong>de</strong> informações através do TAD permite a melhor <strong>com</strong>preensão dos<br />

algoritmos e maior facilida<strong>de</strong> <strong>de</strong> programação.<br />

ˆ<br />

Ocultamento: separa o código <strong>de</strong> implementação do código <strong>de</strong> uso do TAD, que funciona <strong>com</strong>o<br />

um tipo <strong>de</strong> dados fornecido pela linguagem.<br />

ˆ Integrida<strong>de</strong>: a manipulação dos atributos por operações <strong>de</strong>finidas sobre o tipo impe<strong>de</strong>m a<br />

ocorrência <strong>de</strong> inconsistências.<br />

Na prática, essas vantagens tornam o código mais fácil <strong>de</strong> se escrever, mais <strong>com</strong>preensível para<br />

quem lê e mais fácil <strong>de</strong> se modificar.<br />

4.3.2 Definição <strong>de</strong> Atributos <strong>de</strong> um TAD<br />

Os atributos <strong>de</strong> um TAD são os dados que se relacionam a ele. Por exemplo, no caso do estudante,<br />

seus atributos são: ida<strong>de</strong>, matrícula, coeficiente <strong>de</strong> rendimento e período. Conforme <strong>de</strong>finido na Seção<br />

4.2.1.<br />

4.3.3 Definição <strong>de</strong> Operações <strong>de</strong> um TAD<br />

As operações <strong>de</strong> um TAD são funções utilizadas para acesso aos dados. Estas operações visam impedir<br />

o acesso direto aos dados, assim, o usuário só <strong>de</strong>ve acessar os dados através <strong>de</strong>ssas operações.<br />

Tipos <strong>de</strong> Operações <strong>de</strong> um TAD<br />

Um TAD não é <strong>de</strong>finido por seus atributos, mas sim por suas operações. As operações são a interface do<br />

programador usuário <strong>com</strong> a própria representação interna. Existem cinco tipos diferentes <strong>de</strong> operações<br />

que po<strong>de</strong>m ser realizadas sobre um TAD:<br />

Construtoras<br />

DRAFT<br />

Operações construtoras são aquelas que inicializam variáveis, logo <strong>de</strong>vem ser utilizadas antes <strong>de</strong> qualquer<br />

outra para garantir que o TAD foi inicializado corretamente. Observe no Exemplo 4.10 diferentes<br />

implementações <strong>de</strong> funções construtoras para o TAD estudante.<br />

1 tEstudante inicializacao (){<br />

2 tEstudante novo ;<br />

3<br />

4 novo . ida<strong>de</strong> = 0;<br />

5 novo . matricula = 0;<br />

6 novo . coeficiente = 0;<br />

7 novo . periodo = 0;<br />

8<br />

9 return novo ;<br />

10 }<br />

11<br />

12 tEstudante inicializacaoValores ( int ida<strong>de</strong> , int matricula , float coeficiente , int<br />

periodo ){<br />

13 tEstudante novo ;<br />

14<br />

15 novo . ida<strong>de</strong> = ida<strong>de</strong> ;<br />

16 novo . matricula = matricula ;


104<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

17 novo . coeficiente = coeficiente ;<br />

18 novo . periodo = periodo ;<br />

19<br />

20 return novo ;<br />

21 }<br />

Exemplo 4.10: Diferentes formas <strong>de</strong> Implementação da função construtora para o TAD tEstudante.<br />

A função inicializacao inicia <strong>com</strong> zero todos os atributos <strong>de</strong> uma variável do tipo tEstudante,<br />

esta variável é retornada pela função <strong>de</strong> inicialização. A função inicializacaoValores exerce o mesmo<br />

papel <strong>de</strong> inicializar que a função inicializacao. Contudo, esta recebe os valores a serem inicializados<br />

<strong>com</strong>o parâmetros.<br />

Analisadoras<br />

As operações analisadoras ou consultoras analisam o conteúdo <strong>de</strong> um TAD e retornam proprieda<strong>de</strong>s,<br />

ou seja, essas operações obtêm informações do TAD. O Exemplo 4.11 mostra uma função analisadora.<br />

1 int bomAluno ( tEstudante aluno ){<br />

2 if( aluno . coeficiente > 7.0) {<br />

3 return 1;<br />

4 } else {<br />

5 return 0;<br />

6 }<br />

7 }<br />

Exemplo 4.11: Função analisadora.<br />

Observa-se, no Exemplo 4.11, que a função bomAluno é um exemplo <strong>de</strong> função analisadora para<br />

o TAD tEstudante, pois retorna uma proprieda<strong>de</strong> do mesmo (se é um bom aluno).<br />

Modificadoras<br />

As operações modificadoras, ou atualizadoras, permitem alterações <strong>de</strong> atributos do TAD. O Exemplo<br />

4.12 mostra uma função modificadora para o TAD tEstudante.<br />

DRAFT<br />

1 tEstudante alteracaoIda<strong>de</strong> ( tEstudante aluno , int novaIda<strong>de</strong> ){<br />

2 aluno . ida<strong>de</strong> = novaIda<strong>de</strong> ;<br />

3<br />

4 return aluno ;<br />

5 }<br />

Produtoras<br />

Exemplo 4.12: Função modificadora.<br />

As operações produtoras são aquelas que, a partir dos dados <strong>de</strong> um TAD, produzem uma nova informação.<br />

A função calculoPeriodosRestantes, do Exemplo 4.13, produz um resultado (os períodos<br />

restantes) a partir dos dados <strong>de</strong> um estudante.<br />

1 int calculoPeriodosRestantes ( tEstudante estudante ){<br />

2 int periodosTotais , periodosRestantes ;<br />

3<br />

4 printf (" Entre <strong>com</strong> a quantida<strong>de</strong> <strong>de</strong> periodos do curso do estudante <strong>de</strong> matricula %<br />

d:", estudante . matricula );<br />

5 scanf ("%d", & periodosTotais );<br />

6<br />

7 periodosRestantes = periodosTotais - estudante . periodo ;<br />

8<br />

9 return periodosRestantes ;


4.3. TIPOS ABSTRATOS DE DADOS 105<br />

10 }<br />

Exemplo 4.13: Exemplo <strong>de</strong> função produtora.<br />

Destrutoras<br />

As operações <strong>de</strong>strutoras são utilizadas para realizar algum tipo <strong>de</strong> finalização quando o valor do TAD<br />

não é mais necessário. Por exemplo, no caso do estudante, po<strong>de</strong>ria ser uma função que solicitasse que<br />

o aluno fosse removido do quadro <strong>de</strong> estudantes da instituição.<br />

4.3.4 Uso do TAD<br />

Consi<strong>de</strong>re o Exemplo 4.21 que faz uso do TAD tData.<br />

operações pré-<strong>de</strong>finidas.<br />

1 # inclu<strong>de</strong> <br />

2<br />

Note que o TAD é acessado apenas pelas<br />

3 // A <strong>de</strong>finicao do TAD , bem <strong>com</strong>o suas operacoes , estao no Exemplo 4.8<br />

4<br />

5 int main (){<br />

6 tData data ;<br />

7 int anoBissexto ;<br />

8 int nDias ;<br />

9<br />

10 data = leituraData ();<br />

11 anoBissexto = serBissexto ( data );<br />

12<br />

13 if( anoBissexto ){<br />

14 printf (" Ano Bissexto .\n");<br />

15 } else {<br />

16 printf (" Ano nao Bissexto .\n");<br />

17 }<br />

18<br />

19 nDias = diasNoMes ( data );<br />

20 printf (" Numero <strong>de</strong> dias no mes : %d\n", nDias );<br />

21<br />

22 return 0;<br />

23 }<br />

Exemplo 4.14: Uso do TAD tData.<br />

O Exemplo 4.21 <strong>de</strong>termina se uma data digitada pelo teclado é <strong>de</strong> um ano bissexto e o número<br />

<strong>de</strong> dias no mês da data digitada. Po<strong>de</strong>-se afirmar que o programa usuário manipula o TAD somente<br />

através das operações pre<strong>de</strong>finidas pelo implementador, assim o código usuário fica mais legível. Po<strong>de</strong>se<br />

observar que as operações separam o código usuário do código <strong>de</strong> implementação do TAD. A<br />

redigibilida<strong>de</strong> também aumenta, visto que o acesso aos dados é realizado apenas por simples operações.<br />

O código também fica mais confiável, pois o usuário não altera livremente os dados, isso só po<strong>de</strong> ser<br />

feito através das operações do TAD. E, por fim, caso a implementação do TAD precise ser alterada, o<br />

código usuário não sofrerá mudanças, a menos que os cabeçalhos das funções sejam alterados.<br />

4.3.5 Tipos <strong>de</strong> TADs<br />

DRAFT<br />

Os TADs po<strong>de</strong>m se dividir em TADs <strong>de</strong> Domínio e TADs Implementacionais, conforme sua relação<br />

<strong>com</strong> o problema ou <strong>com</strong> sua solução.<br />

TADs <strong>de</strong> Domínio<br />

São aqueles que <strong>de</strong>finem um tipo <strong>de</strong> dados que está no domínio do problema. Como por exemplo, os<br />

TADs tEstudante e tData.


106<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

TADs Implementacionais<br />

São objetos <strong>de</strong> programação que não tem relação direta <strong>com</strong> o problema, mas sim <strong>com</strong> sua implementação.<br />

Nos próximos capítulos, serão apresentados alguns tipos <strong>de</strong> TADs implementacionais.<br />

4.4 Exercícios Resolvidos<br />

Exercício Resolvido 4.1 - Operações sobre a estrutura tData<br />

Faça um programa <strong>com</strong> a estrutura do tipo data que realize operações (sobre este tipo) <strong>de</strong> edição<br />

e consulta.<br />

Solução Possível:<br />

Este programa utiliza operações <strong>de</strong> alteração e apresentação sobre o TAD para datas. A estrutura<br />

para datas é <strong>de</strong>clarada <strong>com</strong>o um tipo utilizando o <strong>com</strong>ando type<strong>de</strong>f. A operação alteracaoData<br />

recebe <strong>com</strong>o parâmetros o dia, o mês e o ano <strong>de</strong> uma <strong>de</strong>terminada data e retorna a estrutura tData<br />

<strong>com</strong> a data informada. A operação apresentacaoData realiza a apresentação <strong>de</strong> uma data. Assim,<br />

po<strong>de</strong>-se observar as vantagens da utilização <strong>de</strong> TADs. Essas duas operações possibilitam escrever<br />

menos, visto que, uma vez <strong>de</strong>finidas, po<strong>de</strong>m ser reaproveitadas. A data é inicializada no corpo do<br />

programa em 30/01/1984, em seguida é alterada. A saída do programa é a apresentação da data<br />

16/05/2007.<br />

Pseudocódigo 4.1 Manipulação do TAD tData.<br />

Descrição: Operações sobre um TAD que representa data.<br />

Dados <strong>de</strong> Entrada: Valores inteiros correspon<strong>de</strong>ntes a datas.<br />

Saída do Programa: Apresentação da data pre<strong>de</strong>finida na tela.<br />

Tipo abstrato <strong>de</strong> dados " tData ":<br />

Variável do tipo inteiro dia .<br />

Variável do tipo inteiro m^es.<br />

Variável do tipo inteiro ano .<br />

FIM - Tipo abstrato <strong>de</strong> dados<br />

DRAFT<br />

Funç~ao Principal :<br />

Declarar uma variável do TAD tData chamada dt.<br />

Usar o Processo <strong>com</strong>ponente " alterarData " para <strong>de</strong>finir a data armazenada em dt ,<br />

passando <strong>com</strong>o par^ametro tr^es valores inteiros ( novo dia , novo m^es e novo ano )<br />

.<br />

Usar o Processo <strong>com</strong>ponente " alterarData " para alterar a data armazenada em dt ,<br />

passando <strong>com</strong>o par^ametro tr^es valores inteiros (dia , m^es e ano ).<br />

Usar o Processo <strong>com</strong>ponente " apresentarData " para apresentar o valor <strong>de</strong> dt na<br />

tela , passando <strong>com</strong>o par^ametro a própria variável dt.<br />

FIM - Funç~ao Principal<br />

Processo <strong>com</strong>ponente " alterarData ":<br />

Armazenar na variável dia do TAD tData o valor do par^ametro novo dia .<br />

Armazenar na variável m^es do TAD tData o valor do par^ametro novo m^es.<br />

Armazenar na variável ano do TAD tData o valor do par^ametro novo ano .<br />

FIM - Processo <strong>com</strong>ponente " alterarData "<br />

Processo <strong>com</strong>ponente " apresentarData ":<br />

Apresentar na tela o valor <strong>de</strong> dia , m^es e ano , armazenados no par^ametro do tipo<br />

tData .<br />

FIM - Processo <strong>com</strong>ponente " apresentarData "<br />

1 # inclu<strong>de</strong> <br />

2


4.4.<br />

EXERCÍCIOS RESOLVIDOS 107<br />

3 type<strong>de</strong>f struct data {<br />

4 int dia ;<br />

5 int mes ;<br />

6 int ano ;<br />

7 } tData ;<br />

8<br />

9 tData alterarData ( int d,int m,int a){<br />

10 tData dt;<br />

11<br />

12 dt.dia =d;<br />

13 dt.mes =m;<br />

14 dt.ano =a;<br />

15<br />

16 return dt;<br />

17 }<br />

18<br />

19 void apresentarData ( tData data ) {<br />

20 printf (" Data : %d/%d/%d\n", data .dia , data .mes , data . ano );<br />

21 }<br />

22<br />

23 int main () {<br />

24 tData dataNascimento ;<br />

25<br />

26 dataNascimento = alterarData (30 ,01 ,1984) ;<br />

27 dataNascimento = alterarData (16 ,05 ,2007) ;<br />

28<br />

29 apresentarData ( dataNascimento );<br />

30<br />

31 return 0;<br />

32 }<br />

Exemplo 4.15: Programa que realiza operações <strong>de</strong> alteração e apresentação.<br />

Exercício Resolvido 4.2 - Menor Data<br />

Escreva um programa em C que leia duas datas e retorne a menor data cronologicamente. As<br />

datas <strong>de</strong>vem ser armazenadas em estruturas.<br />

Solução Possível:<br />

O programa <strong>de</strong>termina qual é a menor data entre duas. A inicialização das datas é realizada<br />

por leitura do teclado. O retorno da operação menorData é a menor entre duas datas, a primeira<br />

verificação é realizada quanto ao ano, caso o ano das datas sejam iguais verifica-se o mês, se os meses<br />

são iguais verifica-se o dia.<br />

Pseudocódigo 4.2 Manipulação do TAD tData.<br />

DRAFT<br />

Descrição: Leitura e <strong>com</strong>paração <strong>de</strong> datas utilizando operações em TAD.<br />

Dados <strong>de</strong> Entrada: Valores inteiros correspon<strong>de</strong>ntes a datas.<br />

Saída do Programa: Apresentação na tela da data mais antiga.<br />

Tipo abstrato <strong>de</strong> dados " tData ":<br />

Variável do tipo inteiro dia .<br />

Variável do tipo inteiro m^es.<br />

Variável do tipo inteiro ano .<br />

FIM - Tipo abstrato <strong>de</strong> dados<br />

Funç~ao Principal :<br />

Declarar duas variáveis do TAD tData chamadas data0 e data1 .<br />

Usar o Processo <strong>com</strong>ponente " leituraData " para <strong>de</strong>finir a data armazenada em<br />

data0 .<br />

Usar o Processo <strong>com</strong>ponente " leituraData " para <strong>de</strong>finir a data armazenada em<br />

data1 .


108<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

Usar o Processo <strong>com</strong>ponente " menorData " para <strong>de</strong>terminar a data mais antiga ,<br />

passando <strong>com</strong>o par^ametro data0 e data1 .<br />

Apresentar a data mais antiga na tela .<br />

FIM - Funç~ao Principal<br />

Processo <strong>com</strong>ponente " menorData ":<br />

SE o ano <strong>de</strong> data0 é menor que o ano <strong>de</strong> data1 :<br />

A data mais antiga será data0 .<br />

FIM -SE<br />

SE o ano <strong>de</strong> data1 é menor que o ano <strong>de</strong> data0 :<br />

A data mais antiga será data1 .<br />

FIM -SE<br />

SE o m^es <strong>de</strong> data0 é menor que o m^es <strong>de</strong> data1 :<br />

A data mais antiga será data0 .<br />

FIM -SE<br />

SE o m^es <strong>de</strong> data1 é menor que o m^es <strong>de</strong> data0 :<br />

A data mais antiga será data1 .<br />

FIM -SE<br />

SE o dia <strong>de</strong> data0 é menor que o dia <strong>de</strong> data1 :<br />

A data mais antiga será data0 .<br />

FIM -SE<br />

SE o dia <strong>de</strong> data1 é menor que o dia <strong>de</strong> data0 :<br />

A data mais antiga será data1 .<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " menorData "<br />

Processo <strong>com</strong>ponente " leituraData ":<br />

Pedir ao usuário que entre <strong>com</strong> a data .<br />

Ler a entrada do usuário .<br />

Retornar a data lida do teclado .<br />

FIM - Processo <strong>com</strong>ponente " leituraData "<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 type<strong>de</strong>f struct data {<br />

4 int dia ;<br />

5 int mes ;<br />

6 int ano ;<br />

7 } tData ;<br />

8<br />

10<br />

9 tData menorData ( tData data0 , tData data1 ){<br />

11 if( data0 . ano < data1 . ano ){<br />

12 return data0 ;<br />

13 }<br />

14<br />

15 if( data1 . ano < data0 . ano ){<br />

16 return data1 ;<br />

17 }<br />

18<br />

19 if( data0 . mes < data1 . mes ){<br />

20 return data0 ;<br />

21 }<br />

22<br />

23 if( data1 . mes < data0 . mes ){<br />

24 return data1 ;<br />

25 }<br />

26<br />

27 if( data0 . dia < data1 . dia ){<br />

28 return data0 ;<br />

29 }<br />

30<br />

31 return data1 ;<br />

32 }<br />

DRAFT


4.4.<br />

EXERCÍCIOS RESOLVIDOS 109<br />

33<br />

34 tData leituraData (){<br />

35 tData d;<br />

36<br />

37 printf (" Entre <strong>com</strong> a data ");<br />

38 scanf ("%d %d %d", &d.dia , &d.mes , &d. ano );<br />

39<br />

40 return d;<br />

41 }<br />

42<br />

43 int main (){<br />

44 tData data0 , data1 , menor ;<br />

45<br />

46 printf (" Primeira data :\n");<br />

47<br />

48 data0 = leituraData ();<br />

49<br />

50 printf ("\ nSegunda data :\n");<br />

51<br />

52 data1 = leituraData ();<br />

53 menor = menorData ( data0 , data1 );<br />

54<br />

55 printf ("\nA menor data e: %d/ %d/ %d.\n", menor .dia , menor .mes , menor . ano );<br />

56<br />

57 return 0;<br />

58 }<br />

Exemplo 4.16: Programa que lê duas datas e retorna a menor data cronologicamente.<br />

Exercício Resolvido 4.3 - TAD tPonto<br />

Defina a estrutura <strong>de</strong> dados necessária para um TAD tPonto que representa os pontos no plano<br />

cartesiano <strong>de</strong> duas dimensões.<br />

Solução Possível:<br />

Para representar um ponto, é criada uma estrutura <strong>com</strong> dois atributos, as coor<strong>de</strong>nadas x e y.<br />

Pseudocódigo 4.3 Definição <strong>de</strong> TAD tPonto.<br />

Descrição: Definição do TAD tPonto.<br />

Dados <strong>de</strong> Entrada: Nenhuma.<br />

Saída do Programa: Nenhuma.<br />

DRAFT<br />

Tipo abstrato <strong>de</strong> dados " tPonto ":<br />

Variável do tipo inteiro x.<br />

Variável do tipo inteiro y.<br />

FIM - Tipo abstrato <strong>de</strong> dados<br />

1 type<strong>de</strong>f struct {<br />

2 int x;<br />

3 int y;<br />

4 } tPonto ;<br />

Exemplo 4.17: Programa que <strong>de</strong>fine a estrutura tPonto.<br />

Exercício Resolvido 4.4 - Operação tPonto simetricoOrigem (tPonto ponto)<br />

Implemente a operação tPonto simetricoOrigem (tPonto ponto), para <strong>de</strong>terminar o ponto<br />

simétrico <strong>de</strong> um ponto em relação à origem.


110<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

Solução Possível:<br />

A operação simetricoOrigem tem <strong>com</strong>o retorno uma variável do tipo tPonto. Para obter um<br />

ponto simétrico a outro em relação a origem, basta inverter as coor<strong>de</strong>nadas do ponto dado.<br />

Pseudocódigo 4.4 Operação que retorna o valor simétrico ao dado em relação a origem.<br />

Descrição: Operação que retorna o valor simétrico ao dado em relação a origem.<br />

Dados <strong>de</strong> Entrada: Valor ponto do tipo tPonto.<br />

Saída do Programa: Simétrico <strong>de</strong> ponto.<br />

Processo <strong>com</strong>ponente " simetricoOrigem ":<br />

Atribuir para a variável x <strong>de</strong> ponto o seu oposto , ou seja , -x.<br />

Atribuir para a variável y <strong>de</strong> ponto o seu oposto , ou seja , -y.<br />

Retornar ponto .<br />

FIM - Processo <strong>com</strong>ponente " simetricoOrigem "<br />

1 tPonto simetricoOrigem ( tPonto ponto ){<br />

2 ponto .x = -ponto .x;<br />

3 ponto .y = -ponto .y;<br />

4<br />

5 return ponto ;<br />

6 }<br />

Exemplo 4.18: Programa que <strong>de</strong>fine a operação simetricoOrigem.<br />

Exercício Resolvido 4.5 - Operação int qualQuadrante (tPonto ponto)<br />

Implemente a operação int qualQuadrante (tPonto ponto) que <strong>de</strong>termina a qual quadrante<br />

pertence um ponto.<br />

Solução Possível:<br />

Dado um ponto, a operação qualQuadrante retorna a qual quadrante esse ponto pertence. A<br />

função retorna 0 quando o ponto for parte do limite <strong>de</strong> quadrantes, 1 quando o ponto pertencer ao<br />

DRAFT<br />

1º quadrante, 2 quando pertencer ao 2º quadrante, 3 se pertencer ao 3º quadrante e 4 caso seja do 4º<br />

quadrante. Para <strong>de</strong>terminar a que quadrante o ponto pertence, é utilizado um conjunto <strong>de</strong> if e else<br />

aninhados que verificam os sinais das coor<strong>de</strong>nadas.<br />

Pseudocódigo 4.5 Operação que <strong>de</strong>termina a qual quadrante pertence um ponto.<br />

Descrição: Operação que <strong>de</strong>termina a qual quadrante pertence um ponto.<br />

Dados <strong>de</strong> Entrada: Valor ponto do tipo tPonto.<br />

Saída do Programa: Valor que representa o quadrante em que está ponto, que será um inteiro <strong>de</strong> 0 a 4, sendo<br />

que 0 significa que ponto está sobre os eixos.<br />

Processo <strong>com</strong>ponente " qualQuadrante ":<br />

SE x <strong>de</strong> ponto é zero ou y <strong>de</strong> ponto é zero :<br />

Retornar 0.<br />

FIM -SE<br />

SE x <strong>de</strong> ponto é maior que zero :<br />

SE y <strong>de</strong> ponto é maior que zero :<br />

Retornar 1.<br />

SEN~AO<br />

Retornar 4.<br />

FIM -SE<br />

FIM -SE<br />

SE y <strong>de</strong> ponto é maior que zero :


4.4.<br />

EXERCÍCIOS RESOLVIDOS 111<br />

Retornar 2.<br />

SEN~AO<br />

Retornar 3.<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " qualQuadrante "<br />

1 int qualQuadrante ( tPonto ponto ){<br />

2<br />

3 if( ponto .x == 0 || ponto .y == 0){<br />

4 return 0;<br />

5 }<br />

6<br />

7 if( ponto .x > 0){<br />

8 if( ponto .y > 0){<br />

9 return 1;<br />

10 } else {<br />

11 return 4;<br />

12 }<br />

13 }<br />

14<br />

15 if( ponto .y > 0){<br />

16 return 2;<br />

17 } else {<br />

18 return 3;<br />

19 }<br />

20 }<br />

Exemplo 4.19: Programa que <strong>de</strong>fine a operação qualQuadrante.<br />

Exercício Resolvido 4.6 - Operação float distanciaPontos (tPonto a, tPonto b)<br />

Defina um programa que calcule a distância entre dois pontos utilizando a estrutura tPonto.<br />

Solução Possível:<br />

A função distanciaPontos calcula a distância entre dois pontos, dada pela raiz quadrada da<br />

soma do quadrado da diferença entre as abscissas e entre as or<strong>de</strong>nadas.<br />

DRAFT<br />

Pseudocódigo 4.6 Operação que calcula a distância entre dois pontos.<br />

Descrição: Operação que calcula a distância entre dois pontos.<br />

Dados <strong>de</strong> Entrada: Dois valores, ponto1 e ponto2 do tipo tPonto.<br />

Saída do Programa: Distância euclidiana entre os dois pontos dados.<br />

Processo <strong>com</strong>ponente " distanciaPontos ":<br />

Declarar tr^es variáveis do tipo ponto flutuante , chamadas <strong>de</strong>ltaX , <strong>de</strong>ltaY e dist<br />

^ancia .<br />

Atribuir a <strong>de</strong>ltaX a soma da variável x <strong>de</strong> ponto1 <strong>com</strong> o negativo da variável x<br />

<strong>de</strong> ponto2 .<br />

Atribuir a <strong>de</strong>ltaY a soma da variável y <strong>de</strong> ponto1 <strong>com</strong> o negativo da variável y<br />

<strong>de</strong> ponto2 .<br />

Atribuir a dist^ancia a soma dos quadrados <strong>de</strong> <strong>de</strong>ltaX e <strong>de</strong>ltaY .<br />

Atribuir a dist^ancia sua própria raiz quadrada .<br />

Retornar dist^ancia .<br />

FIM - Processo <strong>com</strong>ponente " distanciaPontos "<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 float distanciaPontos ( tPonto a, tPonto b){<br />

4 float distancia , <strong>de</strong>ltaX , <strong>de</strong>ltaY ;


112<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

5<br />

6 <strong>de</strong>ltaX = a.x - b.x;<br />

7 <strong>de</strong>ltaY = a.y - b.y;<br />

8<br />

10<br />

9 distancia = sqrt ( pow ( <strong>de</strong>ltaX ,2) + pow ( <strong>de</strong>ltaY ,2) );<br />

11 return distancia ;<br />

12 }<br />

Exemplo 4.20: Programa que calcula a distância entra dois pontos.<br />

Exercício Resolvido 4.7 - Operações inicializacao() e finalizacao()<br />

Defina um programa que implemente e use operações construtoras e <strong>de</strong>strutoras utilizando a estrutura<br />

tPonto. Utilize também a operação distanciaPontos <strong>de</strong>finida anteriormente.<br />

Solução Possível:<br />

Inicialmente, são <strong>de</strong>finidas as funções inicializacao e finalizacao. A função inicializacao inicializa<br />

o tPonto a partir <strong>de</strong> valores fornecidos pelo usuário e a função finalizacao zera as coo<strong>de</strong>rnadas<br />

do ponto. A função principal utiliza os métodos <strong>de</strong>clarados <strong>de</strong> forma a correspon<strong>de</strong>r à funcionalida<strong>de</strong><br />

<strong>de</strong>sejada.<br />

Pseudocódigo 4.7 Operações <strong>de</strong> construção e <strong>de</strong>struição em TADs<br />

Descrição: Programa que calcula a distância entra dois pontos.<br />

Dados <strong>de</strong> Entrada: Dois valores ponto1 e ponto2 do tipo tPonto.<br />

Saída do Programa: Distância euclidiana entre os dois pontos dados.<br />

Funç~ao Principal :<br />

Declarar duas variáveis do tipo tPonto chamadas a e b.<br />

Declarar um variável do tipo ponto flutuante chamada dist^ancia .<br />

Usar o Processo <strong>com</strong>ponente " inicializaç~ao", inicializando a.<br />

Usar o Processo <strong>com</strong>ponente " inicializaç~ao", inicializando b.<br />

Usar o processo <strong>com</strong>ponente " ditanciaPontos ", passando a e b <strong>com</strong>o par^ametros e<br />

atribuindo o resultado variável dist^ancia .<br />

Apresentar o valor <strong>de</strong> dist^ancia na tela .<br />

Usar o Processo <strong>com</strong>ponente " finalizaç~ao", finalizando a.<br />

Usar o Processo <strong>com</strong>ponente " finalizaç~ao", finalizando b.<br />

FIM - Funç~ao Principal<br />

DRAFT<br />

Processo <strong>com</strong>ponente " inicializaç~ao":<br />

Declarar variável ponto do tipo tPonto .<br />

Pedir ao usuário que entre <strong>com</strong> um valor inteiro .<br />

Atribuir o valor dado a variável x <strong>de</strong> ponto .<br />

Pedir ao usuário que entre <strong>com</strong> um valor inteiro .<br />

Atribuir o valor dado a variável y <strong>de</strong> ponto .<br />

Retornar ponto .<br />

FIM - Processo <strong>com</strong>ponente " inicializaç~ao"<br />

Processo <strong>com</strong>ponente " finalizaç~ao":<br />

Declarar variável ponto do tipo tPonto .<br />

Atribuir o valor zero a variável x <strong>de</strong> ponto .<br />

Atribuir o valor zero a variável y <strong>de</strong> ponto .<br />

Retornar ponto .<br />

FIM - Processo <strong>com</strong>ponente " finalizaç~ao"<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 \\ Operacao Construtora<br />

4 tPonto inicializacao (){


4.5. RESUMO 113<br />

5 tPonto ponto ;<br />

6<br />

7 printf (" Entre <strong>com</strong> as coor<strong>de</strong>nadas \n");<br />

8 printf ("X: ");<br />

9 scanf ("%d", & ponto .x);<br />

10 printf ("Y: ");<br />

11 scanf ("%d", & ponto .y);<br />

12<br />

13 return ponto ;<br />

14 }<br />

15<br />

16 \\ Operacao Destrutora<br />

17 tPonto finalizacao (){<br />

18 tPonto origem = {0 , 0};<br />

19<br />

20 return origem ;<br />

21 }<br />

22<br />

23 int main (){<br />

24 tPonto a, b;<br />

25 float distancia ;<br />

26<br />

27 a = inicializacao ();<br />

28 b = inicializacao ();<br />

29<br />

30 distancia = distanciaPontos (a, b);<br />

31<br />

32 printf (" Distancia entre pontos : %f\n", distancia );<br />

33<br />

34 a = finalizacao ();<br />

35 b = finalizacao ();<br />

36<br />

37 return 0;<br />

38 }<br />

Exemplo 4.21: Programa que implementa as operações inicializacao e finalizacao.<br />

4.5 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

Neste capítulo foram discutidas as seguintes técnicas <strong>de</strong> programação:<br />

1. bottom-up: propõe consi<strong>de</strong>rar o programa <strong>com</strong>o um conjunto <strong>de</strong> módulos correlacionados,<br />

implementar cada um <strong>de</strong>sses módulos e <strong>de</strong>pois juntá-los por meio <strong>de</strong> uma estrutura global.<br />

DRAFT<br />

2. top-down: o programa é visto <strong>com</strong>o uma <strong>de</strong>scrição <strong>de</strong> um processo. Primeiramente <strong>de</strong>finese<br />

a estrutura global do programa. O processo é, então, dividido em subprocessos, os quais<br />

são responsáveis por cumprir partes da funcionalida<strong>de</strong> geral do processo. Por sua vez, cada<br />

subprocesso ainda po<strong>de</strong> ser dividido em novos subprocessos.<br />

Uma estrutura serve para agrupar um conjunto <strong>de</strong> dados não similares, formando um novo tipo<br />

<strong>de</strong> dados. Estruturas permitem a criação <strong>de</strong> tipos não <strong>de</strong>finidos pela linguagem facilitando a<br />

programação.<br />

O uso <strong>de</strong> estruturas é consi<strong>de</strong>rado uma ótima prática <strong>de</strong> programação, visto que, além <strong>de</strong> permitirem<br />

uma organização melhor, possibilitam realizar atribuições ou passagem <strong>de</strong> parâmetros<br />

em uma única ação.<br />

ˆ<br />

ˆ<br />

Uma estrutura po<strong>de</strong> ser manipulada <strong>de</strong> forma seletiva (acesso a um único atributo) ou <strong>de</strong> forma<br />

integral (acesso a estrutura <strong>com</strong>o um todo).<br />

Os TADs são generalizações das estruturas. Nos TADs operações são associadas à estrutura.


114<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

ˆ<br />

As operações associadas a um TAD po<strong>de</strong>m ser dos seguintes tipos: construtoras, analisadoras,<br />

modificadoras, produtoras e <strong>de</strong>strutoras.<br />

ˆ<br />

Os TADs são <strong>de</strong>finidos a partir <strong>de</strong> uma estrutura <strong>de</strong> dados e das operações sobre os dados.<br />

ˆ<br />

O uso <strong>de</strong> TADs possui diversas vantagens <strong>com</strong>o: abstração, facilida<strong>de</strong> <strong>de</strong> alteração, reutilização,<br />

ocultamento e integrida<strong>de</strong>.<br />

ˆ<br />

Os Tipos Abstratos <strong>de</strong> Dados são classificados em TADs <strong>de</strong> Domínio e TADs Implementacionais.<br />

TADs <strong>de</strong> domínio são aqueles que <strong>de</strong>screvem um tipo do problema, enquanto TADs Implementacionais<br />

<strong>de</strong>screvem uma estrutura que irá ajudar a resolver o problema, mas não se refere ao<br />

problema. Exemplos <strong>de</strong> TADs <strong>de</strong> domínio são os registros <strong>de</strong> alunos, funcionários, datas etc.<br />

Exemplos <strong>de</strong> TADs implementacionais são as pilhas, listas etc.<br />

4.6 Exercícios Propostos<br />

1. Crie um TAD para mo<strong>de</strong>lar um cilindro. A entrada dos dados referentes ao cilindro <strong>de</strong>ve ser<br />

realizada via console (teclado). As possíveis operações sobre o tipo são:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Inicializa Cilindro;<br />

Leitura dos Dados;<br />

Altera Altura;<br />

Altera Raio;<br />

Calcula Volume;<br />

Apresenta Dimensões;<br />

Apresenta Volume.<br />

2. Modifique o TAD tData do Exemplo 4.8 incluindo operações que contenham a diferença em<br />

dias entre duas datas. Em seguida, use o novo tData para fazer um programa que <strong>de</strong>termine<br />

à ida<strong>de</strong> <strong>de</strong> uma pessoa, e quantos dias faltam para seu aniversário tendo <strong>com</strong>o entradas a data<br />

<strong>de</strong> nascimento e a data atual. Deve-se consi<strong>de</strong>rar anos bissextos e meses <strong>com</strong> o número <strong>de</strong> dias<br />

conforme o calendário oci<strong>de</strong>ntal.<br />

3. Implemente um TAD tPonto para representar um ponto no plano <strong>com</strong> as seguintes operações:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Leitura: leitura via console;<br />

DRAFT<br />

Deslocamento Horizontal: faz o ponto se <strong>de</strong>slocar horizontalmente no plano a uma distância<br />

especificada na chamada da operação;<br />

Deslocamento Vertical;<br />

Atualização <strong>de</strong> Coor<strong>de</strong>nadas: atribui novos valores às coor<strong>de</strong>nadas <strong>de</strong> um ponto;<br />

Distância: calcula a distância entre dois pontos;<br />

Apresente: apresente as coor<strong>de</strong>nadas do ponto.<br />

4. Implemente um TAD tCirculo para representar um círculo (utilize o tipo tPonto <strong>de</strong>finido no<br />

Exercício 3 para representar o centro do tCirculo) <strong>com</strong> as seguintes operações:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Leitura: leitura via console;<br />

Atualização do raio: atribui um valor r ao raio do círculo;<br />

Atualização do centro: atribui novo valor ao centro do círculo;<br />

Área: calcula a área do círculo;<br />

Interior: verifica se um dado ponto está <strong>de</strong>ntro do círculo.


4.7. TRABALHOS SUGERIDOS 115<br />

5. Implemente um TAD tTrapezio para representar um trapézio <strong>com</strong> as seguintes operações:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Leitura: leitura via console das bases e da altura do trapézio;<br />

Atualização: atualização das bases e altura do trapézio<br />

Área: calcula a área do trapézio;<br />

Interior: verifica se um dado ponto está <strong>de</strong>ntro do trapézio.<br />

6. O sistema responsável pelo controle <strong>de</strong> entrada e saída <strong>de</strong> veículos <strong>de</strong> um estacionamento funciona<br />

24h por dia. Um motorista ao entrar no estacionamento recebe um ticket indicando o horário e a<br />

data <strong>de</strong> entrada, na saída do estacionamento o aten<strong>de</strong>nte realiza a cobrança pelo uso do serviço.<br />

O preço do uso do estacionamento por hora é <strong>de</strong> R$1,00 nos dias úteis e R$2,00 aos sábados,<br />

domingos e feriados.<br />

O sistema <strong>de</strong>ve ler do ticket do usuário o horário e a data <strong>de</strong> entrada, <strong>de</strong>ve i<strong>de</strong>ntificar o horário<br />

atual e a respectiva data, calcular o tempo <strong>de</strong> uso do estacionamento e o valor a ser pago.<br />

Caso o motorista permaneça no estacionamento por menos <strong>de</strong> 15 minutos ele não <strong>de</strong>verá pagar<br />

pelo uso do estacionamento. Caso o motorista permaneça por mais <strong>de</strong> 15 minutos e menos <strong>de</strong><br />

uma hora ele <strong>de</strong>verá pagar pelo preço <strong>de</strong> uma hora <strong>com</strong>pleta.<br />

Implemente esse sistema utilizando TADs para representar uma data, um horário e o estacionamento.<br />

7. O gerente <strong>de</strong> uma agência bancária te contratou para fazer um programa em C que obtenha<br />

algumas informações das contas dos correntistas <strong>de</strong> sua agência. Para tanto leia sucessivamente<br />

os dados do número da conta (um valor inteiro positivo) e o valor das operações (um valor ponto<br />

flutuante positivo para as operações <strong>de</strong> crédito e negativo para as operações <strong>de</strong> débito) realizadas<br />

no último mês. Seu programa <strong>de</strong>ve usar os dados da listagem para informar:<br />

ˆ<br />

ˆ<br />

ˆ<br />

As operações suspeitas, isto é, aquelas que movimentaram acima <strong>de</strong> 20.000 reais;<br />

Os dois correntistas que produziram o maior saldo nas suas operações;<br />

O saldo total das operações na agência.<br />

Nos ítens 1, 2 e 3 também <strong>de</strong>vem ser apresentados os números das contas dos correntistas.<br />

Consi<strong>de</strong>re que os dados <strong>de</strong> cada conta são fornecidos contiguamente, isto é, são fornecidos todos os<br />

dados das operações <strong>de</strong> uma conta, <strong>de</strong>pois todos os dados <strong>de</strong> outra conta e assim sucessivamente.<br />

O processamento <strong>de</strong>ve ser encerrado quando for lido um número <strong>de</strong> conta igual a zero. Utilize<br />

um TAD para representar as contas bancárias.<br />

4.7 Trabalhos Sugeridos<br />

DRAFT<br />

1. A Jogos Matemáticos Ltda. é uma empresa que <strong>de</strong>senvolve jogos <strong>com</strong>putacionais educativos para<br />

apoio ao ensino <strong>de</strong> matemática. Ela te contratou para fazer um programa em C que implemente<br />

um jogo <strong>de</strong> adivinhação. Este jogo ocorre da seguinte maneira: o jogador <strong>de</strong>fine um intervalo<br />

<strong>de</strong> números naturais, por exemplo, entre 0 e 1000, e o <strong>com</strong>putador escolhe aleatoriamente um<br />

valor neste intervalo. O jogador tem, então, um número <strong>de</strong>terminado <strong>de</strong> chances (<strong>de</strong>pen<strong>de</strong>nte<br />

do tamanho do intervalo) para acertar o valor escolhido pelo <strong>com</strong>putador. A cada tentativa,<br />

o <strong>com</strong>putador respon<strong>de</strong> se a tentativa foi bem sucedida (neste caso, o jogador acertou o valor<br />

escolhido pelo <strong>com</strong>putador), se a tentativa é baixa (neste caso o valor é inferior ao valor escolhido)<br />

ou se a tentativa é alta (neste caso o valor é superior ao valor escolhido). Se o jogador consegue<br />

acertar o valor escolhido antes <strong>de</strong> expirar seu número <strong>de</strong> chances, ele vence. Caso o número<br />

<strong>de</strong> chances termine sem que ele acerte o valor escolhido, a vitória é do <strong>com</strong>putador. Ao final<br />

<strong>de</strong> cada jogo, o programa <strong>de</strong>ve perguntar ao jogador se ele quer continuar ou parar <strong>de</strong> jogar.<br />

Para gerar o valor a ser adivinhado, antes do início <strong>de</strong> cada rodada, o <strong>com</strong>putador <strong>de</strong>ve pedir ao<br />

jogador que forneça um número inteiro no intervalo entre 1 e 10000. Este número, chamado <strong>de</strong>


116<br />

CAPÍTULO 4. TIPOS ABSTRATOS DE DADOS<br />

n, será usado para obter o n-ésimo termo primo da série <strong>de</strong> fibonacci, chamado <strong>de</strong> f. O valor<br />

f <strong>de</strong>ve ser então ajustado ao intervalo pré-<strong>de</strong>finido pelo jogador, através <strong>de</strong> um procedimento<br />

<strong>de</strong> normalização. Para tanto, o resto da divisão inteira do número f por 101, chamado <strong>de</strong> r, é<br />

usado juntamente <strong>com</strong> o intervalo <strong>de</strong> escolha [min, max] para obter o valor a ser adivinhado,<br />

chamado <strong>de</strong> x, através da seguinte fórmula:<br />

x = arredondamento((r/100.00) ∗ (max–min) + min)<br />

O número máximo <strong>de</strong> chances, chamado <strong>de</strong> mc, que o jogador tem para acertar o valor é dado<br />

pela seguinte fórmula:<br />

mc = parteinteira(log 2 (max–min + 1)) + 1<br />

Seu programa <strong>de</strong>ve tratar ainda as seguintes condições <strong>de</strong> entrada <strong>de</strong> dados:<br />

(a) Se o valor inteiro n, fornecido para obtenção do valor a ser adivinhado, está no intervalo<br />

entre 1 e 10000.<br />

(b) Se os valores inteiros min e max fornecidos pelo jogador são números naturais, se min é<br />

menor que max, e se max é um valor inferior ao valor máximo inteiro possível do intervalo<br />

(consi<strong>de</strong>rar 1.000.000.000 <strong>com</strong>o máximo valor possível).<br />

(c) Se os valores das tentativas se encontram sempre no intervalo entre min e max, inclusive.<br />

(d) Se a resposta à pergunta <strong>de</strong> continuação do jogo é o caractere ’s’ ou ’n’.<br />

Sempre que alguma <strong>de</strong>ssas condições não for satisfeita o jogador <strong>de</strong>ve ser avisado do seu erro<br />

e <strong>de</strong>ve po<strong>de</strong>r repetir a entrada <strong>de</strong> dados. Apresenta-se, a seguir, um exemplo <strong>de</strong> execução do<br />

programa.<br />

Jogo <strong>de</strong> Adivinhacao<br />

Forneca um numero no intervalo entre 1 e 10000: 4<br />

Forneca um intervalo <strong>de</strong> numeros naturais: 23 18<br />

O primeiro numero do intervalo <strong>de</strong>ve ser inferior ao segundo<br />

Forneca um intervalo <strong>de</strong> numeros naturais: 0 10<br />

Voce tem direito a 4 tentativas<br />

Tentativa 1: 9<br />

Alta<br />

Tentativa 2: 7<br />

Alta<br />

Tentativa 3: 5<br />

Alta<br />

Tentativa 4: 3<br />

Voce per<strong>de</strong>u! O numero escolhido foi 1<br />

Deseja continuar a jogar (s/n): n<br />

Obrigado por jogar <strong>com</strong>igo. Ate a proxima.<br />

DRAFT


Capítulo 5<br />

Vetores<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Introduzir a estrutura <strong>de</strong> dados vetor e mostrar sua importância;<br />

Apresentar suas operações básicas e <strong>de</strong>monstrar o seu uso;<br />

Coautores:<br />

Definir um TAD Implementacional lista vetorial <strong>de</strong> inteiros, TListaVetInt;<br />

Apresentar aplicações para o TAD TListaVetInt.<br />

Alan Floriano<br />

André Boechat<br />

Ebenézer Silva<br />

Thiago Salviato<br />

Este capítulo apresenta o conceito <strong>de</strong> vetor. Um vetor é usado para armazenar uma coleção <strong>de</strong><br />

objetos semelhantes. Se vetores não estivessem disponíveis para uso, quando o programador precisasse<br />

lidar <strong>com</strong> uma gran<strong>de</strong> quantida<strong>de</strong> <strong>de</strong> “objetos” semelhantes – por exemplo, os milhares <strong>de</strong> alunos em<br />

uma escola –, seria necessário criar uma variável distinta (isto é, <strong>com</strong> um nome diferente) para cada<br />

um <strong>de</strong>sses objetos. Já <strong>com</strong> o uso <strong>de</strong> vetores, conjuntos <strong>de</strong> objetos semelhantes po<strong>de</strong>m ser tratados <strong>de</strong><br />

uma forma simples e que não <strong>de</strong>manda a <strong>de</strong>finição <strong>de</strong> múltiplas variáveis.<br />

5.1 Vetores e sua importância<br />

DRAFT<br />

Imagine que se queira fazer um programa para manusear dados <strong>de</strong> um mesmo tipo - as ida<strong>de</strong>s das<br />

pessoas <strong>de</strong> uma família, ou os salários dos funcionários <strong>de</strong> uma empresa, por exemplo. Uma alternativa<br />

seria a utilização <strong>de</strong> muitas variáveis ou então a leitura <strong>de</strong> valores sempre que necessários. Mas será que<br />

essas seriam as melhores soluções? E se o programa for gran<strong>de</strong> e houver a necessida<strong>de</strong> <strong>de</strong> modularizálo?<br />

Não seria incômodo quando fosse necessário passar todas essas variáveis <strong>com</strong>o parâmetros? Ao<br />

refletir sobre essas perguntas, outra idéia po<strong>de</strong> vir à tona: a utilização <strong>de</strong> um TAD. Dessa forma,<br />

as variáveis po<strong>de</strong>m ser encapsuladas em uma só estrutura e apenas ela po<strong>de</strong>ria ser passada <strong>com</strong>o<br />

parâmetro. Para muitos casos isso po<strong>de</strong>ria ser uma boa idéia.<br />

Mas e se fossem 100 valores diferentes? E se quiséssemos or<strong>de</strong>nar 100 valores? Seriam necessárias<br />

100 variáveis, uma para armazenar cada valor, o que implicaria em escrever mais e tornaria o código<br />

pouco legível.<br />

Mesmo que o programador consi<strong>de</strong>re abordagens que não usam muitas variáveis, não empregar<br />

vetores po<strong>de</strong> <strong>de</strong>cisivamente limitar a funcionalida<strong>de</strong> do programa <strong>de</strong>senvolvido. Para ilustrar a diferença<br />

entre usar ou não vetores, apresentamos a seguir dois exemplos nos quais a ausência <strong>de</strong> vetores<br />

torna o código menos legível e muito maior que o realmente necessário.<br />

O Pseudocódigo 5.1 mostra um algoritmo para or<strong>de</strong>nar seis elementos sem a utilização <strong>de</strong> vetores.<br />

117


118<br />

CAPÍTULO 5. VETORES<br />

Pseudocódigo 5.1 Programa para or<strong>de</strong>nar seis inteiros.<br />

Descrição: Or<strong>de</strong>nar seis inteiros.<br />

Dados <strong>de</strong> Entrada: Seis inteiros, x1, x2, x3, x4, x5, x6.<br />

Saída do Programa: Exibe na tela os seis inteiros or<strong>de</strong>nados crescentemente.<br />

Funç~ao Principal :<br />

PARA um loop <strong>de</strong> 1 a 6<br />

SE o retorno da chamada processo <strong>com</strong>ponente " Trocar " passando <strong>com</strong>o<br />

par^ametros x1 e x2 for igual a um<br />

Trocar os valores <strong>de</strong> x1 e x2<br />

FIM -SE<br />

SE o retorno da chamada processo <strong>com</strong>ponente " Trocar " passando <strong>com</strong>o<br />

par^ametros x2 e x3 for igual a um<br />

Trocar os valores <strong>de</strong> x2 e x3<br />

FIM -SE<br />

SE o retorno da chamada processo <strong>com</strong>ponente " Trocar " passando <strong>com</strong>o<br />

par^ametros x3 e x4 for igual a um<br />

Trocar os valores <strong>de</strong> x3 e x4<br />

FIM -SE<br />

SE o retorno da chamada processo <strong>com</strong>ponente " Trocar " passando <strong>com</strong>o<br />

par^ametros x4 e x5 for igual a um<br />

Trocar os valores <strong>de</strong> x4 e x5<br />

FIM -SE<br />

SE o retorno da chamada processo <strong>com</strong>ponente " Trocar " passando <strong>com</strong>o<br />

par^ametros x5 e x6 for igual a um<br />

Trocar os valores <strong>de</strong> x5 e x6<br />

FIM -SE<br />

FIM - PARA<br />

Apresentar x1 x2 x3 x4 x5 x6<br />

FIM - Funç~ao Principal<br />

Processo <strong>com</strong>ponente " Trocar "<br />

SE o primeiro elemento passado <strong>com</strong>o par^ametro for maior que o segundo elemento<br />

passado <strong>com</strong>o par^ametro<br />

Retorna um<br />

SEN~AO:<br />

Retorna zero<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " Trocar "<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int trocar ( int valor1 , int valor2 )<br />

4 {<br />

5 if( valor1 > valor2 ){<br />

6 return 1;<br />

7 } else {<br />

8 return 0;<br />

9 }<br />

10 }<br />

11<br />

12 int main ()<br />

13 {<br />

DRAFT<br />

14 int i, elem1 , elem2 , elem3 , elem4 , elem5 , elem6 , elemAux ;<br />

15<br />

16 printf (" Digite os valores dos 6 inteiros : ");<br />

17 scanf ("%d%d%d%d%d%d", & elem1 , & elem2 , & elem3 , & elem4 , & elem5 , & elem6 );<br />

18<br />

19 for (i =0; i


5.1. VETORES E SUA IMPORTÂNCIA 119<br />

22 elem1 = elem2 ;<br />

23 elem2 = elemAux ;<br />

24 }<br />

25 if( trocar ( elem2 , elem3 ) == 1){<br />

26 elemAux = elem2 ;<br />

27 elem2 = elem3 ;<br />

28 elem3 = elemAux ;<br />

29 }<br />

30 if( trocar ( elem3 , elem4 ) == 1){<br />

31 elemAux = elem3 ;<br />

32 elem3 = elem4 ;<br />

33 elem4 = elemAux ;<br />

34 }<br />

35 if( trocar ( elem4 , elem5 ) == 1){<br />

36 elemAux = elem4 ;<br />

37 elem4 = elem5 ;<br />

38 elem5 = elemAux ;<br />

39 }<br />

40 if( trocar ( elem5 , elem6 ) == 1){<br />

41 elemAux = elem5 ;<br />

42 elem5 = elem6 ;<br />

43 elem6 = elemAux ;<br />

44 }<br />

45 }<br />

46<br />

47 printf ("%d %d %d %d %d %d\n", elem1 , elem2 , elem3 , elem4 , elem5 , elem6 );<br />

48<br />

49 return 0;<br />

50 }<br />

Exemplo 5.1: Or<strong>de</strong>nação <strong>de</strong> seis inteiros sem a utilização <strong>de</strong> vetores.<br />

Como já se po<strong>de</strong> perceber, nem sempre os tipos básicos <strong>de</strong> dados (int, float, char) e as estruturas<br />

são suficientes para expressar estruturas <strong>de</strong> dados em algoritmos.<br />

Para ilustrar melhor o problema, consi<strong>de</strong>re que um professor tenha uma turma <strong>de</strong> 50 alunos e<br />

<strong>de</strong>seja saber quantos <strong>de</strong>les tiveram nota acima da média da turma. Com as estruturas e conceitos<br />

apresentados até o capítulo anterior, seria necessária a leitura das notas dos alunos por duas vezes (ou<br />

a utilização <strong>de</strong> 50 variáveis - o que também seria um gran<strong>de</strong> incômodo): uma para calcular a média<br />

e outra para verificar quais alunos tiveram notas superiores a esse valor. O Exemplo 5.2 mostra uma<br />

maneira <strong>de</strong> resolver o problema do professor utilizando a linguagem C e fazendo a dupla leitura.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 # <strong>de</strong>fine QTD_NOTAS 50<br />

4<br />

5 int main (){<br />

6 int i, conta ;<br />

7 float nota , soma , media ;<br />

8<br />

10<br />

9 soma = 0.0;<br />

11 for (i =0; i < QTD_NOTAS ; i ++) {<br />

12 printf (" Digite uma nota : ");<br />

13 scanf ("%f", & nota );<br />

14 soma = soma + nota ;<br />

15 }<br />

16<br />

17 media = soma / QTD_NOTAS ;<br />

18<br />

19 conta = 0;<br />

20<br />

21 for (i =0; i < QTD_ALUNOS ; i ++) {<br />

22 printf (" Digite uma nota : ");<br />

23 scanf ("%f", & nota );<br />

DRAFT


120<br />

CAPÍTULO 5. VETORES<br />

24<br />

25 if( nota > media ){<br />

26 conta ++;<br />

27 }<br />

28 }<br />

29<br />

30 printf ("\n%d alunos obtiveram nota acima da media \n", conta );<br />

31<br />

32 return 0;<br />

33 }<br />

Exemplo 5.2: Resolução do problema do professor sem a utilização <strong>de</strong> vetores.<br />

Todos os problemas citados até agora no capítulo po<strong>de</strong>riam ser resolvidos <strong>com</strong> a utilização <strong>de</strong><br />

vetores.<br />

Em resumo, um vetor é uma estrutura <strong>de</strong> dados <strong>com</strong>posta e homogênea; isto é, ele possui, em<br />

geral, mais <strong>de</strong> um elemento – por isso, <strong>com</strong>posto –, e estes elementos são sempre do mesmo tipo –<br />

logo, homogêneo. O uso <strong>de</strong> vetores é necessário quando um conjunto <strong>de</strong> dados <strong>de</strong> um mesmo tipo <strong>de</strong>ve<br />

ser armazenado, a fim <strong>de</strong> ser utilizado durante a execução do programa. Se vetores fossem empregados<br />

no Exemplo 5.2, as notas <strong>de</strong> todos os alunos po<strong>de</strong>riam ter sido armazenadas num único vetor durante<br />

a primeira leitura dos dados, e assim elas estariam disponíveis para uso durante toda a execução<br />

seguinte do programa; assim, após o cálculo da média, não seria necessário fazer novamente a entrada<br />

<strong>de</strong> dados das notas para checar as que estão acima da média, já que todas as notas ainda estariam<br />

armazenadas.<br />

5.2 Representação<br />

A Figura 5.1 mostra a maneira mais <strong>com</strong>um <strong>de</strong> se representar um vetor graficamente.<br />

Figura 5.1: Representação <strong>de</strong> um vetor.<br />

A Figura 5.1 representa um vetor <strong>de</strong> inteiros chamado vet <strong>com</strong> os nove primeiros números primos.<br />

O terceiro elemento, <strong>de</strong> índice igual a 2, é o número 5 e o <strong>de</strong> índice 4 é o número 11. É importante<br />

lembrar que o primeiro elemento <strong>de</strong> um vetor, na linguagem C, sempre correspon<strong>de</strong> ao índice zero.<br />

Analisando a Figura 5.1, ficam evi<strong>de</strong>ntes outras importantes características <strong>de</strong>ssa estrutura: a<br />

sequencialização, a in<strong>de</strong>xação <strong>de</strong> seus elementos e a sua dimensão.<br />

Quando se executa um programa que contém um vetor, reserva-se um espaço <strong>de</strong> memória sequencial<br />

<strong>com</strong> o tamanho necessário para que seja possível armazenar todos os elementos do vetor. Por exemplo,<br />

para um vetor <strong>de</strong> inteiros <strong>com</strong> tamanho igual a oito, é reservado um espaço <strong>de</strong> memória necessário<br />

para armazenar oito números inteiros. Se um inteiro ocupar 32 bits, então é reservado um espaço<br />

sequencial <strong>de</strong> 256 bits na memória.<br />

Essa proprieda<strong>de</strong> facilita bastante o acesso do programa ao elemento <strong>de</strong>sejado <strong>de</strong>ntro do vetor,<br />

pois, para que o dado seja recuperado, é necessário apenas o nome do vetor, que localiza o primeiro<br />

elemento, e um índice, que indica ao programa a que distância do início está o dado <strong>de</strong>sejado.<br />

Discute-se nas próximas seções <strong>com</strong>o essa estrutura po<strong>de</strong> ser utilizada na prática, abordando<br />

assuntos <strong>com</strong>o sua <strong>de</strong>finição e as operações possíveis sobre ela.<br />

DRAFT<br />

5.3 Definição<br />

Na linguagem C, o vetor é <strong>de</strong>finido da seguinte maneira:


5.3.<br />

DEFINIÇÃO 121<br />

[];<br />

on<strong>de</strong> tipoDosDados representa o tipo dos dados dos elementos que são armazenados no vetor, nome-<br />

DoVetor é o nome pelo qual o vetor será referenciado e tamanhoDoVetor o número <strong>de</strong> elementos que<br />

po<strong>de</strong>m ser armazenados no vetor. O Exemplo 5.3 mostra alguns exemplos <strong>de</strong> <strong>de</strong>claração <strong>de</strong> vetores.<br />

1 int vet [9];<br />

2<br />

3 char nome [9];<br />

4<br />

5 float nota [6];<br />

6<br />

7 float notasAlunos [50];<br />

Exemplo 5.3: Algumas <strong>de</strong>clarações <strong>de</strong> vetores.<br />

No Exemplo 5.3, o primeiro vetor po<strong>de</strong> ser representado graficamente pela Figura 5.1 mostrada<br />

na seção anterior, ou seja, seu nome é vet e ele po<strong>de</strong> armazenar até 9 elementos do tipo int. O<br />

segundo e o terceiro são representados pela Figura 5.2. O vetor chamado nome armazena no máximo<br />

9 elementos do tipo char, e o chamado nota, até 6 do tipo float. Já o último po<strong>de</strong>ria ser utilizado no<br />

problema do professor citado anteriormente, por exemplo. Nesse vetor, chamado notasAlunos, po<strong>de</strong>m<br />

ser armazenados 50 valores do tipo float, que po<strong>de</strong>riam representar as notas dos 50 alunos.<br />

Figura 5.2: Vetores na memória do <strong>com</strong>putador.<br />

É possível <strong>de</strong>finir vetores <strong>de</strong>ntro <strong>de</strong> estruturas. Suponha que se queira fazer um programa para<br />

cadastrar os alunos <strong>de</strong> uma turma <strong>de</strong> uma escola <strong>de</strong> ensino médio e fazer um a<strong>com</strong>panhamento <strong>de</strong><br />

suas notas. Consi<strong>de</strong>re que o aluno terá oito avaliações no ano. O Exemplo 5.4 mostra uma estrutura<br />

que po<strong>de</strong>ria ser utilizada para representar um aluno na linguagem C.<br />

1 type<strong>de</strong>f struct aluno {<br />

2 char nome [50];<br />

3 int matricula ;<br />

4 int ida<strong>de</strong> ;<br />

5 float notas [8];<br />

6 } tAluno ;<br />

DRAFT<br />

Exemplo 5.4: Definição da estrutura tAluno.<br />

A estrutura proposta no Exemplo 5.4 possui um vetor chamado nome, do tipo char e <strong>de</strong> tamanho<br />

igual a 50 para armazenar o nome <strong>com</strong>pleto <strong>de</strong> um aluno; duas variáveis do tipo int chamadas matricula<br />

e ida<strong>de</strong>, para armazenar, respectivamente, a matrícula do aluno e sua ida<strong>de</strong>; e um vetor do tipo float<br />

<strong>de</strong> tamanho igual a 8 chamado notas, para armazenar as notas <strong>de</strong>sse aluno.<br />

Repare que o nome do aluno po<strong>de</strong> ocupar um espaço menor que o tamanho máximo do vetor.<br />

Porém, não será possível armazenar um nome maior que o tamanho do vetor, o que po<strong>de</strong> ser um<br />

problema. Para tais casos <strong>de</strong>ve-se usar uma estrutura apropriada.<br />

No caso <strong>de</strong> um vetor <strong>com</strong> menos elementos do que o tamanho <strong>de</strong>finido, é necessário que esteja<br />

disponível uma informação explícita acerca <strong>de</strong> quantos elementos “<strong>de</strong> fato” o vetor armazena – uma<br />

quantida<strong>de</strong> que é menor ou igual ao seu tamanho máximo <strong>de</strong>finido. Por exemplo, uma outra variável<br />

(distinta do vetor) que indique quantos elementos o vetor armazena, ou, no caso <strong>de</strong> vetores <strong>de</strong> caracteres,<br />

o uso <strong>de</strong> um caractere específico que indica que, a partir <strong>de</strong>le, todos os outros elementos do


122<br />

CAPÍTULO 5. VETORES<br />

vetor (isto é, os elementos <strong>com</strong> índice maior) não tem um valor válido <strong>de</strong>finido. Vetores <strong>de</strong> caracteres,<br />

chamados <strong>de</strong> strings, serão discutidos em <strong>de</strong>talhes na Seção 5.5.<br />

É possível <strong>de</strong>finir o tamanho do vetor durante a execução. Isso po<strong>de</strong> ser implementado substituindo<br />

o número inteiro que é colocado entre colchetes na <strong>de</strong>claração do vetor por uma variável que só ganha<br />

um valor durante a execução do programa. O Exemplo 5.5 mostra <strong>com</strong>o isso po<strong>de</strong> ser feito na<br />

linguagem C.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int num ;<br />

5<br />

6 printf (" Quantas notas <strong>de</strong>seja armazenar ?");<br />

7 scanf ("%d", & num );<br />

8<br />

10<br />

9 float notas [ num ];<br />

11 return 0;<br />

12 }<br />

Exemplo 5.5: Definição <strong>de</strong> um vetor em tempo <strong>de</strong> execução.<br />

Repare que <strong>de</strong>clarando o vetor notas <strong>de</strong>ssa forma, o <strong>de</strong>sperdício <strong>de</strong> memória po<strong>de</strong> ser eliminado,<br />

já que o vetor é utilizado por <strong>com</strong>pleto. Isso po<strong>de</strong> ser feito <strong>de</strong>s<strong>de</strong> que o usuário tenha conhecimento<br />

prévio do número <strong>de</strong> elementos que serão armazenados e que ele possa informá-lo à aplicação.<br />

É importante ressalvar que essa forma dinâmica <strong>de</strong> <strong>de</strong>finição <strong>de</strong> tamanho não funciona no caso <strong>de</strong><br />

vetores <strong>de</strong>ntro <strong>de</strong> estruturas, <strong>com</strong>o o vetor notas da estrutura tAluno do Exemplo 5.4, por exemplo.<br />

No caso das estruturas o tamanho <strong>de</strong> cada atributo <strong>de</strong>ve, necessariamente, ser conhecido no momento<br />

da <strong>de</strong>finição da estrutura.<br />

O programador <strong>de</strong>ve ficar atento ao momento da <strong>de</strong>claração dinâmica do vetor. Note que, no<br />

Exemplo 5.5, o vetor notas só foi <strong>de</strong>clarado <strong>de</strong>pois <strong>de</strong> haver um valor válido na variável num. Um erro<br />

lógico aconteceria se o vetor fosse <strong>de</strong>clarado logo após a <strong>de</strong>claração da variável num, <strong>com</strong>o mostrado<br />

no Exemplo 5.6. Neste exemplo, o vetor notas não possui um tamanho válido, já que a variável num<br />

não foi inicializada até o momento da <strong>de</strong>claração do vetor. Na execução do programa, o vetor notas<br />

terá um tamanhjo qualquer e <strong>de</strong>sconhecido, possivelmente ina<strong>de</strong>quado para armazenar as notas.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int num ;<br />

5 float notas [ num ];<br />

6<br />

7 printf (" Quantas notas <strong>de</strong>seja armazenar ?");<br />

8 scanf ("%d", & num );<br />

9<br />

10 return 0;<br />

11 }<br />

DRAFT<br />

Exemplo 5.6: Definição errônea <strong>de</strong> um vetor em tempo <strong>de</strong> execução.<br />

5.4 Operações<br />

Na linguagem C não existem operações pré-<strong>de</strong>finidas para a manipulação <strong>de</strong> um vetor <strong>com</strong>o um todo.<br />

As operações só po<strong>de</strong>m ser feitas para cada elemento do vetor, individualmente.<br />

Como já mencionado na Seção 5.2, para acessar um elemento <strong>de</strong> um vetor, são necessários apenas<br />

seu nome e o índice que informa sua localização. Na linguagem C, a sintaxe <strong>de</strong> acesso a um elemento<br />

<strong>de</strong> um vetor é dada por:


5.4.<br />

OPERAÇÕES 123<br />

[]<br />

no qual o índice po<strong>de</strong> ser tanto um número inteiro maior ou igual a zero quanto uma expressão inteira<br />

<strong>com</strong>posta por variáveis e números.<br />

Um elemento acessado por um índice po<strong>de</strong> ser manipulado <strong>com</strong>o uma variável qualquer e ser<br />

utilizado em diversas operações, <strong>com</strong>o atribuição, operações aritméticas etc. O Exemplo 5.7 mostra<br />

algumas <strong>de</strong>ssas operações em C.<br />

1 # inclu<strong>de</strong> < stdio .h><br />

2<br />

3 int main (){<br />

4 int i;<br />

5 int medias [10];<br />

6<br />

7 printf (" Digite as notas dos alunos \n");<br />

8<br />

9 for (i =0;i


124<br />

CAPÍTULO 5. VETORES<br />

22 conta ++;<br />

23 }<br />

24 }<br />

25<br />

26 printf ("\n%d alunos obtiveram nota acima da media \n", conta );<br />

27<br />

28 return 0;<br />

29 }<br />

Exemplo 5.8: Resolução do exemplo do professor utilizando vetores.<br />

Na solução do problema do professor apresentada no Exemplo 5.8, as notas são lidas do teclado<br />

apenas uma vez; são, então, armazenados no vetor notas, e a soma total <strong>de</strong> notas é obtida, para,<br />

em seguida, ser calculado o valor da média das notas da turma. Então, as notas <strong>com</strong> valor acima<br />

da média po<strong>de</strong>m ser obtidas, via acesso ao vetor notas; não é necessário ler novamente as notas do<br />

teclado, <strong>com</strong>o foi preciso no Exemplo 5.2.<br />

Vetores po<strong>de</strong>m ser usados <strong>com</strong>o parâmetro <strong>de</strong> funções. Porém, é importante <strong>de</strong>stacar que vetores<br />

não po<strong>de</strong>m ser usados <strong>com</strong>o valores <strong>de</strong> retorno <strong>de</strong> funções, em C (ao contrário <strong>de</strong> estruturas, que<br />

po<strong>de</strong>m ser valores <strong>de</strong> retorno <strong>de</strong> funções).<br />

O Exemplo 5.9 mostra uma nova solução para o exemplo do professor, já tratado nos Exemplos<br />

5.2 e 5.8. Nesta nova solução, é utilizada modularização, e os sub-problemas do cálculo da média das<br />

notas e do cálculo da quantida<strong>de</strong> <strong>de</strong> notas acima da média são tratados <strong>com</strong> uso <strong>de</strong> funções. Estas<br />

funções recebem vetores <strong>com</strong>o parâmetros. Também, a quantida<strong>de</strong> <strong>de</strong> notas (tamanho do vetor) não<br />

é <strong>de</strong>finida <strong>com</strong>o uma contante, mas, sim, lida durante a execução do programa.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 float calculaMedia ( float vet [] , int tam ) {<br />

4 int i;<br />

5 float soma , media ;<br />

6<br />

7 soma = 0.0;<br />

8 for (i =0; i < tam ; i ++) {<br />

9 soma = soma + vet [i];<br />

10 }<br />

11<br />

12 media = soma / tam ;<br />

13<br />

14 return media ;<br />

15 }<br />

16<br />

17 int contaAcima ( float vet [] , int tam , float valor ) {<br />

18 int i, conta ;<br />

19<br />

20 conta = 0;<br />

21 for (i =0; i < tam ; i ++) {<br />

22 if(vet [i] > valor ){<br />

23 conta ++;<br />

24 }<br />

25 }<br />

26<br />

27 return conta ;<br />

28 }<br />

29<br />

30 int main () {<br />

31 int i, conta , qtd ;<br />

32 float media ;<br />

33<br />

DRAFT<br />

34 printf (" Informe a quantida<strong>de</strong> <strong>de</strong> notas que serao digitadas : ");<br />

35 scanf ("%d", & qtd );<br />

36<br />

37 float notas [ qtd ];<br />

38


5.5. STRINGS 125<br />

39 for (i =0; i < qtd ; i ++) {<br />

40 printf (" Digite uma nota : ");<br />

41 scanf ("%f", & notas [i]);<br />

42 }<br />

43<br />

44 media = calculaMedia ( notas , qtd );<br />

45 conta = contaAcima ( notas , qtd , media );<br />

46<br />

47 printf ("%d notas estao acima da media .\n", conta );<br />

48<br />

49 return 0;<br />

50 }<br />

Exemplo 5.9: Resolução do exemplo do professor <strong>com</strong> utilização <strong>de</strong> vetores e funções.<br />

No Exemplo 5.9, inicialmente, é lida a quantida<strong>de</strong> total <strong>de</strong> notas a serem informadas. Essa informação<br />

é armazenada na variável qtd e usada na <strong>de</strong>claração do vetor notas. Após as notas serem<br />

todas lidas a partir do teclado, a média <strong>de</strong>ssas notas é calculada, <strong>com</strong> uso da função calculaMedia,<br />

e o valor <strong>de</strong> retorno <strong>de</strong>ssa função é armazenado na variável media. Em seguida, é verificada a quantida<strong>de</strong><br />

<strong>de</strong> alunos que obtiveram nota maior que a média, <strong>com</strong> uso da função contaAcima, e o valor <strong>de</strong><br />

retorno <strong>de</strong>ssa função é armazenado na variável conta. Finalmente, é exibida a a quantida<strong>de</strong> <strong>de</strong> notas<br />

que ficaram acima da média.<br />

5.5 Strings<br />

O vetor <strong>de</strong> elementos do tipo char do Exemplo 5.3, chamado nome, assim <strong>com</strong>o todos os vetores<br />

do tipo char, po<strong>de</strong>m ser consi<strong>de</strong>rados <strong>de</strong> um novo tipo, o tipo string. Strings correspon<strong>de</strong>m a uma<br />

sequência <strong>de</strong> caracteres. Geralmente, são usadas para realizar a entrada e saída <strong>de</strong> dados em um<br />

programa e para armazenar dados não numéricos.<br />

É <strong>com</strong>um representar uma string <strong>com</strong>o um vetor <strong>de</strong> caracteres (tipo char), dispondo das mesmas<br />

operações <strong>com</strong>uns a essa estrutura <strong>de</strong> dados. A Figura 5.3 exemplifica a representação <strong>de</strong> uma string<br />

<strong>com</strong>o um vetor <strong>de</strong> caracteres.<br />

DRAFT<br />

Figura 5.3: Vetor <strong>de</strong> caracteres.<br />

Toda string armazenada em um vetor é terminada por um caracter especial, conhecido <strong>com</strong>o<br />

caracter nulo ‘\0’. A principal função <strong>de</strong>sse caracter é indicar o fim <strong>de</strong> uma string, evitando um acesso<br />

in<strong>de</strong>sejado a uma posição do vetor que se encontra “vazia”. O programa do Exemplo 5.10 <strong>de</strong>monstra<br />

uma forma não usual <strong>de</strong> apresentar strings, mas aplica o conceito <strong>de</strong> caracter nulo.<br />

1 void apresenta_string ( char palavra []) {<br />

2 int i;<br />

3<br />

4 for (i =0; palavra [i ]!= ‘\0 ’; i ++) {<br />

5 printf ("% c", palavra [i]);<br />

6 }<br />

7<br />

8 printf ("\ n"); // quebra <strong>de</strong> linha .<br />

9 }<br />

Exemplo 5.10: Subprograma para apresentação <strong>de</strong> strings, utilizando diretamente o ‘\0’.<br />

No Exemplo 5.10, a condição <strong>de</strong> parada do laço for é encontrar o caracter ‘\0’, e, durante cada<br />

iteração, cada caracter do vetor é apresentado separadamente. A forma mais <strong>com</strong>um (e simples) <strong>de</strong><br />

apresentar uma string é a mostrada no Exemplo 5.11.


126<br />

CAPÍTULO 5. VETORES<br />

1 void apresenta_string ( char palavra []) {<br />

2 printf ("%s\n", palavra );<br />

3 }<br />

Exemplo 5.11: Apresentação <strong>de</strong> uma string sem a utilização direta do caracter “barra-zero”.<br />

O programa do Exemplo 5.11 produz o mesmo resultado do Exemplo 5.10, porém, no 5.11 o<br />

caracter ‘\0’ é verificado implicitamente pela função printf.<br />

A biblioteca padrão <strong>de</strong> C ainda oferece algumas funções muito úteis para a manipulação <strong>de</strong> strings,<br />

<strong>com</strong>o a strcpy (cópia), a strlen (tamanho) e a strcmp (<strong>com</strong>paração). O Exemplo 5.12 <strong>de</strong>monstra o<br />

uso <strong>de</strong>ssas funções.<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> < string .h> // funcoes da biblioteca padrao para manipulacao <strong>de</strong> strings<br />

3<br />

4 int main (){<br />

5 char vet1 [20] = " ola enfermeira ";<br />

6 char vet2 [20];<br />

7 char vet3 [20];<br />

8<br />

10<br />

9 printf (" Tamanho da string : %d \n\n", strlen ( vet1 ));<br />

11 strcpy (vet2 , vet1 );<br />

12<br />

13 printf ("%s \n %s \n\n", vet1 , vet2 );<br />

14<br />

15 strcpy (vet3 , " sim senhor ");<br />

16<br />

17 printf ("%s \n\n", vet3 );<br />

18<br />

19 if( strcmp (vet1 , vet2 ) == 0){<br />

20 printf ("As strings sao iguais ");<br />

21 } else {<br />

22 printf ("As strings sao diferentes ");<br />

23 }<br />

24<br />

25 if( strcmp (vet1 , vet3 ) == 0){<br />

26 printf ("As strings sao iguais ");<br />

27 } else {<br />

28 printf ("As strings sao diferentes ");<br />

29 }<br />

30<br />

31 return 0;<br />

32 }<br />

DRAFT<br />

Exemplo 5.12: Programa <strong>de</strong>monstrativo <strong>de</strong> algumas funções da biblioteca padrão <strong>de</strong> C para<br />

manipulação <strong>de</strong> strings.<br />

A primeira linha <strong>de</strong>ntro da função main mostra uma maneira <strong>de</strong> criar um vetor, no caso do exemplo<br />

o vetor chamado vet1, e já preenchê-lo <strong>com</strong> valores (linha 5). Em seguida são <strong>de</strong>clarados mais dois<br />

vetores <strong>de</strong> caracteres: vet2 e vet3, ambos <strong>de</strong> tamanho igual a 20. Depois disso as funções da biblioteca<br />

padrão string.h são utilizadas para, respectivamente: apresentar o tamanho da string em vet1, <strong>com</strong><br />

a função strlen (linha 9); copiar o conteúdo <strong>de</strong> vet1 em vet2, <strong>com</strong> a função strcpy e em seguida<br />

apresentá-los na tela <strong>com</strong> a função printf da biblioteca stdio.h (linhas 11 e 13); copiar a string “sim<br />

senhor” para <strong>de</strong>ntro do vetor vet3 e em seguida apresentar seu conteúdo na tela (linhas 15 e 17); e,<br />

finalmente, <strong>com</strong>parar o conteúdo das strings contidas em vet1 e vet2 (linhas 19 a 23), e vet1 e vet3<br />

(linhas 25 a 29) <strong>com</strong> a função strcmp.<br />

Para o uso da função strcpy, a or<strong>de</strong>m dos parâmetros é <strong>de</strong> suma importância; o primeiro parâmetro<br />

é o vetor <strong>de</strong> <strong>de</strong>stino da string que se <strong>de</strong>seja copiar, enquanto o segundo é o vetor <strong>de</strong> origem da string.<br />

Em relação a função strcmp, ela retorna o valor zero se as strings armazenadas em ambos os vetores<br />

forem iguais (letras maiúsculas são consi<strong>de</strong>radas diferentes das minúsculas).


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 127<br />

5.6 O TAD Implementacional Lista Vetorial <strong>de</strong> Inteiros<br />

Como dito na seção 5.4, na linguagem C não existem operações básicas para a manipulação <strong>de</strong> vetores<br />

<strong>com</strong>o um todo. Porém a manipulação individual <strong>de</strong> todos os seus elementos po<strong>de</strong> ser muito trabalhosa<br />

e muitas vezes operações <strong>com</strong>uns <strong>de</strong>vem ser repetidas várias vezes ao longo do código do programa. Por<br />

isso, as operações básicas sobre um vetor <strong>de</strong>vem ser modularizadas pela utilização <strong>de</strong> subprogramas<br />

e, para isso, a utilização <strong>de</strong> um TAD se mostra oportuna.<br />

Nessa seção será apresentado na linguagem C o TAD Lista Vetorial <strong>de</strong> Inteiros, <strong>de</strong> natureza implementacional,<br />

chamado tListaVetInt, que po<strong>de</strong>rá ser usado em aplicações que necessitam manipular<br />

vetores <strong>de</strong> inteiros.<br />

5.6.1 Atributos<br />

O Exemplo 5.13 mostra a representação da estrutura utilizada no TAD Implementacional tListaVetInt.<br />

Ela contém um vetor e o número <strong>de</strong> elementos correntes do vetor.<br />

1 # <strong>de</strong>fine TAM 100<br />

2<br />

3 type<strong>de</strong>f struct vetor {<br />

4 int vet [ TAM ];<br />

5 int n;<br />

6 } tListaVetInt ;<br />

Exemplo 5.13: Definição da Estrutura tListaVetInt.<br />

O Exemplo 5.13 mostra a <strong>de</strong>finição da estrutura tListaVetInt. Ela possui um vetor <strong>de</strong> inteiros<br />

chamado vet, <strong>de</strong> tamanho <strong>de</strong>finido por TAM e uma variável n do tipo int que representa o número<br />

corrente <strong>de</strong> elementos em vet, ou seja, o número <strong>de</strong> elementos armazenados no vetor num <strong>de</strong>terminado<br />

momento da execução do programa. Esse valor <strong>de</strong>ve ser zero quando o vetor estiver vazio e<br />

<strong>de</strong>ve ser incrementado ou <strong>de</strong>crementado sempre que se adicionar ou excluir um elemento do vetor,<br />

respectivamente.<br />

A primeira linha do código do Exemplo 5.13 indica que TAM é uma constante <strong>de</strong> valor 100. Esse<br />

artifício é bastante utilizado quando se trabalha <strong>com</strong> vetores <strong>com</strong> tamanho máximo, já que permite<br />

que uma alteração no valor <strong>de</strong> TAM no início do código modifique os tamanhos <strong>de</strong> todos os vetores<br />

do código que utilizam TAM para <strong>de</strong>finir seu tamanho.<br />

A Figura 5.4 mostra uma maneira simples <strong>de</strong> representar graficamente a estrutura proposta no<br />

Exemplo 5.13.<br />

DRAFT<br />

Figura 5.4: Representação gráfica da estrutura tListaVetInt.<br />

A figura mostra duas estruturas do tipo tListaVetInt. Como po<strong>de</strong> ser observado, apesar <strong>de</strong> vet<br />

possuir tamanho igual a 100, ele possui apenas 8 elementos na primeira estrutura e 5 na segunda,<br />

valores representados pela variável n.


128<br />

CAPÍTULO 5. VETORES<br />

5.6.2 Operações<br />

Agora serão ilustradas as funções que <strong>de</strong>vem ser utilizadas <strong>com</strong>o operações para manipular a estrutura<br />

tListaVetInt. Tal <strong>com</strong>o visto no capítulo anterior, essas operações se divi<strong>de</strong>m em quatro categorias<br />

diferentes: construtoras, analizadoras, produtoras e modificadoras.<br />

Construtoras<br />

As operações construturas do TAD tListaVetInt são usadas na criação <strong>de</strong> novas variáveis <strong>de</strong>sse tipo.<br />

Após <strong>de</strong>finir uma nova variável do tipo tListaVetInt, é necessário que uma função construtura do<br />

TAD seja chamada e então receba essa variável <strong>com</strong>o parâmetro; isto é, é necessário usar uma função<br />

construtura antes <strong>de</strong> se usar qualquer outra função do TAD. Serão apresentadas duas funções construtoras:<br />

uma que inicializa uma variável tListaVetInt que não possui nenhum elemento armazenado,<br />

e outra que inicializa uma variável tListaVetInt já <strong>com</strong> alguns elementos armazenados.<br />

O Exemplo 5.14 apresenta a função construtora inicializacaoVaziaListaVetInt, que inicializa<br />

uma variável do tipo tListaVetInt sem elementos armazenados.<br />

1 tListaVetInt inicializacaoVaziaListaVetInt ( tListaVetInt v){<br />

2 v.n = 0;<br />

3<br />

4 return v;<br />

5 }<br />

Exemplo 5.14: Inicialização <strong>de</strong> um tListaVetInt vazio.<br />

Repare que a função tem <strong>com</strong>o tipo <strong>de</strong> retorno uma estrutura do tipo tListaVetInt, ou seja, antes<br />

<strong>de</strong>sta função ser utilizada, uma variável <strong>de</strong>ste tipo <strong>de</strong>ve ser <strong>de</strong>clarada no programa para receber o<br />

retorno da função.<br />

O Exemplo 5.15 mostra o código da função leituraListaVetInt que inicializa o TAD já <strong>com</strong><br />

alguns que <strong>de</strong>vem ser inseridos pelo usuário, por meio do teclado.<br />

1 tListaVetInt leituraListaVetInt ( tListaVetInt v, int num ){<br />

2 int i;<br />

3<br />

4 for (i =0; i


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 129<br />

O Exemplo 5.16 apresenta uma função analisadora simples: a partir do primeiro elemento, sequencialmente<br />

e até o último elemento do vetor, a função <strong>com</strong>para esse elemento <strong>com</strong> o informado no<br />

parâmetro <strong>de</strong> entrada; se o elemento for encontrado, a função encerra e retorna seu índice. Já se o<br />

final do vetor for alcançado e o elemento não for encontrado, a função retorna “−1”.<br />

1 int pesquisaSequencialListaVetInt ( tListaVetInt v, int elem ){<br />

2 int i;<br />

3<br />

4 for (i =0; i


130<br />

CAPÍTULO 5. VETORES<br />

FIM -SE<br />

FIM -SE<br />

FIM - ENQUANTO<br />

Retornar -1.<br />

FIM - Processo <strong>com</strong>ponente " busca binária "<br />

1 int pesquisaBinariaListaVetInt ( tListaVetInt v, int elem ){<br />

2 int inicio ;<br />

3 int fim ;<br />

4 int meio ;<br />

5<br />

6 inicio = 0;<br />

7<br />

8 fim = v.n - 1;<br />

9<br />

10 while ( inicio v. vet [ meio ]){<br />

17 inicio = meio + 1;<br />

18 } else {<br />

19 return meio ;<br />

20 }<br />

21 }<br />

22 }<br />

23<br />

24 return -1;<br />

25 }<br />

Exemplo 5.17: Pesquisa binária.<br />

A função pesquisaBinariaListaVetInt, do Exemplo 5.17, recebe <strong>com</strong>o parâmetro <strong>de</strong> entrada a<br />

estrutura do tipo tListaVetInt que possui o vetor que se <strong>de</strong>seja pesquisar e o elemento a ser encontrado.<br />

São <strong>de</strong>claradas, então, três variáveis: inicio, fim e meio. A variável inicio recebe o valor do índice<br />

do menor elemento do vetor, ou seja, zero, e fim recebe o valor do índice do maior elemento, ou<br />

seja, v.n−1. Enquanto o valor <strong>de</strong> inicio for menor ou igual ao valor <strong>de</strong> fim, meio recebe o índice do<br />

elemento central da região por eles <strong>de</strong>limitada. É exatamente esse elemento central que sempre será<br />

<strong>com</strong>parado ao elemento procurado. Se aquele for maior que este, em virtu<strong>de</strong> da or<strong>de</strong>nação do vetor,<br />

todos os elementos posteriores ao central são também maiores que o elemento procurado. Logo, fim<br />

<strong>de</strong>ve receber o valor do índice anterior a meio. Caso contrário, todos os elementos anteriores ao central<br />

são menores que o elemento procurado. Logo, inicio <strong>de</strong>ve receber o valor do índice posterior a meio.<br />

Se nenhuma das duas alternativa acontecerem, quer dizer que o elemento foi encontrado e seu índice<br />

é igual a meio. Se em algum momento inicio passar a ser maior que fim, então o elemento não existe<br />

no vetor e a busca é encerrada.<br />

As Figuras 5.5 e 5.6 mostram o funcionamento do algoritmo do Exemplo 5.17 para duas pesquisas<br />

diferentes.<br />

A Figura 5.5 ilustra as etapas da busca do elemento 4 <strong>de</strong>ntro do vetor vet da estrutura do tipo<br />

tListaVetInt mostrada na figura. Primeiramente inicio e fim adquirem os valores 0 e 10, respectivamente.<br />

Como inicio é menor que fim, meio recebe o índice 5, e o elemento apontado por ele, o valor<br />

10, é <strong>com</strong>parado ao valor procurado. Como 10 é maior que 4, fim recebe o índice 4. Como inicio<br />

continua menor que fim, meio recebe o índice 2. Dessa vez, o elemento apontado por meio é igual ao<br />

elemento procurado. A função retorna, então, o valor <strong>de</strong> seu índice: 2.<br />

A Figura 5.6 apresenta três etapas da busca pelo elemento 23 no mesmo vetor apresentado na<br />

Figura 5.5. Inicialmente, inicio e fim adquirem os valores 0 e 10, respectivamente. Como inicio é<br />

menor que fim, meio recebe o índice 5, e o elemento apontado por ele, <strong>de</strong> valor 10, é <strong>com</strong>parado<br />

DRAFT


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 131<br />

Figura 5.5: Etapas da pesquisa binária <strong>com</strong> o elemento procurado no início do vetor.<br />

DRAFT<br />

Figura 5.6: Etapas da pesquisa binária <strong>com</strong> o elemento procurado no final do vetor.<br />

ao valor procurado. Então, já que 10 é menor que 23, inicio recebe o índice 6. Em seguida, <strong>com</strong>o<br />

inicio continua menor que fim, meio recebe o índice 8, e o elemento apontado por ele, o valor 19, é<br />

<strong>com</strong>parado ao valor procurado. Novamente, 19 é menor que 23, e inicio recebe o índice 9. E <strong>com</strong>o<br />

inicio continua menor que fim, meio também recebe o índice 9. O elemento apontado por meio é<br />

<strong>com</strong>parado ao elemento buscado, e, <strong>de</strong>sta vez, os valores são iguais. Então, a função retorna o valor 9.<br />

É importante <strong>de</strong>stacar que, na busca apresentada na Figura 5.6, o algoritmo <strong>de</strong> pesquisa binária faz<br />

apenas três <strong>com</strong>parações <strong>de</strong> valores; já o algoritmo <strong>de</strong> pesquisa sequencial realizaria <strong>de</strong>z <strong>com</strong>parações,<br />

pois o elemento buscado ocupa a décima posição.<br />

Produtoras<br />

As funções produtoras geram novas informações que resultam <strong>de</strong> operações sobre vetores. Por exemplo,<br />

a escrita, o tamanho da lista, o elemento presente em uma posição <strong>de</strong>terminada, a adição <strong>de</strong> vetores<br />

e o produto escalar entre vetores.<br />

O Exemplo 5.18 apresenta uma função que retorna a quantida<strong>de</strong> atual <strong>de</strong> elementos armazenados.


132<br />

CAPÍTULO 5. VETORES<br />

1 int tamListaVetInt ( tListaVetInt v){<br />

2 return v.n;<br />

3 }<br />

Exemplo 5.18: Obtenção do tamanho do vetor.<br />

O Exemplo 5.19 apresenta uma função que retorna um elemento <strong>de</strong> uma <strong>de</strong>terminada posição do<br />

vetor.<br />

1 int iesimoElemListaVetInt ( tListaVetInt v, int i) {<br />

2 return v. vet [i];<br />

3 }<br />

Exemplo 5.19: Obtenção do i-esimo elemento do vetor.<br />

O Exemplo 5.20 apresenta uma função que imprime todos os elementos armazenados.<br />

1 void escritaListaVetInt ( tListaVetInt v) {<br />

2 int i;<br />

3<br />

4 printf ("\n\ nOs elementos sao :\n");<br />

5<br />

6 for (i =0; i < v.n; i ++) {<br />

7 printf ("%d ", v. vet [i]);<br />

8 }<br />

9<br />

10 printf ("\n\n");<br />

11 }<br />

Exemplo 5.20: Escrita em tela.<br />

O Exemplo 5.21 apresenta uma função que recebe duas variáveis do tipo tListaVetInt, as quais<br />

<strong>de</strong>vem ter a mesma quantida<strong>de</strong> <strong>de</strong> elementos; então, uma nova variável do tipo tListaVetInt é criada,<br />

que armazenará, <strong>com</strong>o seu elemento <strong>de</strong> índice i, o valor que é a soma dos valores na posição i em<br />

cada uma das duas variáveis <strong>de</strong> entrada. Caso as duas variáveis <strong>de</strong> entrada possuam vetores <strong>de</strong><br />

tamanhos diferentes, uma mensagem <strong>de</strong> erro é exibida, e a variável retornada armazenará um vetor<br />

sem elementos.<br />

DRAFT<br />

1 tListaVetInt adicaoListaVetInt ( tListaVetInt v1 , tListaVetInt v2) {<br />

2 int i;<br />

3 tListaVetInt soma ;<br />

4<br />

5 if (v1.n != v2.n) {<br />

6 printf (" Vetores <strong>com</strong> tamanhos diferentes \n");<br />

7 soma .n = 0;<br />

8 } else {<br />

9 soma .n = v1.n;<br />

10 for (i =0; i < soma .n; i ++) {<br />

11 soma . vet [i] = v1.vet [i] + v2.vet [i];<br />

12 }<br />

13 }<br />

14<br />

15 return soma ;<br />

16 }<br />

Exemplo 5.21: Adição <strong>de</strong> dois vetores.<br />

O Exemplo 5.22 apresenta uma função que calcula o produto escalar entre dois vetores. Para isto,<br />

os vetores <strong>de</strong>vem possuir o mesmo número <strong>de</strong> elementos correntes; senão, uma mensagem <strong>de</strong> erro é<br />

exibida, e o retorno terá valor “0”.


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 133<br />

1 int prodEscalarListaVetInt ( tListaVetInt v1 , tListaVetInt v2) {<br />

2 int i;<br />

3 int prod ;<br />

4<br />

5 prod = 0;<br />

6<br />

7 if (v1.n != v2.n) {<br />

8 printf (" Vetores <strong>com</strong> tamanhos diferentes \n");<br />

9 } else {<br />

10 for (i =0; i < v1.n; i ++) {<br />

11 prod = prod + v1.vet [i] * v2.vet [i];<br />

12 }<br />

13 }<br />

14<br />

15 return prod ;<br />

16 }<br />

Modificadoras<br />

Exemplo 5.22: Produto escalar entre dois vetores.<br />

Operações modificadoras realizam alterações nos elementos da variável tListaVetInt à qual são aplicadas.<br />

Nesta seção, serão apresentadas funções que inserem um elemento, que excluem um elemento,<br />

e que or<strong>de</strong>nam os elementos armazenados no vetor.<br />

A função apresentada no Exemplo 5.23 realiza a inserção <strong>de</strong> um elemento numa posição pré<strong>de</strong>terminada.<br />

A função insereListaVetInt recebe <strong>com</strong>o parâmetros <strong>de</strong> entrada uma variável do tipo<br />

tListaVetInt (que será modificada), o valor do elemento a ser inserido e a posição na qual isso <strong>de</strong>ve<br />

ocorrer. No código da função, a valida<strong>de</strong> da posição informada é avaliada; se esta for inválida – <strong>com</strong><br />

valor menor que 0 ou maior que o tamanho do vetor –, uma mensagem <strong>de</strong> erro é apresentada e o<br />

elemento não é inserido. Em caso contrário, o tamanho do vetor é aumentado em 1, significando que<br />

um elemento adicional foi inserido na posição <strong>de</strong> maior índice; então, cada elemento já armazenado<br />

no vetor é movido uma posição à direita, até que se chegue à posição da inserção. O elemento a<br />

ser inserido é copiado no elemento <strong>de</strong> índice <strong>de</strong>sejado. Por fim, a variável tListaVetInt modificada é<br />

retornada.<br />

Pseudocódigo 5.3 Processo <strong>com</strong>ponente para inserção <strong>de</strong> um elemento numa posição pré-<strong>de</strong>finida.<br />

DRAFT<br />

Descrição: Inserir um elemento em uma posição pré-<strong>de</strong>finida.<br />

Dados <strong>de</strong> Entrada: Estrutura do tipo lista vetorial <strong>de</strong> inteiros, elemento a ser inserir (elem), posição <strong>de</strong><br />

inserção (pos).<br />

Saída do Programa: Estrutura do tipo lista vetorial atualizada.<br />

Processo <strong>com</strong>ponente " insere no vetor ":<br />

SE a posiç~ao on<strong>de</strong> será inserido for menor que zero OU a posiç~ao on<strong>de</strong> será<br />

inserido for maior que o tamanho do vetor<br />

Apresentar a mensagem : Entrada <strong>de</strong> Dados Incorreta .<br />

SEN~AO<br />

Incrementa a quantida<strong>de</strong> <strong>de</strong> elementos do vetor .<br />

PARA um loop da quantida<strong>de</strong>s <strong>de</strong> elementos do vetor menos 1 à posiç~ao on<strong>de</strong><br />

será inserido menos 1 FAÇA:<br />

Posiç~ao posterior recebe o valor da posiç~ao anterior .<br />

FIM - PARA<br />

Atribui o elemento a ser inserido para a posiç~ao a ser inserido .<br />

FIM -SE<br />

FIM - Processo <strong>com</strong>ponente " insere no vetor "<br />

1 tListaVetInt insereListaVetInt ( tListaVetInt v, int elem , int pos ) {<br />

2 int i;


134<br />

CAPÍTULO 5. VETORES<br />

v.vet 1 2 3 4 5<br />

elem 10 pos 3<br />

v.n 5<br />

v.vet 1 2 3 4 5<br />

elem 10 pos 3<br />

v.n 6<br />

3<br />

v.vet 1 2 3 4 5 5<br />

v.n 6<br />

v.vet 1 2 3 4 4 5<br />

v.n 6<br />

v.vet 1 2 3 10 4 5<br />

v.n 6<br />

elem 10 pos 3<br />

elem 10 pos 3<br />

elem 10 pos 3<br />

Figura 5.7: Etapas da inserção <strong>de</strong> um elemento em uma posição especificada.<br />

4 if (( pos < 0) || ( pos > v.n)) {<br />

5 printf (" Entrada <strong>de</strong> Dados Incorreta ");<br />

6 } else {<br />

7 v.n ++;<br />

8 for (i=v.n - 2; i > pos - 1; i - -) {<br />

9 v. vet [i +1] = v. vet [i];<br />

10 }<br />

11 v. vet [i +1] = elem ;<br />

12 }<br />

13<br />

14 return v;<br />

15 }<br />

DRAFT<br />

Exemplo 5.23: Inserção em uma posição pré-<strong>de</strong>terminada.<br />

A função apresentada no Exemplo 5.24 realiza a exclusão <strong>de</strong> todos os elementos que possuem valor<br />

igual ao valor informado <strong>com</strong>o parâmetro. A função excluiListaVetInt verifica cada elemento do<br />

vetor, do primeiro elemento ao último, e quando encontra um elemento <strong>com</strong> valor igual ao valor a ser<br />

excluído, esse elemento é apagado; para isso, cada elemento à frente <strong>de</strong>ste elemento a ser excluído é<br />

movido uma posição à esquerda, e, em seguida, o tamanho do vetor é reduzido em um. Após realizar<br />

a exclusão <strong>de</strong> um elemento, a função prossegue a busca no vetor, até verificar todos os elementos. Por<br />

fim, a variável tListaVetInt modificada é retornada.<br />

Pseudocódigo 5.4 Processo <strong>com</strong>ponente para excluir elementos <strong>de</strong> um vetor que possuem um valor<br />

especificado.<br />

Descrição: Exclui elementos <strong>de</strong> um vetor.<br />

Dados <strong>de</strong> Entrada: Estrutura do tipo lista vetorial <strong>de</strong> inteiros, valor a ser excluido.<br />

Saída do Programa: Estrutura do tipo lista vetorial atualizada.<br />

Processo <strong>com</strong>ponente " excluir do vetor ":<br />

Atraibuir 0 variável pos.


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 135<br />

ENQUANTO variável pos for menor que o tamanho do vetor<br />

SE valor na posiç~ao pos for igual ao elemento a ser excluido<br />

PARA variável i variando da posiç~ao pos a penúltima posiç~ao do vetor FAÇA<br />

:<br />

Atribuir ao valor na posiç~ao i o valor da posiç~ao i + 1.<br />

FIM - PARA<br />

Tamanho do votor é subtraido <strong>de</strong> 1.<br />

SEN~AO<br />

Variável pos é acrescida <strong>de</strong> 1.<br />

FIM -SE<br />

FIM - ENQUANTO<br />

FIM - Processo <strong>com</strong>ponente " excluir do vetor "<br />

1 tListaVetInt excluiListaVetInt ( tListaVetInt v, int elem ) {<br />

2 int i, pos ;<br />

3<br />

4 pos = 0;<br />

5 while ( pos < v.n) {<br />

6 if (v. vet [ pos ] == elem ) {<br />

7 for (i= pos ; i < v.n - 1; i ++) {<br />

8 v. vet [i] = v. vet [i +1];<br />

9 }<br />

10 v.n - -;<br />

11 } else {<br />

12 pos ++;<br />

13 }<br />

14 }<br />

15<br />

16 return v;<br />

17 }<br />

Exemplo 5.24: Exclusão <strong>de</strong> elementos <strong>com</strong> um valor especificado.<br />

v.vet 1 2 3 10 4 5<br />

v.n 6<br />

v.vet 1 2 3 4 4 5<br />

v.n 6<br />

elem 10<br />

elem 10<br />

DRAFT<br />

v.vet 1 2 3 4 5 5<br />

v.n 6<br />

v.vet 1 2 3 4 5<br />

v.n 5<br />

elem 10<br />

elem 10<br />

Figura 5.8: Etapas da exclusão <strong>de</strong> elementos <strong>com</strong> um valor especificado.<br />

A função apresentada no Exemplo 5.25 realiza a or<strong>de</strong>nação dos elementos armazenados na variável<br />

tListaVetInt.<br />

Ambas colocam em or<strong>de</strong>m crescente os elementos <strong>de</strong> um vetor, mas utilizando métodos diferentes.<br />

A função or<strong>de</strong>naMenorListaVetInt utiliza uma estratégia <strong>de</strong>nominada “método do menor elemento”.<br />

Ela recebe uma variável do tipo tListaVetInt, cujo vetor será or<strong>de</strong>nado. Inicialmente, a função verifica


136<br />

CAPÍTULO 5. VETORES<br />

todos os elementos do vetor, e localiza a posição do elemento <strong>de</strong> menor valor; então, esse elemento é<br />

trocado <strong>com</strong> o elemento na primeira posição do vetor. Assim, neste momento, o primeiro elemento do<br />

vetor já contém o menor valor. Em seguida, a função busca a posição do segundo menor elemento do<br />

vetor, e, quando este elemento é encontrado, ele é trocado <strong>com</strong> o segundo elemento do vetor. Assim,<br />

neste momento, os dois primeiros elementos do vetor já estão corretamente or<strong>de</strong>nados. De forma<br />

semelhante, são também or<strong>de</strong>nados o terceiro, o quarto, e assim sucessivamente, até o penúltimo<br />

elemento do vetor. Por fim, a variável tListaVetInt modificada é retornada.<br />

Pseudocódigo 5.5 Processo <strong>com</strong>ponente para or<strong>de</strong>nar um vetor <strong>de</strong> forma crescente.<br />

Descrição: Or<strong>de</strong>na um vetor <strong>de</strong> forma crescente.<br />

Dados <strong>de</strong> Entrada: Estrutura do tipo lista vetorial <strong>de</strong> inteiros.<br />

Saída do Programa: Estrutura do tipo lista vetorial or<strong>de</strong>nada crescentemente.<br />

Processo <strong>com</strong>ponente " or<strong>de</strong>na crescente ":<br />

PARA variável pos variando <strong>de</strong> 0 até penúltima posiç~ao FAÇA:<br />

Atribuir a variável menor o valor do elemento do vetor na posiç~ao pos.<br />

Atribuir a variável indice menor valor da variável pos.<br />

PARA variável i variando <strong>de</strong> pos + 1 até última posiç~ao FAÇA:<br />

SE o elemento na posiç~ao i for menor que menor<br />

Atribuir a variável menor o valor do elemento do vetor na posiç~ao i.<br />

Atribuir a variável indice menor o valor da variável i.<br />

SE - FIM<br />

FIM - PARA<br />

Atribuir ao elemento do vetor na posiç~ao indice menor o valor do elemento do<br />

vetor na posiç~ao pos.<br />

Atribuir ao elemento do vetor na posiç~ao pos o valor da variável menor.<br />

FIM - PARA<br />

FIM - Processo <strong>com</strong>ponente " or<strong>de</strong>na crescente "<br />

1 tListaVetInt or<strong>de</strong>naMenorListaVetInt ( tListaVetInt v) {<br />

2 int pos , i, indice_menor , menor ;<br />

3<br />

4 for ( pos =0; pos < v.n - 1; pos ++) {<br />

5 menor = v. vet [ pos ];<br />

6 indice_menor = pos ;<br />

7 for (i= pos +1; i < v.n; i ++) {<br />

8 if (v. vet [i] < menor ) {<br />

9 menor = v. vet [i];<br />

10 indice_menor = i;<br />

11 }<br />

12 }<br />

13<br />

DRAFT<br />

14 v. vet [ indice_menor ] = v. vet [ pos ];<br />

15 v. vet [ pos ] = menor ;<br />

16 }<br />

17<br />

18 return v;<br />

19 }<br />

Exemplo 5.25: Or<strong>de</strong>nação pelo método do menor elemento.<br />

A Figura 5.9 ilustra o funcionamento do algoritmo <strong>de</strong> or<strong>de</strong>nação pelo método do menor elemento.<br />

A função apresentada no Exemplo 5.26 também realiza a or<strong>de</strong>nação dos elementos do vetor, mas<br />

utiliza uma estratégia diferente da do método do menor elemento; esta estratégia é <strong>de</strong>nominada<br />

método da bolha. A função or<strong>de</strong>naBolhaListaVetInt recebe <strong>com</strong>o parâmetro <strong>de</strong> entrada a variável<br />

tListaVetInt cujo vetor será or<strong>de</strong>nado. Então, a função percorre o vetor por <strong>com</strong>pleto, do elemento<br />

<strong>de</strong> maior índice para o elemento <strong>de</strong> menor índice, a cada etapa <strong>com</strong>parando o elemento <strong>de</strong> índice i<br />

<strong>com</strong> o elemento <strong>de</strong> índice i − 1, e trocando-os se o elemento <strong>de</strong> maior índice possui valor menor do


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 137<br />

Figura 5.9: Método do menor.<br />

DRAFT<br />

que o elemento <strong>de</strong> menor índice. Após percorrer uma vez o vetor, o elemento <strong>de</strong> menor valor fica<br />

armazenado na primeira posição do vetor. Então, o algoritmo ignora esse primeiro elemento, e repete<br />

o procedimento para todo o restante do vetor. Este procedimento é repetido uma quantida<strong>de</strong> <strong>de</strong><br />

vezes igual ao número total <strong>de</strong> elementos armazenados menos um. Por fim, a variável tListaVetInt<br />

modificada é retornada.<br />

Pseudocódigo 5.6 Processo <strong>com</strong>ponente método da bolha.<br />

Descrição: Or<strong>de</strong>na um vetor <strong>de</strong> forma crescente usando o método da bolha.<br />

Dados <strong>de</strong> Entrada: Estrutura do tipo lista vetorial <strong>de</strong> inteiros.<br />

Saída do Programa: Estrutura do tipo lista vetorial or<strong>de</strong>nada crescentemente.<br />

Processo <strong>com</strong>ponente "método da bolha ":<br />

Atribuir verda<strong>de</strong>iro à variável houve troca.<br />

Atribuir à variável limite a quantida<strong>de</strong> <strong>de</strong> elementos da estrutura do tipo lista<br />

vetorial <strong>de</strong> inteiros passada <strong>com</strong>o entrada menos um.<br />

ENQUANTO houve troca for verda<strong>de</strong>iro FAÇA:<br />

Atribuir falso a variável houve troca.<br />

PARA variável i variando <strong>de</strong> 0 a limite FAÇA:<br />

SE elemento do vetor na posiç~ao i for maior que o elemento do vetor na<br />

posiç~ao i + 1


138<br />

CAPÍTULO 5. VETORES<br />

Troque o valor entre os elementos dos vetor nas posiç~oes i e i + 1.<br />

Atribuir verda<strong>de</strong>iro a variável houve troca.<br />

Atribuir o valor <strong>de</strong> i -1 à variável limite<br />

FIM -SE<br />

FIM - PARA<br />

FIM - ENQUANTO<br />

FIM - Processo <strong>com</strong>ponente "método da bolha "<br />

1 tListaVetInt or<strong>de</strong>naBolhaListaVetInt ( tListaVetInt v) {<br />

2 int i, temp , houve_troca , limite ;<br />

3<br />

4 limite = v.n -1;<br />

5 houve_troca = 1;<br />

6 while ( houve_troca == 1) {<br />

7 houve_troca = 0;<br />

8 for (i =0; i < limite ; i ++) {<br />

9 if (v. vet [i] > v. vet [i +1]) {<br />

10 temp = v. vet [i];<br />

11 v. vet [i] = v. vet [i +1];<br />

12 v. vet [i +1] = temp ;<br />

13 houve_troca = 1;<br />

14 limite = i -1;<br />

15 }<br />

16 }<br />

17 }<br />

18<br />

19 return v;<br />

20 }<br />

Exemplo 5.26: Or<strong>de</strong>nação pelo método da bolha.<br />

A Figura 5.10 ilustra o funcionamento do algoritmo <strong>de</strong> or<strong>de</strong>nação pelo método da bolha.<br />

Exemplo <strong>de</strong> Utilização do TAD tListaVetInt<br />

Será apresentado agora um exemplo <strong>de</strong> utilização do TAD tListaVetInt. Vale lembrar que o Exemplo<br />

5.27 apresenta apenas o programa principal contendo a chamada das funções <strong>de</strong>finidas até aqui.<br />

Para seu funcionamento correto, todas as funções <strong>de</strong>vem estar <strong>de</strong>finidas anteriormente no arquivo do<br />

programa.<br />

1 int main (){<br />

2 tListaVetInt vet1 ;<br />

3 tListaVetInt vet2 ;<br />

4 tListaVetInt vet3 ;<br />

5 int elem ;<br />

6 int pos ;<br />

7 int prodEscalar ;<br />

8 int enter ;<br />

9<br />

10 vet1 = leituraListaVetInt (vet1 ,10) ;<br />

11 vet2 = leituraListaVetInt (vet2 ,10) ;<br />

12 vet3 = inicializacaoVaziaListaVetInt ( vet3 );<br />

13<br />

14 printf (" Vet1 :");<br />

15 exibeListaVetInt ( vet1 );<br />

16<br />

17 printf (" Vet2 :");<br />

18 exibeListaVetInt ( vet2 );<br />

19<br />

DRAFT<br />

20 printf ("\n\ nQual elemento <strong>de</strong>seja localizar utilizando a pesquisa sequencial ?\n\n")<br />

;<br />

21 scanf ("%d", & elem );


5.6. O TAD IMPLEMENTACIONAL LISTA VETORIAL DE INTEIROS 139<br />

22<br />

Figura 5.10: Método da bolha<br />

23 pos = pesquisaSequencialListaVetInt (vet1 , elem );<br />

24<br />

25 if(pos >= 0){<br />

DRAFT<br />

26 printf ("\n\ nElemento encontrado na posicao %d\n\n", pos );<br />

27 } else {<br />

28 printf ("\n\ nElemento nao encontrado \n\n");<br />

29 }<br />

30<br />

31 printf ("\n\ nQual elemento <strong>de</strong>seja localizar utilizando a pesquisa binaria ?\n\n");<br />

32 scanf ("%d", & elem );<br />

33<br />

34 pos = pesquisaBinariaListaVetInt (vet1 , 3);<br />

35<br />

36 if(pos >= 0){<br />

37 printf ("\n\ nElemento encontrado na posicao %d\n\n", pos );<br />

38 } else {<br />

39 printf ("\n\ nElemento nao encontrado \n\n");<br />

40 }<br />

41<br />

42 vet3 = adicaoListaVetInt (vet1 , vet2 , vet3 );<br />

43<br />

44 printf (" Vet1 :");


140<br />

CAPÍTULO 5. VETORES<br />

45 exibeListaVetInt ( vet1 );<br />

46<br />

47 printf (" Vet2 :");<br />

48 exibeListaVetInt ( vet2 );<br />

49<br />

50 printf (" Vet3 :");<br />

51 exibeListaVetInt ( vet3 );<br />

52 prodEscalar = prodEscalarListaVetInt (vet1 , vet2 );<br />

53<br />

54 printf ("\n\n");<br />

55 printf (" Vet1 :");<br />

56 exibeListaVetInt ( vet1 );<br />

57<br />

58 printf (" Vet2 :");<br />

59 exibeListaVetInt ( vet2 );<br />

60<br />

61 printf ("\n\ nProduto escalar = %d\n\n", prodEscalar );<br />

62<br />

63 vet3 = leituraListaVetInt (vet3 , 0);<br />

64 vet3 = insereListaVetInt (vet3 , 5, 0);<br />

65<br />

66 printf (" Vet3 :");<br />

67 exibeListaVetInt ( vet3 );<br />

68<br />

69 vet3 = insereListaVetInt (vet3 , 3, 0);<br />

70<br />

71 printf (" Vet3 :");<br />

72 exibeListaVetInt ( vet3 );<br />

73<br />

74 vet3 = insereListaVetInt (vet3 , 7, 1);<br />

75<br />

76 printf (" Vet3 :");<br />

77 exibeListaVetInt ( vet3 );<br />

78<br />

79 vet3 = insereListaVetInt (vet3 , 10 , 3);<br />

80<br />

81 printf (" Vet3 :");<br />

82 exibeListaVetInt ( vet3 );<br />

83<br />

84 vet3 = excluiListaVetInt (vet3 , 3);<br />

85<br />

86 printf (" Vet3 :");<br />

87 exibeListaVetInt ( vet3 );<br />

88<br />

89 vet3 = excluiListaVetInt (vet3 , 7);<br />

90<br />

91 printf (" Vet3 :");<br />

92 exibeListaVetInt ( vet3 );<br />

93<br />

94 vet3 = excluiListaVetInt (vet3 , 10) ;<br />

95<br />

96 printf (" Vet3 :");<br />

97 exibeListaVetInt ( vet3 );<br />

98<br />

99 vet3 = excluiListaVetInt (vet3 , 5);<br />

100<br />

101 printf (" Vet3 :");<br />

102 exibeListaVetInt ( vet3 );<br />

103<br />

104 vet1 = or<strong>de</strong>naMenorListaVetInt ( vet1 );<br />

105<br />

106 printf (" Vet1 :");<br />

107 exibeListaVetInt ( vet1 );<br />

108<br />

109 vet2 = or<strong>de</strong>naBolhaListaVetInt ( vet2 );<br />

110<br />

DRAFT


5.7.<br />

EXERCÍCIOS RESOLVIDOS 141<br />

111 printf (" Vet2 :");<br />

112 exibeListaVetInt ( vet2 );<br />

113<br />

114 return 0;<br />

115 }<br />

Exemplo 5.27: Exemplo <strong>de</strong> Utilização do TAD tListaVetInt.<br />

5.7 Exercícios Resolvidos<br />

Exercício Resolvido 5.1 - Soma <strong>de</strong> um vetor <strong>de</strong> 100 inteiros<br />

Crie uma função do tipo lista vetorial <strong>de</strong> inteiros na linguagem C que some os elementos <strong>de</strong> um<br />

vetor <strong>com</strong> ’n’ elementos inteiros.<br />

Solução Possível:<br />

É mostrada uma possível solução no Pseudocódigo 5.7 e no Exemplo 5.28:<br />

Pseudocódigo 5.7 Passos a serem realizados pela função Soma <strong>de</strong> 100 elementos <strong>de</strong> um vetor<br />

<strong>de</strong> inteiros.<br />

Descrição: Calcular a soma dos 100 elementos <strong>de</strong> um vetor <strong>de</strong> inteiros.<br />

Dados <strong>de</strong> Entrada: Elemento do tipo lista vetorial <strong>de</strong> inteiros e a quantida<strong>de</strong> n <strong>de</strong> elementos.<br />

Saída do Programa: A soma dos elementos.<br />

Processo <strong>com</strong>ponente " soma <strong>de</strong> n elementos <strong>de</strong> um vetor <strong>de</strong> inteiros "<br />

Atribuir 0 a variável soma.<br />

PARA variável i variando <strong>de</strong> 0 à n -1 FAÇA:<br />

Somar a variável soma o valor do elemento do vetor na posiç~ao i.<br />

FIM - PARA<br />

Retornar o valor <strong>de</strong> soma.<br />

FIM - Processo <strong>com</strong>ponente " soma <strong>de</strong> n elementos <strong>de</strong> um vetor <strong>de</strong> inteiros "<br />

1 int somaElementosListaVetInt ( TListaVetInt v, int n){<br />

2 int i, soma ;<br />

3 soma = 0;<br />

4 for (i =0; i


142<br />

CAPÍTULO 5. VETORES<br />

Pseudocódigo 5.8 Passos a serem realizados pela função apresenta os 100 primeiros números<br />

primos.<br />

Descrição: Apresentar os 100 primeiros números primos.<br />

Dados <strong>de</strong> Entrada: Não existe.<br />

Saída do Programa: Os 100 primeios números primos.<br />

Processo <strong>com</strong>ponente " apresenta os 100 primeiros números primos "<br />

Atribuir 2 à primeira posiç~ao do vetor primos .<br />

Atribuir 1 a v a r i v e l contador .<br />

Atribuir 3 a v a r i v e l numero .<br />

ENQUANTO a variável contador for menor que 100 FAÇA:<br />

Atribuir o valor da raiz quadrada da variável numero a variável limite .<br />

Atribuir 1 a variável eh_primo .<br />

PARA variável i variando <strong>de</strong> 0 até limite FAÇA:<br />

SE o resto da divis~ao da variável numero pelo valor do vetor primos na<br />

posiç~ao i for igual a 0<br />

Atribuir 0 a variável eh_primo .<br />

INTERROMPER o PARA .<br />

FIM -SE<br />

FIM - PARA<br />

SE a variável eh_primo for igual a 1<br />

Atribuir numero ao vetor primos na p o s i o contador .<br />

Incrementar 1 a variável contador.<br />

FIM -SE<br />

Incrementar 2 a variável numero .<br />

FIM - ENQUANTO<br />

PARA variável i variando <strong>de</strong> 0 até 100 FAÇA:<br />

Apresentar o valor do vetor primos na posiç~ao i.<br />

FIM - PARA<br />

FIM - Processo <strong>com</strong>ponente " apresenta os 100 primeiros números primos "<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> <br />

3<br />

4 int main (){<br />

5 int primos [100];<br />

6 int contador , numero , i, eh_primo ;<br />

7 float limite ;<br />

8<br />

9 primos [0] = 2;<br />

10 contador = 1;<br />

11 numero = 3;<br />

12<br />

13 while ( contador < 100) {<br />

14 limite = sqrt ( numero );<br />

15 eh_primo = 1;<br />

16 for (i =0; primos [i]


5.7.<br />

EXERCÍCIOS RESOLVIDOS 143<br />

30 printf ("%d\n", primos [i]);<br />

31 }<br />

32<br />

33 return 0;<br />

34 }<br />

Exemplo 5.29: Programa que apresenta os 100 primeiros números primos.<br />

Exercício Resolvido 5.3 - Intercala dois vetores <strong>de</strong> inteiros previamente or<strong>de</strong>nados<br />

Faça um programa em linguagem C que leia dois vetores or<strong>de</strong>nados em M e N elementos respectivamente<br />

e os intercale gerando um novo vetor U, também or<strong>de</strong>nado. Consi<strong>de</strong>re o exemplo:<br />

M: 5<br />

N: 4<br />

Primeiro vetor :<br />

1 7 13 14 30<br />

Segundo vetor :<br />

2 3 7 16<br />

Resultado :<br />

1 2 3 7 7 13 14 16 30<br />

Obs.: O terceiro vetor não po<strong>de</strong> ser gerado copiando-se primeiramente os dois vetores e fazendo a<br />

or<strong>de</strong>nação posteriormente.<br />

Solução Possível:<br />

É mostrada uma possível solução no Pseudocódigo 5.9 e no Exemplo 5.30:<br />

Pseudocódigo 5.9 Passos a serem realizados pela função intercala.<br />

Descrição: Intercalar dois vetores <strong>de</strong> inteiros previamente or<strong>de</strong>nados.<br />

Dados <strong>de</strong> Entrada: Três estruturas TListaVetInt, duas contendo os vetores or<strong>de</strong>nados e U.<br />

Saída do Programa: Estrutura TListaVetInt contendo o vetor intercalado.<br />

Processo <strong>com</strong>ponente " intercala "<br />

Inicializar as v a r i v e i s i,j, e k <strong>com</strong> 0.<br />

ENQUANTO a variável i for menor que o tamanho do vetor contido em A e j for menor<br />

que o tamanho do vetor contido em B passados <strong>com</strong>o argumento para a funç~ao<br />

FAÇA:<br />

SE o elemento da posiç~ao i do vetor contido em A for menor ou igual ao<br />

elemento da posiç~ao j do vetor contido em B<br />

Atribuir ao elemento da posiç~ao k do vetor contido em U o valor do<br />

elemento da posiç~ao i do vetor contido em A.<br />

Incrementar 1 a variável i.<br />

SEN~AO<br />

Atribuir ao elemento da posiç~ao k do vetor contido em U o valor do<br />

elemento da posiç~ao j do vetor contido em B.<br />

Incrementar 1 a variável j.<br />

FIM -SE<br />

Incrementar 1 a variável k.<br />

FIM - ENQUANTO<br />

PARA variável iAux variando <strong>de</strong> i até o tamanho do vetor contido em A FAÇA:<br />

Atribuir ao elemento da posiç~ao k do vetor contido em U o valor do elemento<br />

da posiç~ao iAux do vetor contido em A.<br />

Incrementar 1 a variável k.<br />

FIM - PARA<br />

PARA variável iAux variando <strong>de</strong> j até o tamanho do vetor contido em B FAÇA:<br />

Atribuir ao elemento da posiç~ao k do vetor contido em U o valor do elemento<br />

da posiç~ao iAux do vetor contido em B.<br />

Incrementar 1 a variável k.<br />

FIM - PARA<br />

Atribuir a variável n contida em U a soma dos tamanhos dos vetores contidos em A<br />

e B.<br />

Retornar o valor <strong>de</strong> U.<br />

FIM - Processo <strong>com</strong>ponente " intercala "<br />

DRAFT


144<br />

CAPÍTULO 5. VETORES<br />

1 # inclu<strong>de</strong> < stdio .h><br />

2<br />

3 # <strong>de</strong>fine TAM 100<br />

4<br />

5 TListaVetInt intercalaListaVetInt ( TListaVetInt U, TListaVetInt A, TListaVetInt B){<br />

6<br />

7 int i = 0, j = 0, k = 0, iAux ;<br />

8<br />

9 while (i


5.7.<br />

EXERCÍCIOS RESOLVIDOS 145<br />

Pseudocódigo 5.10 Passos a serem realizados pela função calcula fatuamento armazém.<br />

Descrição: Calcular o faturamento do armazém.<br />

Dados <strong>de</strong> Entrada: Dois vetores, um <strong>com</strong> as quantida<strong>de</strong>s <strong>de</strong> produtos e um <strong>com</strong> os preços dos produtos.<br />

Saída do Programa: Faturamento do armazém.<br />

Processo <strong>com</strong>ponente " calcula faturamento armazém"<br />

Utiliza funç~ao prodEscalarListaVetInt já <strong>de</strong>finida para obter o faturamento .<br />

FIM - Processo <strong>com</strong>ponente " calcula faturamento armazém"<br />

1 float calculaFaturamentoArmazem ( TListaVetInt quantida<strong>de</strong> , TListaVetInt precos ){<br />

2 return prodEscalarListaVetInt ( quantida<strong>de</strong> , precos );<br />

3 }<br />

Exemplo 5.31: Função que calcula o faturamento do armazém.<br />

Exercício Resolvido 5.5 - Gerencia <strong>de</strong> Turmas e Cursos<br />

Você foi contratado para fazer um programa em C para processar algumas informações a respeito<br />

dos alunos do seu curso. Para tanto o coor<strong>de</strong>nador do curso te forneceu uma listagem <strong>com</strong> as médias<br />

finais obtidas em cada disciplina cursada pelos alunos do curso. Portanto, cada linha da listagem<br />

contém o código da disciplina (um valor inteiro positivo), a matrícula do aluno (um valor inteiro<br />

positivo) e a média final obtida pelo aluno (um valor ponto flutuante não negativo). Você <strong>de</strong>ve:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Definir as estruturas <strong>de</strong> dados que serão usadas no programa.<br />

Criar uma função para a leitura dos dados da listagem.<br />

Criar uma função para or<strong>de</strong>nar crescentemente a listagem por disciplina cursada e por matrícula<br />

do aluno, isto é, os dados da listagem <strong>de</strong>vem ficar or<strong>de</strong>nados crescentemente por código da<br />

disciplina e, em uma mesma disciplina, or<strong>de</strong>nados crescentemente por matrícula.<br />

Criar uma função que receba a matrícula <strong>de</strong> um aluno, um código <strong>de</strong> disciplina e os dados<br />

or<strong>de</strong>nados da listagem (conforme item c), utilize uma pesquisa binária para encontrar a nota<br />

obtida por esse aluno na disciplina e retorne essa nota ou o ponto flutuante -1.0, caso o aluno<br />

não tenha cursado esta disciplina. Observe que só há registros na listagem da última vez que<br />

os alunos cursaram a disciplina, isto é, não há registros repetidos <strong>de</strong> um mesmo aluno em uma<br />

disciplina.<br />

DRAFT<br />

Criar um programa que leia os dados da listagem, or<strong>de</strong>ne-os conforme item c, leia a matrícula<br />

<strong>de</strong> um aluno e o código <strong>de</strong> uma disciplina e diga se ele cursou a disciplina e qual nota obteve, se<br />

for o caso.<br />

É um requisito do programa que a passagem <strong>de</strong> parâmetros para as funções seja realizada sem que haja<br />

gasto <strong>de</strong> uma gran<strong>de</strong> quantida<strong>de</strong> <strong>de</strong> memória. Note que os dados não estão or<strong>de</strong>nados na listagem.<br />

Consi<strong>de</strong>re ainda que existem no máximo 30 disciplinas distintas no curso e que não existem mais <strong>de</strong><br />

100 alunos no curso. A leitura dos dados <strong>de</strong>ve ser encerrada quando for lido um código <strong>de</strong> disciplina<br />

igual a zero. Um exemplo <strong>de</strong> listagem é apresentado na tabela 5.11:<br />

Solução Possível:<br />

Para facilitar <strong>de</strong>finiu-se as constantes mostradas em 5.32, que são os limites exigidos no exercício:<br />

1 # <strong>de</strong>fine TAM_ALUNO 100<br />

2 # <strong>de</strong>fine TAM_DISCIPLINAS 30<br />

Exemplo 5.32: Constantes


146<br />

CAPÍTULO 5. VETORES<br />

Código da Disciplina Matrícula Média Final<br />

121 1313 4.1<br />

27 2222 9.3<br />

121 2032 6.1<br />

17 1313 4.2<br />

121 4546 3.8<br />

322 2222 8.0<br />

0 0 0.0<br />

Figura 5.11: Exemplo <strong>de</strong> listagem<br />

A estrutura que foi <strong>de</strong>finida para a resolução do problema é apresentada em 5.33:<br />

1 type<strong>de</strong>f struct {<br />

2 int codigo ;<br />

3 int matricula ;<br />

4 float media ;<br />

5 } registro ;<br />

Exemplo 5.33: Estruturas<br />

Para fazer a leitura dos códigos das disciplinas, das matrículas e das notas, faz-se um loop que<br />

percorre o arquivo <strong>de</strong> entrada e guarda-se o código da disciplina, a matrícula do aluno e a média em<br />

um vetor <strong>de</strong> estruturas do tipo registro, que foi <strong>de</strong>finida para esse exercício.<br />

É mostrada uma possível implementação para a leitura no Pseudocódigo 5.11 e no Exemplo 5.34:<br />

Pseudocódigo 5.11 Passos a serem realizados pela função leitura.<br />

Descrição: Faz a leitura das disciplinas, matrículas e notas.<br />

Dados <strong>de</strong> Entrada: Nome do arquivo <strong>de</strong> on<strong>de</strong> será lido, e vetor da estrutura disciplinas.<br />

Saída do Programa: Quantida<strong>de</strong> <strong>de</strong> disciplinas.<br />

Processo <strong>com</strong>ponente " leitura "<br />

EQUANTO<br />

Ler do arquivo <strong>de</strong> entrada o código da disciplina , a matrícula e a media do<br />

aluno<br />

SE código da disciplina for zero<br />

PARAR EQUANTO<br />

SEN~AO<br />

Armazena na estrutura registro os valores lidos .<br />

FIM -SE<br />

Incrementa a quantida<strong>de</strong> <strong>de</strong> alunos nessa disciplina<br />

FIM - ENQUANTO<br />

FIM - Processo <strong>com</strong>ponente " leitura "<br />

DRAFT<br />

1 int leitura ( char entrada [] , registro reg []) {<br />

2 int quant , cod , mat ;<br />

3 float med ;<br />

4 FILE *f;<br />

5<br />

6 f = fopen ( entrada ,"r");<br />

7<br />

8 if(f == NULL ){<br />

9 printf (" Erro ao abrir o arquivo para leitura .\n");<br />

10 exit (1) ;<br />

11 }<br />

12


5.7.<br />

EXERCÍCIOS RESOLVIDOS 147<br />

13 quant = 0;<br />

14<br />

15 while (1) {<br />

16 fscanf (f,"%d%d%f" ,&cod ,& mat ,& med );<br />

17 if(reg [ quant ]. codigo == 0){<br />

18 break ;<br />

19 }<br />

20 else {<br />

21 reg [ quant ]. codigo = cod ;<br />

22 reg [ quant ]. matricula = mat ;<br />

23 reg [ quant ]. media = med ;<br />

24 }<br />

25 quant ++;<br />

26 }<br />

27<br />

28 return quant ;<br />

29 }<br />

Exemplo 5.34: Programa que faz a leitura das disciplinas, matrículas e notas.<br />

A or<strong>de</strong>nação é feita usando-se um método da bolha mais simplificado do que aquele que foi apresentado<br />

neste capítulo. Primeiro or<strong>de</strong>na-se <strong>de</strong> forma crescente <strong>de</strong> acordo <strong>com</strong> o código da disciplina.<br />

Se as disciplinas forem <strong>de</strong> mesmo código or<strong>de</strong>na-se pela matrícula do aluno.<br />

1 void or<strong>de</strong>na ( registro reg [] , int n){<br />

2 registro regAux ;<br />

3 int i,j;<br />

4<br />

5 for (i =0;i


148<br />

CAPÍTULO 5. VETORES<br />

10 if( inicio == fim ){<br />

11 return -1;<br />

12 }<br />

13 else {<br />

14 if(reg [ pivot ]. codigo < cod ){<br />

15 return buscaBinariaDisciplina (cod , reg , pivot + 1, fim );<br />

16 }<br />

17 else {<br />

18 return buscaBinariaDisciplina (cod , reg , inicio , pivot - 1);<br />

19 }<br />

20 }<br />

21 }<br />

Exemplo 5.36: Programa que usa busca binária para encontrar uma <strong>de</strong>terminada disciplina.<br />

1 float busca ( int cod , int mat , registro reg [] , int n){<br />

2 int pos , i;<br />

3<br />

4 pos = buscaBinariaDisciplina (cod , reg , 0, n);<br />

5<br />

6 if(pos == -1){<br />

7 return -1.0;<br />

8 }<br />

9<br />

10 if(reg [ pos ]. matricula < mat ){<br />

11 for (i = pos ; reg [i]. codigo == cod && i < n;i ++) {<br />

12 if(reg [i]. matricula == mat ){<br />

13 return reg [i]. media ;<br />

14 }<br />

15 }<br />

16 }<br />

17 else {<br />

18 for (i= pos ; reg [i]. codigo == cod && i >= 0;i - -){<br />

19 if(reg [ pos ]. matricula == mat ){<br />

20 return reg [ pos ]. media ;<br />

21 }<br />

22 }<br />

23 }<br />

24<br />

25 return -1.0;<br />

26 }<br />

DRAFT<br />

Exemplo 5.37: Programa que usa busca binária para encontrar um <strong>de</strong>terminado aluno.<br />

Por fim temos o Exemplo 5.38 que une todas as funcionalida<strong>de</strong>s mostradas e exibe a nota do aluno<br />

em uma <strong>de</strong>terminada matéria.<br />

1 void sistemaDisciplina ( char entrada []) {<br />

2 registro reg [ TAM_ALUNO * TAM_DISCIPLINAS ];<br />

3 int n, mat , cod ;<br />

4 float nota ;<br />

5<br />

6 n = leitura ( entrada , reg );<br />

7 or<strong>de</strong>na (reg , n);<br />

8<br />

9 printf (" Digite a matricula do aluno : ");<br />

10 scanf ("%d", & mat );<br />

11<br />

12 printf (" Digite o codigo da disciplina : ");<br />

13 scanf ("%d", & cod );<br />

14<br />

15 nota = busca (cod , mat , reg , n);<br />

16<br />

17 if( nota == -1.0) {


5.8. RESUMO 149<br />

18 printf (" Aluno ou disciplina inexistente .\n");<br />

19 }<br />

20 else {<br />

21 printf ("A nota do aluno %d na disciplina %d foi : %f\n", mat , cod , nota );<br />

22 }<br />

23 }<br />

5.8 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Exemplo 5.38: Programa final que usa todas as outras funções acima.<br />

Um vetor é uma estrutura <strong>de</strong> dados <strong>com</strong>posta e homogênea, isto é, ele possui, em geral, mais <strong>de</strong><br />

um elemento <strong>de</strong> um mesmo tipo.<br />

São características importantes dos vetores a sequencialização, a in<strong>de</strong>xação e a sua dimensão.<br />

Deve-se tomar cuidado para não se acessar um vetor in<strong>de</strong>vidamente, <strong>com</strong>o por exemplo utilizando<br />

um índice maior que seu tamanho.<br />

A dimensão <strong>de</strong> um vetor po<strong>de</strong> ser <strong>de</strong>finida, em C, tanto em tempo <strong>de</strong> <strong>com</strong>pilação, quanto em<br />

tempo <strong>de</strong> execução.<br />

Na linguagem C não existem operações básicas para a manipulação <strong>de</strong> um vetor <strong>com</strong>o um todo.<br />

Seus elementos <strong>de</strong>vem ser manipulado separadamente.<br />

Quando acessado individualmente, cada elemento <strong>de</strong> um vetor po<strong>de</strong> ser encarado <strong>com</strong>o uma<br />

variável básica.<br />

A utilização <strong>de</strong> expressões <strong>com</strong>o índice no acesso a elementos <strong>de</strong> um vetor é uma ferramenta<br />

po<strong>de</strong>rosa.<br />

A utilização <strong>de</strong> funções para a manipulação <strong>de</strong> vetores <strong>com</strong>o um todo é importante para a<br />

legibilida<strong>de</strong> e reusabilida<strong>de</strong> do programa e <strong>de</strong>ve ser usada.<br />

A utilização <strong>de</strong> TAD’s Implementacionais é um artifício para facilitar a manipulação <strong>de</strong> vetores<br />

e aumentar a legibilida<strong>de</strong> e reusabilida<strong>de</strong> do programa.<br />

O TAD Implementacional TListaVetInt, implementado aqui na linguagem C, po<strong>de</strong> ser utilizado,<br />

sempre que necessário, para a manipulação <strong>de</strong> vetores <strong>de</strong> números inteiros.<br />

5.9 Exercícios Propostos<br />

DRAFT<br />

1. Implemente uma operação do tipo lista vetorial <strong>de</strong> inteiros que inverta a sequência na qual se<br />

encontram na lista. Use essa operação e as operações <strong>de</strong> leitura e escrita para fazer um programa<br />

na linguagem C que leia 100 números inteiros e os apresente na or<strong>de</strong>m inversa em que foram<br />

lidos.<br />

2. Faça um programa em linguagem C que leia N (N < 1000) números <strong>de</strong> matrículas <strong>de</strong> alunos que<br />

fazem Programação 1 e os coloque em or<strong>de</strong>m crescente num vetor à medida que vão sendo lidas<br />

as matrículas. Posteriormente escreva uma função que i<strong>de</strong>ntifique se um certo conjunto <strong>de</strong> M<br />

alunos fazem Programação 1. Deve-se utilizar o algoritmo <strong>de</strong> pesquisa binária para fazer esta<br />

verificação.<br />

3. Faça um programa em linguagem C que:<br />

(a) leia N números reais colocando-os num vetor <strong>de</strong> 100 elementos (consi<strong>de</strong>rar N < 1000);


150<br />

CAPÍTULO 5. VETORES<br />

(b) or<strong>de</strong>ne crescentemente os elementos <strong>de</strong> índices ímpares utilizando o método da bolha para<br />

tal (consi<strong>de</strong>rar apenas os N elementos);<br />

(c) escreva os N números após o ajuste do ítem (b).<br />

4. Crie um procedimento em linguagem C que cumpra a seguinte especificação:<br />

(a) Dados <strong>de</strong> entrada:<br />

i. um vetor <strong>de</strong> caracteres <strong>com</strong> um máximo <strong>de</strong> 100 elementos;<br />

ii. o tamanho corrente do vetor (suponha que o vetor inicie na primeira posição);<br />

iii. um caractere a ser inserido;<br />

iv. a posição do vetor on<strong>de</strong> o caractere <strong>de</strong>ve ser inserido.<br />

(b) Dados <strong>de</strong> saída:<br />

i. o vetor <strong>com</strong> o caractere inserido na posição;<br />

ii. o vetor <strong>de</strong>ve ser mantido inalterado se a posição on<strong>de</strong> <strong>de</strong>veria ser inserido o carctere<br />

superior ao tamanho corrente do vetor ou se o vetor já estiver <strong>com</strong>pleto.<br />

5. Baseado no tipo vetorial <strong>de</strong> inteiros crie um novo tipo e escreva um algoritmo em linguagem C<br />

que:<br />

(a) leia um conjunto A <strong>de</strong> 100 elementos reais;<br />

(b) construa e apresente um outro conjunto B formado da seguinte maneira:<br />

i. os elementos <strong>de</strong> or<strong>de</strong>m par são os correspon<strong>de</strong>ntes <strong>de</strong> A divididos por 2;<br />

ii. os elementos <strong>de</strong> or<strong>de</strong>m ímpar são os correspon<strong>de</strong>ntes <strong>de</strong> A multiplicados por 3.<br />

6. Dado um vetor contendo uma frase <strong>com</strong> 80 caracteres (incluindo espaços em branco), escreva<br />

um algoritmo em linguagem C para:<br />

(a) contar quantos brancos existem na frase;<br />

(b) contar quantas vezes aparece a letra ’A’;<br />

(c) contar quantas vezes aparece um mesmo par <strong>de</strong> letras na frase e quais são eles.<br />

7. Faça um algoritmo em linguagem C para ler um vetor <strong>de</strong> <strong>com</strong>primento N (para N


5.9.<br />

EXERCÍCIOS PROPOSTOS 151<br />

14. O Colegiado <strong>de</strong> seu curso mantém uma listagem <strong>com</strong> informações sobre o <strong>de</strong>sempenho <strong>de</strong> cada<br />

aluno do curso. Esta listagem contém as notas obtidas pelo aluno em cada uma das disciplinas<br />

que ele cursou e é organizada da seguinte maneira (note que as notas <strong>de</strong> um aluno nas disciplinas<br />

não estão necessariamente em sequência):<br />

Matrícula do Aluno Código da Disciplina Carga Horária Nota<br />

00018 0001 60 4.5<br />

11111 3232 30 8.7<br />

00234 0500 75 9.0<br />

00018 0001 60 7.0<br />

00234 0500 90 9.5<br />

.<br />

.<br />

.<br />

.<br />

09999 0786 60 7.5<br />

Figura 5.12: Exemplo <strong>de</strong> listagem<br />

Para facilitar a consulta a esta listagem, o coor<strong>de</strong>nador do colegiado precisa <strong>de</strong> um programa<br />

que realize algumas operações sobre os dados da lista. Ele te pediu para que você elabore este<br />

programa. Para isso, ele pe<strong>de</strong> para que você faça:<br />

(a) Um suprograma que leia os dados da lista.<br />

(b) Um subprograma que imprima as notas obtidas por um aluno numa <strong>de</strong>terminada disciplina.<br />

Lembre-se que o aluno po<strong>de</strong> ter cursado mais <strong>de</strong> uma vez uma mesma disciplina por motivo<br />

<strong>de</strong> reprovação.<br />

(c) Um subprograma que exclua todos os dados <strong>de</strong> um aluno que foi jubilado.<br />

(d) Um subprograma que calcule o coeficiente <strong>de</strong> rendimento (C.R.) <strong>de</strong> um aluno. Lembre-se<br />

que o C.R. é calculado da seguinte maneira:<br />

C.R. = ( ∑ (Carga Horária x Nota )) / ( ∑ (Carga Horária))<br />

(e) Um programa interativo que permita ao usuário:<br />

Ler os dados da listagem.<br />

Imprimir as notas <strong>de</strong> um aluno numa disciplina.<br />

Excluir um aluno jubilado.<br />

Calcular o C.R. <strong>de</strong> um aluno.<br />

DRAFT<br />

Observações: Assuma que existem, no máximo, 1000 (mil) alunos no seu curso.<br />

15. Uma gran<strong>de</strong> empresa capixaba necessita fazer um estudo sobre os salários pagos aos seus funcionários.<br />

Para tanto, ela dispões <strong>de</strong> uma listagem on<strong>de</strong> constam as matrículas e os salários <strong>de</strong><br />

cada um <strong>de</strong>les (tal <strong>com</strong>o na Figura 5.13).<br />

Funcionário Salário<br />

00001 1500.00<br />

12897 300.00<br />

00032 734.00<br />

09000 1886.00<br />

00666 1201.00<br />

.<br />

.<br />

12345 1113.00<br />

Figura 5.13: Exemplo <strong>de</strong> listagem


152<br />

CAPÍTULO 5. VETORES<br />

Sabendo <strong>de</strong> tua gran<strong>de</strong> <strong>com</strong>petência <strong>com</strong>o programador, a empresa te contratou para elaborar<br />

um programa interativo que produza algumas informações para o estudo. A partir dos dados da<br />

listagem, o programa <strong>de</strong>ve:<br />

(a) Ler os dados da lista.<br />

(b) Calcular o salário médio da empresa.<br />

Salário médio =( ∑ salários) / (total <strong>de</strong> funcionários)<br />

(c) Calcular o percentual <strong>de</strong> funcionários que ganham abaixo do salário médio.<br />

Perc. Abaixo =(número quad <strong>de</strong> func. abaixo x 100) / (total <strong>de</strong> funcionários)<br />

(d) Calcular o percentual da <strong>de</strong>spesa total em salários que é pago aos funcionários que ganham<br />

o maior salário.<br />

Perc. Maior = ( ∑ maiores salários x 100) / ( ∑ salários)<br />

16. Consi<strong>de</strong>re uma seqüência <strong>de</strong> números inteiros não negativos armazenada em uma lista vetorial<br />

<strong>de</strong> inteiros. Os elementos da seqüência estão em qualquer or<strong>de</strong>m e po<strong>de</strong>m ocorrer subseqüências<br />

<strong>de</strong> números repetidos. Por exemplo, na seqüência:<br />

S1= 4, 4, 5, 9, 1023, 4, 4, 4, 4, 2, 7, 4, 6, 6, 7, 8, 8, 8, 8, 3<br />

existem 4 subseqüências <strong>de</strong> elementos repetidos (duas <strong>de</strong> 4, uma <strong>de</strong> tamanho 2 e outra <strong>de</strong><br />

tamanho 4, a <strong>de</strong> 6 <strong>com</strong> 2, e a <strong>de</strong> 8 <strong>com</strong> 4). Escreva um subprograma que tenha <strong>com</strong>o parâmetro<br />

uma lista vetorial <strong>de</strong> inteiros v preenchida <strong>com</strong> uma sequência qualquer <strong>de</strong> números inteiros<br />

não negativos, um número natural x especificando um possível <strong>com</strong>ponente da seqüência e um<br />

tamanho t. O objetivo do subprograma é localizar em v, a menor subseqüência <strong>de</strong> elementos<br />

iguais a x <strong>com</strong> tamanho mínimo igual a t. O retorno da função <strong>de</strong>ve ser o índice do primeiro<br />

elemento <strong>de</strong>sta subseqüência. Para a seqüência S1 acima, se o argumento da busca (x) é 4 e o<br />

tamanho (t) é 3 o resultado retornado <strong>de</strong>verá ser 5. Se não for encontrada uma seqüência que<br />

satisfaça a condição, <strong>de</strong>ve ser retornado -1.<br />

17. O <strong>com</strong>itê organizador dos jogos pan-americanos <strong>de</strong> 2007, no Rio <strong>de</strong> Janeiro, <strong>de</strong>seja apresentar os<br />

resultados da <strong>com</strong>petição indicando o total <strong>de</strong> medalhas <strong>de</strong> ouro, prata e bronze <strong>de</strong> cada país.<br />

Faça um programa em C para apresentar esses resultados. Os dados <strong>de</strong>vem ser lidos da entrada<br />

padrão <strong>de</strong> uma listagem organizada <strong>com</strong>o no exemplo seguinte (cada linha da listagem apresenta<br />

o resultado <strong>de</strong> uma <strong>com</strong>petição).<br />

12 23 43 <br />

17 12 34 <br />

· · ·<br />

11 12 33 <br />

DRAFT<br />

Assuma que o número máximo <strong>de</strong> países participantes dos jogos é 30. Consi<strong>de</strong>re ainda que a<br />

classificação dos países é feita primeiramente pelo critério total <strong>de</strong> medalhas <strong>de</strong> ouro, <strong>de</strong>pois<br />

pelo critério total <strong>de</strong> medalhas <strong>de</strong> prata e, por fim, pelo critério total <strong>de</strong> medalhas <strong>de</strong> bronze.<br />

Desconsi<strong>de</strong>re a hipótese <strong>de</strong> haver empate nos três critérios: total <strong>de</strong> medalhas <strong>de</strong> ouro, prata e<br />

bronze. Os resultados <strong>de</strong>vem ser apresentados na saída padrão apresentando o código do país,<br />

seguido do total <strong>de</strong> medalhas <strong>de</strong> ouro, prata e bronze obtidos, or<strong>de</strong>nados <strong>de</strong>crescentemente (ou<br />

seja, primeiro <strong>de</strong>vem ser mostrados os dados do país campeão dos jogos, em seguida, os dados<br />

do vice-campeão e assim por diante). O exemplo seguinte mostra <strong>com</strong>o <strong>de</strong>ve ser organizada a<br />

saída.<br />

17 34 48 63 <br />

34 30 57 29 <br />

· · ·<br />

22 0 0 1


5.10. TRABALHOS SUGERIDOS 153<br />

18. Consi<strong>de</strong>re uma seqüência <strong>de</strong> números inteiros não negativos armazenada em uma lista vetorial<br />

<strong>de</strong> inteiros. Nela po<strong>de</strong>m ocorrer subseqüências <strong>de</strong> números consecutivos. Por exemplo, na<br />

seqüência:<br />

1, 4, 5, 9, 10, 13, 1, 2, 3, 4, 2, 7, 5, 6, 7, 7, 8, 9, 10, 8, 3<br />

existem 5 subseqüências <strong>de</strong> números consecutivos (uma <strong>com</strong> 4 e 5, uma <strong>com</strong> 9 e 10, uma <strong>com</strong><br />

1, 2, 3 e 4, uma <strong>com</strong> 5, 6 e 7 e outra <strong>com</strong> 7, 8, 9 e 10). Escreva um subprograma que receba<br />

<strong>com</strong>o parâmetro uma lista vetorial <strong>de</strong> inteiros preenchida <strong>com</strong> uma sequência qualquer<br />

<strong>de</strong> números inteiros não negativos e retorne o tamanho da maior subseqüência encontrada <strong>de</strong><br />

números consecutivos. No exemplo, acima, o subprograma <strong>de</strong>verá retornar o valor 4.<br />

19. Escrever um programa que leia uma palavra do teclado e conte as ocorrências <strong>de</strong> todos pares<br />

<strong>de</strong> letras nesta palavra. Por exemplo, na palavra Mississippi, as seguintes <strong>com</strong>binações <strong>de</strong> dois<br />

caracteres ocorrem.<br />

5.10 Trabalhos Sugeridos<br />

1. Extrato Bancário<br />

Mississippi<br />

MI 1 VEZ<br />

IS 2<br />

SS 2<br />

SI 2<br />

IP 1<br />

PP 1<br />

PI 1<br />

Figura 5.14: Exemplo <strong>de</strong> ocorrências<br />

O gerente <strong>de</strong> uma agência bancária te contratou para fazer um programa em C para processar<br />

algumas informações das contas dos correntistas <strong>de</strong> sua agência. Para tanto o gerente te forneceu<br />

uma listagem contendo, em cada linha, os dados do número da conta (um valor inteiro positivo),<br />

o código da operação (um valor inteiro positivo) e o valor da operação (um valor ponto flutuante<br />

positivo para as operações <strong>de</strong> crédito e negativo para as operações <strong>de</strong> débito) realizadas no último<br />

mês. Você <strong>de</strong>ve:<br />

DRAFT<br />

(a) Ler os dados da listagem.<br />

(b) Apresentar as operações realizadas por cada cliente or<strong>de</strong>nadas por número da conta. As<br />

operações individuais <strong>de</strong> cada cliente <strong>de</strong>vem estar or<strong>de</strong>nadas por código da operação.<br />

(c) Apresentar os saldos totais das operações realizadas no mês pelos clientes que se encontram<br />

no grupo dos 40% <strong>de</strong> clientes <strong>com</strong> maior saldo.<br />

(d) Apresentar a movimentação financeira <strong>de</strong> cada tipo <strong>de</strong> operação realizada na agência. As<br />

operações <strong>de</strong>vem ser apresentadas or<strong>de</strong>nadas <strong>de</strong>crescentemente pelo valor da movimentação<br />

financeira total no mês. Consi<strong>de</strong>re que tanto as operações <strong>de</strong> crédito quanto as <strong>de</strong> débito dos<br />

clientes <strong>de</strong>vem ser consi<strong>de</strong>radas para <strong>de</strong>terminar a movimentação financeira da operação,<br />

isto é, o valor total da movimentação financeira <strong>de</strong> uma operação é a soma <strong>de</strong> todas as<br />

operações <strong>de</strong> crédito <strong>com</strong> o valor absoluto <strong>de</strong> todas as operações <strong>de</strong> débito daquela operação.<br />

Note que os dados <strong>de</strong> cada conta não estão or<strong>de</strong>nados na listagem. Consi<strong>de</strong>re ainda que existem<br />

no máximo 100 clientes na agência e que no máximo ocorrem 100 operações na agência a cada<br />

mês. O processamento <strong>de</strong>ve ser encerrado quando for lido um número <strong>de</strong> conta igual a zero. Um<br />

exemplo <strong>de</strong> listagem é apresentado na Figura 5.15:


154<br />

CAPÍTULO 5. VETORES<br />

Número <strong>de</strong> Conta Código da Operação Valor <strong>de</strong> Operação<br />

1 17 123,02<br />

7 32 -22,54<br />

2 54 1000,01<br />

1 28 22222,22<br />

... ... ...<br />

0 0 0,00<br />

Figura 5.15: Exemplo <strong>de</strong> listagem<br />

DRAFT


Capítulo 6<br />

Matrizes<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

Coautores:<br />

Clebson Oliveira<br />

Julio Dalfior<br />

Rafael Favoreto<br />

Ramon Schiavo<br />

Thales Carvalho<br />

Thaylo <strong>de</strong> Freitas<br />

Mostrar a importância <strong>de</strong> se utilizar a estrutura <strong>de</strong> dados matriz para resolver problemas;<br />

Introduzir o conceito do tipo abstrato <strong>de</strong> dados matriz;<br />

Mostrar <strong>com</strong>o mo<strong>de</strong>lar um problema através do TAD Matriz <strong>de</strong> inteiros.<br />

No capítulo anterior, foi discutida a estrutura <strong>de</strong> dados vetor, que é capaz <strong>de</strong> armazenar dados <strong>de</strong><br />

um mesmo tipo, poupando o programador <strong>de</strong> <strong>de</strong>clarar uma gran<strong>de</strong> quantida<strong>de</strong> <strong>de</strong> variáveis.<br />

Neste, capítulo é apresentada a estrutura <strong>de</strong> dados matriz que, diferentemente do vetor, armazena<br />

dados <strong>de</strong> forma multidimensional.<br />

6.1 Matrizes e sua importância<br />

Uma matriz é um tipo <strong>de</strong> dado <strong>com</strong>posto em que os elementos são do mesmo tipo e organizados em<br />

uma estrutura multidimensional. Uma matriz bidimensional, por exemplo, é formada pela <strong>com</strong>binação<br />

<strong>de</strong> linhas e colunas. Com isso, cada elemento passa a ser associado a um indicador <strong>de</strong> linha e um<br />

indicador <strong>de</strong> coluna, <strong>com</strong>o em uma tabela. A Figura 6.1 mostra uma matriz 5 por 3. Note que a<br />

matriz possui 5 linhas e 3 colunas. Embora matrizes possam ter mais que 2 dimensões, neste livro<br />

enfatiza-se as matrizes bidimensionais. Uma matriz <strong>de</strong> m linhas e n colunas é chamada matriz m por<br />

n.<br />

DRAFT<br />

Figura 6.1: Uma matriz 5 por 3 preenchida <strong>com</strong> zeros.<br />

155


156<br />

CAPÍTULO 6. MATRIZES<br />

Para mostrar que matrizes bidimensionais são muito <strong>com</strong>uns no nosso dia-a-dia po<strong>de</strong>-se citar vários<br />

exemplos: um cartão <strong>de</strong> bingo, uma agenda <strong>com</strong> a disponibilida<strong>de</strong> para marcar <strong>com</strong>promissos (ver<br />

Figura 6.2) etc. É interessante que haja uma maneira <strong>de</strong> representar esse tipo <strong>de</strong> estrutura, para que<br />

se possa utilizá-la na solução <strong>de</strong> problemas <strong>com</strong>putacionais.<br />

Figura 6.2: Agenda <strong>de</strong> disponibilida<strong>de</strong> e sua representação matricial.<br />

Na Figura 6.2, as linhas representam os dias do mês e as colunas representam os meses do ano.<br />

Dessa forma, cada posição (ou célula) da matriz representa a disponibilida<strong>de</strong> em um <strong>de</strong>terminado dia<br />

<strong>de</strong> um <strong>de</strong>terminado mês.<br />

Consi<strong>de</strong>rando que essa matriz será utilizada para representar se há ou não <strong>com</strong>promisso naquele<br />

dia do mês, se tratará <strong>de</strong> uma matriz bidimensional, pois a cada célula <strong>de</strong>ssa matriz estão associadas<br />

duas informações, mês e dia. Por outro lado, se for necessário especificar as horas <strong>de</strong> um dia que estão<br />

ou não ocupadas, ter-se-ia uma matriz tridimensional, porque cada célula da matriz estaria associada<br />

a três informações (mês, dia e hora).<br />

A forma <strong>de</strong> se visualizar uma matriz facilita o entendimento do conceito <strong>de</strong> dimensão. Por exemplo,<br />

uma matriz bidimensional po<strong>de</strong> ser visualizada <strong>com</strong>o um quadro e uma tridimensional po<strong>de</strong> ser<br />

visualizada <strong>com</strong>o um cubo formado por vários cubos menores. Apesar <strong>de</strong> ser difícil visualizar matrizes<br />

<strong>com</strong> mais <strong>de</strong> três dimensões, vale ressaltar que elas existem e que é possível <strong>de</strong>clará-las em C. Como<br />

exemplo da utilização <strong>de</strong> matrizes <strong>com</strong> mais <strong>de</strong> três dimensões, po<strong>de</strong>-se utilizar a Figura 6.2 supondo<br />

que, além <strong>de</strong> representar o horário, se queira também representar o ano. Nesse caso seria necessária<br />

uma matriz <strong>de</strong> quatro dimensões (ano, mês, dia e hora).<br />

6.2 Definição e Acesso<br />

DRAFT<br />

Para que um problema seja mo<strong>de</strong>lado através <strong>de</strong> uma matriz é necessário que se <strong>de</strong>fina uma variável do<br />

tipo matriz para representá-la. Assim será possível utilizar seus elementos para guardar informações<br />

e, posteriormente, aplicar operações sobre essa estrutura.<br />

6.2.1 Definição<br />

A <strong>de</strong>finição <strong>de</strong> uma variável do tipo matriz exige que se informe o tamanho <strong>de</strong> suas dimensões.<br />

No entanto, existem duas maneiras <strong>de</strong> estabelecer o tamanho <strong>de</strong>ssas dimensões: estaticamente e<br />

dinamicamente. Este capítulo tem um foco maior na <strong>de</strong>finição estática do tamanho das dimensões.<br />

Para se <strong>de</strong>finir uma matriz estaticamente é necessário estabelecer um tamanho para cada dimensão,<br />

sendo que esse tamanho não po<strong>de</strong>rá ser alterado durante a execução do programa. O código do<br />

Exemplo 6.1 mostra <strong>com</strong>o isso po<strong>de</strong> ser feito em C:<br />

1 int matriz [5][10];<br />

Exemplo 6.1: Definição estática.


6.2.<br />

DEFINIÇÃO E ACESSO 157<br />

O número entre o primeiro par <strong>de</strong> colchetes ([5]) <strong>de</strong>fine o tamanho da primeira dimensão (número<br />

<strong>de</strong> linhas). O número entre o segundo par <strong>de</strong> colchetes ([10]) <strong>de</strong>fine o tamanho da segunda dimensão<br />

(número <strong>de</strong> colunas), e assim por diante para matrizes <strong>com</strong> mais <strong>de</strong> duas dimensões. No Exemplo 6.1,<br />

a variável matriz possui 5 linhas e 10 colunas.<br />

Inicialização<br />

Na <strong>de</strong>claração <strong>de</strong> matrizes mostrada anteriormente, os valores das células da matriz não foram inicializados<br />

e, por isso, geram resultados inesperados, uma vez que não se sabe quais valores estavam<br />

armazenados anteriormente nas áreas <strong>de</strong> memória utilizadas. Para evitar esse tipo <strong>de</strong> problema, é<br />

necessário, <strong>com</strong>o uma boa prática <strong>de</strong> programação, inicializar os elementos das matrizes antes <strong>de</strong><br />

qualquer acesso a seus valores, mesmo que posteriormente esses elementos sejam configurados <strong>com</strong><br />

novos valores. A forma mais simples <strong>de</strong> se fazer isso, em C, po<strong>de</strong> ser vista no Exemplo 6.2.<br />

1 int main (){<br />

2 int matriz [2][2] = {0};<br />

3<br />

4 return 0;<br />

5 }<br />

Exemplo 6.2: Inicialização <strong>de</strong> uma matriz.<br />

Na linha 2 do Exemplo 6.2, há a inicialização <strong>de</strong> todos os elementos da matriz <strong>com</strong> o valor zero.<br />

6.2.2 Acesso<br />

Com a matriz já inicializada, para se utilizar os dados contidos nela será necessário fazer uma operação<br />

<strong>de</strong> acesso, <strong>com</strong>o no Exemplo 6.3:<br />

1 # <strong>de</strong>fine NMESES 12<br />

2 # <strong>de</strong>fine NDIAS 31<br />

3 # <strong>de</strong>fine NHORAS 24<br />

4<br />

5 int main (){<br />

6 int reservaSala [ NMESES ][ NDIAS ][ NHORAS ] = {0};<br />

7 int resposta = 0;<br />

8 .<br />

9 .<br />

10 .<br />

11 resposta = reservaSala [4][0][9];<br />

12<br />

13 if ( resposta == 0){<br />

14 reservaSala [4][0][9] = 1;<br />

15 }<br />

16<br />

17 return 0;<br />

18 }<br />

DRAFT<br />

Exemplo 6.3: Acesso e atualização <strong>de</strong> um elemento.<br />

A variável resposta recebe 0 ou 1 indicando, respectivamente, se às 10 horas do dia 1 <strong>de</strong> maio a<br />

sala está livre ou reservada. Note que, assim <strong>com</strong>o em vetores, a primeira posição <strong>de</strong> cada dimensão<br />

da matriz tem índice 0, por isso, os índices dos meses, dias e horas são subtraídos por 1, tornando<br />

os índices iguais a 4, 0 e 9. Após acessar um elemento da matriz chamada reservaSala (linha 11) e<br />

verificar que em uma <strong>de</strong>terminada data e horário a sala está livre (linha 13), atualiza-se o estado da<br />

sala <strong>de</strong> livre para ocupada (linha 14).


158<br />

CAPÍTULO 6. MATRIZES<br />

6.2.3 Definição dinâmica <strong>de</strong> uma matriz<br />

Uma matriz po<strong>de</strong> ser <strong>de</strong>finida dinamicamente. Nesse caso, o tamanho <strong>de</strong> suas dimensões só será<br />

estabelecido durante a execução do programa, conforme é visto no Exemplo 6.4:<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 int main (){<br />

4 int m, n;<br />

5<br />

6 printf (‘‘ Forneca as dimensoes da matriz :’’);<br />

7 scanf (‘‘%d %d’’, &m, &n);<br />

8<br />

10<br />

9 int matriz [m][n];<br />

11 return 0;<br />

12 }<br />

Exemplo 6.4: Definição dinâmica.<br />

Nesse exemplo, a matriz só será <strong>de</strong>finida após a execução da função scanf, em que o tamanho <strong>de</strong><br />

suas dimensões será lido do teclado.<br />

6.3 O TAD Implementacional Matriz <strong>de</strong> Inteiros<br />

Nesta seção será mostrada a implementação <strong>de</strong> um tipo abstrato <strong>de</strong> dados envolvendo o uso <strong>de</strong> matrizes,<br />

o TAD Matriz <strong>de</strong> Inteiros. Primeiramente serão <strong>de</strong>finidos os atributos do TAD, em seguida as operações<br />

e por fim será mostrado um exemplo <strong>de</strong> uso. Doravante o TAD Matriz <strong>de</strong> Inteiros será referido <strong>com</strong>o<br />

tMatrizInt.<br />

6.3.1 Atributos<br />

O primeiro passo para <strong>de</strong>finir o TAD tMatrizInt envolve escolher os seus atributos. Como a i<strong>de</strong>ia<br />

é mo<strong>de</strong>lar um problema por uma matriz, é necessário que um dos atributos seja a própria matriz<br />

que armazenará os elementos. Além disso, é necessário guardar a quantida<strong>de</strong> <strong>de</strong> elementos <strong>de</strong> cada<br />

dimensão.<br />

Apesar <strong>de</strong> ser possível <strong>de</strong>finir uma matriz <strong>com</strong> um número qualquer <strong>de</strong> dimensões e que armazene<br />

um tipo qualquer <strong>de</strong> dados (int, float, char, etc), nesta seção serão utilizadas matrizes bidimensionais<br />

<strong>de</strong> inteiros, por serem <strong>com</strong>umente utilizadas.<br />

Portanto, os atributos <strong>de</strong> uma matriz bidimensional <strong>de</strong> inteiros são:<br />

ˆ<br />

ˆ<br />

ˆ<br />

DRAFT<br />

Número <strong>de</strong> linhas (nLinhas): armazena a quantida<strong>de</strong> <strong>de</strong> elementos <strong>de</strong> cada coluna;<br />

Número <strong>de</strong> colunas (nColunas): armazena a quantida<strong>de</strong> <strong>de</strong> elementos <strong>de</strong> cada linha;<br />

Matriz (valores): armazena os dados da matriz propriamente ditos.<br />

No Exemplo 6.5 é vista uma maneira <strong>de</strong> se <strong>de</strong>finir o TAD tMatrizInt, <strong>de</strong> forma a representar<br />

matrizes bidimensionais <strong>de</strong> inteiros.<br />

1 # <strong>de</strong>fine MAX_DIM 5<br />

2<br />

3 type<strong>de</strong>f struct {<br />

4 int valores [ MAX_DIM ][ MAX_DIM ];<br />

5 int nLinhas ;<br />

6 int nColunas ;<br />

7 } tMatrizInt ;<br />

Exemplo 6.5: Estrutura básica do tipo tMatrizInt.


6.3. O TAD IMPLEMENTACIONAL MATRIZ DE INTEIROS 159<br />

No Exemplo 6.5, a matriz valores é <strong>de</strong>clarada estaticamente, sendo seu tamanho máximo <strong>de</strong>finido<br />

pela constante MAX DIM.<br />

Na Figura 6.3 po<strong>de</strong>-se visualizar a estrutura da matriz dados, do tipo tMatrizInt, inicializada<br />

<strong>com</strong>o no Exemplo 6.6:<br />

1 tMatrizInt dados ;<br />

2 int i,j;<br />

3<br />

4 dados . nLinhas = 3;<br />

5 dados . nColunas = 3;<br />

6<br />

7 for (i = 0; i < dados . nLinhas ; i ++) {<br />

8 for (j = 0; j < dados . nColunas ; j ++) {<br />

9 dados . valores [i][j] = 0;<br />

10 }<br />

11 }<br />

Exemplo 6.6: Inicialização <strong>de</strong> uma estrutura tMatrizInt.<br />

Nas linhas 4 e 5, o tamanho da matriz é <strong>de</strong>finido <strong>com</strong>o 3 por 3. Na linha 7, o <strong>com</strong>ando for percorre as<br />

linhas da matriz <strong>de</strong> índice zero a nLinhas - 1. O segundo <strong>com</strong>ando for percorre todas as colunas (para<br />

cada laço do for anterior) <strong>de</strong> índice zero a nColunas - 1. Dessa forma percorre-se todos os elementos<br />

da matriz valores, <strong>de</strong>ntro das dimensões passadas, atribuindo a eles o valor zero.<br />

Figura 6.3: Estrutura da matriz valores pertencente à variável dados (para MAX DIM igual a 5).<br />

Apesar da matriz valores, pertencente à variável dados, ter 5 linhas e 5 colunas, somente os<br />

elementos pertencentes às 3 primeiras linhas e colunas foram inicializados. Isso porque se <strong>de</strong>finiu, nas<br />

linhas 4 e 5, que a matriz <strong>de</strong>veria ter somente esse número <strong>de</strong> linhas e colunas. Dessa forma, em<br />

todas as operações efetuadas sobre essa variável, somente os elementos pertencentes a essa submatriz<br />

(formada pelos zeros na figura) <strong>de</strong>vem ser consi<strong>de</strong>rados. Todos os outros (marcados <strong>com</strong> sinal ’-’)<br />

possuem valores não <strong>de</strong>terminados, por não terem sido inicializados, e <strong>de</strong>vem ser ignorados.<br />

6.3.2 Operações<br />

DRAFT<br />

Uma das vantagens <strong>de</strong> se implementar um tipo abstrato <strong>de</strong> dados é facilitar a solução <strong>de</strong> problemas<br />

por meio do uso <strong>de</strong> operações que atuem sobre o tipo abstrato <strong>de</strong> dados <strong>de</strong>finido. A seguir serão<br />

implementadas as operações classificadas por seu tipo.<br />

sobre tMatrizInt: inicialização, atualização <strong>de</strong> valor, acesso a valor, leitura, exibição,<br />

soma dos elementos <strong>de</strong> uma linha, soma dos elementos <strong>de</strong> uma coluna, soma dos elementos<br />

<strong>de</strong> uma diagonal e produto escalar.<br />

Construtoras<br />

Uma operação construtora essencial para se realizar sobre tMatrizInt é a inicialização. Ela <strong>de</strong>ve ser<br />

a primeira a ser realizada, caso contrário, as <strong>de</strong>mais po<strong>de</strong>m gerar resultados inesperados, <strong>com</strong>o o<br />

término do programa, por exemplo. Isso porque, durante a inicialização, preparam-se as estruturas


160<br />

CAPÍTULO 6. MATRIZES<br />

internas do TAD para se a<strong>de</strong>quar ao caso <strong>de</strong>sejado. No caso do tipo tMatrizInt proposto, a operação<br />

<strong>de</strong> inicialização <strong>de</strong>finirá as dimensões iniciais da matriz.<br />

O código do Exemplo 6.7 mostra <strong>com</strong>o isso po<strong>de</strong> ser implementado:<br />

1 tMatrizInt inicializaMatrizInt ( int nLinhas , int nColunas ){<br />

2 tMatrizInt resultado ;<br />

3 int i,j;<br />

4<br />

5 resultado . nLinhas = nLinhas ;<br />

6 resultado . nColunas = nColunas ;<br />

7<br />

8 for (i = 0; i < nLinhas ; i ++) {<br />

9 for (j = 0; j < nColunas ; j ++) {<br />

10 resultado . valores [i][j] = 0;<br />

11 }<br />

12 }<br />

13<br />

14 return resultado ;<br />

15 }<br />

Exemplo 6.7: Função <strong>de</strong> inicialização.<br />

Na <strong>de</strong>finição da função inicializaMatrizInt (linha 1), os argumentos nLinhas e nColunas servem<br />

para <strong>de</strong>finir a quantida<strong>de</strong> <strong>de</strong> linhas e colunas da matriz, respectivamente, e esses valores são atribuídos<br />

à estrutura tMatrizInt nas linhas 5 e 6. Finalmente, na linha 14, a variável resultado, que contém a<br />

estrutura inicializada, é retornada.<br />

Modificadoras<br />

Naturalmente, é necessário <strong>de</strong>finir uma forma <strong>de</strong> atualizar os valores armazenados em uma matriz<br />

individualmente. Isso po<strong>de</strong> ser feito, por meio, da operação <strong>de</strong> escrita atualizaMatrizInt <strong>de</strong>finida<br />

pela função do Exemplo 6.8.<br />

1 tMatrizInt atualizaMatrizInt ( tMatrizInt matriz , int linha , int coluna , int valor ){<br />

2 if ( ( linha >= 0 && linha < matriz . nLinhas ) &&<br />

3 ( coluna >= 0 && coluna < matriz . nColunas ) ){<br />

4 matriz . valores [ linha ][ coluna ] = valor ;<br />

5 } else {<br />

6 printf ("Os limites da matriz nao <strong>com</strong>portam o valor <strong>de</strong> linha e coluna<br />

especificados ");<br />

7 }<br />

8<br />

9 return matriz ;<br />

10 }<br />

DRAFT<br />

Exemplo 6.8: Escrita em um elemento da matriz.<br />

Na linha 2 é verificado se o elemento pertence à matriz, ou seja, se os índices <strong>de</strong> sua linha e <strong>de</strong> sua<br />

coluna não ultrapassam os limites <strong>de</strong> linha e coluna da matriz. Se o elemento pertencer à matriz, o<br />

valor passado <strong>com</strong>o parâmetro é atribuído ao elemento <strong>de</strong>sejado. Por fim, a função retorna a variável<br />

matriz atualizada.<br />

Em algumas aplicações po<strong>de</strong> ser importante ler um conjunto <strong>de</strong> valores inseridos pelo teclado e<br />

armazena-los na matriz. O Exemplo 6.9 mostra uma implementação <strong>de</strong>sta funcionalida<strong>de</strong>.<br />

1 tMatrizInt leMatrizInt ( tMatrizInt matriz ){<br />

2 int i = 0, j = 0;<br />

3<br />

4 printf (" Insira os %d elementos da matriz :\n", matriz . nLinhas * matriz . nColunas );<br />

5<br />

6 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

7 for (j = 0; j < matriz . nColunas ; j ++) {


6.3. O TAD IMPLEMENTACIONAL MATRIZ DE INTEIROS 161<br />

8 scanf (" %d", &( matriz . valores [i][j]));<br />

9 }<br />

10 }<br />

11<br />

12 return matriz ;<br />

13 }<br />

Exemplo 6.9: Função <strong>de</strong> leitura dos dados da matriz.<br />

No Exemplo 6.9 os elementos serão lidos linha a linha, ou seja, todas as colunas <strong>de</strong> uma linha<br />

<strong>de</strong>vem ser lidas e só <strong>de</strong>pois se passa para a próxima linha. Cabe <strong>de</strong>stacar que a função leMatrizInt só<br />

<strong>de</strong>sempenhará seu papel corretamente se a variável matriz, passada <strong>com</strong>o parâmetro, for corretamente<br />

inicializada, por meio da função inicializaMatrizInt.<br />

Analizadoras<br />

Tendo em vista a importância <strong>de</strong> utilizar o valor <strong>de</strong> um <strong>de</strong>terminado item, é necessário construir uma<br />

função para acessar os dados da matriz (Exemplo 6.10).<br />

1 int acessaMatrizInt ( tMatrizInt matriz , int linha , int coluna ){<br />

2 if ( ( linha >= 0 && linha < matriz . nLinhas ) &&<br />

3 coluna >= 0 && coluna < matriz . nColunas ){<br />

4 return matriz . valores [ linha ][ coluna ];<br />

5 } else {<br />

6 printf (‘‘ In<strong>de</strong>xador invalido \n’’);<br />

7 return -1;<br />

8 }<br />

9 }<br />

Exemplo 6.10: Função <strong>de</strong> acesso aos dados da matriz.<br />

Na linha 2 é realizada a mesma verificação que no Exemplo 6.8. Se o elemento pertencer à matriz o<br />

seu valor é retornado. Caso contrário, uma mensagem <strong>de</strong> erro é exibida na tela e o valor -1 é retornado.<br />

Note que, em algumas aplicações, não será possível verificar a execução correta da função analisando<br />

apenas o valor <strong>de</strong> retorno, pois o valor retornado (-1) po<strong>de</strong> fazer parte do universo <strong>de</strong> valores válidos<br />

para a aplicação. Por isso, é emitida a mensagem <strong>de</strong> erro.<br />

Para po<strong>de</strong>r visualizar todos os elemetos <strong>de</strong> uma matriz <strong>de</strong> inteiros é necessário <strong>de</strong>finir uma operação<br />

<strong>de</strong> exibição da matriz na tela (Exemplo 6.11).<br />

DRAFT<br />

1 int exibeMatrizInt ( tMatrizInt matriz ){<br />

2 int i = 0, j = 0;<br />

3<br />

4 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

5 for (j = 0; j < matriz . nColunas ; j ++) {<br />

6 printf (" %5d", matriz . valores [i][j]);<br />

7 }<br />

8 printf ("\n");<br />

9 }<br />

10 }<br />

Exemplo 6.11: Exibição da matriz na tela.<br />

No Exemplo 6.11, tem-se na linha 4 um <strong>com</strong>ando for para varrer as linhas da matriz, e para cada<br />

linha tem-se outro <strong>com</strong>ando for, na linha 5, para varrer os elementos <strong>de</strong>ssa linha. Na linha 6, o trecho<br />

“%5d” faz <strong>com</strong> que os números sejam exibidos sempre <strong>com</strong> 5 dígitos, o que faz <strong>com</strong> que a forma <strong>de</strong><br />

exibição seja regular, <strong>com</strong>o po<strong>de</strong> ser visto na Figura 6.4.


162<br />

CAPÍTULO 6. MATRIZES<br />

Figura 6.4: Exemplo <strong>de</strong> saída da operação exibeMatrizInt.<br />

Produtoras<br />

Em muitas aplicações é necessário obter o valor da soma dos elementos <strong>de</strong> uma linha da matriz. Por<br />

isso, no Exemplo 6.12 é <strong>de</strong>finida uma operação para efetuar esse cálculo.<br />

1 int somaLinhaMatrizInt ( tMatrizInt matriz , int linha ){<br />

2 int i = 0, soma = 0;<br />

3<br />

4 for (i = 0; i < matriz . nColunas ; i ++) {<br />

5 soma = soma + matriz . valores [ linha ][i];<br />

6 }<br />

7<br />

8 return soma ;<br />

9 }<br />

Exemplo 6.12: Soma dos elementos <strong>de</strong> uma linha.<br />

A variável soma é inicializada <strong>com</strong> o valor zero. O for percorre todos os elementos da linha da<br />

matriz adicionando o valor da célula da matriz à variável soma. A variável soma funciona, então,<br />

<strong>com</strong>o um acumulador e, ao final das repetições, armazena o valor da soma dos elementos da linha.<br />

Agora será <strong>de</strong>finida, no Exemplo 6.13 uma operação para efetuar a soma dos elementos <strong>de</strong> uma<br />

coluna.<br />

1 int somaColunaMatrizInt ( tMatrizInt matriz , int coluna ){<br />

2 int i = 0, soma = 0;<br />

3<br />

4 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

5 soma = soma + matriz . valores [i][ coluna ];<br />

6 }<br />

7<br />

8 return soma ;<br />

9 }<br />

DRAFT<br />

Exemplo 6.13: Soma dos elementos <strong>de</strong> uma coluna.<br />

A operação é análoga à soma dos elementos <strong>de</strong> uma linha. Porém, recebe uma coluna e não uma<br />

linha <strong>com</strong>o parâmetro.<br />

O Exemplo 6.14 é uma operação que soma os valores dos elementos pertencentes à diagonal principal<br />

<strong>de</strong> uma matriz quadrada.<br />

1 int somaDiagonalMatrizInt ( tMatrizInt matriz ){<br />

2 int i;<br />

3 int soma = 0;<br />

4<br />

5 if ( matriz . nLinhas != matriz . nColunas ){<br />

6 printf ("A matriz precisa ser quadrada .\n");<br />

7 return -1;<br />

8 }<br />

9<br />

10 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

11 soma += matriz . valores [i][i];


6.3. O TAD IMPLEMENTACIONAL MATRIZ DE INTEIROS 163<br />

12 }<br />

13<br />

14 return soma ;<br />

15 }<br />

Exemplo 6.14: Soma da Diagonal.<br />

Assim <strong>com</strong>o no Exemplo 6.10, é necessário ter cuidado, pois o valor -1 po<strong>de</strong> pertencer ao conjunto<br />

<strong>de</strong> valores válidos para a soma. Nesse caso, um valor mais apropriado <strong>de</strong>ve ser escolhido para indicar<br />

erro.<br />

Será <strong>de</strong>finida uma operação <strong>de</strong> <strong>com</strong>posição chamada produto escalar, que gera uma matriz M<br />

cujos elementos são resultados <strong>de</strong> uma <strong>com</strong>posição dos elementos <strong>de</strong> uma matriz A <strong>com</strong> uma matriz<br />

B. Nesta operação os elementos m ij da matriz M são resultantes do somatório dos produtos entre os<br />

elementos da linha i da primeira matriz <strong>com</strong> os elementos da coluna j da segunda matriz. Para que<br />

esta operação seja executada é necessário que o número <strong>de</strong> colunas da matriz A seja igual ao número<br />

<strong>de</strong> linhas da matriz B.<br />

1 tMatrizInt produtoEscalarMatrizInt ( tMatrizInt matriz1 , tMatrizInt matriz2 ){<br />

2 int i = 0, j = 0, k = 0;<br />

3 tMatrizInt produto ;<br />

4<br />

5 if ( matriz1 . nColunas == matriz2 . nLinhas ){<br />

6 for (i = 0; i < matriz1 . nLinhas ; i ++) {<br />

7 for (j = 0; j < matriz2 . nColunas ; j ++) {<br />

8 produto . valores [i][j] = 0;<br />

9 for (k = 0; k < matriz1 . nColunas ; k ++) {<br />

10 produto . valores [i][j] += matriz1 . valores [i][k] * matriz2 . valores [<br />

k][j];<br />

11 }<br />

12 }<br />

13 }<br />

14<br />

15 produto . nLinhas = matriz1 . nLinhas ;<br />

16 produto . nColunas = matriz2 . nColunas ;<br />

17 } else {<br />

18 produto . nLinhas = produto . nColunas = 0;<br />

19 }<br />

20<br />

21 return produto ;<br />

22 }<br />

DRAFT<br />

Exemplo 6.15: Produto Escalar <strong>de</strong> 2 matrizes.<br />

6.3.3 Exemplo <strong>de</strong> utilização do TAD tMatrizInt<br />

A seguir, no Exemplo 6.16, é <strong>de</strong>monstrada a utilização das operações <strong>de</strong>finidas sobre o TAD tMatrizInt,<br />

no programa <strong>com</strong>o um todo.<br />

1 int main (){<br />

2 tMatrizInt matrizA ;<br />

3 tMatrizInt matrizB ;<br />

4 tMatrizInt matrizProduto ;<br />

5<br />

6 matrizA = inicializaMatrizInt (4 ,4) ;<br />

7 matrizB = inicializaMatrizInt (4 ,4) ;<br />

8<br />

9 matrizA = leMatrizInt ( matrizA ); // Usuario insere os valores da matriz A pelo<br />

teclado .<br />

10 matrizB = leMatrizInt ( matrizB ); // Usuario insere os valores da matriz B pelo<br />

teclado .<br />

11


164<br />

CAPÍTULO 6. MATRIZES<br />

12 // Os indices <strong>de</strong> posicao <strong>com</strong>ecam em 0.<br />

13 matrizA = atualizaMatrizInt ( matrizA , 2, 2, 10) ; // Atualiza a matriz A <strong>com</strong> o valor<br />

10 na linha 2, coluna 2.<br />

14 matrizB = atualizaMatrizInt ( matrizB , 3, 3, 20) ; // Atualiza a matriz B <strong>com</strong> o valor<br />

20 na linha 3, coluna 3.<br />

15<br />

16 exibeMatrizInt ( matrizA ); // Exibe a matriz A atualizada na tela .<br />

17 exibeMatrizInt ( matrizB ); // Exibe a matriz B atualizada na tela .<br />

18<br />

19 printf (" Soma da primeira linha da matriz A: %d.\n", somaLinhaMatrizInt ( matrizA , 0)<br />

);<br />

20 printf (" Soma da primeira coluna da matriz B: %d.\n", somaColunaMatrizInt ( matrizB ,<br />

0));<br />

21<br />

22 printf (" Elemento da posicao (1 , 1) da matriz A: %d.\n" , acessaMatrizInt ( matrizA ,<br />

1, 1));<br />

23<br />

24 printf (" Soma da diagonal da matrizA : %d.\n", somaDiagonalMatrizInt ( matrizA ));<br />

25<br />

26 matrizProduto = produtoEscalarMatrizInt ( matrizA , matrizB );<br />

27 printf (" Produto escalar A X B:\n");<br />

28 exibeMatrizInt ( matrizProduto );<br />

29<br />

30 return 0;<br />

31 }<br />

Exemplo 6.16: Uso do TAD tMatrizInt na função principal.<br />

Vale lembrar que os atributos e operações do TAD <strong>de</strong>vem estar <strong>de</strong>finidos, fora da função principal,<br />

no corpo do arquivo, para que o programa funcione corretamente.<br />

6.4 Exercícios Resolvidos<br />

Exercício Resolvido 6.1 - Operações em matrizes<br />

Dada uma matriz bidimensional <strong>de</strong> inteiros, <strong>de</strong>fina operações que realize a soma dos elementos da<br />

submatriz triangular superior.<br />

DRAFT<br />

Solução Possível:<br />

Como os elementos da submatriz triangular superior são os elementos que estão situados acima dos<br />

elementos da diagonal principal, po<strong>de</strong>-se notar que, em cada linha, esses elementos estão situados nas<br />

colunas à direita do elemento da diagonal principal. Dessa forma, percorre-se a submatriz triangular<br />

superior por meio <strong>de</strong> um loop, na linha 5, que varre todas as linhas i da matriz, e para cada linha<br />

tem-se outro laço (linha 6) para varrer as colunas <strong>de</strong> índice i+1 até nColunas, somando o valor <strong>de</strong> cada<br />

elemento visitado. Para acessar os elementos das matrizes, será utilizada a função acessaMatrizInt<br />

do Exemplo 6.10.<br />

Pseudocódigo 6.1 Cálculo da soma dos elementos da submatriz triangular superior.<br />

Descrição: Calcular a soma dos elementos da submatriz triangular superior.<br />

Dados <strong>de</strong> Entrada: A estrutura da matriz (tMatrizInt).<br />

Saída da Função: O valor da soma.<br />

Processo <strong>com</strong>ponente " soma dos elementos da submatriz triangular superior ":<br />

Criar a variável que receberá o resultado da soma da submatriz .<br />

PARA todos os índices linha da matriz :<br />

PARA cada índice coluna direita do índice linha atual da matriz :<br />

Incrementar à soma , o elemento da posiç~ao atual acessado na matriz .<br />

FIM - PARA .<br />

FIM - PARA .


6.4.<br />

EXERCÍCIOS RESOLVIDOS 165<br />

FIM - Processo <strong>com</strong>ponente " soma dos elementos da submatriz triangular superior "<br />

1 int somaTriangular ( tMatrizInt matriz ){<br />

2 int soma = 0;<br />

3 int i,j;<br />

4<br />

5 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

6 for (j = i + 1; j < nColunas ; j ++) {<br />

7 soma = soma + acessaMatrizInt ( matriz , i, j);<br />

8 }<br />

9 }<br />

10<br />

11 return soma ;<br />

12 }<br />

Exemplo 6.17: Soma dos elementos da matriz triangular superior.<br />

Exercício Resolvido 6.2 - Controle <strong>de</strong> reserva <strong>de</strong> sala<br />

Deseja-se <strong>de</strong>senvolver um programa para controlar a reserva <strong>de</strong> uma sala ao longo <strong>de</strong> um ano. Ao<br />

usuário <strong>de</strong>vem ser fornecidas as seguintes operaçoes:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Reservar a sala;<br />

Cancelar reserva;<br />

Dado um mês, listar dias em que a sala está disponível;<br />

Informar o índice <strong>de</strong> ocupação <strong>de</strong> cada mês.<br />

Implemente o programa utilizando o TAD tMatrizInt.<br />

Solução Possível:<br />

Para armazenar as informações <strong>de</strong> reserva da sala será utilizada uma matriz <strong>com</strong> 31 linhas (representando<br />

os dias) e 12 colunas (representado os meses). Dessa forma, para reservar a sala para o dia<br />

1º <strong>de</strong> janeiro, atribui-se ao elemento da linha 0 e coluna 0, o valor 1.<br />

Para resolver o problema, será criada uma função para cada operação. Além disso, serão utilizadas<br />

as funções atualizaMatrizInt e acessaMatrizInt dos Exemplos 6.8 e 6.10, respectivamente, quando<br />

necessário.<br />

Reservar a sala<br />

Pseudocódigo 6.2 Reserva <strong>de</strong> sala.<br />

DRAFT<br />

Descrição: Fazer a reserva <strong>de</strong> uma sala.<br />

Dados <strong>de</strong> Entrada: Matriz <strong>de</strong> ocupação, dia e mês da reserva.<br />

Saída da Função: Matriz <strong>de</strong> ocupação atualizada.<br />

Processo <strong>com</strong>ponente " reserva sala ":<br />

SE a data for válida :<br />

SE estiver a data estiver disponível :<br />

Exibir aviso <strong>de</strong> reserva concluída.<br />

Retornar matriz <strong>de</strong> ocupaç~ao atualizada .<br />

SEN~AO:<br />

Exibir aviso <strong>de</strong> indisponibilida<strong>de</strong> .<br />

Retornar matriz inalterada .<br />

FIM -SE.<br />

SEN~AO:<br />

Exibir aviso <strong>de</strong> data inválida .<br />

Retornar matriz inalterada .


166<br />

CAPÍTULO 6. MATRIZES<br />

FIM -SE.<br />

FIM - Processo <strong>com</strong>ponente " reserva sala "<br />

1 tMatrizInt reservaSala ( tMatrizInt mat , int dia , int mes ){<br />

2 if ( (dia


6.4.<br />

EXERCÍCIOS RESOLVIDOS 167<br />

14 }<br />

Exemplo 6.19: Cancelar reserva.<br />

Listar dias livres do mês<br />

Deve-se verificar, em um laço, todos os dias do mês escolhido e, para cada dia, verificar a reserva<br />

da sala. Se ela estiver <strong>de</strong>socupada, então o dia será impresso na tela <strong>de</strong> modo a informar isso ao<br />

usuário. Note que o número <strong>de</strong> dias <strong>de</strong> cada mês varia e, portanto, <strong>de</strong>ve haver um controle <strong>de</strong> forma<br />

que o laço termine <strong>com</strong> o número <strong>de</strong> dias correto para o mês escolhido.<br />

Pseudocódigo 6.4 Listar dias livres do mês.<br />

Descrição: Exibir os dias não reservados <strong>de</strong> uma sala em um <strong>de</strong>terminado mês.<br />

Dados <strong>de</strong> Entrada: Matriz <strong>de</strong> ocupação, mês da consulta.<br />

Saída da Função: Exibe na tela os dias livres.<br />

Processo <strong>com</strong>ponente " dias n~ao reservados ":<br />

Exibir mensagem informando o m^es consultado .<br />

PARA todos os dias do m^es da consulta :<br />

Verificar se a sala está reservada no dia do m^es.<br />

SE estiver <strong>de</strong>socupada :<br />

Exibir na tela o dia .<br />

FIM -SE<br />

FIM - PARA<br />

FIM - Processo <strong>com</strong>ponente " dias n~ao reservados "<br />

1 void listaDiasLivres ( tMatrizInt mat , int mes ){<br />

2 int dia ;<br />

3 int numeroDiasMes [] = {31 ,28 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31};<br />

4<br />

5 printf (" Dias livres para o mes %d\n", mes );<br />

6<br />

7 for ( dia = 0; dia < numeroDiasMes [mes -1]; dia ++) {<br />

8 if ( acessaMatrizInt (mat , dia , mes ) == 0){<br />

9 printf ("%d\n", dia + 1);<br />

10 }<br />

11 }<br />

12 }<br />

DRAFT<br />

Exemplo 6.20: Listar dias livres do mês.<br />

Obter o índice <strong>de</strong> ocupação <strong>de</strong> cada mês<br />

O índice <strong>de</strong> ocupação <strong>de</strong> um mês nada mais é do que o número <strong>de</strong> dias <strong>com</strong> a sala reservada naquele<br />

mês. Além disso, <strong>com</strong>o a sala ocupada é representada pelo número 1 e a sala vazia pelo número 0,<br />

somando-se a coluna que representa um <strong>de</strong>terminado mês obtem-se o número <strong>de</strong> dias ocupados para<br />

esse mês. Assim sendo, para resolver o problema, basta percorrer todas as colunas da matriz e, para<br />

cada uma <strong>de</strong>las, efetuar a soma <strong>de</strong> seus elementos. Para <strong>com</strong>putar o número <strong>de</strong> dias ocupados no mês,<br />

será utilizada a função somaColunaMatrizInt do Exemplo 6.13<br />

Pseudocódigo 6.5 Obter o índice <strong>de</strong> ocupação <strong>de</strong> cada mês.<br />

Descrição: Exbir os números <strong>de</strong> dias ocupados em cada mês.<br />

Dados <strong>de</strong> Entrada: Matriz <strong>de</strong> ocupação.<br />

Saída da Função: Exibe na tela os números <strong>de</strong> dias ocupados no meses.<br />

Processo <strong>com</strong>ponente " exibe números <strong>de</strong> dias ocupados ":<br />

Exibir mensagem informando que será verificado o índice <strong>de</strong> ocupaç~ao <strong>de</strong> um<br />

<strong>de</strong>terminado m^es.


168<br />

CAPÍTULO 6. MATRIZES<br />

PARA todos os meses :<br />

Computar o número <strong>de</strong> dias ocupados no m^es através <strong>de</strong> uma funç~ao auxiliar .<br />

Exibir na tela o número <strong>de</strong> dias ocupados no m^es.<br />

FIM - PARA<br />

FIM - Processo <strong>com</strong>ponente " exibe números <strong>de</strong> dias ocupados "<br />

1 void imprimeIndiceOcupacao ( tMatrizInt mat ){<br />

2 int mes ;<br />

3 int indice ;<br />

4<br />

5 printf (" Indice <strong>de</strong> ocupacao dos meses do ano \n");<br />

6<br />

7 for ( mes = 0; mes < 12; mes ++) {<br />

8 indice = somaColunaMatrizInt (mat , mes );<br />

9 printf (" Mes %d: %d dias ocupados \n", mes +1 , indice );<br />

10 }<br />

11 }<br />

Exemplo 6.21:<br />

Índice <strong>de</strong> ocupação <strong>de</strong> cada mês.<br />

Uma vez <strong>de</strong>finidas as funções que realizam as operações, falta então <strong>de</strong>finir a função principal do<br />

programa on<strong>de</strong> a interação <strong>com</strong> o usuário será feita, ou seja, on<strong>de</strong> as funções <strong>de</strong>finidas ao longo <strong>de</strong>ste<br />

exercício serão chamadas.<br />

O programa principal segue os passos <strong>de</strong>scritos no Pseudocódigo 6.6.<br />

Pseudocódigo 6.6 Sistema <strong>de</strong> controle <strong>de</strong> ocupação <strong>de</strong> sala.<br />

Descrição: Programa <strong>com</strong> objetivo <strong>de</strong> agregar as funcionalida<strong>de</strong>s relacionadas ao controle <strong>de</strong> ocupação <strong>de</strong><br />

uma sala.<br />

Dados <strong>de</strong> Entrada: Variam <strong>com</strong> a funcionalida<strong>de</strong> escolhida.<br />

Saída do Programa: Variam <strong>com</strong> a funcionalida<strong>de</strong> escolhida.<br />

Funç~ao Principal<br />

Cria matriz <strong>de</strong> ocupaç~ao.<br />

FAÇA:<br />

Exibir na tela mensagens informativas .<br />

Ler opç~ao escolhida .<br />

CASO a opç~ao SEJA :<br />

1, ENT~AO exibir mensagem requerendo uma data .<br />

Fazer a leitura da data .<br />

Processo <strong>com</strong>ponente " reservaSala ".<br />

DRAFT<br />

2, ENT~AO exibir mensagem requerendo uma data .<br />

Fazer a leitura da data .<br />

Processo <strong>com</strong>ponente " cancelaReserva ".<br />

3, ENT~AO exibir uma mensagem requerendo um m^es.<br />

Fazer a leitura do m^es.<br />

Processo <strong>com</strong>ponente " listaDiasLivres ".<br />

4, ENT~AO Processo <strong>com</strong>ponente " imprimeIndiceOcupacao ".<br />

5, ENT~AO Fazer nada .<br />

OUTRO VALOR , ENT~AO Exibir mensagem avisando que a opç~ao inválida .<br />

FIM - CASO<br />

ENQUANTO a opç~ao for diferente <strong>de</strong> 5.<br />

FIM - Funç~ao Principal


6.4.<br />

EXERCÍCIOS RESOLVIDOS 169<br />

1 int main (){<br />

2 tMatrizInt reservas ;<br />

3 int codigo , dia , mes ;<br />

4<br />

5 reservas = inicializaMatrizInt (31 , 12) ;<br />

6<br />

7 do{<br />

8 printf ("\\n\\n\\n\\n\\n\\n\\n");<br />

9 printf ("## Reserva <strong>de</strong> Salas ##\\ n\\ nEscolha uma operacao :\\ n");<br />

10 printf (" 1- Reservar a sala \\n");<br />

11 printf (" 2- Cancelar uma reserva \\n");<br />

12 printf (" 3- Listar dias livres \\n");<br />

13 printf (" 4- Exibir indice <strong>de</strong> ocupacao \\n");<br />

14 printf (" 5- Sair \\n");<br />

15 printf (" Digite o codigo da operacao escolhida : ");<br />

16 scanf ("%d", & codigo );<br />

17<br />

18 switch ( codigo ){<br />

19 case 1:<br />

20 printf ("\\n\\ nDigite a data da reserva ( dia / mes ): ");<br />

21 scanf ("%d/%d", &dia , & mes );<br />

22 reservas = reservaSala ( reservas , dia , mes );<br />

23 break ;<br />

24<br />

25 case 2:<br />

26 printf ("\\n\\ nDigite a data da reserva a cancelar ( dia / mes ): ");<br />

27 scanf ("%d/%d", &dia , & mes );<br />

28 reservas = cancelaReserva ( reservas , dia , mes );<br />

29 break ;<br />

30<br />

31 case 3:<br />

32 printf ("\\n\\ nDigite o mes : ");<br />

33 scanf ("%d", & mes );<br />

34 listaDiasLivres ( reservas , mes );<br />

35 break ;<br />

36<br />

37 case 4:<br />

38 imprimeIndiceOcupacao ( reservas );<br />

39 break ;<br />

40<br />

41 case 5:<br />

42 break ;<br />

43<br />

44 <strong>de</strong>fault :<br />

DRAFT<br />

45 printf (" Codigo <strong>de</strong>ve ter valor entre 1 e 5\n");<br />

46 }<br />

47 } while ( codigo != 5);<br />

48<br />

49 return 0;<br />

50 }<br />

Exercício Resolvido 6.3 - Uns isolados<br />

Exemplo 6.22: Interação <strong>com</strong> usuário.<br />

Dada uma matriz bidimensional <strong>com</strong> m linhas e n colunas, <strong>de</strong> “zeros” e “uns”, <strong>de</strong>fina uma operação<br />

para calcular o número <strong>de</strong> uns isolados <strong>de</strong>ssa matriz. Consi<strong>de</strong>re que um número um está isolado se<br />

nenhum dos elementos adjacentes a ele, são “uns”.<br />

Solução Possível:<br />

Implementa-se uma função auxiliar que verificará se uma posição a ij da matriz está isolada, ou<br />

seja, não possui um 1 adjacente. Os dois laços <strong>de</strong> repetição aninhados (linhas 4 e 6) permitirão verificar<br />

os quadrados adjacentes à posição indicada. As variáveis auxiliares k e l servirão <strong>com</strong>o <strong>de</strong>slocadores


170<br />

CAPÍTULO 6. MATRIZES<br />

<strong>de</strong> posição, a fim <strong>de</strong> realizar os acessos. Note que só serão consi<strong>de</strong>radas as posições acima, abaixo, à<br />

direita e à esquerda. As diagonais não serão levadas em conta no critério implementado.<br />

Em seguida implementa-se uma função que irá percorrer toda a matriz <strong>com</strong> dois laços <strong>de</strong> repetição<br />

aninhados (linhas 22 e 23) verificando se o elemento acessado é 1, e se é uma posição isolada, em caso<br />

afirmativo, um contador (no caso, a variável quantida<strong>de</strong>) é incrementado. Por fim, essa quantida<strong>de</strong><br />

é retornada. Para acessar os elementos da matriz, utiliza-se a função acessaMatrizInt do Exemplo<br />

6.10.<br />

Pseudocódigo 6.7 Processo para verificar se a posição a ij <strong>de</strong> uma matriz é isolada<br />

Descrição: Verificar se a posição a ij <strong>de</strong> uma matriz é isolada.<br />

Dados <strong>de</strong> Entrada: A estrutura da matriz (tMatrizInt) e os índices ’i’ e ’j’.<br />

Saída do Programa: 1, se a posição a ij <strong>de</strong> uma matriz é isolada e 0, caso contrário.<br />

Processo <strong>com</strong>ponente " verifica se a posiç~ao (i,j) <strong>de</strong> uma matriz é isolada ":<br />

PARA a primeira à última linha adjacente ao elemento (i,j) da matriz :<br />

PARA a primeira à última coluna adjacente ao elemento (i,j) da matriz :<br />

SE a posiç~ao atual for igual à posiç~ao (i,j) ou a posiç~ao atual n~ao for<br />

adjacente à posiç~ao (i,j):<br />

Voltar à primeira instruç~ao do loop .<br />

SE o valor do elemento da posiç~ao atual for igual a um:<br />

Retornar falso .<br />

FIM - PARA .<br />

FIM - PARA .<br />

Retornar verda<strong>de</strong>iro .<br />

FIM - Processo <strong>com</strong>ponente " verifica se a posiç~ao (i,j) <strong>de</strong> uma matriz é isolada "<br />

Pseudocódigo 6.8 Número <strong>de</strong> uns isolados <strong>de</strong> uma matriz <strong>de</strong> zeros e uns.<br />

Descrição: Calcular o número <strong>de</strong> uns isolados <strong>de</strong> uma matriz <strong>de</strong> zeros e uns.<br />

Dados <strong>de</strong> Entrada: A estrutura da matriz (tMatrizInt).<br />

Saída do Programa: A quantida<strong>de</strong> <strong>de</strong> uns isolados.<br />

DRAFT<br />

Processo <strong>com</strong>ponente "número <strong>de</strong> uns isolados ":<br />

Criar a variável que receberá a quantida<strong>de</strong> <strong>de</strong> uns isolados .<br />

PARA todos os índices linha da matriz :<br />

PARA todos os índices coluna da matriz :<br />

SE o elemento atual for igual a um e isolado :<br />

Incrementar a quantida<strong>de</strong> <strong>de</strong> uns isolados .<br />

FIM - PARA .<br />

FIM - PARA .<br />

FIM - Processo <strong>com</strong>ponente "número <strong>de</strong> uns isolados "<br />

1 int isolado ( tMatrizInt matriz , int i, int j){<br />

2 int k,l;<br />

3<br />

4 for (k = -1; k


6.5. RESUMO 171<br />

15 return 1;<br />

16 }<br />

17<br />

18 int unsIsolados ( tMatrizInt matriz ){<br />

19 int i,j;<br />

20 int quantida<strong>de</strong> = 0;<br />

21<br />

22 for (i = 0; i < matriz . nLinhas ; i ++) {<br />

23 for (j = 0; j < matriz . nColunas ; j ++) {<br />

24 if ( ( acessaMatrizInt ( matriz ,i,j) == 1) && isolado ( matriz ,i,j) ){<br />

25 quantida<strong>de</strong> ++;<br />

26 }<br />

27 }<br />

28 }<br />

29<br />

30 return quantida<strong>de</strong> ;<br />

31 }<br />

6.5 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Exemplo 6.23: Uns Isolados.<br />

Uma matriz é um tipo <strong>de</strong> dados <strong>com</strong>posto homogêneo no qual os elementos são organizados em<br />

uma estrutura multidimensional.<br />

A dimensão <strong>de</strong> uma matriz po<strong>de</strong> ser <strong>de</strong>finida, em C, tanto em tempo <strong>de</strong> <strong>com</strong>pilação, quanto em<br />

tempo <strong>de</strong> execução.<br />

Assim <strong>com</strong>o os vetores, em C, os elementos <strong>de</strong> uma matriz <strong>de</strong>vem ser manipulados separadamente.<br />

Foi implementado o TAD Matriz <strong>de</strong> Inteiros, <strong>com</strong>posto pelos seguintes atributos: número <strong>de</strong><br />

linhas da matriz, número <strong>de</strong> colunas da matriz e a matriz que armazenará os elementos.<br />

Para manipular os dados do TAD Matriz <strong>de</strong> Inteiros foram criadas as operações: inicialização,<br />

atualização <strong>de</strong> valor, acesso a valor, leitura, exibição, soma dos elementos <strong>de</strong> uma linha, soma<br />

dos elementos <strong>de</strong> uma coluna, soma dos elementos <strong>de</strong> uma diagonal e produto escalar.<br />

Deve-se tomar cuidado para não acessar uma matriz in<strong>de</strong>vidamente, por exemplo utilizando<br />

índice <strong>de</strong> linha ou coluna maior que o tamanho da linha ou coluna.<br />

6.6 Exercícios Propostos<br />

DRAFT<br />

1. Escreva um subprograma que <strong>de</strong>termine o maior valor em uma matriz <strong>de</strong> valores inteiros <strong>com</strong><br />

m linhas e n colunas (m e n são inteiros positivos).<br />

2. Faça um subprograma que calcule a matriz resultante da soma <strong>de</strong> duas matrizes <strong>de</strong> dimensões<br />

m linhas por n colunas, ambas preenchidas <strong>com</strong> valores inteiros.<br />

3. Escreva um subprograma que calcule a transposta <strong>de</strong> uma dada matriz <strong>de</strong> m linhas e n colunas.<br />

Consi<strong>de</strong>re <strong>com</strong>o matriz transposta A t , a matriz cujos elementos A t [i,j] são iguais aos elementos<br />

A[j][i].<br />

4. Escreva um subprograma que verifique se uma matriz quadrada <strong>de</strong> dimensão n é simétrica. Uma<br />

matriz A é simétrica se A[i,j] = A[j,i] para todo valor <strong>de</strong> i e j.<br />

5. Faça um subprograma que calcule a soma dos termos que se situam na diagonal secundária ou<br />

abaixo <strong>de</strong>la numa matriz quadrada <strong>com</strong> elementos inteiros. Assuma que o número máximo <strong>de</strong><br />

linhas e colunas é 100, mas que a matriz po<strong>de</strong> estar preenchida apenas parcialmente.


172<br />

CAPÍTULO 6. MATRIZES<br />

Observação: Antes <strong>de</strong> escrever o subprograma, você <strong>de</strong>ve apresentar a <strong>de</strong>claração do tipo da<br />

matriz que <strong>de</strong>ve ser colocada nos programas que usarão este subprograma.<br />

6. Uma matriz quadrada inteira é chamada <strong>de</strong> ‘’quadrado mágico” se a soma dos elementos <strong>de</strong> cada<br />

linha, a soma dos elementos <strong>de</strong> cada coluna e a soma dos elementos das diagonais principal e<br />

secundária são todos iguais.<br />

Exemplo <strong>de</strong> um quadrado mágico:<br />

8 0 7<br />

4 5 6<br />

3 10 2<br />

Escreva uma função que verifique se uma matriz quadrada <strong>de</strong> dimensão n é um quadrado mágico.<br />

7. Um quadrado latim <strong>de</strong> or<strong>de</strong>m n é preenchido <strong>com</strong> números <strong>de</strong> 1 até n <strong>de</strong> forma que nenhum<br />

número é repetido na mesma linha ou coluna. Este quadrado po<strong>de</strong> ser usado, por exemplo, em<br />

alguns torneios esportivos para assegurar que cada equipe joga <strong>com</strong> todas outras equipes uma<br />

e somente uma vez. Escreva uma função que receba uma matriz quadrada e verifica se ela é<br />

realmente um quadrado latim.<br />

Exemplo <strong>de</strong> quadrado latim:<br />

1 2 3 4<br />

2 3 4 1<br />

3 4 1 2<br />

4 1 2 3<br />

8. A matriz abaixo representa o triângulo <strong>de</strong> pascal <strong>de</strong> or<strong>de</strong>m 6:<br />

1<br />

1 1<br />

1 2 1<br />

1 3 3 1<br />

1 4 6 4 1<br />

1 5 10 10 5 1<br />

Os elementos extremos <strong>de</strong> cada linha são iguais a 1. Os outros elementos são obtidos somando-se<br />

os dois elementos que aparecem imediatamente acima e à esquerda na linha anterior. Assim 10<br />

= 4 + 6. Escreva um programa que, dado n, gere e exiba na tela o triângulo <strong>de</strong> Pascal <strong>de</strong> or<strong>de</strong>m<br />

n. A exibição não <strong>de</strong>ve conter zeros acima da diagonal principal.<br />

DRAFT<br />

9. Consi<strong>de</strong>re uma matriz <strong>de</strong> inteiros. Define-se <strong>com</strong>o vizinhança <strong>de</strong> uma posição da matriz a soma<br />

<strong>de</strong> todos os números que estejam em posições adjacentes. Escreva um programa que <strong>de</strong>termine<br />

a posição do elemento <strong>de</strong> maior vizinhança.<br />

10. Consi<strong>de</strong>re 2 matrizes quadradas do tipo tMatrizInt. Faça um subprograma para cada item abaixo<br />

(note que as matrizes <strong>de</strong>vem obrigatoriamente ser passadas <strong>com</strong>o parâmetros aos subprogramas):<br />

(a) Determinar se as duas matrizes são idênticas;<br />

(b) Determinar se a segunda matriz é uma rotação <strong>de</strong> 90 graus à direita sobre a primeira;<br />

(c) Determinar se a segunda matriz é uma rotação <strong>de</strong> 180 graus à direita sobre a primeira;<br />

(d) Determinar se a segunda matriz é a imagem espelhada vertical da primeira;<br />

(e) Determinar se a segunda matriz é a imagem espelhada horizontal da primeira;<br />

A Figura 6.5 ilustra cada tipo <strong>de</strong> matriz <strong>com</strong> um exemplo <strong>de</strong> dimensão 3 x 3:


6.7. TRABALHOS SUGERIDOS 173<br />

Figura 6.5: Figura exemplo relativa ao exercício 11.<br />

11. Escreva ainda um programa que leia 2 matrizes e <strong>de</strong>termine as relações existentes entre elas<br />

utilizando os subprogramas do exercício anterior.<br />

12. Implemente os tipos tMatrizChar e tVetChar (para armazenar variáveis do tipo char ao inves<br />

<strong>de</strong> int) e escreva uma função que receba uma matriz preenchida <strong>com</strong> caracteres maiúsculos do<br />

tipo tMatrizChar e um vetor do tipo tVetChar contendo uma palavra em letras maiúsculas<br />

e retorne o número <strong>de</strong> ocorrências da palavra na matriz. A palavra po<strong>de</strong> estar escrita na matriz<br />

<strong>de</strong> cima para baixo, da esquerda para a direita ou nas diagonais paralelas à diagonal principal<br />

ou na própria.<br />

6.7 Trabalhos Sugeridos<br />

1. Caça-Palavras<br />

Consi<strong>de</strong>re o jogo caça-palavras que consiste em procurar uma palavra dada em uma matriz <strong>de</strong><br />

letras. Consi<strong>de</strong>ra-se que a palavra foi encontrada se ela estiver inteiramente disposta em uma<br />

linha, em uma coluna ou em uma diagonal da matriz. Define-se uma palavra <strong>com</strong>o uma sequência<br />

<strong>de</strong> letras maiúsculas (para facilitar não consi<strong>de</strong>re acentuação). As palavras estão escritas na<br />

matriz sempre <strong>de</strong> cima para baixo, da esquerda para a direita ou nas diagonais paralelas à<br />

diagonal principal ou na própria diagonal. Faça um programa que tenha <strong>com</strong>o entrada um<br />

conjunto <strong>de</strong> n palavras e a matriz <strong>de</strong> caracteres, ambas fornecidas pelo teclado. O programa<br />

<strong>de</strong>ve ser capaz <strong>de</strong>:<br />

DRAFT<br />

(a) Verificar quais palavras foram encontradas e <strong>com</strong>putar o número <strong>de</strong> ocorrências <strong>de</strong> cada<br />

uma <strong>de</strong>las na matriz.<br />

(b) Exibir a lista das palavras encontradas e as listas das palavras não encontradas. As duas<br />

listas <strong>de</strong>vem estar em or<strong>de</strong>m alfabética.<br />

(c) Exibir a lista das palavras encontradas na matriz, or<strong>de</strong>nadas pelo seu número <strong>de</strong> ocorrências<br />

(consi<strong>de</strong>rar or<strong>de</strong>m <strong>de</strong>crescente). Informar também, nestes casos, a posição na matriz do<br />

caractere inicial <strong>de</strong> cada ocorrência da palavra, além da direção que ela se encontra na<br />

matriz. As direções são <strong>de</strong>finidas <strong>com</strong>o: diagonal, vertical, horizontal.<br />

(d) Informe a direção na qual mais palavras foram encontradas exibindo a quantida<strong>de</strong> <strong>de</strong> palavras.<br />

A saída <strong>de</strong>ve seguir o formato apresentado no exemplo a seguir:<br />

Exemplo:<br />

Conjunto <strong>de</strong> palavras: CAPELA, LAPIS, FLORESTA, AULA, ALEGRIA, MANGA<br />

Matriz:


174<br />

CAPÍTULO 6. MATRIZES<br />

Saída:<br />

F L O R E S T A R S<br />

H J V N O A C I W Z<br />

C A P E L A P I S C<br />

I K V D I P M B S F<br />

T Y G C S A L U O P<br />

Q L K Ç A D U O L Ç<br />

A A S A R P R Y O A<br />

N E N E F T E B A U<br />

J K D D S H W L F L<br />

I O T U G J J V A A<br />

Lista <strong>de</strong> palavras encontradas em or<strong>de</strong>m alfabética:<br />

AULA<br />

CAPELA<br />

FLORESTA<br />

LAPIS<br />

Lista <strong>de</strong> palavras não encontradas em or<strong>de</strong>m alfabética:<br />

ALEGRIA<br />

MANGA<br />

Lista <strong>de</strong> palavras encontradas, or<strong>de</strong>nadas pelo número <strong>de</strong> ocorrências na matriz:<br />

CAPELA 2 (2, 0) horizontal (4, 3) diagonal<br />

AULA 1 (6,9) vertical<br />

FLORESTA 1 (0, 0) horizontal<br />

LAPIS 1 (2,4) horizontal<br />

Direção em que mais palavras foram encontradas: horizontal<br />

Número <strong>de</strong> palavras encontradas nesta direção: 3<br />

DRAFT


Capítulo 7<br />

Apontadores<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Definir o que são apontadores;<br />

Coautores:<br />

Alan Floriano<br />

Douglas Almonfrey<br />

Igor Vale<br />

Ivan Nunes<br />

Juan Souza<br />

Mostrar a importância dos apontadores na passagem <strong>de</strong> parâmetros sem cópia, no retorno <strong>de</strong><br />

múltiplos valores nas funções e na alocação dinâmica <strong>de</strong> memória;<br />

Apresentar os principais problemas no uso <strong>de</strong> apontadores;<br />

Definir o TAD Lista Enca<strong>de</strong>ada e suas principais operações;<br />

Neste capítulo serão apresentados os conceitos relacionados aos apontadores. Estes conceitos estão<br />

intimamente ligados à manipulação da memória do <strong>com</strong>putador e são fundamentais para a criação <strong>de</strong><br />

estruturas <strong>de</strong> dados muito importantes <strong>com</strong>o listas, pilhas e árvores. Por esta razão, o conhecimento<br />

a cerca dos apontadores é fundamental para <strong>de</strong>senvolver programas em C.<br />

7.1 Variáveis Apontadoras<br />

Em um programa, cada variável possui seu en<strong>de</strong>reço <strong>de</strong> memória - que representa o local, ou posição,<br />

na memória on<strong>de</strong> o dado está <strong>de</strong> fato armazenado - e um conteúdo, que é a informação propriamente<br />

dita. A Figura 7.1 exibe cinco en<strong>de</strong>reços <strong>de</strong> memória e seus respectivos conteúdos.<br />

DRAFT<br />

Figura 7.1: Formato abstrato da memória.<br />

Os apontadores são um tipo especial <strong>de</strong> variável, cujo conteúdo não é um simples valor, e sim um<br />

en<strong>de</strong>reço <strong>de</strong> memória. Na Figura 7.2, po<strong>de</strong> ser observado que o conteúdo <strong>de</strong> uma variável apontador<br />

175


176<br />

CAPÍTULO 7. APONTADORES<br />

correspon<strong>de</strong> a um en<strong>de</strong>reço <strong>de</strong> uma variável não apontador. Nota-se que os conteúdos das variáveis à<br />

esquerda (apontadores) indicam os en<strong>de</strong>reços das variáveis à direita (não apontadores).<br />

Figura 7.2: Apontadores e não apontadores.<br />

Neste capítulo, serão estudados os apontadores, também chamados <strong>de</strong> ponteiros. Como os apontadores<br />

são variáveis que guardam en<strong>de</strong>reços, trata-se <strong>de</strong> um conceito <strong>de</strong> baixo nível muito ligado à<br />

arquitetura <strong>de</strong> <strong>com</strong>putadores. Apontadores são ferramentas po<strong>de</strong>rosas na linguagem <strong>de</strong> programação<br />

C. Dentre diversas funções, apontadores permitem passagem <strong>de</strong> parâmetros sem cópia <strong>de</strong> muitos dados,<br />

retorno <strong>de</strong> múltiplos valores em funções, alocação dinâmica <strong>de</strong> memória e construção <strong>de</strong> listas<br />

enca<strong>de</strong>adas.<br />

No <strong>de</strong>correr do capítulo, serão utilizados mo<strong>de</strong>los <strong>de</strong> figuras ilustrativas para auxiliar na explicação.<br />

Na Figura 7.3, tem-se o mo<strong>de</strong>lo para representar uma variável e seu en<strong>de</strong>reço.<br />

Figura 7.3: Formato abstrado <strong>de</strong> uma variável.<br />

Como po<strong>de</strong> ser observado na Figura 7.3, um quadrado será usado <strong>com</strong>o formato abstrato <strong>de</strong><br />

variável <strong>de</strong> memória. Dentro <strong>de</strong>ste quadrado estará representado o conteúdo da variável. Além disso,<br />

um círculo negro no seu vértice superior esquerdo representará <strong>de</strong> forma abstrata seu en<strong>de</strong>reço.<br />

Já para representar a ligação entre um apontador e a variável que está sendo apontada por ele,<br />

será utilizado o mo<strong>de</strong>lo da Figura 7.4. Tal ligação é ilustrada por meio <strong>de</strong> uma seta, que sai da variável<br />

apontador, e aponta o círculo negro (en<strong>de</strong>reço) da variável não apontador.<br />

DRAFT<br />

Figura 7.4: Abstração <strong>de</strong> uma variável apontador.<br />

Existe ainda um valor especial para apontadores conhecido <strong>com</strong>o valor nulo ou simplesmente NULL.<br />

O valor NULL indica que um apontador, intencionalmente, não aponta para nenhuma variável. Vale


7.2. A SINTAXE DOS APONTADORES 177<br />

lembrar que um apontador, quando não inicializado, não necessariamente aponta para NULL. A aplicabilida<strong>de</strong><br />

do valor NULL ficará mais clara no <strong>de</strong>correr do capítulo. Doravante o valor NULL será<br />

representado pelo símbolo da Figura 7.5.<br />

7.2 A Sintaxe dos Apontadores<br />

Figura 7.5: Representação gráfica do valor NULL.<br />

Na linguagem C, o operador asterisco * é que especifica se uma variável guarda um en<strong>de</strong>reço, ou seja,<br />

se é um apontador. A <strong>de</strong>claração <strong>de</strong> um apontador segue o seguinte formato:<br />

* <br />

No lugar do tipo do apontador, <strong>de</strong>vem-se utilizar alguns dos tipos padrões da linguagem C, <strong>com</strong>o<br />

char, int e float, ou até mesmo novos tipos <strong>de</strong>finidos pelo programador, por meio <strong>de</strong> structs. No<br />

Exemplo 7.1 são <strong>de</strong>clarados apontadores dos tipos char, int, float e tAluno.<br />

1 type<strong>de</strong>f struct {<br />

2 char nome [30];<br />

3 int matricula ;<br />

4 } tAluno ;<br />

5<br />

6 int main (){<br />

7 char *c;<br />

8 int *p;<br />

9 float *f;<br />

10 tAluno *x;<br />

11<br />

12 return 0;<br />

13 }<br />

DRAFT<br />

Exemplo 7.1: Declaração <strong>de</strong> apontadores.<br />

Assim, no código do Exemplo 7.1, c po<strong>de</strong> apontar para uma área <strong>de</strong> memória que guarda uma<br />

variável do tipo caractere, enquanto p, f e x dos tipos inteiro, ponto flutuante e tAluno, respectivamente.<br />

Dois outros operadores também estão associados à sintaxe <strong>de</strong> apontadores: o operador en<strong>de</strong>reço<br />

<strong>de</strong> memória e o operador seta. Eles serão discutidos nas duas próximas subseções.<br />

7.2.1 Operador En<strong>de</strong>reço <strong>de</strong> Memória<br />

Em C, o operador unário &, quando aplicado a uma variável, retorna o en<strong>de</strong>reço <strong>de</strong>la. Portanto,<br />

quando um apontador é <strong>de</strong>clarado, po<strong>de</strong>-se inicializá-lo usando o operador &, que faz o apontador<br />

receber um en<strong>de</strong>reço <strong>de</strong> uma variável já existente.<br />

O Exemplo 7.2 mostra o uso do operador & para inicializar uma variável apontador. A variável p<br />

recebe o en<strong>de</strong>reço da variável d. Note que a variável apontador p é do mesmo tipo da variável d, pois<br />

é fundamental que o apontador aponte para uma variável <strong>de</strong> tipo <strong>com</strong>patível <strong>com</strong> a <strong>de</strong>claração <strong>de</strong>le.<br />

1 # inclu<strong>de</strong> <br />

2


178<br />

CAPÍTULO 7. APONTADORES<br />

3 int main (){<br />

4 int *p;<br />

5 int d = 10;<br />

6 p = &d;<br />

7<br />

8 printf ("%p\n%p\n", &d, p);<br />

9<br />

10 return 0;<br />

11 }<br />

Exemplo 7.2: Inicialização <strong>de</strong> um apontador usando o operador en<strong>de</strong>reço <strong>de</strong> memória.<br />

No Exemplo 7.2, serão apresentados o en<strong>de</strong>reço <strong>de</strong> d, e logo após, o valor do apontador p, que é o<br />

en<strong>de</strong>reço <strong>de</strong> d. Portanto, dois valores iguais serão apresentados na tela. O %p, utilizado no Exemplo<br />

7.2, é usado pela função printf para i<strong>de</strong>ntificar o tipo <strong>de</strong> valor que será apresentado, neste caso %p<br />

informa que o valor <strong>de</strong> um apontador será apresentado, ou seja, o en<strong>de</strong>reço <strong>de</strong> uma variável.<br />

7.2.2 Acesso a Variável por Meio <strong>de</strong> Apontadores<br />

O operador unario * tem outra função além das já conhecidas que estão relacionadas a multiplicação<br />

e <strong>de</strong>finição <strong>de</strong> apontadores. Esse operador também po<strong>de</strong> ser usado junto a um apontador para que se<br />

possa retornar o valor da variável apontada. Por esse motivo, apontadores po<strong>de</strong>m ser usados para<br />

atribuir valores a outras variáveis. Observe o Exemplo 7.3.<br />

1 int *p;<br />

2 int c = 10;<br />

3 int d;<br />

4 p = &c;<br />

5 d = *p;<br />

Exemplo 7.3: Acesso ao conteúdo <strong>de</strong> variáveis por meio <strong>de</strong> apontadores.<br />

No Exemplo 7.3, p recebe o en<strong>de</strong>reço <strong>de</strong> c. Através <strong>de</strong> p portanto, po<strong>de</strong>-se agora acessar o valor<br />

<strong>de</strong> c. Com esse recurso, na quinta linha do Exemplo 7.3, d recebe o valor <strong>de</strong> c por meio <strong>de</strong> p.<br />

Uma variável po<strong>de</strong> ser atribuída por meio do uso <strong>de</strong> apontadores. No Exemplo 7.4, a variável c<br />

tem seu valor alterado através <strong>de</strong> uma atribuição feita a p.<br />

1 float *p;<br />

2 float c = 15;<br />

3 p = &c;<br />

4 *p = *p + 1;<br />

5 printf ("%f", c);<br />

DRAFT<br />

Exemplo 7.4: Alterando valor <strong>de</strong> variáveis por meio <strong>de</strong> apontadores.<br />

Po<strong>de</strong> ser observado no Exemplo 7.4, que p aponta para c. Assim, a expressão na linha 4 incrementa<br />

o conteúdo da variável apontada por p em uma unida<strong>de</strong>, ou seja, c passa a ter o valor 16, o qual é<br />

apresentado na tela.<br />

Uma variável po<strong>de</strong> receber o valor <strong>de</strong> outra por meio <strong>de</strong> apontadores. Na linha 7 do Exemplo 7.5,<br />

a variável i apontada por v tem seu valor alterado para o <strong>de</strong> d, pois d está apontado por j.<br />

1 float *v;<br />

2 float *j;<br />

3 float d = 15.0;<br />

4 float i = 17.0;<br />

5 j = &d;<br />

6 v = &i;<br />

7 *v = *j;<br />

8 v = j;<br />

Exemplo 7.5: Alterando valor <strong>de</strong> variáveis através <strong>de</strong> apontadores.


7.2. A SINTAXE DOS APONTADORES 179<br />

Figura 7.6: Atribuição dos conteúdos <strong>de</strong> apontadores.<br />

Figura 7.7: Atribuição dos en<strong>de</strong>reços <strong>de</strong> apontadores.<br />

Um apontador também po<strong>de</strong> ser atribuído a outro apontador. No Exemplo 7.5, linha 8, v passa a<br />

apontar para o mesmo en<strong>de</strong>reço que j aponta.<br />

Por fim, esse acesso a variáveis através <strong>de</strong> apontadores é muito importante, pois é por meio <strong>de</strong>ste<br />

recurso que as variáveis passadas <strong>com</strong>o parâmetros <strong>de</strong> uma função são alteradas <strong>de</strong>finitivamente, <strong>de</strong>ntro<br />

da própria função.<br />

7.2.3 O Operador Seta<br />

Outro operador associado a apontadores é a seta (->). Quando um apontador indica uma variável do<br />

tipo estrutura, para que se acesse os atributos <strong>de</strong>sta variável, ao invés do ponto (.), utiliza-se (->).<br />

Observe o Exemplo 7.6.<br />

1 # inclu<strong>de</strong> <br />

2<br />

3 type<strong>de</strong>f struct {<br />

4 char nome [30];<br />

5 int matricula ;<br />

6 } tAluno ;<br />

7<br />

8 int main (){<br />

9 tAluno *x;<br />

10 tAluno y;<br />

11<br />

12 x = &y;<br />

13 x-> matricula = 2031;<br />

14<br />

15 printf ("%d\n", y. matricula );<br />

16<br />

17 return 0;<br />

18 }<br />

DRAFT<br />

Exemplo 7.6: Acesso ao atributo <strong>de</strong> uma estrutura por meio do operador seta.<br />

Note que no Exemplo 7.6, x é um apontador para uma estrutura tAluno e y uma variável tAluno.<br />

Após fazer x apontar para o en<strong>de</strong>reço <strong>de</strong> y, para acessar a matrícula <strong>de</strong> y através <strong>de</strong> x, <strong>de</strong>ve ser


180<br />

CAPÍTULO 7. APONTADORES<br />

utilizado o operador ->. Já para exibir o atual valor da matrícula <strong>de</strong> y, que passou a ser 2031, basta<br />

utilizar o ponto.<br />

O operador seta é uma sintaxe alternativa muito utilizada por sua simplicida<strong>de</strong>. Seria possível<br />

também utilizar o acesso ao conteúdo seguido do ponto. Na linha 13 do Exemplo 7.6 a sintaxe<br />

equivalente seria:<br />

1 (*x). matricula = 2031;<br />

Exemplo 7.7: Acesso ao atributo <strong>de</strong> uma estrutura por meio do operador asterisco seguido <strong>de</strong> ponto.<br />

7.3 Uso <strong>de</strong> Apontadores nas Passagens <strong>de</strong> Parâmetros<br />

O conceito <strong>de</strong> função em C, conforme já discutido em capítulos prece<strong>de</strong>ntes, é fundamental. Uma das<br />

principais vantagens <strong>de</strong> apontadores, no que diz respeito à função, é a passagem <strong>de</strong> valores sem cópia.<br />

Na passagem por cópia, as variáveis que são passadas <strong>com</strong>o argumentos da função tem seus valores<br />

copiados para uma região <strong>de</strong> memória criada especificamente para a execução da função. São essas<br />

cópias que a função utiliza no <strong>de</strong>correr da sua execução. Assim, qualquer alteração dos valores das<br />

cópias não implicará em mudança nas variáveis originais.<br />

Por meio <strong>de</strong> apontadores, é possível alterar os valores das variáveis passadas <strong>com</strong>o argumentos<br />

para uma função. Ao <strong>de</strong>clarar que um parâmetro <strong>de</strong> uma função é um apontador, <strong>de</strong>ve-se passar o<br />

en<strong>de</strong>reço <strong>de</strong> uma variável <strong>com</strong>o argumento correspon<strong>de</strong>nte. Nesse tipo <strong>de</strong> passagem, não é copiado o<br />

valor da variável argumento, mas <strong>com</strong> o en<strong>de</strong>reço <strong>de</strong>la, po<strong>de</strong>-se acessar o conteúdo e modificá-lo no<br />

<strong>de</strong>correr da execução da função. O Exemplo 7.8 mostra a passagem por cópia e por apontadores.<br />

1 void adicionaX1 ( int x, int b){<br />

2 b = b + x;<br />

3 }<br />

4<br />

5 void adicionaX2 ( int x, int *b){<br />

6 *b = *b + x;<br />

7 }<br />

8<br />

9 int main (){<br />

10 int a = 0;<br />

11<br />

12 adicionaX1 (10 , a);<br />

13 printf ("a = %d\n", a);<br />

14 adicionaX2 (10 , &a);<br />

15 printf ("a = %d\n", a);<br />

16<br />

17 return 0;<br />

18 }<br />

DRAFT<br />

Exemplo 7.8: Passagem <strong>de</strong> valor por cópia e através <strong>de</strong> apontadores.<br />

Em adicionaX1 , no Exemplo 7.8, uma cópia do valor <strong>de</strong> a é passada <strong>com</strong> argumento da função,<br />

ou seja, b recebe uma cópia do valor 0 <strong>de</strong> a. Dentro da função, o valor <strong>de</strong> b muda para 10, mas o <strong>de</strong><br />

a continua o mesmo. Assim, o primeiro valor impresso é 0. Já em adicionaX2 , o en<strong>de</strong>reço <strong>de</strong> a é<br />

passado para o apontador b e, na execução da função, é adicionado x ao conteúdo da variável apontada<br />

por b, o que faz a ter seu valor modificado para 10. Portanto, o que é apresentado no segundo printf é<br />

a = 10. A Figura 7.8 ilustra as passagens <strong>de</strong> parâmetro <strong>de</strong> a para b, em adicionaX1 e adicionaX2 .


7.4.<br />

ALOCAÇÃO DINÂMICA DE MEMÓRIA 181<br />

Figura 7.8: Passagem <strong>de</strong> valor por cópia e por apontadores.<br />

Na Figura 7.8, repare que na passagem por cópia, o valor <strong>de</strong> a é copiado para o conteúdo <strong>de</strong> b,<br />

enquanto que na passagem por apontador, b passa a apontar para o en<strong>de</strong>reço <strong>de</strong> a.<br />

Uma aplicação da passagem <strong>de</strong> valor por apontadores é proporcionar que uma função retorne<br />

múltiplas variáveis. O Exemplo 7.9 mostra <strong>com</strong>o isso é feito.<br />

1 void troca ( int *x, int *y){<br />

2 int aux ;<br />

3<br />

4 aux = *x;<br />

5 *x = *y;<br />

6 *y = aux ;<br />

7 }<br />

8<br />

9 int main (){<br />

10 int a, b;<br />

11 a = 10;<br />

12 b = 20;<br />

13<br />

14 troca (&a, &b);<br />

15 printf ("a = %d, b = %d\n", a, b);<br />

16<br />

17 return 0;<br />

18 }<br />

DRAFT<br />

Exemplo 7.9: Retorno <strong>de</strong> múltiplas variáveis por uma função.<br />

No Exemplo 7.9, <strong>de</strong>sejava-se uma função para trocar o conteúdo <strong>de</strong> a e b. Contudo, uma função<br />

po<strong>de</strong> retornar apenas um valor no return. Assim, por meio dos apontadores, os dois conteúdos são<br />

alterados e permanecem assim após o fim da execução da função, pois a e b são passados sem cópia,<br />

ou seja, são passados seus en<strong>de</strong>reços <strong>com</strong>o parâmetros da função troca.<br />

7.4 Alocação Dinâmica <strong>de</strong> Memória<br />

Apontadores também são fundamentais no que diz respeito à alocação dinâmica, economia <strong>de</strong> memória<br />

e tempo <strong>de</strong> execução.<br />

Apontadores permitem alocação <strong>de</strong> memória em tempo <strong>de</strong> execução (alocação dinâmica). Para<br />

tanto, uma variável ponteiro aponta para uma área <strong>de</strong> memória livre <strong>de</strong>finida durante a execução do<br />

programa. As Figuras 7.9 e 7.10 ilustram o processo <strong>de</strong> alocação dinâmica.<br />

A Figura 7.9 mostra as áreas livres da memória. Em um <strong>de</strong>terminado momento, um en<strong>de</strong>reço, que


182<br />

CAPÍTULO 7. APONTADORES<br />

Figura 7.9: Áreas <strong>de</strong> memória livres.<br />

indicava uma região <strong>de</strong> memória livre, passa a ser apontado por uma variável apontador, <strong>de</strong>ssa forma<br />

a região <strong>de</strong> memória passa a po<strong>de</strong>r ser utilizada, o que é ilustrado na Figura 7.10.<br />

Figura 7.10: Área <strong>de</strong> memória alocada dinamicamente.<br />

Em C, a função malloc (abreviatura <strong>de</strong> memory allocation), da biblioteca padrão stdlib, aloca um<br />

bloco <strong>de</strong> bytes consecutivos na memória do <strong>com</strong>putador e <strong>de</strong>volve o en<strong>de</strong>reço <strong>de</strong>sse bloco. O Exemplo<br />

7.10 mostra seu uso.<br />

1 int *p<br />

2 p = ( int *) malloc (4 * ( sizeof ( int )));<br />

DRAFT<br />

Exemplo 7.10: Alocação dinâmica <strong>de</strong> quatro inteiros.<br />

No Exemplo 7.10, a expressão sizeof retorna o número <strong>de</strong> bytes <strong>de</strong> um tipo passado <strong>com</strong>o<br />

parâmetro, no caso int. Além disso, <strong>com</strong>o a função malloc retorna um apontador do tipo void *<br />

para um bloco <strong>de</strong> bytes consecutivos, esse apontador <strong>de</strong>ve ser convertido em apontador para o tipo<br />

<strong>de</strong>sejado, nesse caso, por meio do operador <strong>de</strong> conversão <strong>de</strong> tipo (int *), uma vez que a variável p é<br />

do tipo int. Deste modo fica garantida a consistência <strong>de</strong> tipos. A Figura 7.11 ilustra um espaço <strong>de</strong> 4<br />

inteiros, alocados dinamicamente pelo Exemplo 7.10.<br />

Vale ressaltar que a função malloc, antes <strong>de</strong> alocar a região <strong>de</strong> memória especificada, <strong>de</strong>ve buscar<br />

na memória do <strong>com</strong>putador um espaço correspon<strong>de</strong>nte ao <strong>de</strong>sejado no programa. Esse processo <strong>de</strong><br />

busca po<strong>de</strong> <strong>com</strong>prometer a velocida<strong>de</strong> <strong>de</strong> execução do programa, embora para a maioria das aplicações<br />

esse tempo <strong>de</strong> busca seja <strong>de</strong>sprezível.


7.4.<br />

ALOCAÇÃO DINÂMICA DE MEMÓRIA 183<br />

Figura 7.11: Vetor <strong>de</strong> inteiros alocados dinamicamente.<br />

Um espaço <strong>de</strong> memória <strong>de</strong>ve ser <strong>de</strong>salocado quando não é mais necessário. Isto significa que a área<br />

<strong>de</strong> memória que foi apontada por um apontador agora passa a ser novamente livre. Somente variáveis<br />

alocadas dinamicamente po<strong>de</strong>m ser <strong>de</strong>salocadas em tempo <strong>de</strong> execução.<br />

O processo <strong>de</strong> <strong>de</strong>salocação <strong>de</strong> memória, em C, está ilustrado no Exemplo 7.11.<br />

1 int *p;<br />

2 p = ( int *) malloc (4 * sizeof ( int ));<br />

3 free (p);<br />

Exemplo 7.11: Utilização da função free para liberar memória.<br />

No Exemplo 7.11, a função free, que assim <strong>com</strong>o malloc, está na biblioteca stdlib tem o papel <strong>de</strong><br />

<strong>de</strong>salocar uma área <strong>de</strong> memória. Note que a função free <strong>de</strong>ve receber <strong>com</strong>o parâmetro uma variável<br />

apontador. Assim, a área <strong>de</strong> memória apontada por ele será então liberada. A Figura 7.12 ilustra a<br />

<strong>de</strong>salocação <strong>de</strong> memória.<br />

DRAFT<br />

Figura 7.12: Desalocação dinâmica <strong>de</strong> memória.<br />

Na Figura 7.12, po<strong>de</strong>-se observar que no <strong>de</strong>correr da execução do programa, a variável apontador<br />

<strong>de</strong>ixa <strong>de</strong> apontar para área <strong>de</strong> memória, que por sua vez volta para o grupo <strong>de</strong> en<strong>de</strong>reços livres.<br />

O processo <strong>de</strong> alocação dinâmica po<strong>de</strong> ser usado para ler linhas <strong>de</strong> um documento <strong>de</strong> <strong>texto</strong>. Sem o<br />

uso <strong>de</strong> alocação dinâmica, seria necessário <strong>de</strong>finir previamente um tamanho fixo n x m <strong>de</strong> uma matriz<br />

limitando o tamanho do <strong>texto</strong> e da linha que po<strong>de</strong>m ser lidos. Para se conseguir ler todas as linhas,<br />

<strong>de</strong>fine-se o tamanho m da matriz <strong>com</strong>o o tamanho da maior linha que será lida e n um número gran<strong>de</strong><br />

suficiente para armazenar todas as linhas. Entretanto, esse procedimento acarreta perda <strong>de</strong> memória<br />

<strong>com</strong> linhas pequenas, que não utilizam todo o espaço alocado para elas, e tratando-se <strong>de</strong> <strong>texto</strong>s <strong>com</strong>


184<br />

CAPÍTULO 7. APONTADORES<br />

gran<strong>de</strong>s quantida<strong>de</strong>s <strong>de</strong> linhas essa perda torna-se consi<strong>de</strong>rável.<br />

Consi<strong>de</strong>re a Figura 7.13, que ilustra <strong>com</strong>o seria o processo <strong>de</strong> alocação dinâmica <strong>de</strong> uma matriz<br />

para ler um pequeno <strong>texto</strong> <strong>de</strong> caracteres. Percebe-se facilmente que, para a quarta linha da matriz, 9<br />

espaços seriam perdidos.<br />

Figura 7.13: Matriz que armazena um <strong>texto</strong>.<br />

Para contornar o problema <strong>de</strong> perda <strong>de</strong> memória <strong>com</strong> espaços não utilizados, faz-se uso da alocação<br />

dinâmica. A cada necessida<strong>de</strong> <strong>de</strong> se ler uma linha <strong>com</strong> certo número <strong>de</strong> caracteres, aloca-se o exato<br />

tamanho da linha, ou seja, a quantida<strong>de</strong> <strong>de</strong> caracteres da string que será lida.<br />

O Exemplo 7.12 mostra a implementação em linguagem C <strong>de</strong> uma matriz <strong>de</strong> caracteres dinamicamente<br />

alocada. Esta matriz possui 4 linhas <strong>de</strong> tamanhos alocados <strong>de</strong> acordo <strong>com</strong> o tamanho da string<br />

armazenada, e cada linha da matriz recebe uma linha do <strong>texto</strong> da Figura 7.13. A matriz <strong>de</strong>clarada no<br />

Exemplo 7.12 é simplesmente um vetor <strong>de</strong> apontadores para strings e os elementos do vetor g contém<br />

os en<strong>de</strong>reços dos primeiros elementos <strong>de</strong> cada string. Na Figura 7.14 está ilustrado o vetor <strong>de</strong> strings<br />

correspon<strong>de</strong>nte ao <strong>texto</strong>.<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> < stdlib .h><br />

3<br />

4 int main (){<br />

5 char *g [4];<br />

6 g [0] = ( char *) malloc ( ( strlen (" Joao ama Maria ") + 1) * sizeof ( char ));<br />

7 strcpy (g[0] , " Joao ama Maria ");<br />

8 g [1] = ( char *) malloc ( ( strlen (" Maria ama pedro ") + 1 ) * sizeof ( char ));<br />

9 strcpy (g[1] , " Maria ama pedro ");<br />

10 g [2] = ( char *) malloc ( ( strlen (" Ana ama quem ama Maria ") + 1) * sizeof ( char ));<br />

11 strcpy (g[2] , " Ana ama quem ama Maria ");<br />

12 g [3] = ( char *) malloc ( ( strlen (" Quem Ana ama ?") + 1) * sizeof ( char ));<br />

13 strcpy (g[3] , " Quem Ana ama ?");<br />

14<br />

15 return 0;<br />

16 }<br />

DRAFT<br />

Exemplo 7.12: Definição <strong>de</strong> uma matriz <strong>de</strong> caracteres dinâmica<br />

Figura 7.14: Vetor <strong>de</strong> strings.<br />

Para <strong>de</strong>terminar o tamanho alocado dinamicamente é calculado o tamanho da string usando a<br />

função strlen e soma-se 1 que é a posição ocupada pelo caracter \0, sinalizador <strong>de</strong> fim <strong>de</strong> string.


7.5. PROBLEMAS GERADOS POR APONTADORES 185<br />

Po<strong>de</strong>-se acessar um elemento da matriz utilizando a notação g[i][j] no Exemplo 7.12, on<strong>de</strong> i e j são<br />

os indices da matriz. Alternativamente, é possível acessar o primeiro elemento da matriz por meio do<br />

operador asterisco <strong>com</strong> a sintaxe: **g.<br />

7.5 Problemas Gerados por Apontadores<br />

Apesar <strong>de</strong> serem muito importantes, quando usados inapropriadamente, apontadores são fontes <strong>de</strong><br />

erros difíceis <strong>de</strong> serem encontrados. Apontadores não inicializados, objetos pen<strong>de</strong>ntes, referência<br />

pen<strong>de</strong>nte, e programação macarrônica são alguns <strong>de</strong>sses erros.<br />

7.5.1 Apontadores Não Inicializados<br />

Quando se trata <strong>de</strong> apontadores, um erro muito <strong>com</strong>um é utilizá-los antes <strong>de</strong> fazê-los apontar para<br />

algum en<strong>de</strong>reço válido, ou seja, sem inicializá-los. O Exemplo 7.13 mostra <strong>com</strong>o isso po<strong>de</strong> ocorrer. O<br />

valor da variável apontada por p recebe o valor <strong>de</strong> h, mas p não foi inicializado ainda, ou seja, não<br />

apontava para nenhum espaço <strong>de</strong> memória válido.<br />

1 float *p, h = 15.0;<br />

2 *p = h;<br />

Exemplo 7.13: Apontador não inicializado.<br />

As consequências da utilização <strong>de</strong> um apontador não inicializado são imprevisíveis, po<strong>de</strong>ndo provocar<br />

uma paralisação do programa.<br />

7.5.2 Objetos Pen<strong>de</strong>ntes<br />

Objetos pen<strong>de</strong>ntes ocorrem quando uma área <strong>de</strong> memória alocada fica inacessível. Veja o Exemplo<br />

7.14. A área <strong>de</strong> memória apontada por p fica inacessível, pois p passa a apontar para o mesmo en<strong>de</strong>reço<br />

<strong>de</strong> q. Durante o restante da execução do programa este espaço <strong>de</strong> memória permanece reservado,<br />

impedindo sua reutilização e <strong>com</strong>prometendo a economia <strong>de</strong> memória. A Figura 7.15 ilustra <strong>com</strong>o<br />

ocorrem objetos pen<strong>de</strong>ntes.<br />

DRAFT<br />

Figura 7.15: Objetos pen<strong>de</strong>ntes.<br />

1 int *p = ( int *) malloc ( sizeof ( int ));<br />

2 int *q = ( int *) malloc ( sizeof ( int ));<br />

3 p = q;<br />

Exemplo 7.14: Objetos pen<strong>de</strong>ntes.


186<br />

CAPÍTULO 7. APONTADORES<br />

7.5.3 Referência Pen<strong>de</strong>nte<br />

Quando é liberado um en<strong>de</strong>reço <strong>de</strong> memória que é apontado por mais <strong>de</strong> uma variável apontador ocorre<br />

a referência pen<strong>de</strong>nte. Assim, algumas variáveis ficam referenciando um en<strong>de</strong>reço que foi <strong>de</strong>salocado.<br />

Veja o Exemplo 7.15 que mostra um caso <strong>de</strong> referência pen<strong>de</strong>nte. O en<strong>de</strong>reço da variável h é liberado,<br />

portanto p aponta para um espaço <strong>de</strong> memória liberado. A Figura 7.16 ilustra o problema <strong>de</strong> referência<br />

pen<strong>de</strong>nte. Um espaço <strong>de</strong> memória livre po<strong>de</strong> ser alocado a qualquer momento por outras variáveis do<br />

sistema. Ao se utilizar variáveis que tiveram seu espaço <strong>de</strong> memória liberado, po<strong>de</strong>-se estar acessando<br />

áreas importantes do sistema, que alocou o espaço <strong>de</strong> memória que acabara <strong>de</strong> ser liberado, e isto<br />

po<strong>de</strong> provocar uma paralisação do programa.<br />

Figura 7.16: Referência pen<strong>de</strong>nte.<br />

DRAFT


7.6. TAD IMPLEMENTACIONAL LISTA ENCADEADA DE INTEIROS 187<br />

1 int *p;<br />

2 int *h;<br />

3 h = ( int *) malloc ( sizeof ( int ));<br />

4 p = h;<br />

5 free (h);<br />

Exemplo 7.15: Referência pen<strong>de</strong>nte.<br />

7.5.4 Programação Macarrônica<br />

Um mesmo en<strong>de</strong>reço <strong>de</strong> memória po<strong>de</strong> ser apontado por vários apontadores. Isso po<strong>de</strong> tornar confuso<br />

o entendimento do programa e a i<strong>de</strong>ntificação <strong>de</strong> erros. O Exemplo 7.16 mostra um trecho <strong>de</strong> código<br />

difícil <strong>de</strong> enten<strong>de</strong>r <strong>de</strong>vido ao uso indiscriminado <strong>de</strong> apontadores.<br />

1 type<strong>de</strong>f struct {<br />

2 int numeroSala ;<br />

3 int numeroAlunos ;<br />

4 } tSala ;<br />

5<br />

6 void acresentaAluno ( tSala *g){<br />

7 g-> numeroAlunos = g-> numeroAlunos + 1;<br />

8 }<br />

9<br />

10 int main (){<br />

11 int p;<br />

12 tSala sala ;<br />

13 sala . numeroSala = 1;<br />

14 sala . numeroAlunos = 0;<br />

15 tSala *x;<br />

16 tSala *y;<br />

17<br />

18 y = & sala ;<br />

19 x = y;<br />

20 acrescentaAluno (x);<br />

21 acrescentaAluno (y);<br />

22<br />

23 return 0;<br />

24 }<br />

Exemplo 7.16: Programação macarrônica causada pelo uso indiscriminado <strong>de</strong> apontadores.<br />

No Exemplo 7.16, o número <strong>de</strong> alunos da variável sala é alterado duas vezes, uma pelo apontador<br />

x, outra por meio do apontador y. Portanto, quando apontadores são usados <strong>de</strong> uma maneira<br />

indiscriminada, po<strong>de</strong>-se diminuir a legibilida<strong>de</strong> do código.<br />

DRAFT<br />

7.6 TAD Implementacional Lista Enca<strong>de</strong>ada <strong>de</strong> Inteiros<br />

Uma lista enca<strong>de</strong>ada é uma estrutura cujos elementos são acessados sequencialmente por meio <strong>de</strong><br />

apontadores. Nessa estrutura estão armazenados os apontadores para o <strong>com</strong>eço e o fim <strong>de</strong> uma<br />

sequência <strong>de</strong> blocos, conhecidos <strong>com</strong>o “nós”, além <strong>de</strong> uma variável inteira que indica a quantida<strong>de</strong><br />

atual <strong>de</strong> elementos na lista. Cada nó, por sua vez, possui informações armazenadas, um apontador<br />

para o próximo nó. Na Figura 7.17, tem-se um esquema <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada, <strong>com</strong><br />

três nós e <strong>com</strong> apontadores para o primeiro e o último elemento.<br />

Note que cada um dos nós possui um apontador para o próximo, <strong>com</strong> exceção do último, no qual<br />

há um apontador para NULL, pois não há próximo. Repare também que a estrutura da lista possui<br />

apontadores para o início e o fim da lista, além <strong>de</strong> armazenar seu tamanho corrente, no caso, três<br />

elementos.<br />

Po<strong>de</strong>-se perceber que incluir elementos em uma lista enca<strong>de</strong>ada torna-se um processo simples.<br />

Se um novo dado necessita ser incluído, basta alocar um espaço <strong>de</strong> memória para o nó, atualizar os


188<br />

CAPÍTULO 7. APONTADORES<br />

Figura 7.17: Esquema <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

apontadores da sequência <strong>de</strong> nós e a quantida<strong>de</strong> <strong>de</strong>les na lista. Excluir um dado da lista é um processo<br />

semelhante, <strong>com</strong> a diferença <strong>de</strong> que, ao invés <strong>de</strong> se alocar, <strong>de</strong>saloca-se uma área da memória.<br />

Vale <strong>de</strong>stacar que as estruturas da lista e <strong>de</strong> cada um dos dados armazenados em um nó são exemplos<br />

do uso <strong>de</strong> abstração, pois se encapsulam informações, seleciona-se o que <strong>de</strong>ve ser apresentado <strong>de</strong><br />

uma função à outra e possibilita-se o trabalho em níveis <strong>de</strong> implementação e uso, prática fundamental<br />

na modularização <strong>de</strong> um código. Conforme visto no capítulo 4, po<strong>de</strong>-se dizer que o tipo <strong>de</strong> abstração<br />

utilizada na lista enca<strong>de</strong>ada é uma abstração <strong>de</strong> dados implementacional, por meio do uso <strong>de</strong> Tipos<br />

Abstratos <strong>de</strong> Dados, TADs.<br />

Anteriormente foi visto que TADs são conjuntos <strong>de</strong> valores <strong>com</strong> <strong>com</strong>portamento uniforme <strong>de</strong>finido<br />

por operações, que são tipicamente os <strong>com</strong>ponentes responsáveis pela interface entre os diferentes<br />

níveis e módulos <strong>de</strong> implementação. Essa interface é responsável por encapsular e proteger os dados.<br />

A implementação do TAD lista enca<strong>de</strong>ada tLista será apresentada a seguir. Também serão <strong>de</strong>talhadas<br />

várias operações fundamentais sobre a lista. Inicialmente, será <strong>de</strong>finido o tipo tNo, o qual é<br />

um <strong>com</strong>ponente importante <strong>de</strong> tLista.<br />

7.6.1 Definição do Tipo tNo<br />

De acordo <strong>com</strong> o que foi dito até agora, cada nó <strong>de</strong>ve ser responsável por armazenar um dado, além <strong>de</strong><br />

conter um apontador para o próximo nó, no caso <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada. O Exemplo<br />

7.17 mostra <strong>com</strong>o po<strong>de</strong> ser a estrutura tNo:<br />

1 type<strong>de</strong>f int tInfo ;<br />

2<br />

3 void imprimetInfo ( tInfo info ){<br />

4 printf (" Elemento : %d\n",info );<br />

5 }<br />

6<br />

7 type<strong>de</strong>f struct no{<br />

8 tInfo info ;<br />

9 struct no * proximo ;<br />

10 } tNo ;<br />

DRAFT<br />

Exemplo 7.17: Estrutura tNo.<br />

Há necessida<strong>de</strong> <strong>de</strong> se incluir o termo no após o primeiro struct porque, ao se incluir o atributo<br />

proximo, ocorre uma <strong>de</strong>finição recursiva do tipo no, ou seja, a estrutura no possui um campo do<br />

mesmo tipo que ela. Assim, caso fosse retirado o primeiro termo no, não se saberia qual o tipo <strong>de</strong><br />

proximo. Também é importante dizer que a variável inteira info po<strong>de</strong>ria ser substituída por qualquer<br />

outro tipo, tais <strong>com</strong>o char, float e, até mesmo, estruturas <strong>com</strong>postas por uma varieda<strong>de</strong> <strong>de</strong> tipos.<br />

Para isso, bastaria alterar o termo int na <strong>de</strong>finição do tipo tInfo.<br />

A partir <strong>de</strong> agora, <strong>de</strong>vido ao uso do type<strong>de</strong>f, sempre que for utilizado o termo tNo antes <strong>de</strong> um<br />

i<strong>de</strong>ntificador, significa que está sendo <strong>de</strong>clarada uma estrutura <strong>com</strong>o a do Exemplo 7.17.<br />

Como frequentemente será necessário incluir novos nós, torna-se importante criar uma função que<br />

aloque dinamicamente um espaço <strong>de</strong> memória para um nó. O Exemplo 7.18 mostra uma forma <strong>de</strong>


7.6. TAD IMPLEMENTACIONAL LISTA ENCADEADA DE INTEIROS 189<br />

implementar tal função.<br />

1 tNo * criaNo ( tInfo elem ){<br />

2 tNo *no = ( tNo *) malloc ( sizeof ( tNo ));<br />

3 no -> proximo = NULL ;<br />

4 no -> info = elem ;<br />

5<br />

6 return no;<br />

7 }<br />

Exemplo 7.18: Implementação da operação criaNo.<br />

Após a alocação do espaço <strong>de</strong> memória, o apontador proximo é inicializado <strong>com</strong>o NULL. Em<br />

seguida, o campo info do nó criado é associado ao valor do elemento passado <strong>com</strong>o argumento. Por<br />

fim, é retornado um apontador para a área <strong>de</strong> memória inicializada na função.<br />

7.6.2 Atributos <strong>de</strong> tLista<br />

A estrutura tLista a ser <strong>de</strong>finida tem apontadores para o primeiro e último nó. Essa estrututa é<br />

chamada cabeçalho da lista. Cabe ressalvar que existem diferentes formas <strong>de</strong> implementar listas<br />

enca<strong>de</strong>adas. A mostrada no Exemplo 7.19 é apenas uma <strong>de</strong>las.<br />

1 type<strong>de</strong>f struct {<br />

2 tNo * primeiro ;<br />

3 tNo * marcador ;<br />

4 tNo * ultimo ;<br />

5 int tam ;<br />

6 } tLista ;<br />

Exemplo 7.19: Estrutura tLista.<br />

Repare que três atributos <strong>de</strong> tLista são apontadores para o tipo tNo, o qual foi <strong>de</strong>finido na<br />

seção anterior. Dois <strong>de</strong>les, primeiro e ultimo, apontam para o <strong>com</strong>eço e para o fim da lista, enquanto<br />

marcador aponta para qualquer posição. A variável inteira tam é a responsável por guardar o tamanho<br />

atual, ou número <strong>de</strong> nós, da lista.<br />

O apontador marcador é responsável por apontar o nó corrente num processo <strong>de</strong> busca sequencial.<br />

Por exemplo, na operação <strong>de</strong> imprimir a lista, que será explicada mais adiante, a informação é extraída<br />

do nó apontado por marcador, o qual é posicionado <strong>de</strong>s<strong>de</strong> o primeiro nó até o último.<br />

7.6.3 Operações <strong>de</strong> tLista<br />

DRAFT<br />

Como já se têm <strong>de</strong>finidos os tipos <strong>de</strong> dados, tNo e tLista, necessita-se criar as operações que serão<br />

responsáveis por trabalhar <strong>com</strong> valores do tipo tLista, concluindo assim, a implementação do TAD<br />

lista enca<strong>de</strong>ada.<br />

Operações Construtoras<br />

As operações construtoras são responsáveis por garantir a alocação da estrutura tLista, além <strong>de</strong><br />

inicializá-la <strong>com</strong> os valores <strong>de</strong>sejados, geralmente <strong>com</strong> os apontadores apontando para NULL e as<br />

variáveis numéricas <strong>com</strong> valor zero. O Exemplo 7.20 mostra a função <strong>de</strong> inicialização <strong>de</strong> uma lista.<br />

1 void inicia ( tLista * lista ){<br />

2 lista -> primeiro = NULL ;<br />

3 lista -> marcador = NULL ;<br />

4 lista -> ultimo = NULL ;<br />

5 lista -> tam = 0;<br />

6 }<br />

Exemplo 7.20: Inicialização <strong>de</strong> uma lista.


190<br />

CAPÍTULO 7. APONTADORES<br />

Na função inicia os apontadores primeiro, marcador e ultimo são inicializados <strong>com</strong> NULL, pois<br />

não há nós na lista e, garante-se assim, que estes não apontem para uma área <strong>de</strong> memória in<strong>de</strong>vida.<br />

Em seguida, o tamanho da lista é zerado uma vez que o atual tamanho da lista é nulo.<br />

Operações Analisadoras<br />

Em algumas situações é importante analisar a posição atual do marcador, se ele está no fim da lista,<br />

se a lista está vazia etc. Por exemplo, ao se percorrer a lista, uma condição <strong>de</strong> parada importante<br />

é quando o final da lista for alcançado e, ao se incluir ou excluir um elemento da lista, é necessário<br />

saber se a lista está vazia.<br />

Essas análises são importantes para que não se <strong>com</strong>eta acessos in<strong>de</strong>vidos <strong>com</strong> os apontadores, um<br />

dos problemas explicados anteriormente.<br />

O Exemplo 7.21 mostra a implementação da função analisadora <strong>de</strong> fim da lista.<br />

1 int final ( tLista * lista ){<br />

2 return ( lista -> marcador == NULL );<br />

3 }<br />

Exemplo 7.21: Verificação <strong>de</strong> fim da lista.<br />

Essa função simplesmente retorna o resultado da <strong>com</strong>paração do marcador da lista <strong>com</strong> NULL.<br />

Isso porque o último nó da lista tem <strong>com</strong>o próximo este valor, bem <strong>com</strong>o a lista vazia, que tem seus<br />

apontadores iniciais todos apontando para NULL. Na Figura 7.18, o marcador não está apontando<br />

para NULL, assim não é o fim da lista e, portanto, a função final retorna 0.<br />

Figura 7.18: Marcador Apontando para uma posição da lista.<br />

Já na Figura 7.19 o marcador aponta para NULL, ou seja para o fim da lista. Assim, o retorno da<br />

função é 1.<br />

DRAFT<br />

Figura 7.19: Marcador Apontando para o fim da lista.<br />

O Exemplo 7.22 mostra a implementação da função analisadora <strong>de</strong> lista vazia.<br />

1 int vazia ( tLista * lista ){<br />

2 return ( lista -> tam == 0);


7.6. TAD IMPLEMENTACIONAL LISTA ENCADEADA DE INTEIROS 191<br />

3 }<br />

Exemplo 7.22: Verificação se a lista está vazia.<br />

Assim <strong>com</strong>o na análise do fim da lista, vazia retorna o resultado <strong>de</strong> uma <strong>com</strong>paração. Nesse caso,<br />

porém, se o tamanho da lista é igual zero. Como o tamanho da lista é inicializado <strong>com</strong> este valor<br />

e, sempre que um novo nó for adicionado, ou removido, este tamanho <strong>de</strong>ve ser atualizado, a única<br />

possibilida<strong>de</strong> <strong>de</strong> ele ser zero é quando a lista estiver realmente vazia.<br />

Um exemplo <strong>de</strong> utilização da função vazia é quando se <strong>de</strong>seja incluir, ou excluir um nó da lista.<br />

É necessário um tratamento especial na primeira inclusão, pois o primeiro e ultimo elemento são os<br />

mesmos, e na exclusão, uma vez que seria um erro tentar remover elementos <strong>de</strong> uma lista vazia.<br />

Operações Modificadoras<br />

Uma das características interessantes da lista enca<strong>de</strong>ada é a facilida<strong>de</strong> <strong>de</strong> se incluir e excluir elementos,<br />

em tempo <strong>de</strong> execução, <strong>com</strong> praticida<strong>de</strong>, uma vez que é necessário somente alocar e <strong>de</strong>salocar nós,<br />

respectivamente. É importante, então, conhecer as funções <strong>de</strong> inserção e exclusão, tratadas <strong>com</strong>o<br />

operações modificadoras, pois alteram a <strong>com</strong>posição corrente da lista. No Exemplo 7.23, o novo<br />

elemento e a lista no qual ele será inserido são passados <strong>com</strong>o argumentos. A passagem do cabeçalho<br />

lista é feita por apontador, pois assim, qualquer modificação em seus elementos é feita diretamente<br />

na função, sem necessida<strong>de</strong> <strong>de</strong> passar toda lista por cópia e retorná-la ao fim da execução da função.<br />

O elemento será incluído no fim da lista, mas diferentes implementações, nas quais ele é inserido no<br />

<strong>com</strong>eço, ou numa dada posição, também são possíveis.<br />

1 void incluirFim ( tLista * lista , tInfo elem ){<br />

2 tNo *no;<br />

3<br />

4 no = criaNo ( elem );<br />

5<br />

6 if( vazia ( lista )){<br />

7 lista -> primeiro = no;<br />

8 } else {<br />

9 lista -> ultimo -> proximo = no;<br />

10 }<br />

11<br />

12 lista -> ultimo = lista -> marcador = no;<br />

13 lista -> tam ++;<br />

14 }<br />

DRAFT<br />

Exemplo 7.23: Função <strong>de</strong> inclusão <strong>de</strong> um novo nó na lista.<br />

Como po<strong>de</strong> ser visto no exemplo acima, inicialmente o novo nó <strong>de</strong>ve ser criado para armazenar o<br />

elemento a ser incluído. Para isso é utilizada a função inicializadora criaNo, que aloca um espaço<br />

<strong>de</strong> memória do tamanho <strong>de</strong> tNo, faz o campo info ser igual ao elemento passado <strong>com</strong>o argumento<br />

e retorna um apontador para o espaço alocado. A Figura 7.20 mostra o estado da lista, antes da<br />

inclusão, e o novo nó a ser incluído.<br />

Agora que já se tem o novo nó, é necessário incluí-lo na lista, ou seja, atualizar o valor <strong>de</strong> tam e<br />

os apontadores. Como a lista tem mais um nó, seu tamanho <strong>de</strong>ve ser incrementado em uma unida<strong>de</strong>.<br />

Quanto à atualização dos apontadores, os apontadores ultimo e marcador <strong>de</strong>vem apontar para o nó<br />

incluído, respectivamente, porque ele é incluído no fim da lista e no último nó acessado. Antes, porém,<br />

é importante verificar se a lista está vazia, pois caso esteja, quem também vai apontar para nó a ser<br />

incluído, será o apontador primeiro da lista, caso contrário, será apontador proximo do ultimo nó da<br />

lista. Vale <strong>de</strong>stacar que a análise se a lista está vazia é um exemplo <strong>de</strong> uso da função vazia, que foi<br />

explicada anteriormente. A Figura 7.21 exibe a lista após a inclusão do novo nó.


192<br />

CAPÍTULO 7. APONTADORES<br />

Figura 7.20: Lista antes da inclusão.<br />

Figura 7.21: Lista após a inclusão.<br />

O Exemplo 7.24 mostra a implementação <strong>de</strong> uma operação <strong>de</strong> exclusão.<br />

1 void excluir ( tLista * lista , int pos ){<br />

2 tNo *auxA , * auxB ;<br />

3 int i;<br />

4<br />

5 if(pos < 0 || pos >= lista -> tam ){<br />

6 return ;<br />

7 }<br />

8<br />

10<br />

9 auxA = lista -> primeiro ;<br />

11 for (i =0;i proximo ;<br />

14 }<br />

15<br />

16 if( auxA != lista -> primeiro ){<br />

17 auxB -> proximo = auxA -> proximo ;<br />

18 if( auxA == lista -> ultimo ){<br />

19 lista -> ultimo = auxB ;<br />

20 }<br />

21 } else {<br />

22 lista -> primeiro = auxA -> proximo ;<br />

23 if(lista -> ultimo == auxA ){<br />

24 lista -> ultimo = auxA -> proximo ;<br />

25 }<br />

26 }<br />

27<br />

28 lista -> marcador = NULL ;<br />

29 lista ->tam - -;<br />

DRAFT


7.6. TAD IMPLEMENTACIONAL LISTA ENCADEADA DE INTEIROS 193<br />

30 free ( auxA );<br />

31 }<br />

Exemplo 7.24: Função <strong>de</strong> exclusão <strong>de</strong> um nó da lista.<br />

Na função <strong>de</strong> exclusão, são passadas <strong>com</strong>o parâmetros a lista e a posição do nó a ser excluído.<br />

Consi<strong>de</strong>ra-se que a primeira posição é zero. Assim, é importante saber, inicialmente, se o valor <strong>de</strong> pos<br />

é válido e, caso não seja, a função é encerrada.<br />

São criados dois apontadores auxiliares do tipo tNo: auxA e auxB. Para buscar o nó da posição pos,<br />

auxA aponta para o primeiro nó da lista e inicia-se um laço for, até que o valor <strong>de</strong> i, que inicialmente<br />

é zero, seja pos. A cada iteração <strong>de</strong>sse laço, auxB vai apontar para o último nó apontado por auxA e<br />

este, por sua vez, aponta para o próximo nó da lista. Portanto, quando auxA estiver apontando para o<br />

nó a ser excluído, o anterior a ele é apontado por auxB, o que é importante na hora <strong>de</strong> se atualizarem<br />

os apontadores, conforme será explicado.<br />

Após ter encontrado o nó da posição pos, tem que se analisar quatro situações possíveis: 1) esse<br />

nó a ser excluído não ser nem o primeiro e nem o último nó da lista; 2) ser o último; 3) ser o primeiro;<br />

4) e ser o único nó. No caso 1, basta fazer o apontador proximo do nó apontado por auxB apontar<br />

para o nó apontado pelo proximo do nó apontado por auxA. No caso 2, também se <strong>de</strong>ve fazer o último<br />

nó da lista ser auxB. Vale lembrar que, no caso <strong>de</strong> auxA ser o último, ao se fazer o proximo <strong>de</strong> auxB<br />

ser o proximo <strong>de</strong> auxA, está se fazendo simplesmente auxB ter <strong>com</strong>o próximo o valor NULL. Já no<br />

caso 3, coloca-se o próximo <strong>de</strong> auxA <strong>com</strong>o o nó inicial e, no caso 4, faz-se também o apontador ultimo<br />

da lista apontar para o próximo <strong>de</strong> auxA. Nesse último caso, está se redirecionando os apontadores,<br />

primeiro e ultimo da lista, para NULL.<br />

Agora que já se tem os apontadores atualizados e retirado o nó da seqüência <strong>de</strong> nós, coloca-se o<br />

marcador da lista <strong>com</strong>o NULL, pois será perdido o último nó acessado. Então, diminui-se o tamanho<br />

da lista e, finalmente, libera-se o espaço <strong>de</strong> memória apontado por auxA. A Figura 7.22 ilustra a lista<br />

da Figura 7.19 após a exclusão do nó 2.<br />

DRAFT<br />

Figura 7.22: Lista após a exclusão do nó 2.<br />

Outro importante tipo <strong>de</strong> operação modificadora é a que permite posicionar o marcador em um<br />

nó. Elas são úteis para acessar informações em um nó <strong>de</strong>terminado previamente.<br />

O Exemplo 7.25 é a implementação da função que posiciona o marcador no primeiro nó da lista.<br />

1 void primeiro ( tLista * lista ){<br />

2 lista -> marcador = lista -> primeiro ;<br />

3 }<br />

Exemplo 7.25: Posicionado o marcador no <strong>com</strong>eço da lista.<br />

Para fazer o marcador <strong>de</strong> uma lista apontar para o primeiro elemento <strong>de</strong>la, basta igualar o marcador<br />

ao apontador primeiro. O objetivo da função primeiro é posicionar o marcador no início da lista,<br />

para permitir que seja feita uma busca nos elementos da lista a partir do seu início.<br />

A função proximo é mostrada no Exemplo 7.26.<br />

1 void proximo ( tLista * lista ){<br />

2 if(lista -> marcador != NULL ){<br />

3 lista -> marcador = lista -> marcador -> proximo ;<br />

4 }


194<br />

CAPÍTULO 7. APONTADORES<br />

5 }<br />

Exemplo 7.26: Posicionado o marcador no proximo nó da lista.<br />

A função proximo é para posicionar o marcador, fazendo-o apontar para o próximo elemento da<br />

lista. A verificação se o marcador atual é diferente <strong>de</strong> NULL evita o acesso in<strong>de</strong>vido à memória.<br />

A utilida<strong>de</strong> das operações <strong>de</strong> posicionamento <strong>de</strong> marcador será ilustrada a seguir na seção Operações<br />

Produtoras.<br />

Operações Produtoras<br />

Uma vez armazenados os dados na lista é fundamental permitir o acesso e a recuperação <strong>de</strong>stas<br />

informações. As funções produtoras possibilitam extrair alguma informação da lista.<br />

O Exemplo 7.27 mostra a operação responsável por retornar a informação do nó apontado pelo<br />

marcador da lista.<br />

1 int obterInfo ( tLista * lista , tInfo * info ){<br />

2 if(lista -> marcador == NULL ){<br />

3 return 0;<br />

4 }<br />

5 * info = lista -> marcador -> info ;<br />

6 return 1;<br />

7 }<br />

Exemplo 7.27: Função para recuperar a informação <strong>de</strong> um nó.<br />

A função obterInfo tem por objetivo atribuir o conteúdo do nó, apontado pelo marcador, à<br />

variável info, passada <strong>com</strong>o parâmetro. A função retorna o valor 1 se houve sucesso na obtenção do<br />

conteúdo do nó e retorna o valor 0 caso contrário. Assim, impe<strong>de</strong>-se o acesso a um local in<strong>de</strong>vido da<br />

memória.<br />

O Exemplo 7.28 ilustra o uso <strong>de</strong>ssas informações por meio do uso <strong>de</strong> uma função que imprime todos<br />

os dados <strong>de</strong> uma lista. Para a função é passada a lista cujos elementos serão impressos. Inicialmente<br />

a função primeiro é utilizada para posicionar o marcador no início da lista e, em seguida, <strong>com</strong>eça<br />

um laço while, que varre a lista até queo final <strong>de</strong>la seja alcançado. A verificação se o final da lista foi<br />

alcançado é feita pela função final, conforme <strong>de</strong>scrito anteriormente.<br />

1 void imprimir ( tLista * lista ){<br />

2 tInfo x;<br />

3 int erro = 0;<br />

4<br />

5 primeiro ( lista );<br />

6<br />

7 while (! final ( lista )){<br />

8 erro = obterInfo ( lista , &x);<br />

9 if( erro ){<br />

10 imprimetInfo (x);<br />

11 }<br />

12 proximo ( lista );<br />

13 }<br />

14 }<br />

DRAFT<br />

Exemplo 7.28: Impressão <strong>de</strong> todos elementos <strong>de</strong> uma lista.<br />

Para cada posição do marcador, obterInfo retorna o valor <strong>de</strong> info do nó apontado pelo marcador<br />

da lista. Esse valor é impresso caso tenha ocorrido sucesso na obtenção da informação, ou seja, a<br />

variável erro ter o valor 1. A operação proximo posiciona o marcador no próximo nó da lista e,<br />

somente quando este marcador for NULL, o laço while será encerrado.<br />

Po<strong>de</strong> ser necessário em algum momento da execução obter o tamanho total da lista. Para isso,<br />

po<strong>de</strong> ser usada a função obterTam mostrada no Exemplo 7.29.


7.6. TAD IMPLEMENTACIONAL LISTA ENCADEADA DE INTEIROS 195<br />

1 int obterTam ( tLista * lista ){<br />

2 return lista -> tam ;<br />

3 }<br />

Exemplo 7.29: Função para obter o tamanho da lista.<br />

Operação Destrutora<br />

Quando a lista não é mais necessária, é importante <strong>de</strong>salocar o espaço <strong>de</strong> memória ocupado por seus<br />

nós. A função responsável por <strong>de</strong>salocar a lista e seus elementos é conhecida <strong>com</strong>o <strong>de</strong>strutora. Repare,<br />

no Exemplo 7.30, que a <strong>de</strong>salocação <strong>de</strong> memória é feita nó por nó. Note que ao final da operação,<br />

os valores dos atributos <strong>de</strong> lista são modificados para apontarem para NULL para evitar que fiquem<br />

referenciando áreas já <strong>de</strong>salocadas.<br />

1 void <strong>de</strong>stroi ( tLista * lista ){<br />

2 tNo * aux ;<br />

3<br />

4 primeiro ( lista );<br />

5<br />

6 while (! final ( lista )){<br />

7 aux = lista -> marcador ;<br />

8 proximo ( lista );<br />

9 free ( aux );<br />

10 }<br />

11<br />

12 lista -> primeiro = NULL ;<br />

13 lista -> marcador = NULL ;<br />

14 lista -> ultimo = NULL ;<br />

15 lista -> tam = 0;<br />

16 }<br />

Exemplo 7.30: Desalocação das áreas <strong>de</strong> memória ocupados pelos nós da lista.<br />

Semelhantemente a função <strong>de</strong> imprimir, a função primeiro é utilizada para posicionar o marcador<br />

no inicio da lista e, em seguida, inicia-se um laço enquanto o final <strong>de</strong>la não é alcançado.<br />

A cada iteração, um nó auxiliar aux guarda o en<strong>de</strong>reço <strong>de</strong> memória apontado pelo marcador da<br />

lista. Em seguida, posiciona-se o marcador no próximo nó da lista e a região apontada por aux é<br />

liberada <strong>com</strong> o uso da função free.<br />

Quando se chega ao final da lista, o laço while é encerrado e os atributos da lista voltam ao seu<br />

estado inicial, assim, seus apontadores apontam para NULL e o tamanho é zerado.<br />

7.6.4 Uso<br />

DRAFT<br />

A fim <strong>de</strong> ilustrar a utilização do TAD Implementacional Lista Enca<strong>de</strong>ada, será utilizado um cadastro<br />

simples <strong>de</strong> alunos na universida<strong>de</strong>. Veja o Pseudocódigo 7.1.<br />

Pseudocódigo 7.1 Uso <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

Descrição: Cadastrar alunos.<br />

Dados <strong>de</strong> Entrada: Nomes e as respectivas matrículas.<br />

Saída do Programa: Lista impressa.<br />

Inicializar lista .<br />

Ler primeiro nome .<br />

Ler primeira matrícula .<br />

ENQUANTO matrícula for maior que zero :<br />

Incluir nome e matrícula na lista .<br />

Ler nome .


196<br />

CAPÍTULO 7. APONTADORES<br />

Ler matrícula .<br />

FIM - ENQUANTO .<br />

ENQUANTO posiç~ao for maior ou igual a zero :<br />

Ler posiç~ao a ser excluída.<br />

Validar posiç~ao a ser excluída.<br />

SE a posiç~ao contiver algum nó:<br />

Excluir o nó.<br />

FIM -SE.<br />

FIM - ENQUANTO .<br />

Exibir lista .<br />

Destruir lista .<br />

O Pseudocódigo 7.1 <strong>de</strong>screve os passos para o programa <strong>de</strong> cadastro simples, no qual apenas<br />

po<strong>de</strong>-se ler e armazenar algumas entradas. Após a leitura, alguns dados po<strong>de</strong>m ser excluídos e as<br />

informações restantes exibidas.<br />

No cadastro, haverá apenas o nome e o número <strong>de</strong> matrícula do aluno, mas vale lembrar que, para<br />

um registro <strong>de</strong> informações mais <strong>de</strong>talhado, basta acrescentar mais atributos no exemplo <strong>de</strong> estrutura<br />

tInfo do exemplo apresentado.<br />

Observe o Exemplo 7.31, no qual se tem a transcrição do Pseudocódigo 7.1. Foram utilizadas todas<br />

as funções estudadas nesta seção, porém <strong>com</strong> algumas modificações, uma vez que o campo info, da<br />

estrutura do nó, não é mais um inteiro, e sim, uma outra estrutura. Só estão mostradas as estruturas<br />

e as operações anteriores que sofreram modificação.<br />

1 type<strong>de</strong>f struct {<br />

2 int matricula ;<br />

3 char nome [30];<br />

4 } tInfo ;<br />

5<br />

6 void imprimirtInfo ( tInfo info ){<br />

7 printf (" Nome : %s.\n", info . nome );<br />

8 printf (" Matricula : %d.\n", info . matricula );<br />

9 }<br />

10<br />

11 int main (){<br />

12 tLista * lista ;<br />

13 tInfo dados ;<br />

14 int pos ;<br />

15<br />

16 inicia ( lista );<br />

17<br />

18 printf (" Entre <strong>com</strong> o nome do aluno : ");<br />

19 scanf ("%s", & dados . nome );<br />

20 printf (" Entre <strong>com</strong> a matricula do aluno : ");<br />

21 scanf ("%d", & dados . matricula );<br />

22<br />

23 while ( dados . matricula > 0){<br />

24 incluirFim ( lista , dados );<br />

25<br />

26 printf (" Entre <strong>com</strong> o nome do aluno : ");<br />

27 scanf ("%s", & dados . nome );<br />

28 printf (" Entre <strong>com</strong> a matricula do aluno : ");<br />

29 scanf ("%d", & dados . matricula );<br />

30 }<br />

31<br />

DRAFT<br />

32 printf (" Digite a posicao do elemento a ser excluido : ");<br />

33 scanf ("%d", & pos );<br />

34<br />

35 while ( pos >= 0){<br />

36 excluir ( lista , pos );<br />

37 printf (" Digite a posicao do elemento a ser excluido : ");<br />

38 scanf ("%d", & pos );<br />

39 }<br />

40


7.7.<br />

EXERCÍCIOS RESOLVIDOS 197<br />

41 imprimir ( lista );<br />

42 <strong>de</strong>stroi ( lista );<br />

43<br />

44 return 0;<br />

45 }<br />

Exemplo 7.31: Cadastro <strong>de</strong> alunos na universida<strong>de</strong>.<br />

O programa implementado no Exemplo 7.31 apenas lê as informações do teclado enquanto não se<br />

digita um valor inválido, no caso matricula menor ou igual a 0. Se for digitado algum <strong>de</strong>sses valores<br />

para matricula o laço while é interrompido. Cada nome e matrícula são armazenados na lista e, após o<br />

término <strong>de</strong> leitura <strong>de</strong> dados, os elementos da lista são exibidos na tela. Po<strong>de</strong>-se apagar as informações<br />

fornecendo a posição na lista, do dado a ser apagado. Por fim, antes <strong>de</strong> se encerrar o programa, a lista<br />

é <strong>de</strong>struída.<br />

7.7 Exercícios Resolvidos<br />

Exercício Resolvido 7.1 - Acesso ao Conteúdo <strong>de</strong> Variáveis por Apontadores<br />

Para o trecho <strong>de</strong> código do Exemplo 7.32, ilustre os estados das variáveis apontadoras e nãoapontadoras.<br />

Utilize para a ilustração os padrões adotados na Figura 7.3 e Figura 7.4 para representar<br />

uma variável não apontador e apontador respectivamente.<br />

1 int *p;<br />

2 int *q;<br />

3 int a;<br />

4 int b;<br />

5 int c;<br />

6<br />

7 b = 10;<br />

8 c = 15;<br />

9 a = c;<br />

10 p = &b;<br />

11 q = &c;<br />

12 *p = *q;<br />

Exemplo 7.32: Código para o exercício resolvido 7.1.<br />

Solução Possível:<br />

Inicialmente são criados dois apontadores para inteiro, p e q, e três variáveis inteiras: a b e c. Em<br />

seguida, b passa a armazenar o valor 10, enquanto c, 15. Já a rebece o valor <strong>de</strong> c, ou seja, 15. Isso é<br />

ilustrado nas três primeiras cenas da Figura 7.23.<br />

Por fim, p e q passam a apontar b e c, repectivamente. Assim, na última linha, o conteúdo da<br />

variável apontada por p recebe o valor <strong>de</strong> c, pois este é a variável apontada por q, o que faz b receber<br />

o valor 15. Vejas os três últimos passos da Figura 7.23.<br />

DRAFT


198<br />

CAPÍTULO 7. APONTADORES<br />

Figura 7.23: Solução do exercício resolvido 7.1.<br />

Exercício Resolvido 7.2 - Múltiplo Retorno em uma Função<br />

A função calculaPot, do Exemplo 7.33, calcula o quadrado <strong>de</strong> um inteiro. Modifique esta função<br />

para que ela passe a retornar também o cubo <strong>de</strong>ste número. Faça as <strong>de</strong>vidas alterações na main.<br />

1 int calculaPot ( int valor ){<br />

2 int potQuadrada ;<br />

3<br />

4 potQuadrada = valor * valor ;<br />

5<br />

6 return potQuadrada ;<br />

7 }<br />

8<br />

9 int main (){<br />

10 int x;<br />

11 int quadrado ;<br />

12<br />

DRAFT<br />

13 scanf ("%d", &x);<br />

14 quadrado = calculaPot (x);<br />

15 printf (" Quadrado <strong>de</strong> %d = %d\n", x, quadrado );<br />

16<br />

17 return 0;<br />

18 }<br />

Exemplo 7.33: Função calculaPot.<br />

Solução Possível:<br />

O dado <strong>de</strong> entrada do programa é um número inteiro, e as saídas <strong>de</strong>vem ser o quadrado e cubo<br />

<strong>de</strong>ste número, calculadas pela função apresentada no Exemplo 7.33, <strong>com</strong> suas <strong>de</strong>vidas alterações. O<br />

Pseudocódigo 7.2 exibe as etapas para a solução.


7.7.<br />

EXERCÍCIOS RESOLVIDOS 199<br />

Pseudocódigo 7.2 Cálculo das potências quadradas e cúbicas <strong>de</strong> um número inteiro.<br />

Descrição: Retornar as potências quadrada e cúbica <strong>de</strong> um número inteiro, calculadas por uma função apenas.<br />

Dados <strong>de</strong> Entrada: Um número inteiro.<br />

Saída do Programa: Potências quadrada e cúbica do valor <strong>de</strong> entrada.<br />

Ler o número inteiro ;<br />

Passar os par^ametros para a funç~ao calculaPot ;<br />

Calcular as pot^encias pela funç~ao calculaPot .<br />

A função calculaPot <strong>de</strong>ve ser alterada para também calcular e retornar o cubo do valor. Contudo,<br />

o retorno <strong>de</strong>ssa função já é o quadrado do parâmetro <strong>de</strong> entrada. Nesse sentido, a passagem por<br />

apontadores é a ferramenta para múltiplos retornos numa função.<br />

As modificações no Exemplo 7.33 po<strong>de</strong>m ser observadas no Exemplo 7.34.<br />

1 int calculaPot ( int valor , int * potCubica ){<br />

2 int potQuadrada ;<br />

3<br />

4 potQuadrada = valor * valor ;<br />

5 * potCubica = potQuadrada * valor ;<br />

6<br />

7 return potQuadrada ;<br />

8 }<br />

9<br />

10 int main (){<br />

11 int x;<br />

12 int quadrado ;<br />

13 int cubo ;<br />

14<br />

15 scanf ("%d", &x);<br />

16 quadrado = calculaPot (x, & cubo );<br />

17 printf (" Quadrado <strong>de</strong> %d = %d\ nCubo <strong>de</strong> %d = %d\n", x, quadrado , x, cubo );<br />

18<br />

19 return 0;<br />

20 }<br />

Exemplo 7.34: Múltiplo retorno em calculaPot.<br />

DRAFT<br />

Como po<strong>de</strong> ser observado, calculaPot passa a ter um parâmetro que irá receber o en<strong>de</strong>reço da<br />

variável cubo, <strong>de</strong>clarada na main. Dessa forma, ao término da execução <strong>de</strong> calculaPot, a variável<br />

cubo irá conter a potência cúbica do valor.<br />

Exercício Resolvido 7.3 - Inserção no Início <strong>de</strong> Lista Simplesmente Enca<strong>de</strong>ada<br />

Foi visto anteriormente <strong>com</strong>o inserir um elemento no final da lista. Agora, preten<strong>de</strong>-se criar uma<br />

função que insere no <strong>com</strong>eço <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

Solução Possível:<br />

São apresentados os passos a serem seguidos pela função no Pseudocódigo 7.3, on<strong>de</strong> também se<br />

po<strong>de</strong> observar os dados <strong>de</strong> entrada e o retorno da função.<br />

Pseudocódigo 7.3 Inserção no <strong>com</strong>eço <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

Descrição: Inserir um nó no <strong>com</strong>eço <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

Dados <strong>de</strong> Entrada: A lista e o elemento a ser inserido.<br />

Saída da Função: A lista após a inserção.


200<br />

CAPÍTULO 7. APONTADORES<br />

Criar um nó para armazenar o novo elemento .<br />

Verificar se a lista está vazia :<br />

SE estiver vazia :<br />

Incluir novo nó <strong>com</strong>o último da lista .<br />

SEN~AO<br />

Inserir o novo nó tendo <strong>com</strong>o seu próximo o antigo primeiro .<br />

FIM -SE.<br />

Posicionar o atributo primeiro no nó criado .<br />

Posicionar o atributo marcador no nó incluído.<br />

Incrementar o tamanho da lista .<br />

O Exemplo 7.35 mostra a implementação em C do Pseudocódigo 7.3. Para tal função, a passagem<br />

da lista será feita por apontador, pois assim, qualquer modificação em seus elementos será feita diretamente<br />

na função e, por consegüinte, o retorno é void. A lista po<strong>de</strong>ria ser passada por cópia, mas<br />

assim a lista modificada <strong>de</strong>veria estar em um <strong>com</strong>ando return.<br />

1 void incluirInicio ( tLista * lista , tInfo elem ){<br />

2 tNo *no;<br />

3<br />

4 no = criaNo ( elem );<br />

5<br />

6 if( vazia ( lista )){<br />

7 lista -> ultimo = no;<br />

8 } else {<br />

9 no -> proximo = lista -> primeiro ;<br />

10 }<br />

11<br />

12 lista -> primeiro = lista -> marcador = no;<br />

13 lista -> tam ++;<br />

14 }<br />

Exemplo 7.35: Função <strong>de</strong> inclusão <strong>de</strong> um novo nó no <strong>com</strong>eço da lista.<br />

No Exemplo 7.35, um novo nó é criado <strong>com</strong> a utilização da função criaNo. Ao incluí-lo no inicío,<br />

os apontadores primeiro e marcador <strong>de</strong>vem apontar para o nó ser incluído, respectivamente porque<br />

ele é incluído no <strong>com</strong>eço da lista e é o último nó acessado.<br />

Contudo, antes <strong>de</strong> atualizar o apontador primeiro é fundamental verificar se a lista está vazia, pois<br />

caso não esteja, o novo nó <strong>de</strong>ve guardar, <strong>com</strong>o seu próximo, o antigo primeiro da lista. Já se a lista<br />

estiver vazia, basta fazer o apontador ultimo também apontar para o novo nó. Por fim, o tamanho da<br />

lista <strong>de</strong>ve ser incrementado em uma unida<strong>de</strong>.<br />

A Figura 7.24 mostra a Figura 7.20, após a inclusão do novo nó no <strong>com</strong>eço da lista.<br />

DRAFT<br />

Figura 7.24: Lista da Figura 7.20, após a inclusão do nó no <strong>com</strong>eço.


7.7.<br />

EXERCÍCIOS RESOLVIDOS 201<br />

Exercício Resolvido 7.4 - Media <strong>de</strong> valores <strong>de</strong> uma Lista Simplesmente Enca<strong>de</strong>ada<br />

Consi<strong>de</strong>re uma lista na qual são armazenados o nome e o salário <strong>de</strong> funcionários <strong>de</strong> uma empresa.<br />

Exibir na tela todos os funcionários cujos salários estão acima da média.<br />

Solução Possível:<br />

O programa principal segue os passos <strong>de</strong>scritos no Pseudocódigo 7.4.<br />

Pseudocódigo 7.4 Média dos valores <strong>de</strong> uma lista simplesmente enca<strong>de</strong>ada.<br />

Descrição: Imprimir os funcionários cujos salários estão acima da média.<br />

Dados <strong>de</strong> Entrada: Nomes e os respectivos salários.<br />

Saída do Programa: Lista <strong>de</strong> nomes que tem o salário acima da média.<br />

Inicializar a lista .<br />

FAZER :<br />

Ler nome .<br />

Ler salário .<br />

SE o salário n~ao for menor que zero :<br />

Incluir no fim da lista .<br />

FIM -SE.<br />

ENQUANTO salário for maior ou igual o zero .<br />

Processo <strong>com</strong>ponente " Verificar quem está acima da média ".<br />

Destruir lista .<br />

O passo Verificar quem está acima da média po<strong>de</strong> ser <strong>de</strong>scrito <strong>com</strong>o o Pseudocódigo 7.6. O<br />

Pseudocódigo 7.5 mostra os passos para calcular a média, basta somar todos os salários e dividir pelo<br />

total <strong>de</strong> nós da lista. Obtida a média, o Pseudocódigo 7.6 procura na lista quem tem o salário maior<br />

que ela.<br />

Pseudocódigo 7.5 Processo para encontrar a média dos salários.<br />

Descrição: Calcular a média dos salários dos funcionários.<br />

Dados <strong>de</strong> Entrada: Lista <strong>com</strong> os nomes e os respectivos salários.<br />

Saída do Programa: Valor da média dos salários.<br />

DRAFT<br />

Processo <strong>com</strong>ponente " Obter média ":<br />

Ir para o <strong>com</strong>eço da lista .<br />

Inicializar soma dos salários igual a zero .<br />

ENQUANTO n~ao chegar no fim da lista :<br />

Somar o salário atual à soma acumulada dos salários .<br />

Ir para o próximo da lista .<br />

FIM - ENQUANTO<br />

Achar média ( Divi<strong>de</strong> -se o total somado pelo tamanho da lista ).<br />

Fim Processo <strong>com</strong>ponente " Obter média ".<br />

Pseudocódigo 7.6 Processo para ver quem está <strong>com</strong> salário acima da média.<br />

Descrição: Verificar os funcionários <strong>com</strong> salário acima da média<br />

Dados <strong>de</strong> Entrada: Lista <strong>com</strong> os nomes e os respectivos salários.<br />

Saída do Programa: Exibição na tela dos funcionários <strong>com</strong> salário acima da média.<br />

Processo <strong>com</strong>ponente " Verificar quem está acima da média ":<br />

Ir para o <strong>com</strong>eço da lista .<br />

Processo <strong>com</strong>ponente " Obter média ".


202<br />

CAPÍTULO 7. APONTADORES<br />

ENQUANTO n~ao chegar no fim da lista :<br />

SE existir um nó <strong>com</strong> o salário maior que a média :<br />

Exibir as informaç~oes do funcionário .<br />

FIM -SE.<br />

Ir para o próximo da lista .<br />

FIM - ENQUANTO .<br />

FIM Processo <strong>com</strong>ponente " Verificar quem está acima da média "<br />

No exemplo 7.36 é mostrada a implementação em C do exercício.<br />

1 type<strong>de</strong>f struct {<br />

2 char nome [30];<br />

3 float salario ;<br />

4 } tInfo ;<br />

5<br />

6 float acharMedia ( tLista * lista ){<br />

7 tInfo elem ;<br />

8 int tam ;<br />

9 int ok = 0;<br />

10 float total , media ;<br />

11<br />

12 total = 0;<br />

13 tam = obterTam ( lista );<br />

14<br />

15 primeiro ( lista );<br />

16<br />

17 while (! final ( lista )){<br />

18 ok = obterInfo ( lista , & elem );<br />

19<br />

20 if(ok)<br />

21 {<br />

22 total += elem . salario ;<br />

23 }<br />

24<br />

25 proximo ( lista );<br />

26 }<br />

27<br />

28 media = total / tam ;<br />

29<br />

30 return media ;<br />

31 }<br />

32 float acimaMedia ( tLista * lista ){<br />

33<br />

34 tInfo elem ;<br />

35 int tam ,ok;<br />

36 float media ;<br />

37<br />

38 media = obterMedia ( lista );<br />

39 primeiro ( lista );<br />

40<br />

41 while (! final ( lista )){<br />

42 ok = obterInfo ( lista , & elem );<br />

43<br />

44 if(ok){<br />

45 if( elem . salario > media ){<br />

46<br />

47 printf (" Nome : %s\n", elem . nome );<br />

48 printf (" Salario : %f\n\n", elem . salario );<br />

49 }<br />

50 }<br />

51<br />

52 proximo ( lista );<br />

53 }<br />

54 }<br />

55<br />

DRAFT


7.8. RESUMO 203<br />

56 int main (){<br />

57 tLista lista ;<br />

58 tInfo dados ;<br />

59 int pos ;<br />

60<br />

61 inicia ( lista );<br />

62<br />

63 do{<br />

64 printf (" Entre <strong>com</strong> o nome : ");<br />

65 scanf ("%s", & dados . nome );<br />

66 printf (" Entre <strong>com</strong> o salario : ");<br />

67 scanf ("%f", & dados . salario );<br />

68<br />

69 if ( dados . salario >= 0)<br />

70 incluirFim (& lista , dados );<br />

71 } while ( dados . salario >= 0);<br />

72<br />

73 acimaMedia (& lista );<br />

74 <strong>de</strong>stroi ( lista );<br />

75<br />

76 return 0;<br />

77 }<br />

Exemplo 7.36: Cadastro <strong>de</strong> nomes e salários.<br />

Na função acimaMedia, a variável total é inicializada <strong>com</strong>o 0 e, a partir do primeiro elemento da<br />

lista, esse total é incrementado <strong>com</strong> o salário <strong>de</strong> cada funcionário. Quando o final da lista é alcançado,<br />

a média <strong>de</strong> salários é <strong>com</strong>putada <strong>com</strong>o sendo o total obtido dividido pelo tamanho da lista, ou seja, o<br />

número <strong>de</strong> funcionários.<br />

Com a média calculada, inicia-se um nova busca na lista, <strong>de</strong>s<strong>de</strong> o primeiro elemento até o final<br />

da lista, a fim <strong>de</strong> que se encontre os salários acima da média. Caso algum funcionário contenha um<br />

salário maior que a média, os dados do funcionário são impressos na tela.<br />

7.8 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

Apontadores são um tipo <strong>de</strong> variável que guarda o en<strong>de</strong>reço <strong>de</strong> outras variáveis. Trata-se <strong>de</strong> um<br />

conceito <strong>de</strong> baixo nível, ligado essencialmente à arquitetura <strong>de</strong> <strong>com</strong>putadores.<br />

Em C, a <strong>de</strong>claração <strong>de</strong> uma variável apontador segue o formato:<br />

DRAFT<br />

* <br />

No lugar do tipo do apontador, po<strong>de</strong>m ser utilizados os tipos padrões da linguagem C e também<br />

os tipos <strong>de</strong>finidos pelo programador.<br />

O operador & retorna o en<strong>de</strong>reço <strong>de</strong> memória <strong>de</strong> uma variável. Já o operador seta (− >) é<br />

utilizado para acessar, por meio <strong>de</strong> apontadores, os atributos <strong>de</strong> uma estrutura.<br />

ˆ Os apontadores po<strong>de</strong>m alterar o conteúdo da variável apontada por ele. Por meio <strong>de</strong> apontadores<br />

também é possível a passagem <strong>de</strong> parâmetros sem cópia. A passagem <strong>de</strong> parâmetros<br />

por apontadores permite múltiplos retornos em uma função, evita a cópia <strong>de</strong> muitos dados e<br />

possibilita a alteração das variáveis do programa no <strong>de</strong>correr da execução da função.<br />

ˆ<br />

ˆ<br />

Dentre os principais problemas <strong>com</strong> o uso <strong>de</strong> apontadores estão: apontadores não inicializados,<br />

objetos pen<strong>de</strong>ntes, referências pen<strong>de</strong>ntes e programação macarrônica.<br />

A alocação dinâmica é uma forma <strong>de</strong> reservar espaços <strong>de</strong> memória no <strong>de</strong>correr da execução do<br />

programa, o que evita o <strong>de</strong>sperdício <strong>de</strong> recursos da máquina. Em C, as funções malloc e free<br />

são responsáveis por alocar e <strong>de</strong>salocar áreas <strong>de</strong> memória, respectivamente.


204<br />

CAPÍTULO 7. APONTADORES<br />

ˆ<br />

O TAD Implementacional Lista Enca<strong>de</strong>ada é uma forma eficiente <strong>de</strong> armazenar dados num<br />

programa, pois aloca-se e <strong>de</strong>saloca-se os espaços para os dados dinâmicamente, o que torna<br />

muito simples as operações <strong>de</strong> incluir e excluir elementos.<br />

7.9 Exercícios Propostos<br />

1. Cite três vantagens e três <strong>de</strong>svantagens <strong>de</strong> se utilizar apontadores.<br />

2. Explique quais as funcionalida<strong>de</strong>s dos operadores * e &.<br />

3. Liste as diferenças entre variáveis apontadoras e não apontadoras. Faça um código em C, que<br />

realize a soma <strong>de</strong> duas variáveis float a e b, usando dois apontadores g e h, que apontem para<br />

a e b respectivamente. Quais são os tipos dos apontadores g e h?<br />

4. No Exemplo 7.37, escrito na linguagem C, encontre os erros <strong>de</strong> sintaxe na utilização <strong>de</strong> apontadores.<br />

Justifique cada erro encontrado.<br />

1 int main (){<br />

2 int p;<br />

3 int *d;<br />

4 int q = 10;<br />

5 float *j;<br />

6 float t = 15.0;<br />

7<br />

8 j = &t;<br />

9 p = &q;<br />

10 d = j;<br />

11<br />

12 return 0;<br />

13 }<br />

Exemplo 7.37: Código do Exercício Proposto 4.<br />

5. No Exemplo 7.38, escrito na linguagem C, encontre os problemas causados pela utilização in<strong>de</strong>vida<br />

<strong>de</strong> apontadores. Justifique cada problema encontrado.<br />

1 int main (){<br />

DRAFT<br />

2 int *p = ( int *) malloc ( sizeof ( int ));<br />

3 int *q = ( int *) malloc ( sizeof ( int ));<br />

4 int *j;<br />

5 int *h;<br />

6 int *v;<br />

7 int d = 20;<br />

8 int e = 30;<br />

9<br />

10 *q = e;<br />

11 *j = d;<br />

12 p = &d;<br />

13 h = &e;<br />

14 v = q;<br />

15 free (q);<br />

16<br />

17 return 0;<br />

18 }<br />

Exemplo 7.38: Código do Exercício Proposto 5.


7.10. TRABALHOS SUGERIDOS 205<br />

6. Ilustre as atribuições e referenciamentos feitos no trecho <strong>de</strong> código do Exemplo 7.5. Utilize para<br />

a ilustração os padrões adotados na Figura 7.3 e na Figura 7.4 para representar uma variável<br />

não apontador e apontador respectivamente.<br />

7. Implemente, na linguagem C, uma matriz <strong>de</strong> caracteres para armazenar strings nas suas linhas,<br />

alocada estaticamente e uma alocada dinamicamente. Explique um caso em que a alocação<br />

dinâmica é importante para economia <strong>de</strong> memória.<br />

8. Explique o que é alocação e <strong>de</strong>salocação <strong>de</strong> memória em tempo <strong>de</strong> execução e quais funções<br />

em C executam essas funcionalida<strong>de</strong>s. Cite uma vantagem <strong>de</strong> se <strong>de</strong>salocar memória não mais<br />

utilizada.<br />

9. Crie uma funcão que insere um novo elemento em uma lista enca<strong>de</strong>ada numa dada posição.<br />

Consi<strong>de</strong>re que os argumentos da função são:<br />

- Um apontador para a lista no qual o elemento será inserido.<br />

- Um elemento <strong>de</strong> um tipo tInfo previamente <strong>de</strong>finido.<br />

- Um inteiro que indica a posição na qual ocorrerá a inserção.<br />

Sugestão: verifique se a posição fornecida à função é válida.<br />

10. Consi<strong>de</strong>re duas listas simplesmente enca<strong>de</strong>adas ”A”e ”B”contendo inteiros or<strong>de</strong>nados crescentemente.<br />

Assim, pe<strong>de</strong>-se para implementar uma função que retorne uma lista enca<strong>de</strong>ada or<strong>de</strong>nada<br />

formada pela intercalação or<strong>de</strong>nada dos elementos <strong>de</strong> ”A”e ”B”garantindo que a lista resultante<br />

não possua valores repetidos. Consi<strong>de</strong>re que ”A”e ”B”também não possuem valores repetidos.<br />

11. Implemente uma lista enca<strong>de</strong>ada que armazene as informações sobre os DVDs <strong>de</strong> uma locadora.<br />

Tais informações são o título do filme, o nome do diretor, os principais atores e o número <strong>de</strong><br />

cópias disponíveis na locadora. Apresente um menu e crie funções que atendam as seguintes<br />

opções:<br />

- Inserir um título na lista.<br />

- Dado um título <strong>de</strong> filme, verificar se locadora possui em seu acervo.<br />

- Dado um título <strong>de</strong> filme, verificar se há alguma cópia disponível.<br />

- Dado um diretor, imprimir as informações sobre os filmes dirigidos por ele.<br />

DRAFT<br />

- Dado um ator, imprimir as informações sobre os filmes nos quais ele foi um dos atores<br />

principais.<br />

- Remover um título da lista.<br />

12. Sabe-se que um <strong>texto</strong> é uma sequência <strong>de</strong> caracteres contendo apenas letras, espaços em branco<br />

e sinais <strong>de</strong> pontuação. Uma palavra é <strong>de</strong>finida <strong>com</strong>o um segmento do <strong>texto</strong> que consiste apenas<br />

<strong>de</strong> letras. Escreva uma função que recebe um <strong>texto</strong> do teclado e imprime uma relação <strong>de</strong> todas<br />

as palavras que ocorrem no <strong>texto</strong> juntamente <strong>com</strong> o número <strong>de</strong> ocorrências <strong>de</strong> cada palavra.<br />

7.10 Trabalhos Sugeridos<br />

1. Notas <strong>de</strong> Alunos<br />

O Colegiado <strong>de</strong> um curso <strong>de</strong> uma instituição <strong>de</strong> ensino mantém uma listagem <strong>com</strong> informações<br />

sobre o <strong>de</strong>sempenho <strong>de</strong> cada aluno do curso. Esta listagem contém as notas obtidas pelo aluno<br />

em cada uma das disciplinas que ele cursou e é organizada da seguinte maneira:


206<br />

CAPÍTULO 7. APONTADORES<br />

Matrícula do Aluno Código da Disciplina Carga Horária Nota<br />

00018 0001 60 4.5<br />

11111 3232 30 8.7<br />

00234 0500 75 9.0<br />

00018 0001 60 7.0<br />

... ... ... ...<br />

09999 0786 60 7.5<br />

Para facilitar a consulta a esta listagem, o coor<strong>de</strong>nador do colegiado precisa <strong>de</strong> um programa<br />

em C que realize algumas operações sobre os dados da lista. Ele te pediu para elaborar um<br />

programa interativo que permita ao usuário:<br />

(a) Ler os dados da listagem e colocá-los em quatro listas. O usuário <strong>de</strong>ve po<strong>de</strong>r incluir tantos<br />

dados quanto quiser. A indicação <strong>de</strong> fim <strong>de</strong> entrada <strong>de</strong> dados é feita através <strong>de</strong> um aluno<br />

<strong>de</strong> Matrícula 0 (zero).<br />

(b) Mostrar as notas <strong>de</strong> um aluno numa disciplina. Lembre-se que o aluno po<strong>de</strong> ter cursado<br />

mais <strong>de</strong> uma vez uma mesma disciplina por motivo <strong>de</strong> reprovação.<br />

(c) Incluir uma nota <strong>de</strong> um aluno em uma disciplina.<br />

(d) Retificar uma nota <strong>de</strong> um aluno em uma disciplina.<br />

(e) Excluir uma nota <strong>de</strong> um aluno em uma disciplina.<br />

(f) Excluir todos os dados <strong>de</strong> um aluno jubilado.<br />

(g) Calcular o o coeficiente <strong>de</strong> rendimento (C.R.) <strong>de</strong> um aluno. O C.R. é calculado da seguinte<br />

maneira:<br />

(h) I<strong>de</strong>ntificar o aluno <strong>de</strong> melhor CR.<br />

C.R. = (Σ (Carga Horária x Nota)) / (Σ (Carga Horária))<br />

(i) I<strong>de</strong>ntificar os alunos <strong>com</strong> CR abaixo <strong>de</strong> 5.0.<br />

Exemplo <strong>de</strong> Programa<br />

Escolha Operação:<br />

0 - Sair<br />

1 - Ler dados<br />

2 - Mostrar Notas<br />

3 - Incluir Nota<br />

4 - Corrigir Nota<br />

5 - Excluir Nota<br />

6 - Excluir Aluno<br />

7 - CR <strong>de</strong> Aluno<br />

8 - Melhor Aluno<br />

9 - Maus Alunos<br />

DRAFT<br />

Opção: 1<br />

Dados do aluno: 18 1 60 4.5<br />

Dados do aluno: 1111 3232 30 8.7<br />

Dados do aluno: 234 500 75 9.0<br />

Dados do aluno: 18 1 60 7.0<br />

... ... ...<br />

Dados do aluno: 0 0 0 0.0<br />

Opção: 2<br />

Matrícula: 18


7.10. TRABALHOS SUGERIDOS 207<br />

Disciplina: 1<br />

Notas: 4.5 7.0<br />

Opção: 3<br />

Matrícula: 1111 Disciplina: 316<br />

Carga Horária: 60<br />

Nota: 7.0<br />

Opção: 4<br />

Matrícula: 1111 Disciplina: 316<br />

Carga Horária: 60<br />

Nota: 7.0<br />

Nova Nota: 8.5<br />

Opção: 5<br />

Matrícula: 1111 Disciplina: 316<br />

Nota: 7.0<br />

Opção: 6<br />

Matrícula: 234<br />

Opção: 7<br />

Matrícula: 1111<br />

CR: 7.2<br />

Opção: 8<br />

Matrícula: 234<br />

Opção: 9<br />

Matrículas: 194<br />

Opção: 10<br />

Matrícula: 1111<br />

Não cumpriu carga horária mínima.<br />

... ... ...<br />

Opção: 0<br />

Até a próxima!<br />

DRAFT<br />

2. Controlador <strong>de</strong> Tráfego Aéreo<br />

Descrição<br />

Controle <strong>de</strong> Tráfego Aéreo é um serviço prestado por controladores, em terra, que guiam aeronaves<br />

(geralmente aviões) no ar e no solo, para garantir um fluxo <strong>de</strong> tráfego seguro e or<strong>de</strong>nado.<br />

Os controladores <strong>de</strong> tráfego áereo fornencem indicações e autorizações <strong>de</strong> vôo, <strong>de</strong> acordo <strong>com</strong> as<br />

características operacionais das aeronaves e as condições <strong>de</strong> tráfego em <strong>de</strong>terminado momento.<br />

Estas autorizações po<strong>de</strong>m incidir sobre a rota, altitu<strong>de</strong> e/ou velocida<strong>de</strong> propostas pelo operador


208<br />

CAPÍTULO 7. APONTADORES<br />

da aeronave para <strong>de</strong>terminado voo, <strong>de</strong>vendo os pilotos cumprir as instruções recebidas.<br />

Espaço Aéreo<br />

Em muitos países, os serviços <strong>de</strong> tráfego aéreo são prestados em toda a extensão do espaço aéreo<br />

e estes serviços são utilizados por todos os usuários (aeronaves privadas, militares e <strong>com</strong>erciais).<br />

Os espaços aéreos on<strong>de</strong> o controlador é responsável por prover separação entre as aeronaves são<br />

chamados <strong>de</strong> espaços áereos controlados em oposição aos espaços áereos não controlados<br />

nos quais pilotos das aeronaves são responsáveis por manter a separação entre a sua aeronave e<br />

outras. Depen<strong>de</strong>ndo do tipo <strong>de</strong> voo e <strong>de</strong> classe do espaço aéreo, o controlador <strong>de</strong> tráfego aéreo<br />

po<strong>de</strong> emitir instruções que os pilotos <strong>de</strong>vem seguir ou apenas informações <strong>de</strong> vôo para ajudar os<br />

pilotos operando no espaço aéreo. Em todos os casos, entretanto, o piloto tem a responsabilida<strong>de</strong><br />

final pela segurança da aeronave, e po<strong>de</strong> não cumprir as instruções numa emergência.<br />

Os serviços <strong>de</strong> controle <strong>de</strong> tráfego aéreo incluem o controle <strong>de</strong> rotas das aeronaves que estão no<br />

espaço áereo do aeroporto, o controle da autorização <strong>de</strong> pousos e <strong>de</strong>colagens e o controle das<br />

pistas <strong>de</strong> táxi-aéreo e pátios.<br />

O Trabalho<br />

O trabalho consiste em implementar um programa que faça o controle dos pousos em um aeroporto<br />

que apresente três portões <strong>de</strong> embarque e <strong>de</strong>sembarque (A,B,C). O trabalho <strong>de</strong>ve ser feito<br />

em dois módulos: controle <strong>de</strong> espaços aéreos e controle <strong>de</strong> pista, e a estrutura para armazenamento<br />

dos dados <strong>de</strong>ve ser uma lista enca<strong>de</strong>ada dinâmica.<br />

ˆ<br />

ˆ<br />

Controle <strong>de</strong> espaço aéreo<br />

Como o controle da torre consiste em controlar as aeronaves enquanto elas estiverem no<br />

espaço aéreo do aeroporto, po<strong>de</strong>-se dividir essa tarefa em duas subtarefas:<br />

Controle <strong>de</strong> rotas<br />

A partir do momento em que as aeronaves entram no espaço aéreo do aeroporto, o controle<br />

das suas rotas <strong>de</strong>verá ser realizado pelo seu programa. Para isso consi<strong>de</strong>re que a função<br />

básica do seu programa é impedir que ocorram colisões, e para isso uma das aeronaves<br />

em risco <strong>de</strong>verá ser redirecionada para a rota mais próxima a uma das rotas envolvidas.<br />

Existem duas ocoasiões em que ocorrerão colisões: se duas aeronaves estiverem utilizando<br />

a mesma rota ou se duas aeronaves estiverem utilizando rotas que apresentem intersecção.<br />

Consi<strong>de</strong>re que duas rotas apresentam intersecção se uma <strong>de</strong>las é múltipla da outra.<br />

DRAFT<br />

Controle <strong>de</strong> aproximação<br />

Dado que o controle <strong>de</strong> rotas já foi realizado será necessário <strong>de</strong>finir qual será a or<strong>de</strong>m das<br />

aeronaves a pousar. Para isso <strong>de</strong>verá ser consi<strong>de</strong>rada a sequência <strong>de</strong> priorida<strong>de</strong>s abaixo:<br />

CLASSE > ALTITUDE > VELOCIDADE<br />

Assim, <strong>de</strong>fine-se que existem apenas duas classes (militar e <strong>com</strong>ercial) e que duas altitu<strong>de</strong>s<br />

são consi<strong>de</strong>radas iguais se a diferença entre elas for menor que 2000 pés. Além disso, a<br />

classe militar tem priorida<strong>de</strong> frente a classe <strong>com</strong>ercial; quanto menor a altitu<strong>de</strong> <strong>de</strong> uma<br />

aeronave maior será a sua priorida<strong>de</strong> e quanto maior a velocida<strong>de</strong> <strong>de</strong> uma aeronave maior<br />

será a sua priorida<strong>de</strong>. Consi<strong>de</strong>re que cada operação <strong>de</strong> pouso dura 5 minutos.<br />

Controle <strong>de</strong> pista<br />

Após o pouso <strong>de</strong> uma aeronave é necessário que o tráfego em solo também seja controlado.<br />

Com isso, a segunda parte do trabalho consistirá em controlar o momento em que cada


7.10. TRABALHOS SUGERIDOS 209<br />

aeronave <strong>de</strong>verá encostar em uma plataforma que está livre. Caso todas as três plataformas<br />

estejam ocupadas no momento em que uma aeronave pouse, esta <strong>de</strong>verá esperar no pátio<br />

<strong>de</strong> espera até que alguma das plataformas seja <strong>de</strong>socupada. Consi<strong>de</strong>re que cada operação<br />

<strong>de</strong> <strong>de</strong>sembarque dure 30 minutos.<br />

Especificação<br />

Módulo 1<br />

Essa primeira parte do trabalho consiste em <strong>de</strong>terminar a fila <strong>de</strong> aeronaves que irão pousar e<br />

as novas rotas das aeronaves que precisam mudar <strong>de</strong> rota. Para isso, consi<strong>de</strong>re que quando<br />

duas aeronaves apresentarem chance <strong>de</strong> colisão a aeronave que apresentar número <strong>de</strong> rota maior<br />

<strong>de</strong>verá ser redirecionada para uma rota <strong>com</strong> número igual ao primeiro número primo maior que<br />

a rota <strong>de</strong> maior número.<br />

Módulo 2<br />

A segunda parte consiste em <strong>de</strong>terminar a que horas a operação <strong>de</strong> <strong>de</strong>sembarque <strong>de</strong> cada aeronave<br />

foi realizada.<br />

Entrada<br />

As informações referente às aeronaves serão fornecidas através do teclado. As informações serão<br />

as seguites: i<strong>de</strong>ntificação da aeronave (0103, 0407, 1114,...); número inteiro que servirá para<br />

in<strong>de</strong>ntificar qual rota que a aeronave está percorrendo (1, 2, 4, 6,...); classe da aeronave (”<strong>com</strong>ercial”ou<br />

”militar”); altitu<strong>de</strong> na qual a aeronave se encontra no momento em que entra no<br />

espaço aéreo do aeroporto (7700, 9060, 1120, ...); velocida<strong>de</strong> <strong>com</strong> qual a aeronave está (650, 680,<br />

810, ...) e a hora <strong>de</strong> entrada da aeronave no espaço áereo do aeroporto (14:30, 14:29, 14:31, ...).<br />

Consi<strong>de</strong>re que a hora apresentará o caracter ”:”para separar hora <strong>de</strong> minuto.<br />

Obs.: As horas <strong>de</strong> entrada no espaço aéreo do aeroporto são muito próximas, <strong>com</strong><br />

diferença entre o menor e o maior horário <strong>de</strong> no máximo 5 minutos. Cada nova<br />

aeronave <strong>de</strong>ve ser adicionada na lista já na or<strong>de</strong>m <strong>de</strong> priorida<strong>de</strong> <strong>de</strong> pouso, do mais<br />

para o menos prioritário. Assim, após todas as inserções, as colisões <strong>de</strong>vem ser<br />

verificadas, aeronave por aeronave, na sequência <strong>de</strong> pouso obtida.<br />

Exemplo:<br />

0103<br />

2<br />

militar<br />

7100<br />

670<br />

14:30<br />

DRAFT<br />

0307<br />

10<br />

<strong>com</strong>ercial<br />

8200<br />

770<br />

14:29


210<br />

CAPÍTULO 7. APONTADORES<br />

0200<br />

13<br />

militar<br />

1000<br />

710<br />

14:30<br />

0708<br />

10<br />

<strong>com</strong>ercial<br />

8600<br />

640<br />

14:29<br />

1102<br />

4<br />

militar<br />

9100<br />

700<br />

14:30<br />

Saída<br />

Os dados <strong>de</strong> saída do programa <strong>de</strong>vem ser exibidos no console. O formato da saída <strong>de</strong>ve seguir<br />

o exemplo abaixo.<br />

Exemplo:<br />

0200<br />

13<br />

15:00<br />

0103<br />

2<br />

15:05<br />

1102<br />

17<br />

15:10<br />

0307<br />

19<br />

15:30<br />

0708<br />

23<br />

15:35<br />

DRAFT


Capítulo 8<br />

Arquivos<br />

Objetivos:<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Definir o conceito <strong>de</strong> arquivos;<br />

Definir e diferenciar variáveis transientes e variáveis persistentes;<br />

Definir e diferenciar arquivos <strong>de</strong> <strong>texto</strong> e arquivos binários;<br />

Mostrar algumas operações que po<strong>de</strong>m ser feitas <strong>com</strong> arquivos;<br />

Mostrar outras funções e exemplos <strong>de</strong> programas que usam arquivos;<br />

Coautores:<br />

Ebenézer Nogueira<br />

Estefhan Wan<strong>de</strong>kokem<br />

Marcos Couto<br />

Este capítulo tem por objetivo apresentar o conceito <strong>de</strong> arquivos. Os arquivos são a forma fundamental<br />

<strong>de</strong> armazenamento <strong>de</strong> informação na memória não volátil do <strong>com</strong>putador. Ou seja, dados<br />

armazenados em arquivos persistem salvos no <strong>com</strong>putador mesmo que o programa do qual se originaram<br />

seja finalizado ou, até mesmo, que o <strong>com</strong>putador seja <strong>de</strong>sligado. Aqui serão estudados os tipos<br />

<strong>de</strong> arquivos e as operações que po<strong>de</strong>m ser realizadas sobre eles.<br />

8.1 Variáveis Transientes X Variáveis Persistentes<br />

Quando os programas são executados, eles lidam <strong>com</strong> variáveis. Elas são a forma abstrata pela qual os<br />

programadores enxergam os dados que seus programas manipulam. Internamente, variáveis indicam<br />

células <strong>de</strong> memória.<br />

A memória principal <strong>de</strong> um <strong>com</strong>putador (muitas vezes chamada <strong>de</strong> memória RAM) é o local on<strong>de</strong><br />

os programas em execução e as variáveis que eles utilizam são armazenados. As variáveis armazenadas<br />

na memória principal são chamadas <strong>de</strong> variáveis transientes porque seu tempo <strong>de</strong> existência é limitado<br />

pelo tempo que o programa está em funcionamento. Assim que o usuário ou o sistema operacional<br />

<strong>de</strong>cidir que o programa <strong>de</strong>ve ser finalizado, todas as variáveis <strong>de</strong>ixarão <strong>de</strong> existir.<br />

Os <strong>com</strong>putadores teriam sua utilida<strong>de</strong> muito reduzida se a informação só pu<strong>de</strong>sse ser armazenada<br />

enquanto os programas estivessem na memória principal (e a máquina, ligada). Para resolver esse<br />

problema, existem as variáveis persistentes, as quais têm seu conteúdo armazenado, e possível <strong>de</strong><br />

ser acessado, in<strong>de</strong>pen<strong>de</strong>ntemente do programa que as criou estar na memória principal. Variáveis<br />

persistentes <strong>de</strong>vem ser armazenadas em algum dispositivo <strong>de</strong> memória secundária, <strong>com</strong>o discos rígidos,<br />

CDs, memória flash e DVDs, os quais tem a capacida<strong>de</strong> <strong>de</strong> manter por um longo tempo o valor da<br />

informação neles contida, in<strong>de</strong>pen<strong>de</strong>nte do conteúdo da memória principal do <strong>com</strong>putador, ou mesmo<br />

<strong>de</strong> ele estar ligado. Deve-se ressaltar que o tempo <strong>de</strong> acesso e <strong>de</strong> gravação das variáveis armazenadas<br />

em meio secundário é muito maior que o das variáveis armazenadas na memória principal, por isso<br />

essa última é tão importante.<br />

DRAFT<br />

211


212<br />

CAPÍTULO 8. ARQUIVOS<br />

O conceito por trás das variáveis persistentes é o <strong>de</strong> arquivo, e esse será o tema <strong>de</strong>sse capítulo.<br />

Por meio <strong>de</strong> arquivos, essas variáveis po<strong>de</strong>m ser armazenadas e as informações que elas guardam,<br />

acessadas e processadas no futuro, tanto pelo programa que as criou quanto por outros programas.<br />

8.2 Tipos <strong>de</strong> Arquivos<br />

Os arquivos po<strong>de</strong>m ser classificados em dois tipos: arquivos <strong>texto</strong> e arquivos binários. Ambos têm a<br />

mesma finalida<strong>de</strong>: armazenar variáveis persistentes. Quando o programador cria um arquivo em seu<br />

programa, ele <strong>de</strong>ve indicar a qual tipo ele pertencerá. Essa escolha <strong>de</strong>terminará <strong>com</strong>o o arquivo <strong>de</strong>ve<br />

ser tratado, quais funções usar e <strong>com</strong>o os dados <strong>de</strong>vem ser interpretados por elas durante a leitura ou<br />

a escrita.<br />

8.2.1 Tipos <strong>de</strong> Arquivos - Arquivos Texto<br />

Um arquivo <strong>texto</strong> é uma sequência <strong>de</strong> caracteres. Se um arquivo <strong>texto</strong> for aberto num editor <strong>de</strong> <strong>texto</strong><br />

convencional, o usuário po<strong>de</strong>rá ler seu conteúdo (ou ao menos ver os caracteres lá contidos), e po<strong>de</strong>rá<br />

até mesmo modificá-lo <strong>de</strong> uma forma que faça sentido.<br />

Por exemplo, na linguagem C, tome uma variável int que guar<strong>de</strong> o numero 43. Uma forma <strong>de</strong><br />

escrever essa variável num arquivo <strong>texto</strong> seria gravar “43”, mas note que, <strong>com</strong> isso, dois caracteres<br />

foram gravados: o ‘4’ seguido do ‘3’. Isso po<strong>de</strong>ria significar, por exemplo, para um arquivo numa<br />

arquitetura que salve caracteres <strong>com</strong>o variáveis <strong>de</strong> 1 byte, que dois bytes foram gravados no arquivo,<br />

o primeiro armazenando o caractere ‘4’ e o segundo armazenando o caractere ‘3’. A Figura 8.1 mostra<br />

um exemplo <strong>de</strong> arquivo <strong>texto</strong>.<br />

Figura 8.1: Exemplo <strong>de</strong> um arquivo <strong>texto</strong>.<br />

DRAFT<br />

8.2.2 Tipos <strong>de</strong> Arquivos - Arquivos Binários<br />

Por meio <strong>de</strong> um arquivo binário, as variáveis armazenadas na memória principal po<strong>de</strong>m ter seus bytes<br />

armazenados num arquivo físico, sem tradução para caracteres e <strong>com</strong> correspondência <strong>de</strong> um para<br />

um. Isso significa que, usando-se arquivos binários, torna-se possível criar um “espelho” da memória<br />

principal na memória secundária.<br />

A fim <strong>de</strong> exemplificar esse conceito na linguagem C, será citada a gravação <strong>de</strong> uma struct. Essa é<br />

uma das razões pela qual arquivos binários são tão úteis nessa linguagem. Já foi estudado que uma<br />

struct é um tipo especial <strong>de</strong> variável que armazena outras variáveis. No Exemplo 8.1 <strong>de</strong>fine-se uma<br />

struct <strong>com</strong> informações básicas <strong>de</strong> uma pessoa.<br />

1 struct pessoa {<br />

2 char nome [50];<br />

3 int ida<strong>de</strong> ;<br />

4 float salario ;<br />

5 }<br />

Exemplo 8.1: Exemplo <strong>de</strong> struct.


8.3.<br />

DEFINIÇÃO DE ARQUIVOS 213<br />

Como guardar essa informação em um arquivo? Po<strong>de</strong>-se guardá-la num arquivo <strong>texto</strong>, escrevendose<br />

o nome da pessoa, então sua ida<strong>de</strong> e finalmente seu salário. Sabendo o formato <strong>com</strong>o essa informação<br />

foi escrita, o programador po<strong>de</strong> criar um programa que a lê.<br />

De modo alternativo, po<strong>de</strong>-se armazená-la num arquivo binário. A struct será tratada <strong>com</strong>o uma<br />

única variável e uma cópia <strong>de</strong>la será armazenada no arquivo ou lida do arquivo para a memória,<br />

<strong>de</strong>pen<strong>de</strong>ndo da operação <strong>de</strong>sejada. Isso é possível, pois se sabe o formato <strong>com</strong>o essa struct foi armazenada<br />

no arquivo binário. Esse formato po<strong>de</strong>ria ser, para uma arquitetura <strong>de</strong> 32 bits <strong>de</strong> palavra, na<br />

linguagem C, <strong>de</strong> 50 bytes que armazenam cada uma das variáveis char, mais 32 bits (4 bytes) que<br />

armazenam uma variável int, e mais 32 bits (4 bytes) que armazenam uma variável float.<br />

Observe que, se não houver bons motivos para usar arquivos <strong>texto</strong> é mais interessante usar arquivos<br />

binários. Se optar pela utilização <strong>de</strong> arquivos <strong>texto</strong> o programador <strong>de</strong>verá trabalhar apenas uma das<br />

variáveis <strong>de</strong> cada vez. Outro problema a ser tratado, <strong>com</strong>o no exemplo <strong>de</strong> armazenar a variável inteira<br />

<strong>de</strong> valor 43, o valor <strong>de</strong>verá ser traduzido em uma string para ser armazenado e traduzido <strong>de</strong> volta<br />

para o tipo <strong>de</strong>sejado após ser lido. O armazenamento binário simplifica o processo permitindo que<br />

você leia toda uma struct <strong>de</strong> uma vez <strong>com</strong> os tipos das variáveis originais. A Figura 8.2 mostra um<br />

exemplo <strong>de</strong> arquivo binário.<br />

8.3 Definição <strong>de</strong> arquivos<br />

Figura 8.2: Exemplo <strong>de</strong> um arquivo binário.<br />

Para serem utilizados nos programas, os arquivos são tratados <strong>com</strong>o variáveis. Então, <strong>com</strong>o todas as<br />

outras variáveis, eles <strong>de</strong>vem ser <strong>de</strong>clarados. Dessa forma, também po<strong>de</strong>m ser usados <strong>com</strong>o argumentos<br />

para funções.<br />

Para lidar <strong>com</strong> arquivos, existem funções responsáveis por realizar todas as operações necessárias.<br />

Por exemplo, criar um novo arquivo em branco, excluir um já existente, gravar informação ou ler as<br />

já contidas num arquivo, <strong>de</strong>ntre outras.<br />

Na linguagem C, o tipo FILE, <strong>de</strong>finido na biblioteca stdio.h, é usado para se tratar arquivos. Um<br />

apontador para FILE <strong>de</strong>ve ser <strong>de</strong>clarado sempre que uma variável arquivo for utilizada no programa.<br />

Por exemplo, o <strong>com</strong>ando do Exemplo 8.2 <strong>de</strong>clara uma variável do tipo apontador para arquivo <strong>de</strong>nominada<br />

arq:<br />

1 FILE * arq ;<br />

DRAFT<br />

Exemplo 8.2: Declaração <strong>de</strong> um apontador para FILE.<br />

Os apontadores para FILE não fazem referência ao arquivo físico em si, mas a uma região <strong>de</strong><br />

memória principal que possui as informações necessárias para leitura e escrita no arquivo. Isso implica<br />

que não é possível manipular o arquivo diretamente, por exemplo, abrir um arquivo e tentar armazenar<br />

o conteúdo do apontador FILE* em outro arquivo. Para copiar um arquivo <strong>de</strong>ve-se ler seu conteúdo e<br />

<strong>de</strong>pois armazená-lo em outro arquivo <strong>com</strong>o será visto mais adiante. De qualquer forma, o programador<br />

<strong>de</strong>ve abstrair esses conceitos e usar a variável FILE* <strong>de</strong>clarada. Ele associará um arquivo físico a ela,<br />

e então a usará <strong>com</strong>o argumento para as funções que operam sobre arquivos.


214<br />

CAPÍTULO 8. ARQUIVOS<br />

8.4 Operações sobre arquivos<br />

Arquivos <strong>de</strong>mandam algumas operações <strong>com</strong>o abertura e fechamento. Os valores já armazenados nos<br />

arquivos <strong>de</strong>vem po<strong>de</strong>r ser lidos, e novos valores <strong>de</strong>vem po<strong>de</strong>r ser escritos, para que tenham utilida<strong>de</strong>.<br />

As operações que realizam essas tarefas são fornecidas pela linguagem <strong>de</strong> programação em vários<br />

formatos.<br />

8.4.1 Abertura<br />

Após a <strong>de</strong>claração <strong>de</strong> uma variável do tipo arquivo, essa <strong>de</strong>ve ser associada a um nome <strong>de</strong> arquivo, o<br />

qual i<strong>de</strong>ntifica um arquivo <strong>de</strong> fato, <strong>com</strong> correspondência na memória secundária.<br />

Se o arquivo <strong>com</strong> o nome especificado já existir, então o programador terá acesso a seu conteúdo,<br />

e po<strong>de</strong>rá lê-lo e alterá-lo. Mas um nome <strong>de</strong> arquivo que ainda não existe também po<strong>de</strong> ser utilizado.<br />

Nesse caso, um novo arquivo, “em branco”, <strong>com</strong> o nome especificado, será criado. Esses <strong>de</strong>talhes são<br />

resolvidos passando-se as informações corretas à função responsável por abrir o arquivo.<br />

Na linguagem C, essa função é a fopen. Seu protótipo é mostrado no Exemplo 8.3.<br />

1 FILE * fopen ( const char * nomearq , const char * modo );<br />

Exemplo 8.3: Protótipo da função para abertura <strong>de</strong> arquivos.<br />

A função retorna um apontador para FILE, que <strong>de</strong>verá ser recebido pela variável usada para manipular<br />

o arquivo. O primeiro argumento <strong>de</strong> fopen, nomearq, é uma string, e refere-se ao nome do<br />

arquivo que será aberto. O segundo argumento, modo, também uma string, é um código passado a<br />

fopen, responsável por indicar que tipo <strong>de</strong> arquivo e operação será realizada sobre esse arquivo. Os<br />

códigos são <strong>de</strong>scritos na Tabela 8.1:<br />

Parâmetro<br />

Efeito<br />

r<br />

Abre um arquivo-<strong>texto</strong> para leitura<br />

w<br />

Cria um arquivo-<strong>texto</strong> para escrita<br />

a<br />

Abre um arquivo-<strong>texto</strong> para gravar ao fim <strong>de</strong>le<br />

r+ Abre um arquivo-<strong>texto</strong> para leitura/escrita<br />

w+ Cria um arquivo-<strong>texto</strong> para leitura/escrita<br />

a+ Abre ou cria (se não existir) um arquivo-<strong>texto</strong> para ler <strong>de</strong>le ou gravar ao fim <strong>de</strong>le<br />

rb<br />

Abre um arquivo binário para leitura<br />

wb<br />

Cria um arquivo binário para escrita<br />

ab<br />

Abre um arquivo binário para gravar ao fim <strong>de</strong>le<br />

r+b<br />

Abre um arquivo binário para leitura/escrita<br />

w+b<br />

Cria um arquivo binário para leitura/escrita<br />

a+b<br />

Abre ou cria um arquivo binário para gravar ao fim <strong>de</strong>le<br />

DRAFT<br />

No Exemplo 8.4 serão criados dois arquivos: o arquivo <strong>texto</strong> somente escrita.txt, que não existia<br />

antes da execução <strong>de</strong> fopen, e que será usado somente para gravação <strong>de</strong> informação (no caso, caracteres);<br />

e leio e escrevo.meu, binário, no qual as informações po<strong>de</strong>rão ser lidas e escritas. Note <strong>com</strong>o<br />

as variáveis FILE* são <strong>de</strong>claradas, inicialmente, e <strong>de</strong>pois recebem o retorno da função fopen.<br />

1 FILE * arq_ex1 , * arq_ex2 ;<br />

2<br />

3 arq_ex1 = fopen (" somente_escrita . txt ", "w");<br />

4 arq_ex2 = fopen (" leio_e_escrevo . meu ", "a+b");<br />

Exemplo 8.4: Abertura <strong>de</strong> arquivo<br />

Um ponto importante a ser ressaltado sobre a função fopen é a avaliação <strong>de</strong> seu valor <strong>de</strong> retorno.<br />

Muitas vezes ocorrem erros na abertura <strong>de</strong> um arquivo, <strong>com</strong>o, por exemplo, passar para fopen o


8.4.<br />

OPERAÇÕES SOBRE ARQUIVOS 215<br />

código “r”e o arquivo <strong>com</strong> o nome especificado não existir no disco. Esses erros po<strong>de</strong>m ser <strong>de</strong>tectados<br />

porque a função fopen retornará NULL para indicar que houve falha na abertura <strong>de</strong> um arquivo.<br />

No Exemplo 8.5, é <strong>de</strong>clarada uma variável do tipo arquivo. Em seguida, é chamada fopen para<br />

realizar a abertura <strong>de</strong> arquivo. Imediatamente <strong>de</strong>pois, é verificado se ele foi aberto corretamente.<br />

Se não foi, o usuário será notificado e o programa encerrado. Esse encerramento é feito <strong>com</strong> o uso<br />

da função exit (<strong>de</strong>finida na biblioteca stdlib.h), a qual finaliza o programa e retorna para o sistema<br />

operacional o código numérico passado <strong>com</strong>o argumento.<br />

1 FILE * arq_ex3 ;<br />

2<br />

3 arq_ex3 = fopen (" alunos . txt ", "r");<br />

4<br />

5 if( arq_ex3 == NULL ){<br />

6 printf (" Erro <strong>com</strong> a abertura <strong>de</strong> arquivo ! O programa sera finalizado ... ");<br />

7 exit (1) ;<br />

8 }<br />

Exemplo 8.5: Abertura <strong>de</strong> arquivo <strong>com</strong> verificação <strong>de</strong> sucesso<br />

Todas as vezes que fopen for usada <strong>de</strong>ve-se verificar imediatamente se a abertura <strong>de</strong> arquivo<br />

ocorreu sem problemas. Essa abordagem evitará muitos problemas posteriores.<br />

Quando um arquivo é aberto, passa a estar associado a ele um indicador <strong>de</strong> posição, responsável<br />

por indicar em qual ponto do arquivo novas informações são lidas ou gravadas. Esse indicador po<strong>de</strong><br />

ser imaginado <strong>com</strong>o o cursor em um <strong>texto</strong> sendo editado em um editor <strong>de</strong> <strong>texto</strong>. De modo geral, no<br />

momento em que um arquivo é aberto, esse indicador estará no <strong>com</strong>eço do arquivo. Sempre que um<br />

dado do arquivo é lido ou gravado, o indicador <strong>de</strong> posição se movimenta, ficando sempre à frente do<br />

último dado lido ou gravado.<br />

8.4.2 Fechamento<br />

Quando um arquivo aberto não for mais utilizado em um programa, ele <strong>de</strong>ve ser fechado. Esse<br />

fechamento <strong>de</strong>sassocia o arquivo físico, em disco (por exemplo), da variável do tipo arquivo usada<br />

para abrí-lo. Um arquivo aberto po<strong>de</strong> ser fechado usando-se uma função que execute essa tarefa e que<br />

o receba <strong>com</strong>o argumento.<br />

Na linguagem C, a função fclose é usada para fechar um arquivo. Seu protótipo é mostrado no<br />

Exemplo 8.6.<br />

1 int fclose ( FILE *fp);<br />

DRAFT<br />

Exemplo 8.6: Protótipo da função para fechamento <strong>de</strong> arquivos.<br />

Ela retorna 0 se a operação <strong>de</strong> fechamento foi bem sucedida, e um número diferente <strong>de</strong> 0, caso<br />

contrário. Ela recebe <strong>com</strong>o parâmetro um apontador para FILE, o qual é o arquivo a ser fechado.<br />

Caso se queira utilizar um arquivo <strong>de</strong>pois que ele foi fechado, <strong>de</strong>ve-se reabrí-lo novamente por meio<br />

da função fopen.<br />

Sempre que não houver mais utilida<strong>de</strong> em um arquivo, ele <strong>de</strong>ve ser fechado. Como já dito, o<br />

que está armazenado na variável FILE* é apenas informação sobre o arquivo. Quando é feita alguma<br />

operação <strong>de</strong> leitura ou armazenamento, os dados necessários são armazenados em um buffer e o sistema<br />

operacional se encarrega do resto, o que não necessáriamente ocorrerá no momento em que se faz a<br />

requisição da operação. Quando fclose é chamada, qualquer informação que ainda esteja no buffer<br />

será gravada no arquivo. Somente após isso o arquivo físico é finalmente <strong>de</strong>sassociado da variável<br />

FILE* usada. Ou seja, não fechar o arquivo corretamente po<strong>de</strong> corrompê-lo.


216<br />

CAPÍTULO 8. ARQUIVOS<br />

8.5 Operações sobre arquivos <strong>texto</strong><br />

Um arquivo <strong>texto</strong> armazena caracteres. Dessa forma, somente caracteres são lidos e gravados em um<br />

arquivo-<strong>texto</strong>; algumas funções especiais existem, contudo, para que strings e números possam ser<br />

lidos e gravados.<br />

8.5.1 Leitura<br />

A linguagem C fornece uma série <strong>de</strong> funções para leitura <strong>de</strong> informações em arquivos <strong>de</strong> <strong>texto</strong>. Serão<br />

mostradas a seguir duas <strong>de</strong>las: fscanf e fgets.<br />

fscanf()<br />

A função fscanf funciona <strong>de</strong> forma semelhante à scanf, já estudada em capítulos anteriores. A diferença<br />

está no fato <strong>de</strong> que fscanf trabalha <strong>com</strong> arquivos, e não <strong>com</strong> a entrada padrão (normalmente o teclado),<br />

<strong>com</strong>o é o caso <strong>de</strong> scanf. Seu protótipo é mostrado no Exemplo 8.7<br />

1 int fscanf ( FILE *fp , const char * format , ... );<br />

Exemplo 8.7: Protótipo da função para leitura em arquivos <strong>de</strong> <strong>texto</strong>.<br />

A passagem <strong>de</strong> argumentos é semelhante à <strong>de</strong> scanf, <strong>com</strong> o acréscimo <strong>de</strong> que <strong>de</strong>ve ser colocado <strong>com</strong>o<br />

primeiro argumento o apontador para FILE representando o arquivo do qual serão lidas as variáveis.<br />

No formato <strong>com</strong>um <strong>de</strong> uso, fscanf, assim <strong>com</strong>o scanf, encerra a leitura <strong>de</strong> uma string (ou seja,<br />

argumento <strong>de</strong> código “%s”) assim que um caractere <strong>de</strong> espaço em branco, tabulação ou quebra <strong>de</strong><br />

linha é encontrado. Dessa forma, fscanf não é re<strong>com</strong>endada para a leitura <strong>de</strong> strings. C oferece outra<br />

função para esse fim, que será estudada em seguida: fgets.<br />

O Exemplo 8.8 mostra <strong>com</strong>o a função fscanf po<strong>de</strong> ser usada para ler um inteiro, uma string (não<br />

formada por espaços ou quebras <strong>de</strong> linha) e um float <strong>de</strong> um arquivo-<strong>texto</strong>. Note que é necessário o<br />

uso <strong>de</strong> & antes da variável int e float, já que se <strong>de</strong>ve passar o en<strong>de</strong>reço <strong>de</strong>las a fscanf, e que isso não<br />

é necessário <strong>com</strong> a variável string, <strong>com</strong>o ocorre <strong>com</strong> no uso <strong>de</strong> scanf).<br />

1 # inclu<strong>de</strong> <br />

2 # <strong>de</strong>fine NOME_ARQUIVO " meu_<strong>texto</strong> . txt "<br />

3 # <strong>de</strong>fine TAM_STR 50<br />

4<br />

5 int main (){<br />

6 int inteiro ;<br />

7 float real ;<br />

8 char str [ TAM_STR ];<br />

9 FILE * arq ;<br />

10<br />

DRAFT<br />

11 if (!( arq = fopen ( NOME_ARQUIVO , "r"))){<br />

12 printf (" Erro na abertura <strong>de</strong> arquivo ! Abortando o programa ... ");<br />

13 exit (1) ;<br />

14 }<br />

15<br />

16 fscanf (arq , "%d\n%s\n%f", & inteiro , str , & real );<br />

17<br />

18 fclose ( arq );<br />

19<br />

20 return 0;<br />

21 }<br />

Exemplo 8.8: Uso <strong>de</strong> fscanf.<br />

1 1145<br />

2 segunda_linha<br />

3 45.99


8.5.<br />

OPERAÇÕES SOBRE ARQUIVOS TEXTO 217<br />

Exemplo 8.9: Exemplo <strong>de</strong> arquivo <strong>de</strong> <strong>texto</strong>.<br />

Dessa forma, um arquivo <strong>texto</strong> <strong>com</strong>o o do Exemplo 8.9 caso lido <strong>com</strong> o código do Exemplo 8.8,<br />

resultaria o valor 1145 na variável inteiro, “segunda linha” em str e 45.99 na variável real.<br />

fgets()<br />

Outra função <strong>de</strong> C utilizada para ler informações <strong>de</strong> um arquivo <strong>texto</strong> é fgets, que permite ler strings<br />

<strong>com</strong>pletas. O Exemplo 8.10 mostra seu protótipo.<br />

1 char * fgets ( char *str , int length , FILE *fp);<br />

Exemplo 8.10: Protótipo da função para leitura em arquivos <strong>de</strong> <strong>texto</strong>.<br />

Essa função lê os caracteres do arquivo fp, passado <strong>com</strong>o argumento, e armazena-os na string str,<br />

também passada <strong>com</strong>o argumento, até que os length - 1 caracteres sejam lidos ou um caractere <strong>de</strong><br />

nova linha ’\n’ seja lido. Se um caractere <strong>de</strong> nova linha for lido, ele será armazenado em str. Já<br />

quando a leitura <strong>de</strong> caracteres do arquivo finaliza, fgets encerrará a string str armazenando ‘\0’ no<br />

próximo caractere (ou seja, finalizando a string).<br />

1 primeira linha<br />

2 segunda linha<br />

Exemplo 8.11: Exemplo <strong>de</strong> arquivo <strong>de</strong> <strong>texto</strong>.<br />

Dessa forma, um arquivo <strong>texto</strong> que contenha os seguintes caracteres: “primeira linha\nsegunda<br />

linha”, tal <strong>com</strong>o mostrado no Exemplo 8.11, po<strong>de</strong> ser lido usando-se duas chamadas a funções fgets.<br />

Duas strings serão lidas e gravadas nas variáveis string: str1 conterá “primeira linha\n”, e str2 conterá<br />

“segunda linha”. O Exemplo 8.12 mostra <strong>com</strong>o isso po<strong>de</strong> ser feito.<br />

1 char str1 [50];<br />

2 char str2 [40];<br />

3 FILE * arquivo ;<br />

4<br />

5 if (!( arquivo = fopen ( NOME_ARQUIVO , "r"))){<br />

6 printf (" Erro na abertura <strong>de</strong> arquivo ! Abortando o programa ... ");<br />

7 exit (1) ;<br />

8 }<br />

9<br />

10 fgets (str1 , 50 , arquivo );<br />

11 fgets (str2 , 40 , arquivo );<br />

DRAFT<br />

Exemplo 8.12: Uso <strong>de</strong> fgets.<br />

Note que o tamanho máximo passado a fgets correspon<strong>de</strong> ao tamanho das strings <strong>de</strong>finidas.<br />

8.5.2 Escrita<br />

A linguagem C oferece a função fprintf que po<strong>de</strong> ser usada para gravar em arquivos <strong>de</strong> <strong>texto</strong>.<br />

fprintf()<br />

A função fprintf é semelhante a printf. Seu protótipo po<strong>de</strong> ser visto no Exemplo 8.13.<br />

1 int fprintf ( FILE *fp , const char * format , ... );<br />

Exemplo 8.13: Protótipo da função para escrita em arquivos <strong>de</strong> <strong>texto</strong>.


218<br />

CAPÍTULO 8. ARQUIVOS<br />

A passagem <strong>de</strong> parâmetros é semelhante a <strong>de</strong> printf, <strong>com</strong> o acréscimo do primeiro argumento, o<br />

apontador para FILE representando o arquivo no qual serão gravadas as informações.<br />

O Exemplo 8.14 mostra o uso <strong>de</strong>ssa função. Nesse programa, três variáveis, uma float, uma <strong>de</strong><br />

caracteres e uma string, são criadas e têm valores associados; então, o arquivo é aberto e elas são<br />

gravadas.<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> < stdlib .h><br />

3 # <strong>de</strong>fine NOME_ARQUIVO " meu_<strong>texto</strong> . txt "<br />

4 # <strong>de</strong>fine TAM_STR 50<br />

5<br />

6 int main (){<br />

7 float real = 547.32;<br />

8 char carac = ‘T’;<br />

9 char str [ TAM_STR ] = " teste para string ";<br />

10 FILE * arq ;<br />

11<br />

12 if (!( arq = fopen ( NOME_ARQUIVO , "w"))){<br />

13 printf (" Erro na abertura <strong>de</strong> arquivo ! Abortando o programa ...") ;<br />

14 exit (1) ;<br />

15 }<br />

16<br />

17 fprintf (arq , "%f\ nIsso e uma string constante \n%s\n%c\n", real , str , carac );<br />

18<br />

19 return 0;<br />

20 }<br />

1 547.32<br />

Exemplo 8.14: Uso <strong>de</strong> fprintf.<br />

A execução <strong>de</strong>sse programa resultará num arquivo <strong>texto</strong> <strong>com</strong>o o do Exemplo 8.15.<br />

2 Isso e uma string constante<br />

3 teste para string<br />

4 T<br />

Exemplo 8.15: Exemplo <strong>de</strong> arquivo <strong>de</strong> <strong>texto</strong>.<br />

8.6 Operações sobre arquivos binários<br />

Como já explicado, arquivos binários armazenam bytes que correspon<strong>de</strong>m diretamente aos valores das<br />

variáveis na memória principal (as variáveis transientes), e não somente armazenam caracteres, <strong>com</strong>o<br />

os arquivos <strong>de</strong> <strong>texto</strong>.<br />

São muito úteis principalmente por serem usados para ler e escrever diretamente tipos <strong>de</strong>finidos<br />

pelo programador, <strong>com</strong>o estruturas.<br />

8.6.1 Leitura<br />

DRAFT<br />

A linguagem C possui a função fread que po<strong>de</strong> ser usada para ler um arquivo binário. O protótipo<br />

da função fread é mostrado no Exemplo 8.16.<br />

1 size_t fread ( void * buffer , size_t num_bytes , size_t count , FILE *fp);<br />

Exemplo 8.16: Protótipo da função para leitura em arquivos binários.<br />

O parâmetro buffer é um apontador para uma região <strong>de</strong> memória que receberá as variáveis lidas<br />

do arquivo. O número <strong>de</strong> bytes a serem lidos é especificado por num bytes. O parâmetro count indica<br />

quantas variáveis do tamanho num bytes <strong>de</strong>verão ser lidas <strong>com</strong> essa chamada da função fread. E fp<br />

é um apontador para o arquivo <strong>de</strong> on<strong>de</strong> serão lidos os valores.


8.6.<br />

OPERAÇÕES SOBRE ARQUIVOS BINÁRIOS 219<br />

O tipo <strong>de</strong> retorno, size t, da função é <strong>de</strong>finido no arquivo stdio.h. Esse retorno po<strong>de</strong> ser avaliado<br />

para verificar se ocorreu algum erro, pois fread retornará a quantida<strong>de</strong> <strong>de</strong> itens lidos. Esse valor <strong>de</strong>ve<br />

ser igual a count; se não for, então o arquivo chegou ao final antes <strong>de</strong> ler a quantida<strong>de</strong> solicitada ou<br />

ocorreu um erro.<br />

O Exemplo 8.17 mostra a leitura <strong>de</strong> um inteiro, <strong>de</strong> um ponto flutuante e <strong>de</strong> um caractere <strong>de</strong> um<br />

arquivo binário. Consi<strong>de</strong>re que o arquivo arq1 já foi aberto nesse trecho <strong>de</strong> código.<br />

1 int inteiro ;<br />

2 float real ;<br />

3 char carac ;<br />

4 /* ... */<br />

5 fread (& inteiro , sizeof ( int ), 1, arq1 );<br />

6 fread (& real , sizeof ( float ), 1, arq1 );<br />

7 fread (& carac , sizeof ( char ), 1, arq1 );<br />

Exemplo 8.17: Uso <strong>de</strong> fread.<br />

Note que as três variáveis <strong>de</strong>vem estar gravadas em seqüência no arquivo. Note também que buffer<br />

é um apontador para as variáveis que armazenarão valores lidos do arquivo.<br />

8.6.2 Escrita<br />

Para se realizar a escrita <strong>de</strong> variáveis persistentes num arquivo binário, a linguagem C oferece a função<br />

fwrite. O Exemplo 8.18 mostra o protótipo da função fwrite.<br />

1 size_t fwrite ( void * buffer , size_t num_bytes , size_t count , FILE *fp);<br />

Exemplo 8.18: Protótipo da função para escrita em arquivos binários.<br />

Essa função se assemelha muito <strong>com</strong> fread. O parâmetro buffer é um apontador para a variável<br />

que será escrita no arquivo. Já num bytes é usado para informar à função quantos bytes contém o tipo<br />

da variável a ser escrita. count indica quantas variáveis (do tamanho <strong>de</strong> num bytes) serão escritas.<br />

E, finalmente, fp é o apontador para FILE que indica em qual arquivo <strong>de</strong>vem ser escritas as variáveis.<br />

O Exemplo 8.19 mostra um programa <strong>com</strong>pleto que gera uma struct, a grava em um arquivo e<br />

<strong>de</strong>pois o fecha. Então, esse arquivo é reaberto e essa struct é lida (somente para exemplo, pois os<br />

valores da struct ainda estavam corretos). Depois, esses dados lidos serão gravados em um arquivo<br />

<strong>texto</strong>.<br />

1 # inclu<strong>de</strong> <br />

2 # inclu<strong>de</strong> < stdlib .h><br />

3<br />

4 type<strong>de</strong>f struct {<br />

5 char nome [50];<br />

6 int ida<strong>de</strong> ;<br />

7 char sexo ;<br />

8 } tPessoa ;<br />

9<br />

10 int main (){<br />

11 FILE * arq ;<br />

12 tPessoa p;<br />

13<br />

14 p. nome = " Marcia Maia ";<br />

15 p. ida<strong>de</strong> = 46;<br />

16 p. sexo = ‘F’;<br />

17<br />

DRAFT<br />

18 if (!( arq = fopen (" arquivo_bin . teste ", "wb "))){<br />

19 printf (" Erro na abertura <strong>de</strong> arquivo ! Finalizando o programa ...") ;<br />

20 exit (1) ;<br />

21 }<br />

22


220<br />

CAPÍTULO 8. ARQUIVOS<br />

23 fwrite (&p, sizeof ( tPessoa ), 1, arq );<br />

24 fclose ( arq );<br />

25<br />

26 if (!( arq = fopen (" arquivo_bin . teste ", "rb "))){<br />

27 printf (" Erro na abertura <strong>de</strong> arquivo ! Finalizando o programa ...") ;<br />

28 exit (1) ;<br />

29 }<br />

30<br />

31 fread (&p, sizeof ( tPessoa ), 1, arq );<br />

32 fclose ( arq );<br />

33<br />

34 if (!( arq = fopen (" arquivo_<strong>texto</strong> . txt ", "w"))){<br />

35 printf (" Erro na abertura <strong>de</strong> arquivo ! Finalizando o programa ...") ;<br />

36 exit (1) ;<br />

37 }<br />

38<br />

39 fprintf (arq , "%s\n%d\n%c\n", p.nome , p. ida<strong>de</strong> , p. sexo );<br />

40<br />

41 fclose ( arq );<br />

42<br />

43 return 0;<br />

44 }<br />

Exemplo 8.19: Gravação e leitura <strong>de</strong> struct em arquivos.<br />

Po<strong>de</strong>-se ver que, ao final da execução do programa, arquivo <strong>texto</strong>.txt conterá os dados da pessoa.<br />

Estes dados po<strong>de</strong>rão ser lidos assim que o arquivo for aberto por um editor <strong>de</strong> <strong>texto</strong> qualquer (fato<br />

que não ocorre <strong>com</strong> o arquivo binário).<br />

8.7 Outras funções úteis para arquivos<br />

As seções anteriores mostraram as funções básicas para se trabalhar <strong>com</strong> arquivos em C. Porém, essas<br />

funções não são suficientes para realizar todas as tarefas que arquivos permitem.<br />

Serão apresentadas duas funções nessa seção: feof, usada para verificar se o indicador <strong>de</strong> posição<br />

chegou ao final <strong>de</strong> um arquivo; e fseek, usada para posicionar o indicador <strong>de</strong> posição num local<br />

específico do arquivo.<br />

Os exemplos apresentados nessa seção serão <strong>de</strong> programas <strong>com</strong>pletos e mais <strong>com</strong>plexos dos que os<br />

anteriormente mostrados.<br />

8.7.1 feof<br />

DRAFT<br />

Uma função essencial usada para trabalhar <strong>com</strong> arquivos é feof. Seu protótipo é visto no Exemplo<br />

8.20.<br />

1 int feof ( FILE *fp);<br />

Exemplo 8.20: Protótipo da função feof.<br />

Essa função retornará 0 se o arquivo fp passado <strong>com</strong>o argumento ainda não chegou ao final. A<br />

verificação se dá pelo indicador <strong>de</strong> posição no arquivo. Assim, a função feof é utilizada para verificar<br />

quando um arquivo, tanto <strong>de</strong> <strong>texto</strong> quando binário, termina.<br />

No Exemplo 8.21, consi<strong>de</strong>re que existe um arquivo previamente criado, binário, que armazena<br />

muitas variáveis struct do tipo tFuncionario. O programa abre esse arquivo, lê todas as variáveis lá<br />

presentes (uma quantia inicialmente <strong>de</strong>sconhecida), e vai gravando-as num arquivo <strong>texto</strong>.<br />

Note que esse programa usa o tipo tFuncionario <strong>com</strong>o um TAD: existem funções para ler e escrever<br />

os dados, eliminando a necessida<strong>de</strong> <strong>de</strong> se operar sobre as variáveis internas ao TAD.<br />

Outra observação importante é sobre a passagem <strong>de</strong> um apontador para tFuncionario <strong>com</strong>o<br />

parâmetro da função leFuncionario. Isso serve para que se possa armazenar o dado <strong>de</strong> forma


8.7. OUTRAS FUNÇÕES ÚTEIS PARA ARQUIVOS 221<br />

que ele não se perca ao final da execução da função. Com isso, o valor <strong>de</strong> retorno fica reservado para<br />

tratamento <strong>de</strong> erros.<br />

1 # inclu<strong>de</strong> <br />

2 # <strong>de</strong>fine ARQUIVO_LEITURA " binario "<br />

3 # <strong>de</strong>fine ARQUIVO_ESCRITA " <strong>texto</strong> . txt "<br />

4<br />

5 type<strong>de</strong>f struct {<br />

6 char nome [50];<br />

7 char sexo ;<br />

8 int ida<strong>de</strong> ;<br />

9 int matricula ;<br />

10 float salario ;<br />

11 } tFuncionario ;<br />

12<br />

13 int leFuncionario ( tFuncionario *func , FILE * arqbin );<br />

14 void gravaFuncionario ( tFuncionario f, FILE * arqtex );<br />

15<br />

16 int main (){<br />

17 FILE * arqbin , * arqtex ;<br />

18 tFuncionario f;<br />

19 int i;<br />

20<br />

21 /* Bloco <strong>de</strong> codigo r e s p o n s v e l pela correta abertura dos arquivos */<br />

22 if (!( arqbin = fopen ( ARQUIVO_LEITURA , "rb")) ||<br />

23 !( arqtex = fopen ( ARQUIVO_ESCRITA , "rb"))){<br />

24 printf (" Erro na abertura <strong>de</strong> arquivos ! Abortando ...\ n");<br />

25 exit (1) ;<br />

26 }<br />

27<br />

28 /* Bloco <strong>de</strong> codigo que contem o loop while , que usa a f u n o feof para<br />

29 ler o arquivo */<br />

30 while (! feof ( arqbin )){<br />

31 if( leFuncionario (&f, arqbin ) < 0){<br />

32 printf (" Erro na leitura <strong>de</strong> funcionarios . Abortando ...\ n");<br />

33 exit (1) ;<br />

34 } else {<br />

35 gravaFuncionario (f, arqtex );<br />

36 }<br />

37 }<br />

38<br />

39 return 0;<br />

40 }<br />

41<br />

DRAFT<br />

42 int leFuncionario ( tFuncionario *func , FILE * arqbin )<br />

43 {<br />

44 if (( fread (func , sizeof ( tFuncionario ), 1, arqbin )) != 1){<br />

45 return -1;<br />

46 }<br />

47<br />

48 return 0;<br />

49 }<br />

50<br />

51 void gravaFuncionario ( tFuncionario f, FILE * arqtex )<br />

52 {<br />

53 fprintf ( arqtex , " Nome : %s\ nSexo : %c\ nIda<strong>de</strong> : %d\ nMatricula : %d\n<br />

54 Salario : %f\n\n", f.nome , f.sexo , f. ida<strong>de</strong> , f. matricula , f. salario );<br />

55 }<br />

Exemplo 8.21: Uso <strong>de</strong> feof e outras funções no TAD tFuncionario


222<br />

CAPÍTULO 8. ARQUIVOS<br />

8.7.2 fseek<br />

Muitas vezes, <strong>de</strong>seja-se ter controle sobre o indicador <strong>de</strong> posição num arquivo. Ao se saber, por<br />

exemplo, qual o índice <strong>de</strong> uma estrutura específica já gravada, do total <strong>de</strong> todas as estruturas que<br />

fazem parte <strong>de</strong> um arquivo binário, po<strong>de</strong>-se buscar essa estrutura <strong>de</strong>sejada sem ter <strong>de</strong> carregar para<br />

a memória todas as outras. Isso po<strong>de</strong> ser feito posicionando-se o indicador <strong>de</strong> posição no arquivo e<br />

lendo somente a próxima estrutura.<br />

A função em C que permite fazer isso é fseek. Veja seu protótipo no Exemplo 8.22.<br />

1 int fseek ( FILE *fp , long numbytes , int origin );<br />

Exemplo 8.22: Protótipo da função fseek.<br />

A função retornará 0 se for bem-sucedida; caso contrário, retornará um int diferente <strong>de</strong> 0. Seus<br />

argumentos são: fp, um apontador para arquivo já aberto por fopen; numbytes, um número que<br />

indica quantos bytes a partir do parâmetro origin estará o indicador <strong>de</strong> posição; e, finalmente, origin<br />

será uma das três macros mostradas abaixo (que estão <strong>de</strong>finidas no arquivo stdio.h):<br />

Posição<br />

Início do arquivo<br />

Posição atual<br />

Final do arquivo<br />

Parâmetro<br />

SEEK SET<br />

SEEK CUR<br />

SEEK END<br />

O Exemplo 8.23 mostra <strong>com</strong>o posicionar o indicador <strong>de</strong> posição duas variáveis int à frente da<br />

posição inicial do arquivo arq, ou seja, pronto para ler a terceira variável int armazenada).<br />

1 fseek (arq , 2 * sizeof ( int ), SEEK_SET );<br />

Exemplo 8.23: Exemplo <strong>de</strong> utilização da função fseek.<br />

O Exemplo 8.24 mostra a função obtemFuncionarioPosicao. Essa função é usada para ler<br />

structs tFuncionario, contidas no arquivo binário <strong>de</strong>finido, passando-se o índice do funcionário que se<br />

<strong>de</strong>seja ler. Ela recebe um apontador para o arquivo binário <strong>de</strong> leitura, já aberto <strong>com</strong> fopen, <strong>de</strong> on<strong>de</strong><br />

tentará ler a struct <strong>de</strong> índice i, um parâmetro inteiro passado. Assim, se i=1, o retorno da função<br />

será a primeira struct; se i=3, será a terceira; etc.<br />

1 int obtemFuncionarioPosicao ( tFuncionario *func , int i, FILE * arqbin )<br />

2 {<br />

DRAFT<br />

3 if( fseek ( arqbin , (i -1) * sizeof ( tFuncionario ), SEEK_SET )){<br />

4 return -1;<br />

5 }<br />

6 if (( fread (func , sizeof ( tFuncionario ), 1, arqbin )) != 1){<br />

7 return -1;<br />

8 }<br />

9<br />

10 return 0;<br />

11 }<br />

Exemplo 8.24: Uso <strong>de</strong> fseek para posicionamento num arquivo binário<br />

8.8 Exercícios Resolvidos<br />

Exercício Resolvido 8.1 - Cópia <strong>de</strong> arquivos <strong>texto</strong>


8.8.<br />

EXERCÍCIOS RESOLVIDOS 223<br />

Escreva um programa em C que solicite ao usuário a digitação do nome <strong>de</strong> um arquivo <strong>texto</strong> já<br />

existente, e que então gere um outro arquivo, que será uma cópia do primeiro.<br />

Solução Possível:<br />

A menor quantida<strong>de</strong> <strong>de</strong> memória que se po<strong>de</strong> alocar em C é um byte, portanto essa unida<strong>de</strong><br />

será usada no problema para que o arquivo copiado sempre seja dividido em um número inteiro <strong>de</strong><br />

segmentos.<br />

O tipo <strong>de</strong> dados a ser utilizado para representar um byte é o char, observe que o tamanho do char<br />

não está <strong>de</strong>finido no padrão do C, mas nas implementações <strong>de</strong> <strong>com</strong>piladores mais <strong>com</strong>uns é esse o<br />

tamanho adotado.<br />

Uma das possíveis soluções é <strong>de</strong>scrita pelo Pseudocódigo 8.1 e sua implementação po<strong>de</strong> ser vista<br />

no Exemplo 8.25.<br />

Pseudocódigo 8.1 Cópia <strong>de</strong> arquivo <strong>texto</strong>.<br />

Descrição: Cópia <strong>de</strong> arquivo escolhido pelo usuário.<br />

Dados <strong>de</strong> Entrada: Nome do arquivo fonte e nome do arquivo cópia.<br />

Saída do Programa: Cópia do arquivo fonte <strong>com</strong> o nome <strong>de</strong>sejado.<br />

Funç~ao principal :<br />

Pedir ao usuário que digite o nome do arquivo fonte .<br />

Pedir ao usuário que digite o nome do arquivo cópia .<br />

Abrir o arquivo fonte para leitura .<br />

Abrir o arquivo cópia para escrita .<br />

ENQUANTO n~ao for fim do arquivo fonte :<br />

Ler caractere do arquivo fonte .<br />

Gravar caractere no arquivo cópia .<br />

FIM - ENQUANTO<br />

Fechar arquivo fonte .<br />

Fechar arquivo cópia .<br />

FIM - Funç~ao principal<br />

Ao inicio os arquivos são abertos <strong>com</strong> as permissões necessárias utilizando a função fopen. Para a<br />

leitura e escrita foram utilizadas, respectivamente, as funções getchar e putchar que são capazes <strong>de</strong><br />

ler um char do arquivo. O funcionamento é bem simples: cada caractere, assim que lido do arquivo<br />

fonte, <strong>de</strong>ve ser armazenado no arquivo cópia mantendo a organização do arquivo original.<br />

1 int main (){<br />

2 char fonte [64] , copia [64];<br />

3 FILE *fon , * cop ;<br />

4<br />

5 printf (" Digite o nome do arquivo fonte : ");<br />

6 scanf ("%s", fonte );<br />

7 printf (" Digite o nome do arquivo fonte : ");<br />

8 scanf ("%s", copia );<br />

9<br />

DRAFT<br />

10 if (!( fon = fopen ( fonte , "r"))) {<br />

11 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

12 exit (1) ;<br />

13 }<br />

14<br />

15 if (!( cop = fopen ( copia , "w"))) {<br />

16 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

17 exit (1) ;<br />

18 }<br />

19<br />

20 while (! feof ( fon )){<br />

21 char c = getc ( fon );<br />

22 putc (c, cop );<br />

23 }


224<br />

CAPÍTULO 8. ARQUIVOS<br />

24<br />

25 fclose ( fon );<br />

26 fclose ( cop );<br />

27 return 0;<br />

28 }<br />

Exemplo 8.25: Programa capaz <strong>de</strong> fazer uma cópia <strong>de</strong> um arquivo.<br />

Exercício Resolvido 8.2 - Leitura e manipulação <strong>de</strong> dados em arquivo <strong>texto</strong><br />

Consi<strong>de</strong>re um arquivo <strong>texto</strong> que armazene números em ponto flutuante em cada uma <strong>de</strong> suas linhas.<br />

Ou seja, o arquivo inicia <strong>com</strong> uma quantida<strong>de</strong> <strong>de</strong> um ou mais caracteres representando números<br />

inteiros, então segue um caracter <strong>de</strong> ponto ’.’ e mais alguns inteiros; em seguida, uma quebra <strong>de</strong> linha;<br />

na próxima linha esse formato prossegue, até que, no fim da última linha, não ocorre quebra <strong>de</strong> linha.<br />

Escreva um programa em C que <strong>de</strong>termine o valor mínimo, o valor máximo e a média <strong>de</strong>sses valores<br />

armazenados no arquivo. Imprima esses valores na tela.<br />

Solução Possível:<br />

Como no Exercício resolvido 8.1, este problema exige que os dados lidos sejam analisados assim que<br />

lidos. A solução escolhida é <strong>de</strong>scrita pelo Pseudocódigo 8.2 e sua implementação é vista no Exemplo<br />

8.26.<br />

Pseudocódigo 8.2 Leitura e manipulação <strong>de</strong> valores em ponto flutuante <strong>de</strong> um arquivo <strong>texto</strong>.<br />

Descrição: Leitura <strong>de</strong> valores em ponto flutuante e calculo do mínimo, do máximo e da média <strong>de</strong>les.<br />

Dados <strong>de</strong> Entrada: Arquivo <strong>texto</strong> <strong>com</strong> valores em ponto flutuante.<br />

Saída do Programa: Valores mínimo, máximo e media dos valores.<br />

Funç~ao principal :<br />

Abrir arquivo <strong>texto</strong> .<br />

Ler primeiro valor .<br />

Atribuir o valor lido às variáveis mínimo , máximo e soma .<br />

Atribuir o valor 1 a quantida<strong>de</strong> <strong>de</strong> valores lidos .<br />

ENQUANTO n~ao for fim do arquivo :<br />

Ler novo valor do arquivo .<br />

Verificar se o valor é mínimo ou máximo :<br />

SE o novo valor é maior que o máximo :<br />

Atibuir novo valor a variável máximo .<br />

FIM -SE<br />

SE o novo valor for menor que o mínimo :<br />

Atribuir novo valor à variável mínimo .<br />

FIM -SE<br />

Somar o novo valor à variável soma .<br />

Incrementar a quantida<strong>de</strong> <strong>de</strong> valores lidos .<br />

FIM - ENQUANTO<br />

Fechar arquivo <strong>texto</strong> .<br />

Calcular média a partir da variável soma e da quantida<strong>de</strong> <strong>de</strong> valores lidos .<br />

FIM - Funç~ao principal<br />

DRAFT<br />

Neste problema a formatação do <strong>texto</strong> faz toda a diferença na hora da leitura do arquivo, por isso<br />

foi utilizada a função fscanf que permite leitura formatada.<br />

Observe que a primeira leitura é feita fora do loop principal e serve para inicializar as variáveis <strong>de</strong><br />

forma consistente para que o resto do código funcione corretamente.<br />

Assim que um valor é lido, são feitos testes e cada variável é atualiazada conforme necessário.<br />

1 # <strong>de</strong>fine ARQUIVO " arquivo . txt "


8.8.<br />

EXERCÍCIOS RESOLVIDOS 225<br />

2<br />

3 int main (){<br />

4 float val , min , max , soma ;<br />

5 int n;<br />

6 FILE * arq ;<br />

7<br />

8 if (!( arq = fopen ( ARQUIVO , "r"))) {<br />

9 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

10 exit (1) ;<br />

11 }<br />

12<br />

13 fscanf (arq , "%f", & val );<br />

14 min = max = soma ;<br />

15 n =1;<br />

16<br />

17 while (! feof (fp)){<br />

18 fscanf (arq , "%f", & val );<br />

19 if(val > max ){<br />

20 max = val ;<br />

21 }<br />

22 else if(val < min ){<br />

23 min = val ;<br />

24 }<br />

25 soma += val ;<br />

26 n ++;<br />

27 }<br />

28<br />

29 fclose ( arq );<br />

30<br />

31 printf (" Minimo : %f\ nMaximo : %f\ nMedia : %f\n", min , max , soma /n);<br />

32 return 0;<br />

33 }<br />

Exemplo 8.26: Mínimo, máximo e média dos valores <strong>de</strong> um arquivo.<br />

Exercício Resolvido 8.3 - Leitura e manipulação <strong>de</strong> dados em arquivo <strong>texto</strong> II<br />

DRAFT<br />

Escreva um programa que leia um arquivo <strong>texto</strong> contendo linhas <strong>de</strong> dados. Em cada linha do<br />

arquivo há o nome <strong>de</strong> um aluno e duas notas. Esses dados estão separados por ponto e vírgula. Existe<br />

um ponto e vírgula no final <strong>de</strong> cada linha. O programa <strong>de</strong>ve ler esses dados e imprimir os valores<br />

lidos, a média das duas notas, e se o aluno foi aprovado ou não (<strong>com</strong> nota maior ou igual a 5).<br />

Solução Possível:<br />

Com algumas semelhanças para os exercícios resolvidos anteriores, este problema exige que os<br />

dados sejam tratados assim que lidos e ainda utiliza leitura formatada um pouco mais <strong>com</strong>plexa.<br />

O Pseudocódigo 8.3 esquematiza uma possível solução que é implementada no Exemplo 8.27.<br />

Pseudocódigo 8.3 Leitura dos dados <strong>de</strong> alunos, cálculo da média <strong>de</strong> cada um e sua situação.<br />

Descrição: Leitura <strong>de</strong> uma lista <strong>de</strong> alunos <strong>com</strong> suas notas, calculo da média das notas <strong>de</strong> cada um e sua<br />

situação (aprovado ou reprovado).<br />

Dados <strong>de</strong> Entrada: Arquivo <strong>texto</strong> formatado contendo a lista <strong>de</strong> alunos <strong>com</strong> suas notas.<br />

Saída do Programa: Lista contendo cada aluno, suas notas, a média <strong>de</strong>las e a situação do aluno.<br />

Funç~ao principal :<br />

Abrir arquivo <strong>texto</strong> .<br />

ENQUANTO n~ao for fim <strong>de</strong> arquivo :<br />

Ler nome e duas notas do arquivo .


226<br />

CAPÍTULO 8. ARQUIVOS<br />

Calcular média das notas .<br />

Apresentar na tela o nome , as duas notas e a média .<br />

Testar se o aluno foi aprovado :<br />

SE a média é maior ou igual a 5.0:<br />

Apresentar na tela que o aluno foi aprovado .<br />

SEN~AO:<br />

Apresentar na tela que o aluno foi reprovado .<br />

FIM - SE<br />

FIM - ENQUANTO<br />

Fechar arquivo .<br />

FIM - Funç~ao principal<br />

Como no Exercício resolvido 8.2, foi utilizada a função printf . Porém <strong>de</strong>sta vez <strong>de</strong>monstrando<br />

toda a versatilida<strong>de</strong> que esta função, tão importante, po<strong>de</strong> oferecer.<br />

Não se po<strong>de</strong> esquecer que, para utilizar leitura ou escrita <strong>de</strong> arquivos, alguns passos <strong>de</strong>vem ser<br />

seguidos a risca: a <strong>de</strong>claração do apontador do tipo FILE, a abertura do arquivo <strong>com</strong> as permissões<br />

corretas, a leitura ou escrita <strong>de</strong>sejada e por último, muito importante mas muitas vezes esquecido, o<br />

fechamento do arquivo.<br />

1 # <strong>de</strong>fine ARQUIVO " arquivo . txt "<br />

2<br />

3 int main (){<br />

4 char nome [64];<br />

5 float nota1 , nota2 ;<br />

6 FILE * arq ;<br />

7<br />

8 if (!( arq = fopen ( ARQUIVO , "r"))) {<br />

9 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

10 exit (1) ;<br />

11 }<br />

12<br />

13 while (! feof ( arq )){<br />

14 fscanf (arq , "%s ,%f ,%f", nome , & nota1 , & nota2 );<br />

15 media = ( nota1 + nota2 ) /2;<br />

16 printf ("%s, %f, %f, %f, ", nome , nota1 , nota2 , media );<br />

17 if( media >= 5.0) {<br />

18 printf (" aprovado .\n");<br />

19 } else {<br />

20 printf (" reprovado .\n");<br />

21 }<br />

22 }<br />

23<br />

24 fclose ( arq );<br />

25 return 0;<br />

26 }<br />

DRAFT<br />

Exemplo 8.27: Leitura <strong>de</strong> dados <strong>de</strong> alunos <strong>de</strong> arquivo, calculo da média e verificação da situação <strong>de</strong><br />

cada um.<br />

Exercício Resolvido 8.4 - Armazenamento <strong>de</strong> dados em arquivo binário<br />

Escreva um programa em C que solicita ao usuário a digitação <strong>de</strong> um nome <strong>de</strong> arquivo. Esse arquivo<br />

será criado e o usuário informará números em ponto flutuante, que serão gravados no arquivo. O<br />

arquivo será um arquivo binário. O usuário po<strong>de</strong> encerrar a entrada <strong>de</strong> novos valores <strong>com</strong> a digitação<br />

<strong>de</strong> um número negativo.<br />

Solução Possível:


8.8.<br />

EXERCÍCIOS RESOLVIDOS 227<br />

Esse exercício resolvido difere dos outros pois são utilizados arquivos binários e não arquivos <strong>texto</strong>.<br />

A idéia, que po<strong>de</strong> ser vista no Pseudocódigo 8.4 é que cada valor que o usuário utiliza <strong>com</strong>o entrada<br />

seja gravado no arquivo binário até que o programa encontre uma entrada negativa.<br />

Veja a implementação no Exemplo 8.28.<br />

Pseudocódigo 8.4 Armazenamento <strong>de</strong> dados em arquivo binário.<br />

Descrição: Armazenamento <strong>de</strong> dados em ponto flutuante para arquivo binário.<br />

Dados <strong>de</strong> Entrada: Nome do arquivo e valores em ponto flutuante.<br />

Saída do Programa: Arquivo binário on<strong>de</strong> estão armazenados os valores escolhidos.<br />

Funç~ao principal :<br />

Pedir ao usuário que digite o nome do arquivo .<br />

Abrir o arquivo binário <strong>com</strong> permiss~ao <strong>de</strong> escrita .<br />

FAZER<br />

Pedir ao usuário que digite um valor .<br />

Testar se o usuário <strong>de</strong>seja encerrar a entrada :<br />

SE o valor inserido é maior ou igual a zero :<br />

Armazenar esse valor no arquivo .<br />

FIM - SE<br />

ENQUANTO o valor inserido é maior ou igual a zero .<br />

Fechar arquivo binário .<br />

FIM - Funç~ao principal<br />

As principais diferenças do que foi mostrado nos exercícios resolvidos anteriores é o uso da função<br />

fwrite, que serve para armazenar dados em binário.<br />

1 int main (){<br />

2 char nome [64];<br />

3 float val ;<br />

4 FILE * arq ;<br />

5<br />

6 if (!( arq = fopen ( ARQUIVO , "w"))) {<br />

7 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

8 exit (1) ;<br />

10<br />

9 }<br />

11 do{<br />

12 printf (" Digite um valor : ");<br />

13 scanf ("%f", & val );<br />

14 if(val >= 0){<br />

15 if( fwrite (& val , sizeof ( float ), 1, arq ) == 0){<br />

16 printf (" I m p o s s v e l gravar no arquivo . Finalizando ...\ n");<br />

17 exit (1) ;<br />

18 }<br />

19 }<br />

20 } while ( val >= 0);<br />

21<br />

22 fclose ( arq );<br />

23 return 0;<br />

24 }<br />

DRAFT<br />

Exemplo 8.28: Armazenamento <strong>de</strong> dados em ponto flutuante em arquivo binário.<br />

Exercício Resolvido 8.5 - Armazenamento dos dados <strong>de</strong> um TAD em arquivo binário<br />

Escreva um programa em C que receba via teclado o nome <strong>de</strong> um arquivo binário. Esse arquivo<br />

armazenará nome, ida<strong>de</strong> e sexo <strong>de</strong> pessoas, <strong>com</strong>o no TAD tPessoa. O programa <strong>de</strong>ve solicitar ao


228<br />

CAPÍTULO 8. ARQUIVOS<br />

usuário a digitação <strong>de</strong>sses dados e armazená-los no arquivo <strong>de</strong>pois. O programa termina quando o<br />

usuário digitar enter na entrada do nome, ou seja, informar um nome vazio.<br />

Solução Possível:<br />

Este exercício resolvido <strong>de</strong>monstra a utilização <strong>de</strong> escrita em arquivos binários para armazenamento<br />

<strong>de</strong> dados mais <strong>com</strong>plexos. Observe no Pseudocódigo 8.5 que os dados são encapsulados em um TAD<br />

em seguida armazenados no arquivo. Isso po<strong>de</strong> ser feito facilmente, veja a implementação no Exemplo<br />

8.29.<br />

Pseudocódigo 8.5 Leitura e armazenamento <strong>de</strong> dados <strong>de</strong> pessoas em arquivo binário.<br />

Descrição: Receber dados do usuário, inseri-los em um TAD e armazená-los em arquivo binário.<br />

Dados <strong>de</strong> Entrada: O nome, ida<strong>de</strong> e sexo <strong>de</strong> cada pessoa que se <strong>de</strong>seja inserir.<br />

Saída do Programa: Arquivo binário <strong>com</strong> os dados armazenados.<br />

Funç~ao principal :<br />

Abrir o arquivo para escrita .<br />

FAZER<br />

Pedir ao usuário que digite um nome .<br />

Testar se o usuário <strong>de</strong>seja encerrar a entrada :<br />

SE o tamanho do nome for maior que zero :<br />

Pedir ao usuário que digite a ida<strong>de</strong> .<br />

Pedir ao usuário que digite o sexo .<br />

Encapsular dados em um TAD .<br />

Armazenar dados no arquivo binário .<br />

FIM -SE.<br />

ENQUANTO o tamanho do nome for maior que zero .<br />

Fechar o arquivo binário .<br />

FIM - Funç~ao principal<br />

Observe que, <strong>com</strong>o no Exercício Resolvido 8.4, é utilizada a função fwrite sem gran<strong>de</strong>s modificações.<br />

mais uma vez, um exemplo que exibe a versatilida<strong>de</strong> das funções responsáveis pela entrada<br />

e saída <strong>de</strong> dados da linguagem C.<br />

Neste caso, há ainda um ponto que vale mencionar: ao se utilizar o scanf , esta função <strong>de</strong>ixa<br />

na stdin um caractere <strong>de</strong> salto <strong>de</strong> linha que não é lido. Esse caractere po<strong>de</strong> prejudicar a leitura do<br />

próximo scanf , por isso o uso da função getchar nesse caso, ela é responsável por eliminar esse<br />

caractere in<strong>de</strong>sejado.<br />

1 type<strong>de</strong>f struct {<br />

2 char nome [64];<br />

3 int ida<strong>de</strong> ;<br />

4 char sexo ; // M ou F<br />

5 } tPessoa ;<br />

6<br />

7 int main (){<br />

8 char arquivo [64];<br />

9 tPessoa pessoa ;<br />

10 int tam ;<br />

11 FILE * arq ;<br />

12<br />

DRAFT<br />

13 printf (" Digite o nome <strong>de</strong> um arquivo para escrita : ");<br />

14 scanf ("%s", arquivo );<br />

15 getchar ();<br />

16<br />

17 if (!( arq = fopen ( arquivo , "w"))) {<br />

18 printf (" Impossivel abrir o arquivo . Finalizando ...\ n");<br />

19 exit (1) ;<br />

20 }<br />

21<br />

22 do{


8.9. RESUMO 229<br />

23 printf (" Digite um nome : ");<br />

24 scanf (" %[^\ n]", pessoa . nome );<br />

25 getchar ();<br />

26<br />

27 tam = strlen ( pessoa . nome );<br />

28 if(tam > 0){<br />

29 printf (" Digite a ida<strong>de</strong> : ");<br />

30 scanf ("%d", & pessoa . ida<strong>de</strong> );<br />

31 getchar ();<br />

32 printf (" Digite o sexo : ");<br />

33 scanf ("%c", & pessoa . sexo );<br />

34 getchar ();<br />

35<br />

36 if( fwrite (& pessoa , sizeof ( tPessoa ), 1, arq ) == 0){<br />

37 printf (" I m p o s s v e l gravar no arquivo . Finalizando ...\ n");<br />

38 exit (1) ;<br />

39 }<br />

40 }<br />

41 } while ( tam > 0);<br />

42<br />

43 fclose ( arq );<br />

44 return 0;<br />

45 }<br />

Exemplo 8.29: Leitura, encapsulamento e armazenamento em arquivo binário <strong>de</strong> dados do usuário.<br />

8.9 Resumo<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

ˆ<br />

Variáveis transientes são armazenadas na memória principal. Tem tempo <strong>de</strong> acesso rápido, mas<br />

duração limitada. Só existem enquanto o programa que as está utilizando estiver na memória.<br />

Variáveis persistentes não per<strong>de</strong>m suas informações quando o programa que as criou não está<br />

mais em memória, pois estão armazenadas em meio secundário, tais <strong>com</strong>o, disco rígido, memória<br />

flash, CD.<br />

Arquivos <strong>texto</strong> só armazenam caracteres, e são <strong>com</strong>preensíveis ao serem lidos em um editor <strong>de</strong><br />

<strong>texto</strong>. Já arquivos binários armazenam variáveis no formato em que elas são armazenadas em<br />

memória;<br />

Um arquivo <strong>de</strong>ve ser aberto para po<strong>de</strong>r ser utilizado, e após essa utilização, <strong>de</strong>ve ser fechado;<br />

As variáveis persistentes po<strong>de</strong>m ser escritas e lidas dos arquivos. Existem funções específicas<br />

para essas tarefas, algumas <strong>de</strong>signadas para arquivos binários e outras para arquivos <strong>texto</strong>;<br />

DRAFT<br />

A linguagem C oferece uma série <strong>de</strong> funções para lidar <strong>com</strong> arquivos, e esse capítulo apresentou<br />

algumas, <strong>com</strong>o fopen, usada para abrir arquivos, e fread, usada para ler variáveis persistentes<br />

<strong>de</strong> arquivos binários.<br />

8.10 Exercícios Propostos<br />

1. Escreva um programa em C que abra um arquivo <strong>texto</strong> e conte a quantida<strong>de</strong> <strong>de</strong> caracteres<br />

armazenados nele. Imprima o número na tela. O programa <strong>de</strong>ve solicitar ao usuário que digite<br />

o nome do arquivo.<br />

2. Consi<strong>de</strong>re o programa escrito para a questão anterior. Exiba na tela, agora, o valor n correspon<strong>de</strong>nte<br />

à quantida<strong>de</strong> <strong>de</strong> números reais contidos no arquivo e o valor máximo, mínimo e a<br />

média calculados anteriormente, porém agora divididos por n. Depois, gere um novo arquivo<br />

que contenha cada um dos números reais do arquivo divididos por n, um por linha. Procure<br />

reutilizar, nessa questão, o maior número possível das funções que você tenha construído para a<br />

questão anterior.


230<br />

CAPÍTULO 8. ARQUIVOS<br />

3. Consi<strong>de</strong>re um arquivo <strong>texto</strong> que armazene caracteres variados, ou seja, um <strong>texto</strong> digitado. Escreva<br />

um programa que o leia e gere um novo arquivo que contenha somente as letras do arquivo<br />

original, na or<strong>de</strong>m em que lá aparecem (ou seja, caracteres <strong>de</strong> A-Z ou a-z).<br />

4. Para um arquivo do mesmo tipo da Questão 3 (que armazene caracteres variados), escreva<br />

um programa em C que <strong>de</strong>termine a média dos <strong>com</strong>primentos <strong>de</strong> todas as palavras que se<br />

encontram nele. Enten<strong>de</strong>-se por palavra um conjunto <strong>de</strong> caracteres <strong>de</strong> letras que está separado<br />

<strong>de</strong> outros conjuntos <strong>de</strong> caracteres no arquivo por um (ou mais) caracteres <strong>de</strong> espaço em branco<br />

( ’ ’, tabulações ou quebra <strong>de</strong> linha); e seu <strong>com</strong>primento será a quantida<strong>de</strong> <strong>de</strong> caracteres que o<br />

formam.<br />

5. Consi<strong>de</strong>re um arquivo <strong>texto</strong> <strong>com</strong>o o usado na Questão 3. Faça um programa que o leia e que<br />

permita ao usuário consultar uma das linhas do arquivo, solicitando a ele que informe o índice<br />

n <strong>de</strong>ssa linha. O programa <strong>de</strong>ve imprimir a linha especificada ou a mensagem <strong>de</strong> que ela não<br />

existe.<br />

6. Escreva um programa em C que receba via teclado o nome <strong>de</strong> um arquivo <strong>texto</strong> e uma palavra.<br />

O programa <strong>de</strong>ve apresentar todas as linhas que possuem essa palavra.<br />

7. Escreva um programa em C que receba via teclado o nome <strong>de</strong> um arquivo <strong>texto</strong>. O programa<br />

<strong>de</strong>ve solicitar ao usuário que digite o índice da linha inicial e da linha final, e o programa <strong>de</strong>ve<br />

apresenta-las e todas as linhas entre elas. Se o índice superior <strong>de</strong> linhas não existe, esse erro<br />

<strong>de</strong>ve ser informado ao usuário (mas as linhas existentes <strong>de</strong>vem, ainda, ser impressas).<br />

8. Escreva um programa em C que receba o nome <strong>de</strong> um arquivo binário, o qual armazena números<br />

em ponto flutuante, no mesmo formato que na questão anterior. O programa <strong>de</strong>ve ler todos<br />

esses valores e gravá-los na memória; então, or<strong>de</strong>ná-los, e regravá-los num arquivo <strong>texto</strong>, <strong>com</strong><br />

um número por linha.<br />

9. Escreva um programa em C que receba via teclado o nome do arquivo binário da questão anterior.<br />

Então, ele <strong>de</strong>ve abrir o arquivo. Deve existir um menu que ofereça ao usuário a possibilida<strong>de</strong> <strong>de</strong><br />

po<strong>de</strong>r: 1) imprimir (na tela) todos os registros lá contidos; 2) acessar os dados <strong>de</strong> uma pessoa<br />

passando o índice <strong>de</strong>la no arquivo (1 para a primeira pessoa no arquivo, 5 para a quinta pessoa no<br />

arquivo...); 3) o programa <strong>de</strong>ve informar a quantida<strong>de</strong> total <strong>de</strong> homens e mulheres armazenadas<br />

no arquivo; 4) O programa <strong>de</strong>ve permitir ao usuário digitar novas pessoas. Esses novos dados<br />

digitados <strong>de</strong>vem ser gravados no arquivo (e posteriormente <strong>de</strong>scarregados da memória) somente<br />

quando o usuário escolher, no menu, a opção para sair do programa.<br />

8.11 Trabalhos Sugeridos<br />

DRAFT<br />

1. Registro <strong>de</strong> alunos e turmas dos cursos <strong>de</strong> uma Universida<strong>de</strong><br />

Faça um programa capaz <strong>de</strong> gerenciar os dados do catálogo <strong>de</strong> curso, turma e aluno <strong>de</strong> uma<br />

universida<strong>de</strong>. O catálogo <strong>de</strong>ve ser lido <strong>de</strong> um arquivo <strong>texto</strong>, no qual cada entrada representará<br />

um curso, turma ou aluno da universida<strong>de</strong>. O formato <strong>de</strong> cada entrada é <strong>de</strong>scrito abaixo e logo<br />

em seguida um exemplo <strong>de</strong> catálogo.<br />

Para um curso:<br />

CURSO<br />

<br />

<br />

Para uma turma:


8.11. TRABALHOS SUGERIDOS 231<br />

TURMA<br />

<br />

<br />

<br />

<br />

<br />

Para um aluno:<br />

ALUNO<br />

<br />

<br />

<br />

<br />

Exemplo:<br />

CURSO<br />

1256<br />

Engenharia <strong>de</strong> <strong>com</strong>putaç~ao<br />

CURSO<br />

9756<br />

Medicina<br />

TURMA<br />

111<br />

1256<br />

2009<br />

1<br />

2<br />

ALUNO<br />

25<br />

Ubirajara<br />

111<br />

9.56<br />

DRAFT<br />

Observe que cada aluno é vinculado a uma turma e cada turma é vinculada a um curso. Dessa<br />

forma, uma turma não po<strong>de</strong> ser inscrita antes do curso ao qual ela é vinculada e um aluno não<br />

po<strong>de</strong> ser inscrito antes que a turma a qual ele é vinculado seja inscrita.<br />

Implemente seu programa usando listas ligadas. Ele <strong>de</strong>ve ser capaz <strong>de</strong> exibir ao usuário um<br />

menu que permita executar as seguintes operações:<br />

(a) Apresentar dados <strong>de</strong> um curso dada sua i<strong>de</strong>ntificação;<br />

(b) Apresentar dados <strong>de</strong> uma turma dada sua i<strong>de</strong>ntificação;<br />

(c) Apresentar dados <strong>de</strong> um aluno dada sua i<strong>de</strong>ntificação;<br />

(d) Apresentar lista <strong>de</strong> alunos <strong>de</strong> um curso em or<strong>de</strong>m crescente <strong>de</strong> CRA;<br />

(e) Apresentar lista <strong>de</strong> alunos <strong>de</strong> uma turma em or<strong>de</strong>m alfabética;<br />

(f) Apresentar CRA médio <strong>de</strong> um curso;<br />

(g) Apresentar CRA médio <strong>de</strong> uma turma;<br />

(h) Apresentar lista <strong>de</strong> cursos em or<strong>de</strong>m <strong>de</strong>crescente <strong>de</strong> CRA médio;


232<br />

CAPÍTULO 8. ARQUIVOS<br />

(i) Inserção, exclusão e modificação dos dados <strong>de</strong> um curso, turma ou aluno;<br />

(j) Ler o catálogo <strong>de</strong> um arquivo binário;<br />

(k) Gravar o catálogo em um arquivo binário;<br />

DRAFT


Referências Bibliográficas<br />

[1] PAUL STRATHERN. Turing e o Computador em 90 Minutos. first edition, 2000.<br />

[2] ANDREW S TANENBAUM and JAMES R GOODMAN. Structured Computer Organization.<br />

fourth edition, 1999.<br />

[3] BRIAN KERNIGHAN and DENNIS RITCHIE. The C Programming Language. second edition,<br />

1988.<br />

DRAFT<br />

233

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!