Você está na página 1de 354

Ciência e Tecnologia de Alimentos

Princípios de
++
Programação em C
Uma abordagem introdutória
e prática para a Engenharia de
Alimentos

Primeira Edição

Roney Alves da Rocha


Ana Carolina Salgado de Oliveira
Moysés Naves de Moraes
Maria José Valenzuela Bell
Virgílio de Carvalho dos Anjos

DEPARTAMENTO DE CIÊNCIA DOS ALIMENTOS - DCA


++
Princípios de Programação em C
Uma abordagem introdutória e prática para a
Engenharia de Alimentos
Página intencionalmente deixada em branco
Roney Alves da Rocha
Ana Carolina Salgado de Oliveira
Moysés Naves de Moraes
Maria José Valenzuela Bell
Virgílio de Carvalho dos Anjos

++
Princípios de Programação em C
Uma abordagem introdutória e prática para a
Engenharia de Alimentos

Editora UFLA
Universidade Federal de Lavras
2022
Página intencionalmente deixada em branco
Dedico este livro aos meus sobrinhos Daniel e Danilo, à minha mãe
Maria da Glória, à minha irmã Flávia, ao Robinson, e a todos os
estudantes do curso de Engenharia de Alimentos do DCA/UFLA.
Roney

Dedico este livro aos meus pais, Maria Auxiliadora e Geraldo Lúcio,
e à minha irmã, Isabela, que sempre me incentivaram e apoiaram
mesmo a distância.
Ana Carolina

Dedico este livro à minha mãe Marilena e à


minha esposa Mária Herminia por todo o apoio nos
momentos difíceis, mesmo a distância.
Moysés

Dedico especialmente àqueles que, de diversas formas, me levaram até onde


estou agora: meus pais, Vicente e Ximena, irmãos, Vicente, Ximena e
Carlos, filhas, Ximena e Chloé, e ao meu esposo, Virgílio.
Maria José

Dedico este livro às minhas filhas Paula, Ximena e Chloé e à memória


de minha mãe, Inah de Carvalho dos Anjos.
Virgílio
Página intencionalmente deixada em branco
Agradecimentos
Eu, prof. Roney, gostaria primeiramente de agradecer a Deus a oportunidade de
escrever este livro, cuja organização, redação e correções contaram também com a
experiência de alguns amigos, que gentilmente aceitaram o convite para compartilhar
com os leitores alguns princípios básicos, conceitos e exemplos de utilização do C++ ,
uma ferramenta computacional de grande aplicabilidade prática em muitas situações
cotidianas de nossa profissão.
Agradeço também à Universidade Federal de Lavras (UFLA, MG) e ao Departa-
mento de Ciência dos Alimentos (DCA/UFLA) que grandemente me encorajaram e
incentivaram na elaboração deste trabalho.
Agradeço imensamente aos co-autores deste livro, prof. Dr. Moysés Naves de
Moraes (UFV, MG), Ana Carolina Salgado de Oliveira, doutoranda no Programa
de Pós-Graduação em Ciência dos Alimentos do DCA/UFLA, prof. Dr. Virgílio de
Carvalho dos Anjos (Depto. de Física, UFJF) e profa. Dra. Maria José Valenzuela
Bell (Depto. de Física, UFJF) pela redação, leitura cuidadosa, sugestões e correções
em todo o texto. Sem a ajuda de vocês a tarefa de escrever este livro seria apenas
uma ideia vaga, rascunhada em uma folha de papel.
Ao amigo, escritor e professor Dr. Leandro da Conceição Luiz (Depto. de Física,
UFJF), que nos incentivou a escrever este livro. Obrigado Leandro, suas dicas são
sempre muito valiosas!
Aos estudantes do curso de Engenharia de Alimentos da UFLA, que gentilmente
fizeram correções, sugestões e melhorias nesta primeira edição do texto, muito obri-
gado a todos vocês. Por favor continuem com suas contribuições.
Expresso meus agradecimentos às agências de fomento que incentivam, promo-
vem e financiam os trabalhos de pesquisa científica nas instituições públicas de ensino
superior do país, em especial ao CNPq, CAPES, FAPEMIG, FAPESP e FINEP. Sem
o apoio dessas e outras instituições a formação de recursos humanos de alto nível, as
publicações técnicas, o apoio financeiro para projetos, a compra e a manutenção de
equipamentos, a aquisição de insumos e reagentes químicos, e a difusão de conheci-
mentos científicos para a sociedade estariam fortemente comprometidos, ou sequer
poderiam ser realizados. Essas instituições merecem todo o nosso respeito, gratidão
e reconhecimento.
Meus agradecimentos e reconhecimento se estendem também aos professores
orientadores de iniciação científica, trabalho de conclusão de curso, mestrado, dou-
torado, que em muito contribuíram para minha formação pessoal e profissional, Prof.
Dr. Luis Antônio Minim (DTA/UFV) e Profa. Dra. Valéria Paula Rodrigues Minim
(DTA/UFV).
Aos meus amigos, o médico dermatologista Dr. Afonso Celso Lacerda de Souza, e
o engenheiro agrônomo Dr. Aurélio Augusto de Souza Filho (in memorian), expresso
aqui os meus agradecimentos por todas as conversas, ensinamentos e incentivos. E
aos demais amigos, técnicos, servidores e toda a equipe da Editora da UFLA o meu
muito obrigado.
Página intencionalmente deixada em branco
Those types are not ”abstract”
they are as real as int and float.
– Doug McIlroy –
Apresentação
Em quase todos os campos das ciências exatas, forenses e experimentais há
a constante necessidade de coletar, organizar e processar dados numéricos. Em
geral esses dados se referem a informações obtidas a partir de ensaios e análises
em campo, processos de fabricação, dados de sensores, saídas de instrumentos de
medição, equipamentos, ou podem ser provenientes de simulações computacionais,
entre muitas outras possibilidades.
O processamento e operacionalização de dados alfanuméricos também é impor-
tante na elaboração de relatórios técnicos gerenciais e na realização de atividades
administrativas como, por exemplo, aquelas ligadas ao cadastro de funcionários,
movimentações de entradas e saídas de estoques de materiais, bancos de dados de
serviços, contabilidade, rastreamento de produtos acabados e informações sobre ven-
das, clientes e fornecedores. Neste contexto os profissionais que trabalham nessas
áreas técnicas têm a missão de selecionar ferramentas que os auxiliem na realização
dessas atividades e, obviamente, há muitas possibilidades para isso. Um exemplo é a
clássica planilha eletrônica, amplamente utilizada e conhecida desde o ano de 1979.
As planilhas auxiliam na realização de cálculos, construção de tabelas, manutenção
de listas, ordenação de palavras, textos e diversas outras atividades. Porém, apesar
de extremamente importantes e úteis, as planilhas eletrônicas possuem limitações
técnicas e de utilização quando comparadas à maioria das linguagens formais de
programação.
O gerenciamento e a manutenção de grandes quantidades de dados, por exemplo,
no setor de expedição de produtos acabados de uma indústria de alimentos, é um
desses problemas. Além das restrições técnicas relatadas aqui, como a dificuldade
para o tratamento de grandes volumes de dados, há também a carência de materiais
didáticos introdutórios, com exemplos e aplicações práticas de alguma linguagem de
programação, voltadas principalmente para os estudantes dos primeiros períodos da
graduação, e que irão futuramente trabalhar e atuar nessas áreas técnicas.
Este livro foi escrito com a intenção de suprir, pelo menos em parte, a carência
de um texto introdutório informal, simples, objetivo e direto, voltado sobretudo para
os graduandos de Engenharia de Alimentos da Universidade Federal de Lavras. No
escopo do texto são fornecidos conceitos básicos de C++ , uma linguagem de pro-
gramação compilada, fortemente tipada, de alto nível, uso geral, flexível, portável e
caracterizada principalmente pelo seu elevado desempenho e velocidade de execução.
Naturalmente o conteúdo deste livro é demasiadamente básico para ser utilizado
pelo leitor que busca conhecimentos mais avançados. Este poderá, contudo, recor-
rer à seção intitulada Bibliografia, localizada mais ao final do livro, onde irá obter
informações sobre outras referências, com maior nível de profundidade.
O livro está subdividido em duas partes. A primeira parte trata da apresentação
de ’fundamentos teóricos e práticos de programação’ em C++ . Na segunda parte é
proposta a construção de três programas com a finalidade de oferecer ao leitor uma
aplicação prática dos conhecimentos adquiridos ao longo do livro. Todo o conteúdo
apresentado aqui é ministrado na disciplina GCA270, Programação Aplicada à Enge-
nharia de Alimentos, oferecida aos estudantes durante os períodos letivos regulares
do calendário escolar da UFLA.
O leitor que quiser contribuir com sugestões, dicas, novos exemplos, correções,
aplicações e informações complementares acerca do conteúdo abordado neste livro
sinta-se à vontade em me contactar. Todas as contribuições e melhorias certamente
serão muito bem-vindas. Meu e-mail institucional é roney.rocha@ufla.br e todas as
sugestões serão prontamente registradas e cuidadosamente avaliadas com o objetivo
de serem implementadas nas futuras edições do livro. Espero que os assuntos abor-
dados aqui, embora bastante simples em sua forma e conteúdo, possam servir como
base para estudos mais aprofundados, auxiliar na formação de nossos estudantes e
despertar o interesse do leitor pelo C++ e suas aplicações em diferentes áreas da
engenharia.

Prof. Roney Alves


Fevereiro, 2022.
Conteúdo

I FUNDAMENTOS TEÓRICOS E PRÁTICOS DE PROGRA-


MAÇÃO 1
1 Histórico, características e aplicações do C++ nas Engenharias 1
1.1 Um breve histórico do C++ . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Principais características do C++ como linguagem de programação . 2
1.3 Compiladores C++ e interfaces gráficas do usuário . . . . . . . . . 3
1.4 Algumas aplicações do C++ em Engenharia . . . . . . . . . . . . . 4
1.5 Como estudar C++ e aplicá-lo para ajudar a resolver problemas de
engenharia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2 Instalação, interface gráfica e uso do Code::Blocks 6


2.1 Download da versão atual do Code::Blocks . . . . . . . . . . . . . 7
2.2 Instalando o Code::Blocks no Microsoft Windows . . . . . . . . . . 7
2.3 Instalando o Code::Blocks no Linux Mint e no Ubuntu . . . . . . . 7
2.3.1 Configurações pós-instalação do Code::Blocks . . . . . . . 8
2.4 O primeiro programa em C++ . . . . . . . . . . . . . . . . . . . . 8
2.4.1 Escrevendo e salvando o programa em um arquivo .cpp . . . 8
2.4.2 Compilando e executando o primeiro programa . . . . . . . 11
2.4.3 Avaliando erros de digitação e erros de sintaxe no código . . 13
2.5 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 14

3 Introdução à programação em C++ 17


3.1 Estruturas básicas de um programa C++ . . . . . . . . . . . . . . . 18
3.1.1 Bibliotecas padrões e a função int main() . . . . . . . . . . 18
3.1.2 O uso de chaves e o marcador de final de linha em C++ . . 19
3.1.3 Inserção de comentários e espaços em branco no código . . 20
3.1.3.1 Exemplo de comentário inline . . . . . . . . . . . 21
3.1.3.2 Exemplo de comentários multiline . . . . . . . . . 21
3.1.4 Instrução de retorno para o sistema operacional . . . . . . . 21
3.2 Declaração de variáveis de memória . . . . . . . . . . . . . . . . . 22
3.3 Tipos de valores que podem ser atribuídos às variáveis . . . . . . . 24
3.4 Escopo de variáveis: as declarações local e global . . . . . . . . . . 25
3.5 Entradas e saídas de dados padrões do programa . . . . . . . . . . 26
3.5.1 Entrada e saída de dados: uso da biblioteca stdio.h . . . . . 26
3.5.1.1 As funções printf() e scanf() da linguagem C . . . 27
3.5.1.2 Principais caracteres de formatação utilizados pe-
las funções printf() e scanf() . . . . . . . . . . . 32
3.5.2 Entrada e saída de dados: uso da biblioteca iostream . . . . 33
3.5.2.1 Os objetos cin e cout do C++ . . . . . . . . . . . 33
3.6 Inserção de caracteres da língua portuguesa nos programas C++ . . 38
3.7 Depuração nos códigos de programas C++ . . . . . . . . . . . . . . 39
3.8 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 46

4 Constantes e variáveis de memória 50


4.1 Os tipos de dados mais comumente utilizados em C++ . . . . . . . 51
4.1.1 Variáveis booleanas e variáveis inteiras . . . . . . . . . . . 51
4.1.2 Os tipos float e double . . . . . . . . . . . . . . . . . . . . 54
4.1.3 Variáveis do tipo string nos padrões C e C++ . . . . . . . . 56
4.1.3.1 Variáveis string no padrão C . . . . . . . . . . . . 56
4.1.3.1.1 Saídas formatadas com o sprintf(): . . . 61
4.1.3.2 Variáveis string no padrão C++ . . . . . . . . . . 62
4.1.4 Enumerações . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.1.5 Variáveis especiais para armazenamento de data e hora . . . 71
4.1.6 O comando typedef para tipos de dados personalizados . . 76
4.1.7 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.1.8 Definição de macros por meio da diretiva #define . . . . . 81
4.2 Os argumentos argc e argv da função int main() . . . . . . . . . . 82
4.3 Comandos de atribuição e comparação de valores . . . . . . . . . . 84
4.3.1 Comandos de atribuição simples e múltipla . . . . . . . . . 84
4.3.2 Operador de comparação de valores . . . . . . . . . . . . . 84
4.4 Operadores matemáticos, regras de precedência, conversão entre ti-
pos e castings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4.4.1 Conversão entre tipos de dados . . . . . . . . . . . . . . . 86
4.5 Operadores lógicos e relacionais . . . . . . . . . . . . . . . . . . . 89
4.6 Operadores numéricos de incremento e de decremento . . . . . . . 90
4.7 Declaração de variáveis com a instrução register . . . . . . . . . . 91
4.8 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 91

5 Desvios condicionais 96
5.1 Desvios condicionais em C++ . . . . . . . . . . . . . . . . . . . . . 96
5.1.1 Desvio condicional simples . . . . . . . . . . . . . . . . . . 96
5.1.1.1 Uso do operador interrogação (operador ternário) 96
5.1.2 Desvio condicional composto . . . . . . . . . . . . . . . . . 98
5.1.3 if’s aninhados . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.1.4 As instruções switch(), case, break e default . . . . . . . . 103
5.2 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 106

6 Laços de repetição e tratamento de exceções 111


6.1 Laços de repetição em C++ . . . . . . . . . . . . . . . . . . . . . . 111
6.1.1 O laço ’for()’ . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.1.2 O laço ’while{}’ . . . . . . . . . . . . . . . . . . . . . . . 117
6.1.3 O laço ’do while{}’ . . . . . . . . . . . . . . . . . . . . . . 118
6.1.4 Laços aninhados e os comandos break e continue . . . . . . 119
6.1.5 O temido salto incondicional goto . . . . . . . . . . . . . . 122
6.2 O tratamento de exceções com try, throw e catch . . . . . . . . . 123
6.3 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 126

7 Biblioteca padrão de funções para cálculos matemáticos 134


7.1 A biblioteca cmath . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.1.1 Funções trigonométricas . . . . . . . . . . . . . . . . . . . 135
7.1.2 Funções hiperbólicas . . . . . . . . . . . . . . . . . . . . . 136
7.1.3 Funções exponenciais e logarítmicas . . . . . . . . . . . . . 136
7.1.4 Função Erro e função Gamma . . . . . . . . . . . . . . . . 138
7.1.5 Funções de truncamento e arredondamento . . . . . . . . . 139
7.1.6 Operações com números complexos . . . . . . . . . . . . . 141
7.2 Bibliotecas para cálculos numéricos avançados . . . . . . . . . . . . 143
7.3 Macros pré-definidas na biblioteca <math.h> . . . . . . . . . . . . 144
7.4 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 145

8 Procedimentos e funções em C++ 149


8.1 A segmentação do código em procedimentos e funções . . . . . . . 149
8.1.1 Procedimentos em C++ . . . . . . . . . . . . . . . . . . . . 152
8.1.1.1 Passagem de parâmetros para procedimentos e fun-
ções em C++ . . . . . . . . . . . . . . . . . . . . 152
8.1.1.2 Protótipos de procedimentos e de funções . . . . 153
8.1.2 Particularidades sobre procedimentos e funções em C++ . . 154
8.1.2.1 Funções inline . . . . . . . . . . . . . . . . . . . 156
8.1.2.2 Sobrecarga de procedimentos e funções . . . . . . 156
8.1.2.3 Domínio de funções em cálculos matemáticos . . 158
8.1.2.4 Parâmetros padrões de procedimentos e funções . 160
8.1.2.5 Recursividade . . . . . . . . . . . . . . . . . . . 162
8.1.2.6 Funções para limpar e posicionar o cursor na tela 163
8.2 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 165

9 Vetores e matrizes 172


9.1 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
9.1.1 Declaração e utilização de vetores . . . . . . . . . . . . . . 173
9.1.2 A classe vector . . . . . . . . . . . . . . . . . . . . . . . . 178
9.1.3 Pilhas de memória . . . . . . . . . . . . . . . . . . . . . . 179
9.2 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
9.2.1 Declaração de matrizes e operações sobre seus elementos . 184
9.2.2 Matrizes de strings de caracteres . . . . . . . . . . . . . . 186
9.2.3 Operações numéricas e algébricas com matrizes . . . . . . . 186
9.2.3.1 Soma e subtração de matrizes . . . . . . . . . . 186
9.2.3.2 Multiplicação de matrizes . . . . . . . . . . . . . 188
9.2.3.3 Transposição de uma matriz . . . . . . . . . . . . 190
9.2.3.4 Outras operações algébricas com matrizes . . . . 192
9.3 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 193

10 Ponteiros e structs 199


10.1 Ponteiros em C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
10.1.1 Declaração e uso de ponteiros . . . . . . . . . . . . . . . . 200
10.2 Ponteiros em procedimentos e funções . . . . . . . . . . . . . . . . 202
10.2.1 Passagem de parâmetros por valor . . . . . . . . . . . . . . 202
10.2.2 Passagem de parâmetros por ponteiros . . . . . . . . . . . 203
10.3 Ponteiro para vetores e matrizes . . . . . . . . . . . . . . . . . . . 204
10.4 Ponteiros para outros ponteiros . . . . . . . . . . . . . . . . . . . . 209
10.5 Vetores de ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . 210
10.6 Passagem de vetores e matrizes para procedimentos e funções por
meio de ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
10.7 Alocação dinâmica de memória com as funções malloc(), realloc() e
free() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
10.7.1 A função malloc() . . . . . . . . . . . . . . . . . . . . . . 215
10.8 Alocação dinâmica de memória com os operadores new e delete . . 220
10.8.1 O operador new . . . . . . . . . . . . . . . . . . . . . . . 220
10.8.2 O operador delete . . . . . . . . . . . . . . . . . . . . . . 221
10.8.3 Declaração dinâmica de vetores com o operador new . . . . 223
10.9 Estruturas de dados com o comando struct{} . . . . . . . . . . . . 224
10.10Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 233

11 Geração de números aleatórios 239


11.1 Os números aleatórios e suas aplicações em simulações e cálculos de
engenharia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
11.1.1 As funções rand() e srand() da biblioteca cstdlib . . . . . . 240
11.2 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 245

12 Arquivos de dados em C++ 247


12.1 Conceitos básicos sobre manipulação de arquivos de dados em C++ 248
12.2 Modos de abertura de arquivos de dados . . . . . . . . . . . . . . . 249
12.3 Análise do status de abertura de um arquivo de dados . . . . . . . 251
12.3.1 Fechando o arquivo de dados com close() . . . . . . . . . . 251
12.4 Leitura e escrita em arquivos de dados no modo texto . . . . . . . 252
12.5 Leitura de caracteres em um arquivo de dados com a função get() . 255
12.6 Leitura e escrita de dados binários em arquivos de acesso aleatório . 258
12.7 Sistemas de Gestão de Bases de Dados, SGBD . . . . . . . . . . . 271
12.8 Arquivos para plotagem de funções matemáticas . . . . . . . . . . 272
12.9 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 273

13 Arquivos de cabeçalho: segmentação do código em arquivos .h e .cpp 280


13.1 Subdivisão do código em arquivos .h e .cpp . . . . . . . . . . . . . 280
13.1.1 Alguns comentários sobre arquivos de cabeçalho . . . . . . 285
13.2 Subdivisão de arquivos de cabeçalho com namespaces . . . . . . . 286
13.2.1 Arquivo de cabeçalho MinhasFuncoes.h . . . . . . . . . . 287
13.2.2 Arquivo de implementações MinhasFuncoes.cpp . . . . . . 287
13.3 Atividades para fixação da aprendizagem . . . . . . . . . . . . . . . 289

II PROGRAMAÇÃO APLICADA 291


14 Módulo 1: Construção de um programa para cálculo de perda de carga
em válvulas e acessórios de tubulação 292
14.1 Referencial teórico da atividade prática . . . . . . . . . . . . . . . . 292
14.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
14.3 Detalhamento e recomendações para a construção do programa . . 295
14.3.1 Passo 1: Cálculo do Número de Reynolds P . . . . . . . . . . 295
14.3.2 Passo 2: Cálculo da perda de carga total, F . . . . . . . 296

15 Módulo 2: Construção de um programa para cálculo da perda de carga


em tubos retos 297
15.1 Referencial teórico da atividade prática . . . . . . . . . . . . . . . . 297
15.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
15.3 Detalhamento e recomendações para a construção do programa . . 298
15.3.1 Passo 1: Cálculo do número de Reynolds . . . . . . . . . . 298
15.3.2 Passo 2: Cálculo da rugosidade relativa . . . . . . . . . . . 298
15.3.3 Passo 3: Cálculo do valor de f , fator de fricção de Fanning 299
15.3.3.1 Como utilizar a Equação 15.7 . . . . . . . . . . . 300

16 Módulo 3: Construção de um programa para dimensionamento de uma


bomba hidráulica 303
16.1 Referencial teórico da atividade prática . . . . . . . . . . . . . . . . 303
16.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
16.3 Detalhamento e recomendações para a construção do programa . . 306
III ANEXOS 309
17 Anexos 310
17.1 Principais palavras reservadas da linguagem C++ . . . . . . . . . . 311
17.2 Tabelas de caracteres ASCII . . . . . . . . . . . . . . . . . . . . . 312
17.3 Fatores de conversão de unidades de medida . . . . . . . . . . . . 315
17.3.1 Conversão de unidades de calor, energia e trabalho . . . . . 315
17.4 Exemplos de formatação com o uso do printf() da linguagem C . . 316
17.4.1 Formatação simples, com um único argumento . . . . . . . 316
17.4.2 Formatação simples, com argumentos de tipos variáveis . . 316
17.4.3 Impressão de aspas duplas . . . . . . . . . . . . . . . . . . 317
17.4.4 Impressão de aspas simples . . . . . . . . . . . . . . . . . . 317
17.4.5 Impressão de uma barra simples . . . . . . . . . . . . . . . 317
17.4.6 Impressão do símbolo de porcentagem . . . . . . . . . . . . 317
17.4.7 Salto para o início da próxima linha com ’\n’ . . . . . . . . 318
17.4.8 Salto de linha com o caractere ’\f’ . . . . . . . . . . . . . 318
17.4.9 Retorno para o início da linha com o caractere ’\r’ . . . . . 318
17.4.10 Tabulação horizontal com o caractere ’\t’ . . . . . . . . . . 318
17.4.11 Tabulação vertical com o caractere ’\v’ . . . . . . . . . . . 318
17.4.12 Sinal sonoro audível (apenas no MS Windows) . . . . . . . 318
17.4.13 Backspace com o caractere ’\b’ . . . . . . . . . . . . . . . 318
17.4.14 Mudança de base: octal e hexadecimal . . . . . . . . . . . 318
17.4.15 Impressão de número de ponto flutuante em notação cientí-
fica, expresso na base 10 . . . . . . . . . . . . . . . . . . . 319
17.4.16 Especificação da largura mínima de impressão de números
inteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
17.4.17 Especificação da largura mínima de impressão de um número
inteiro com passagem de parâmetro referente à quantidade
total de caracteres . . . . . . . . . . . . . . . . . . . . . . 319
17.4.18 Especificação da largura mínima de impressão de uma string
com passagem de parâmetro referente à quantidade total de
caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
17.4.19 Justificando o número à esquerda antes de imprimir . . . . 320
17.4.20 Preenchendo espaços em branco com zeros . . . . . . . . . 320
17.4.21 Inserção do sinal de ’+’ antes de números . . . . . . . . . . 320
17.4.22 Impressão de strings . . . . . . . . . . . . . . . . . . . . . 321
17.4.23 Impressão de números de ponto flutuante . . . . . . . . . . 321

Bibliografia 327
Lista de Figuras

2.1 Janela New From Template do Code::Blocks. (Fonte: autores) . . 9


2.2 Janela Console application do Code::Blocks. (Fonte: autores) . . 9
2.3 Janela Console application do Code::Blocks. (Fonte: autores) . . 10
2.4 Programa-modelo criado automaticamente pelo Code::Blocks. (Fon-
te: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Botão da barra de ferramentas do Code::Blocks, utilizado para au-
tomaticamente compilar e executar um programa escrito em C++ .
(Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Janela de terminal do Microsoft Windows executando o programa
recém compilado no pelo GNU GCC. (Fonte: autores) . . . . . . . 12
2.7 Informações sobre a interrupção do programa e mensagem de erro
exibida na barra de mensagens, localizada no rodapé da janela prin-
cipal do Code::Blocks. (Fonte: autores) . . . . . . . . . . . . . . . 14

3.1 Tela do terminal do Windows com a saída dos comandos printf()


enviados em sequência. (Fonte: autores) . . . . . . . . . . . . . . 27
3.2 Tela do terminal do Windows com a saída dos comandos printf()
enviados com caractere de quebra automática de linha. (Fonte: au-
tores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Exemplo do uso de um caractere de formatação para inserir valor de
ponto flutuante na string a ser enviada para a tela do computador
pela função printf(). (Fonte: autores) . . . . . . . . . . . . . . . . 28
3.4 Saídas do código com exemplos de formatação utilizando a função
printf(). (Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . 30
3.5 Saídas dos exemplos de usos da função scanf(). (Fonte: autores) . 32
3.6 Exemplo de uso dos objetos cin e cout para leitura das notas das
provas de um estudante, cálculo da média e exibição de seu valor no
terminal do Linux. (Fonte: autores) . . . . . . . . . . . . . . . . . 37
3.7 Menu popup para inserção de breakpoints nas linhas de um programa
por meio da IDE do Code::Blocks. (Fonte: autores) . . . . . . . . . 41
3.8 Identificação de linhas do código que servirão como pontos de parada
(breakpoints) durante a execução do programa. (Fonte: autores) . 42
3.9 Mensagem de questionamento ao programador sobre salvar, ou não,
as alterações feitas na IDE do Code::Blocks. (Fonte: autores) . . . 42
3.10 Disposição lado a lado das janelas do terminal do Windows e do
Code::Blocks durante os procedimentos de debug (depuração) do
código. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . 43
3.11 Botão de comandos ”Debugging windows” utilizado para abrir a janela
”Watches” do Code::Blocks. (Fonte: autores) . . . . . . . . . . . . 44
3.12 Exemplo de execução de um programa passo-a-passo por meio de
debugging e detalhes da janela ”Watches” do Code::Blocks. (Fonte:
autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.13 Inspeção de variáveis a partir da janela ”Watches” do Code::Blocks e
a entrada dos dados digitados pelo programador. (Fonte: autores) . 45
3.14 Barra flutuante de ferramentas ”Debugger Toolbar” e o botão Stop
degugger, utilizado para interromper o processo de debugging. (Fonte:
autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

4.1 Vetor de caracteres de seis posições. O caractere nulo vem sempre


na última posição. (Fonte: autores) . . . . . . . . . . . . . . . . . 57
4.2 Comparação entre os elementos da terceira posição de dois vetores
de caracteres. (Fonte: autores) . . . . . . . . . . . . . . . . . . . 59

6.1 Representação gráfica da integração numérica da função y = f (x),


no intervalo [a; b]. (Fonte: autores) . . . . . . . . . . . . . . . . . 129
6.2 Representação gráfica da segmentação de um frasco de polietileno
para acondicionamento de molho de alho. (Fonte: autores) . . . . 130

8.1 Menu de contexto do Code::Blocks para funções sobrecarregadas.


(Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
8.2 Estudo do sinal da função y1 (x). (Fonte: autores) . . . . . . . . . 159
8.3 Estudo do sinal da função y2 (x). (Fonte: autores) . . . . . . . . . 159
8.4 Estudo do sinal da inequação descrita pela Equação 8.2. (Fonte:
autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
8.5 Sistema de coordenadas do terminal do Linux e do console do MS
Windows. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . 164

9.1 Representação gráfica de um vetor na memória RAM do computador.


(Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
9.2 Diagrama esquemático do funcionamento básico de uma pilha de
memória. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . 180
9.3 Configuração típica da disposição dos elementos em uma matriz. À
esquerda, uma matriz bidimensional. À direita, uma matriz tridi-
mensional. As siglas apresentadas na figura são: ’Lin’ (linha), ’Col’
(coluna) e ’Prof’ (profundidade). (Fonte: autores) . . . . . . . . . 184
9.4 Matriz bidimensional de inteiros, com 7 colunas e 4 linhas. (Fonte:
autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

10.1 Sequenciamento contíguo dos elementos de uma matriz na memória


do computador. (Fonte: autores) . . . . . . . . . . . . . . . . . . 208
10.2 Encadeamento ponteiro para ponteiro. (Fonte: autores) . . . . . . 209
10.3 Diagrama esquemático do modo como uma matriz bidimensional do
tipo ’vetor de vetores’ está organizada na memória do computador.
(Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
10.4 Acesso aos membros da struct ’FichaDeDados’ ao teclar um ’ponto’
no editor de códigos do Code::Blocks. (Fonte: autores) . . . . . . 226
10.5 Representação gráfica da estrutura utilizada para armazenamento de
parte dos dados de rastreabilidade do café. (Fonte: autores) . . . . 238

11.1 Caminho destacado evidenciando parte da rota ótima entre diver-


sas cidades a serem percorridas na solução do Problema do Caixeiro
Viajante. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . 240
11.2 Teclado de quatro dígitos utilizado para digitar a senha de desblo-
queio de um antigo equipamento industrial. (Fonte: autores) . . . . 246

12.1 Exemplo de saída de dados para um arquivo físico externo. (Fonte:


autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
12.2 Plotagem dos dados de y (x) = sen(x) utilizando o pacote matemá-
tico Gnuplot. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . 273
12.3 Representação gráfica da estrutura utilizada para armazenamento de
dados de contato com empresas concedentes de estágio aos estu-
dantes de Engenharia de Alimentos. (Fonte: autores) . . . . . . . . 279

13.1 Exemplo de arquivo externo de interface (protótipo) de funções.


(Fonte: autores) . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
13.2 Exemplo da estrutura típica de um arquivo de implementação de
funções externas. (Fonte: autores) . . . . . . . . . . . . . . . . . . 283
13.3 Exemplo da utilização de bibliotecas personalizadas por meio de ar-
quivos de cabeçalho. (Fonte: autores) . . . . . . . . . . . . . . . . 284
13.4 Exemplo de inserção de macros e constantes dentro de um arquivo
de cabeçalho. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . 284
13.5 Exemplo de utilização de macros e constantes a partir de um arquivo
de cabeçalho. (Fonte: autores) . . . . . . . . . . . . . . . . . . . . 285
13.6 Procedimento para inclusão dos arquivos .h e .cpp em um projeto
do Code::Blocks. (Fonte: autores) . . . . . . . . . . . . . . . . . . 286

16.1 Diagrama esquemático de um sistema de transporte de fluidos por


meio de uma bomba hidráulica. (Fonte: autores) . . . . . . . . . . 304
Lista de Tabelas

1.1 Nomes e fornecedores de alguns compiladores C++ disponíveis para


Microsoft Windows e para Linux. . . . . . . . . . . . . . . . . . . . 4

3.1 Tipos de dados mais comuns permitidos em C++ , bytes ocupados na


memória do computador e seus intervalos de valores numéricos. . . 24
3.2 Caracteres especificadores de formato C/C++ utilizados pelas fun-
ções printf() e scanf(). . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3 Tabela de códigos conhecidos como ’sequências de escapes’, utiliza-
das pelos objetos cin e cout do C/C++ . . . . . . . . . . . . . . . . 38

4.1 Comparação da precisão dos tipos float e double em C++ . . . . . . 56


4.2 Operadores de comparação de strings em C++ . . . . . . . . . . . . 65
4.3 Operadores matemáticos básicos do C/C++ . . . . . . . . . . . . . 85
4.4 Operadores lógicos e relacionais do C/C++ . . . . . . . . . . . . . . 89

6.1 Dados coletados a partir de medições feitas em um frasco de polieti-


leno, utilizado para acondicionamento de molho de alho. As medidas
estão em milímetros. . . . . . . . . . . . . . . . . . . . . . . . . . 131

7.1 Macros pré-definidas na biblioteca math.h. . . . . . . . . . . . . . . 144

8.1 Modelos empíricos para cálculo de propriedades termofísicas de ali-


mentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

10.1 Esboço do mapa da memória com a identificação, endereço e con-


teúdo das variáveis. . . . . . . . . . . . . . . . . . . . . . . . . . . 200

12.1 Exemplo da estrutura de uma tabela com registros e campos de


dados de estudantes. . . . . . . . . . . . . . . . . . . . . . . . . . 259
12.2 Exemplo de indicação de estatus de exclusão ou atividade de um
registro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

14.1 Fator adimensional de perda de carga (kf ) no regime de escoamento


turbulento para válvulas e acessórios de tubulação. . . . . . . . . . 294
14.2 Fator adimensional de perda de carga (kf ) no regime de escoamento
laminar para válvulas e acessórios de tubulação. . . . . . . . . . . . 294
17.1 Principais palavras reservadas da linguagem C++ . . . . . . . . . . 311
17.2 Tabela de caracteres ASCII. Valores de 0 a 63 . . . . . . . . . . . . 312
17.3 Tabela de caracteres ASCII. Valores de 64 a 127 . . . . . . . . . . 313
17.4 Tabela de caracteres ASCII extendidos. Valores de 128 a 191 . . . 314
17.5 Tabela de caracteres ASCII extendidos. Valores de 192 a 255 . . . 315
Introdução
Este é um livro-texto básico e introdutório de fundamentos de programação em
C , escrito para atender os requisitos da disciplina GCA270, Programação Apli-
++

cada à Engenharia de Alimentos, ofertada aos graduandos do curso de Engenharia


de Alimentos da UFLA. Do ponto de vista técnico, o livro traz algumas aplicações
práticas, contextualizadas e voltadas principalmente para os estudantes de Enge-
nharia de Alimentos. Além disso o texto tende a ser mais objetivo e direto do que
os tradicionais livros de programação, enfatizando apenas os conceitos considerados
mais importantes para a formação dos estudantes.
Na primeira parte do livro são abordados conceitos teóricos que vão desde o
histórico do C++ , download e instalação do compilador e de um ambiente gráfico
de programação, principais comandos de entrada e saída, variáveis de diferentes
tipos, conversões de tipos de dados, uso da biblioteca matemática padrão, laços
de repetição, desvios condicionais, funções e procedimentos, ponteiros, vetores e
matrizes, geração de números aleatórios, arquivos de dados e arquivos de cabeçalho,
entre outros assuntos. Ao final de cada capítulo estão listadas algumas atividades,
na forma de exercícios, cuja intenção é auxiliar o leitor na fixação da aprendizagem
dos assuntos apresentados e discutidos. Na segunda parte do livro é proposta a
construção de três softwares simples, sob o título ’Programação Aplicada’. Quando
em sala de aula, essas atividades poderão ser realizadas em grupos de dois ou três
estudantes, a critério do professor, e tem como objetivo aprimorar a prática de
programação, bem aos moldes da expressão popular ’colocar a mão na massa!’.
Apesar de o livro ter sido elaborado com a intenção de atender aos estudantes
de Engenharia de Alimentos, os assuntos aqui abordados são comuns em diferentes
grades curriculares e podem ser úteis para estudantes de outras áreas de forma-
ção como, por exemplo, Física, Química, Engenharia Química, Engenharia Agrícola,
Engenharia Ambiental e Engenharia Florestal, entre outras.
Parte I

FUNDAMENTOS TEÓRICOS E
PRÁTICOS DE PROGRAMAÇÃO
Capítulo 1

Histórico, características e aplicações


do C++ nas Engenharias

Conteúdo do capítulo
1.1 Um breve histórico do C++ . . . . . . . . . . . . . . . . . . 1
1.2 Principais características do C++ como linguagem de
programação . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Compiladores C++ e interfaces gráficas do usuário . . . . 3
1.4 Algumas aplicações do C++ em Engenharia . . . . . . . . 4
1.5 Como estudar C++
e aplicá-lo para ajudar a resolver
problemas de engenharia . . . . . . . . . . . . . . . . . . . 5

1.1 Um breve histórico do C++


O C++ teve sua origem no final da década de 70 e início da década de 80, com
os trabalhos de Bjarne Stroustrup nos laboratórios da AT&T Bell, em Murray Hill,
Nova Jérsey (EUA). Segundo STROUSTROUP (1999), o C++ foi projetado e im-
plementado por ele de modo a combinar a organização e os pontos fortes do Simula,
uma antiga linguagem de programação para análise de eventos discretos, muito uti-
lizada naquela época, com as facilidades de programação de sistemas oferecidas pela
linguagem C, precursora do C++ .
A versão inicial do C++ foi chamada de ”C with Classes”. Outros recursos como
orientação a objetos foram adicionados mais tarde, mas a linguagem evoluiu bastante
nesses últimos anos e ainda continua a evoluir. Atualmente é uma das linguagens
mais utilizadas, com bilhões de linhas de códigos escritas em C++ para diversos tipos
de aplicações, plataformas e sistemas operacionais e milhões de programadores em
todo o mundo utilizando essa linguagem (STROUSTROUP, 2011).

1
++
Princípios de programação em C

1.2 Principais características do C++ como linguagem


de programação
O C++ é uma linguagem fortemente tipada, robusta, simples, de fácil compreensão e
aprendizagem. A seguir estão listadas algumas das características que fazem com que
essa linguagem seja a preferida por muitos programadores (BARTON e NACKMAN,
1999; DAMAS, 2007; DAVIS, 2014; KATUPITIYA e BENTLEY, 2006; LIANG, 2014;
MALIK, 2018; STROUSTROUP, 1999, 2013a).

• É uma linguagem de alto nível, bem documentada, de fácil aprendizado, am-


plamente difundida nos meios acadêmicos. É uma das mais utilizadas na cons-
trução de softwares para as áreas acadêmica, industrial e científica.

• É versátil, adequada para a construção de códigos reutilizáveis, o que reduz o


tempo e o custo de desenvolvimento de softwares.

• Possui todos os recursos para orientação a objetos, permitindo facilmente mo-


delar objetos do mundo real.

• Os programas construídos em C++ são compilados, e não interpretados, o que


implica principalmente em ganho de velocidade em sua execução.

• Possui um número de bibliotecas que acrescentam funcionalidades ao código


como, por exemplo, as bibliotecas de funções matemáticas.

• Apesar de ser uma linguagem de alto nível, o C++ também permite a programa-
ção de funções e subrotinas em baixo nível, por meio de códigos Assembly, que
podem ser intercalados e inseridos diretamente aos códigos C++ . Isso permite
ao programador a comunicação e o acesso às funcionalidades dos hardwares e
equipamentos instalados ao computador.

• A portabilidade é uma característica que faz com que os programas C++ possam
ser compilados para serem executados em diferentes sistemas operacionais e
dispositivos, com nenhuma ou pouquíssimas modificações.

• Muitos microcontroladores, controladores industriais e dispositivos eletrônicos


embarcados de robótica, aviões e automóveis são programados em C/C++ .

• O C++ trabalha com muitos tipos de dados: inteiros, caracteres, texto, byte,
booleano, etc., o que implica em uso adequado e eficaz dos recursos de memória
do computador. Essa característica confere ao C++ a particularidade de ser
uma linguagem fortemente tipada, ou seja, é necessário especificar exatamente
o tipo de variável memória que será utilizado para armazenar um determinado
valor, seja ele inteiro, caractere, booleano, etc.

2
++
Princípios de programação em C

• Há uma farta quantidade de rotinas disponíveis, escritas por programadores


de todo o mundo, que podem ser incluídas diretamente nos códigos ao cons-
truir softwares em C++ . Muitas dessas rotinas são gratuitas: funções para
cálculo numérico, conexão e gerenciamento de bancos de dados, construção
de interfaces gráficas de usuário, funções de acesso a câmeras de vídeo, áu-
dio, reconhecimento facial e da fala, sensores, placas de aquisição de dados,
equipamentos laboratoriais, e muitas outras.

• O termo programação modular é uma característica que faz com que uma
aplicação C++ possa ser construída a partir de vários arquivos de códigos que
serão compilados em separado e a seguir unidos a partir de um procedimento
conhecido como linkedição. A vantagem desse recurso está na economia de
tempo, pelo fato de não ser necessário recompilar todo o código novamente ao
realizar uma pequena mudança em seu conteúdo. Apenas o arquivo contendo
a modificação é que será compilado novamente.

• O C++ é adequado para a construção de grandes projetos. Sistemas opera-


cionais importantes, como o Microsoft Windows e o Linux, bem como jogos
famosos como o Quake, Doom e vários outros foram escritos em C/C++ .

• Enquanto que algumas linguagens de programação, como o C# (C Sharp, da


Microsoft), estão sob o domínio particular de empresas, o C++ não está, e há
um número de compiladores e ambientes gráficos de programação disponíveis
gratuitamente para download e utilização, muitos de altíssima qualidade. Além
disso, o C++ segue a padronização ISO1 .

1.3 Compiladores C++ e interfaces gráficas do usuário


Atualmente há muitos compiladores C++ disponíveis para utilização, sendo que al-
guns são gratuitos e outros não. Entre esses há os que vêm acompanhados de um
completo ambiente integrado de desenvolvimento de programação, a IDE (Integra-
ted Development Environment), enquanto que outros operam por meio de instruções
digitadas diretamente no prompt de comando do Microsoft Windows ou no terminal
do Linux.
A Tabela1.1 a seguir lista alguns desses compiladores. Ao longo deste livro será
utilizado o Code::Blocks, um ambiente integrado de programação que é gratuito,
instalado juntamente com o compilador GNU GCC. Os detalhes sobre esse ambiente
de programação, seu download e instalação serão abordados no Capítulo 2.
1
International Organization for Standardization

3
++
Princípios de programação em C

Tabela 1.1: Nomes e fornecedores de alguns compiladores C++ disponíveis para


Microsoft Windows e para Linux.
Compilador/IDE Gratuito Plataforma Página do fornecedor/fabricante
Code::Blocks Sim Win/Linux www.codeblocks.org
DEV C ++
Sim Win https://www.bloodshed.net/dev/
GCC Sim Win/Linux https://gcc.gnu.org/
C++ Builder Não Win https://www.embarcadero.com
Visual C ++
Não Win https://www.microsoft.com/pt-br/
Fonte: Elaborada pelos autores.

1.4 Algumas aplicações do C++ em Engenharia


O C++ pode ser utilizado em praticamente todas as áreas da Engenharia onde exista
a necessidade da realização de cálculos, desde as tarefas mais simples às mais com-
plexas. A seguir são listadas apenas algumas dessas aplicações (BJÖRNANDER,
2016; DUFFY, 2006; GOODRICH et al., 2009; KATUPITIYA e BENTLEY, 2006;
KERNIGHAN e RITCHIE, 1986; NYHOFF, 2012; SAHNI, 2005; SALLEH et al.,
2007; SCHEINERMAN, 2006; SINGH, 1996; VARZAKAS e TZIA, 2014).

• Fluxo de caixa e cálculos de indicadores econômicos em análises de viabilidade


técnica e econômica (VPL, TIR, TRC, etc).

• Simulação computacional envolvendo geração de números aleatórios como, por


exemplo, aplicações do Método de Monte Carlo.

• Cálculos de otimização computacional envolvendo algoritmos evolutivos: algo-


ritmos genéticos, simulated annealing, núvem de partículas, colônia de formi-
gas, etc.

• Cálculos numéricos em geral: operações com vetores e matrizes, solução nu-


mérica de equações diferenciais ordinárias e parciais, análise de convergência,
estudo de erros, análise por elementos finitos, análise por volumes finitos, etc.

• Construção de softwares especialistas para tomada de decisões com base nos


conhecimentos humanos. Os softwares especialistas possuem ampla aplica-
ção nas indústrias químicas, farmacêuticas, de alimentos e análises de dados
ambientais, entre outras aplicações.

• Implementação e manutenção de bancos de dados, com rápida e eficiente


recuperação de informações a partir de dados armazenados em arquivos físicos.

• Construção de softwares para comunicação com instrumentos de controle em


processos industriais.

4
++
Princípios de programação em C

• Softwares para análises de falhas em reatores e processos industriais, em com-


binação com outras técnicas como, por exemplo, redes neurais artificiais.

• Construção de compiladores e interpretadores de comandos.

• Softwares para análises estatísticas descritivas e inferenciais de dados experi-


mentais.

• Uso de estruturas em árvores, pilhas e filas que facilitam a análise de dados


complexos como, por exemplo, aqueles organizados em estruturas hierárqui-
cas de planos de HACCP (APPCC - Análise de Perigos e Pontos Críticos de
Controle), Boas Práticas de Fabricação (BPF ) e outros.

• Construção de aplicativos para dispositivos móveis de diferentes tipos: ta-


blets, smartphones, smartwatches, relógios, em diferentes plataformas (An-
droid, iOS, etc.).

• Aplicativos de back end para processamento massivo de informação em serviços


WEB, bancários, hospitalares, entre outros.

1.5 Como estudar C++ e aplicá-lo para ajudar a resol-


ver problemas de engenharia
A linguagem C++ é constituída por blocos de instruções. Em termos comparativos,
aprender C++ e aplicá-lo para algo que seja útil é como montar uma colcha de
retalhos. Os retalhos são os blocos, e a colcha é o programa a ser construído.
Na primeira parte deste livro serão abordados alguns desses blocos como, por
exemplo, as variáveis, os desvios condicionais, comandos de entrada e saída, os laços
de repetição, as funções, procedimentos, ponteiros, arquivos de dados e vários outros.
Todos esses elementos serão reunidos e ’costurados’, de acordo com o conhecimento,
experiência e a criatividade do ’artesão’, que é o programador, para construir algo
maior, o programa, que neste caso está sendo comparado à colcha de retalhos.
Neste contexto é recomendado ao leitor a não saltar capítulos, e se certificar de
que o conteúdo de um capítulo foi corretamente compreendido e assimilado antes
de avançar as páginas do livro. Por se tratar de um texto muito básico e bastante
simples, recomenda-se também recorrer aos diversos tutoriais, vídeos, livros, artigos
e outras fontes de consulta, além de reservar algum tempo para praticar, junto ao
computador, o assunto abordado.

5
Capítulo 2

Instalação, interface gráfica e uso do


Code::Blocks

Conteúdo do capítulo
2.1 Download da versão atual do Code::Blocks . . . . . . . . 7
2.2 Instalando o Code::Blocks no Microsoft Windows . . . . 7
2.3 Instalando o Code::Blocks no Linux Mint e no Ubuntu . 7
2.3.1 Configurações pós-instalação do Code::Blocks . . . . . . . 8
2.4 O primeiro programa em C++ . . . . . . . . . . . . . . . . 8
2.4.1 Escrevendo e salvando o programa em um arquivo .cpp . . 8
2.4.2 Compilando e executando o primeiro programa . . . . . . 11
2.4.3 Avaliando erros de digitação e erros de sintaxe no código . 13
2.5 Atividades para fixação da aprendizagem . . . . . . . . . 14

Como em qualquer outra linguagem de programação, atualmente há diferentes


implementações do C++ , diferentes compiladores, funcionalidades, semântica e até
mesmo bibliotecas personalizadas, com peculiaridades que são exclusivas para aquela
implementação.
No decorrer deste livro será adotada a versão 20.03 do Code::Blocks, um ambi-
ente de programação de uso livre para as linguagens C, C++ e Fortran. Além de ser
configurável e de fácil utilização, esse ambiente de programação vem acompanhado
do GNU GCC, um compilador moderno de códigos C++ , e tem a vantagem de fun-
cionar muito bem tanto no Microsoft Windows quanto nas distribuições Linux mais
comuns, permitindo também a adição de plugins que estendem em muito as suas
funcionalidades.

6
++
Princípios de programação em C

2.1 Download da versão atual do Code::Blocks


A versão mais atual do Code::Blocks pode ser obtida a partir de sua página oficial
na Internet: http://www.codeblocks.org/
Além da opção de download, na página do Code::Blocks também é possível ob-
ter o ”User Manual” em formato .pdf, documento contendo informações detalhadas
sobre a sua interface gráfica, configurações do editor de texto, seleção de compila-
dores, instalação de plugins, etc. No topo da mesma página pode-se também obter
informações diversas sobre programação em C++ e saber mais sobre os recursos do
Code::Blocks ao clicar no link da seção ”Forum”.

2.2 Instalando o Code::Blocks no Microsoft Windows


A instalação do Code::Blocks no Microsoft Windows® é relativamente simples e
direta. Inicialmente é necessário obter o arquivo de instalação a partir da seção
”Downloads” na página do Code::Blocks. Para as aplicações apresentadas neste livro,
sua instalação foi feita com o arquivo ”codeblocks-20.03mingw-setup.exe”, sendo
executado em modo ”Administrador”.
Durante a instalação é necessário informar a pasta onde o Code::Blocks deverá ser
instalado. O compilador GNU GCC será instalado e configurado automaticamente.
Um ícone de acesso ao software será criado na área de trabalho do Microsoft Windows
e a instalação se encerra. Após isso o Code::Blocks já está pronto para ser utilizado.

2.3 Instalando o Code::Blocks no Linux Mint e no


Ubuntu
O modo mais fácil de fazer a instalação do Code::Blocks nas distribuições Ubuntu e
Mint do Linux é a partir do terminal. Para isso, primeiramente abra o terminal do
Linux (CTRL + ALT + T) e digite os seguintes comandos:
~$ sudo apt-get update
~$ sudo apt-get upgrade
~$ sudo add-apt-repository ppa:codeblocks-devs/release
~$ sudo apt-get update
~$ sudo apt-get install codeblocks codeblocks-contrib

Para desinstalar o Code::Blocks a partir do terminal do Linux, devem ser digitados


os seguintes comandos:
~$ sudo add-apt-repository –remove ppa:codeblocks-devs/release
~$ sudo apt remove –autoremove codeblocks codeblocks-contrib

7
++
Princípios de programação em C

2.3.1 Configurações pós-instalação do Code::Blocks


O Code::Blocks já vem configurado e pronto para ser utilizado. Embora não sejam
obrigatórias, recomenda-se fazer as seguintes configurações pós-instalação:
Menu Settings → Compiler... → Compiler settings → Compiler Flags:

X Enable all common compiler warnings (overrides many other settings)

X Have g++ follow the C++14 ISO C++ language standard

E na aba Toolchain executables:

X C Compiler : deve ser gcc

X C++ Compiler : deve ser g++

X Linker for dynamic libs: deve ser g++

Independentemente do sistema operacional escolhido o Code::Blocks deverá ope-


rar essencialmente do mesmo modo. Os exemplos de programas apresentados ao
longo deste livro foram feitos preferencialmente no Linux Mint (versão 18.3, Sylvia).
Entretanto, os códigos e as saídas serão basicamente os mesmos quando forem
executados no Microsoft Windows versão 10. A seguir são apresentados os proce-
dimentos básicos para escrever, salvar, compilar, executar e fechar um programa em
C++ utilizando o Code::Blocks.

2.4 O primeiro programa em C++


2.4.1 Escrevendo e salvando o programa em um arquivo .cpp
Ao abrir o Code::Blocks para escrever o primeiro programa deve-se seguir a seguinte
sequência de operações: Menu File → New → Project... Esse menu abrirá uma
janela intitulada ”New From Template” (Figura 2.1). Nessa janela escolha a opção
”Console application” → clique no botão GO que fica no lado direito dessa janela.

8
++
Princípios de programação em C

Figura 2.1: Janela New From Template do Code::Blocks. (Fonte: autores)

Em seguida, uma janela de boas vindas intitulada ”Console application” se abrirá.

Figura 2.2: Janela Console application do Code::Blocks. (Fonte: autores)

Nessa janela apenas clique no botão Next. Na próxima janela selecione a opção
C++ e clique em Next novamente (Figura 2.2). Na próxima janela (Figura 2.3)
informe o caminho e o nome da pasta onde o projeto deverá ser construído. Isso é
feito no campo intitulado Folder to create project in. Nessa mesma janela informe
um nome para o projeto (no campo Project title) e clique em Next.

9
++
Princípios de programação em C

Figura 2.3: Janela Console application do Code::Blocks. (Fonte: autores)

Após isso surgirá uma nova janela, também com o título Console application, na
qual é possível escolher um outro compilador, diferente do GNU GCC. Não modifique
as informações contidas nessa janela, apenas clique em Finish. O Code::Blocks sal-
vará o projeto na pasta informada nos passos anteriores e criará automaticamente um
programa-modelo em C++ , que será apresentado em sua janela principal, conforme
mostrado na Figura 2.4.
Esse programa é bem simples e quando compilado sua função será imprimir na tela
do computador a expressão de boas vindas: ”Hello world!”. Observe na Figura 2.4
que alguns comandos internos do C++ aparecem destacados em cores diferentes. Ao
utilizar o Code::Blocks você perceberá que isso é feito automaticamente à medida em
que os comandos são digitados pelo programador. Além das cores, alguns comandos
e símbolos que compõem o código também podem estar destacados em negrito.

10
++
Princípios de programação em C

Figura 2.4: Programa-modelo criado automaticamente pelo Code::Blocks. (Fonte:


autores)

Em muitas linguagens de programação, um programa equivalente ao ”Hello world!


também é gerado automaticamente, e isso é feito com a finalidade de permitir ao
programador testar se o compilador está devidamente instalado e funcionando corre-
tamente. Um típico ”Hello world!” em C, precursor do C++ , é feito como apresentado
a seguir.
1 # include < stdio .h >
2

3 int main () {
4 printf ( " Hello world ! " ) ;
5 return 0;
6 }

Neste momento não se preocupe em tentar compreender os códigos contidos


nesse programa-modelo. Esses códigos serão explicados em detalhes nos próximos
capítulos. Observe na Figura 2.4, na barra lateral mais à esquerda na janela contendo
os códigos, que todas as linhas de programação foram enumeradas sequencialmente,
o que facilita a localização e identificação de erros de sintaxe, de lógica ou de digi-
tação nos programas.

2.4.2 Compilando e executando o primeiro programa


O código-fonte de um programa em C++ é composto por um conjunto de instruções
digitadas em um processador de textos e salvo com a extensão .cpp. Ao fazer a
compilação esse código é convertido em um outro conjunto de instruções, codificadas
em linguagem de máquina e colocadas em um arquivo com a extensão .exe, algo
que o computador ”compreende” como sendo um programa executável.

11
++
Princípios de programação em C

Antes de gerar o arquivo .exe, é gerado um arquivo intermediário, o arquivo


objeto, com a extensão .o. A sequência de operações na etapa de compilação do
código é: Arquivo.cpp → Arquivo.o → Arquivo.exe.
Observe que o Code::Blocks salva todos esses arquivos na pasta que você indicou
para criar o projeto (Figura 2.3), e cria também um arquivo com a extensão .cbp
que serve para organizar e manter atualizada uma lista com referência à todos os
arquivos que compõem o projeto. Assim, ao abrir um arquivo .cbp a partir do
menu File no Code::Blocks, todos os arquivos pertencentes àquele projeto serão
automaticamente carregados para a área de trabalho (workspace do Code::Blocks)
e estarão prontamente disponíveis para edição a partir da aba Projects (Figura 2.4).
Um botão com o desenho de um triângulo verde e uma pequena engrenagem
amarela na barra de ferramentas do Code::Blocks (Figura 2.5) tem a função dupla
de automaticamente compilar e executar um programa escrito em C++ .

Figura 2.5: Botão da barra de ferramentas do Code::Blocks, utilizado para automa-


ticamente compilar e executar um programa escrito em C++ . (Fonte: autores)

Se não houver erros de digitação ou de sintaxe no código, o programa será


executado em uma janela de terminal, como apresentado na Figura 2.6.

Figura 2.6: Janela de terminal do Microsoft Windows executando o programa recém


compilado no pelo GNU GCC. (Fonte: autores)

12
++
Princípios de programação em C

Na barra de mensagens, localizada na parte inferior da janela principal do Co-


de::Blocks, serão apresentadas informações sobre o processo de compilação. Caso
existam erros no código, o programa não será executado e a ’barra de mensagens’
indicará o tipo de erro e o número da linha na qual o erro ocorreu.
Para encerrar o programa-modelo apresentado na Figura 2.6 e retornar ao editor
de textos do Code::Blocks, basta pressionar a tecla Enter.

2.4.3 Avaliando erros de digitação e erros de sintaxe no código


Para entender um pouco melhor o tipo de informação apresentada na barra de mensa-
gens do Code::Blocks quando ocorrer algum erro de digitação ou de sintaxe, vamos
gerar intencionalmente um erro no programa-modelo. Para isso vamos retirar o
ponto e vírgula ”;” que está no final da linha 8, como mostrado no bloco de códigos
a seguir.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 cout << " Hello world ! " << endl ;
8 return 0
9 }

Ao fazermos isso o compilador irá gerar uma mensagem de erro, sugerindo que
está faltando um ponto e vírgula antes da linha 9. Além disso imediatamente à linha
onde está o erro será inserido um pequeno marcador retangular na cor vermelha,
como mostrado na Figura 2.7.
Além das mensagens dos erros de compilação, exibidos na barra de mensagens, há
também um procedimento mais detalhado e completo para analisar os tipos de erros
ocorridos durante a execução dos programas e inspecionar dinamicamente os valores
das variáveis. Esse procedimento de verificação é conhecido pela expressão ”debugar
o código”, e é especialmente útil para análise de erros de lógica de programação.
O Code::Blocks possui recursos de debugger que serão apresentados e discutidos
em maiores detalhes na seção 3.7 do Capítulo 3 (p.39).

13
++
Princípios de programação em C

Figura 2.7: Informações sobre a interrupção do programa e mensagem de erro exibida


na barra de mensagens, localizada no rodapé da janela principal do Code::Blocks.
(Fonte: autores)

2.5 Atividades para fixação da aprendizagem


1. Download e instalação do Code::Blocks

(a) Releia todo o texto apresentado nos Capítulos 1 e 2.


(b) Faça o download do Code::Blocks em: http://www.codeblocks.org/
(c) Salve o arquivo de instalação em seu computador e o instale em uma pasta
raiz (por exemplo, c:\CodeBlocks\). Essa pasta não deve conter espaços
no seu nome, e a instalação deve ser feita com direitos administrativos do
sistema operacional.

2. Escrevendo, salvando e compilando o primeiro programa

(a) Após a instalação do Code::Blocks crie um programa em C++ que escreva


na tela do computador:
i. O nome da sua universidade e o nome do seu departamento
ii. O nome do seu curso e nome da disciplina
iii. O nome completo dos elementos de seu grupo

14
++
Princípios de programação em C

(b) Salve o programa em uma pasta de trabalho com o nome ’Pratica01’


(c) Compile e execute o programa
(d) Verifique as informações apresentadas no console: qual o tempo de exe-
cução do programa?

3. Avaliando erros de digitação e de sintaxe


Crie um projeto novo. Digite o programa a seguir.
1 # include < iostream >
2 using namespace std
3 int main
4 {
5 cout << " Analise de erros << endl
6 return [] 0

Responda às seguintes questões:

(a) Por que o programa não funcionou?


(b) Quais erros foram encontrados?
(c) Como esses erros podem ser corrigidos?

4. Aplicações do C++ na engenharia

(a) Cite 2 (duas) aplicações do C++ na resolução de problemas comuns em


cada uma das seguintes áreas da engenharia. Em cada aplicação, descreva
o problema corretamente.

i. Engenharia de Alimentos vii. Engenharia Aeronáutica


ii. Engenharia Naval viii. Engenharia de Minas
iii. Engenharia Química
ix. Engenharia Elétrica/Eletrônica
iv. Engenharia Cartográfica
x. Engenharia Florestal
v. Engenharia de Petróleo
vi. Engenharia de Controle e Auto- xi. Engenharia Agrícola
mação xii. Engenharia Têxtil

5. Características da linguagem C ++

(a) Faça um levantamento (pesquisa/estudo) e descubra quais são as dife-


renças básicas entre as linguagens C e C++ .
(b) Há alguma ferramenta disponível na loja de aplicativos de seu dispositivo
móvel (celular, tablet, etc) para programação em C++ ? Se sim, que
aplicativo é esse? É livre? É de fácil instalação? Como escrever e compilar
um programa C++ utilizando esse aplicativo?

15
++
Princípios de programação em C

(c) Em 2007 foi lançada a linguagem ’D’ de programação. Embora tenha


muitos recursos e seja completamente baseada no C++ , essa linguagem
ainda não é muito utilizada, sendo relativamente pouco difundida. Discuta
os motivos pelos quais as linguagens C e C++ ainda prevalecem, e por que
a linguagem ’D’ não obteve a mesma projeção acadêmica e comercial que
suas antecessoras.
(d) A linguagem Assembly opera em baixo nível, ou seja, acessando direta-
mente os registradores internos do processador e endereços de memória,
sendo, por isso considerada uma linguagem que produz arquivos execu-
táveis de altíssima velocidade. Faça uma breve revisão de literatura e
compare o código do programa ’Hello world!’, apresentado no Capítulo 2,
com o mesmo programa escrito em linguagem Assembly.
i. Em qual das duas linguagens o código foi mais fácil de ser compre-
endido?
ii. Com relação ao tamanho do código, qual deles é menor? Em C++
ou em Assembly ?
iii. Faça uma revisão de literatura e verifique o motivo de as linguagens
C e C++ serem preferencialmente utilizadas em relação ao Assembly.

16
Capítulo 3

Introdução à programação em C++

Conteúdo do capítulo
3.1 Estruturas básicas de um programa C++ . . . . . . . . . 18
3.1.1 Bibliotecas padrões e a função int main() . . . . . . . . . 18
3.1.2 O uso de chaves e o marcador de final de linha em C++ . 19
3.1.3 Inserção de comentários e espaços em branco no código . . 20
3.1.3.1 Exemplo de comentário inline . . . . . . . . . . 21
3.1.3.2 Exemplo de comentários multiline . . . . . . . . 21
3.1.4 Instrução de retorno para o sistema operacional . . . . . . 21
3.2 Declaração de variáveis de memória . . . . . . . . . . . . 22
3.3 Tipos de valores que podem ser atribuídos às variáveis . 24
3.4 Escopo de variáveis: as declarações local e global . . . . 25
3.5 Entradas e saídas de dados padrões do programa . . . . 26
3.5.1 Entrada e saída de dados: uso da biblioteca stdio.h . . . . 26
3.5.1.1 As funções printf() e scanf() da linguagem C . . 27
3.5.1.2 Principais caracteres de formatação utilizados pe-
las funções printf() e scanf() . . . . . . . . . . . 32
3.5.2 Entrada e saída de dados: uso da biblioteca iostream . . . 33
3.5.2.1 Os objetos cin e cout do C++ . . . . . . . . . . . 33
3.6 Inserção de caracteres da língua portuguesa nos pro-
gramas C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.7 Depuração nos códigos de programas C++ . . . . . . . . 39
3.8 Atividades para fixação da aprendizagem . . . . . . . . . 46

Neste capítulo serão apresentados os elementos básicos e estrutura de um pro-


grama C++ . Para sua leitura recomenda-se, portanto, que o Code::Blocks já esteja
devidamente instalado, testado e funcionando, e que os procedimentos para criar,

17
++
Princípios de programação em C

salvar e compilar um programa, apresentados no capítulo anterior, já estejam bem


sedimentados e familiarizados na compreensão do leitor.

3.1 Estruturas básicas de um programa C++


3.1.1 Bibliotecas padrões e a função int main()
Um programa C++ é lido e avaliado pelo compilador a partir da sua primeira linha de
código. Para a maioria dos compiladores C++ , o código é subdividido basicamente
em duas seções.
Na primeira seção devem ser inseridas as bibliotecas do C++ que serão utilizadas
pelo programa. Essas bibliotecas são arquivos externos que acrescentam funcionali-
dades ao código como, por exemplo, imprimir um caractere ou um texto na tela do
computador, e funções para fazer a leitura de dados digitados pelo usuário a partir
do teclado.
A segunda seção do código fica totalmente contida no interior da função int
main(). Observe que o interior dessa função é delimitado por um par conjugado de
chaves, como mostrado na listagem do programa a seguir. Nesse código, as linhas
de 1 a 4 correspondem à primeira seção do programa, enquanto que as linhas de 5 a
9 correspondem à segunda seção, também chamada de corpo principal do programa.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 cout << " Hello world ! " << endl ;
8 return 0;
9 }

Além de bibliotecas, a primeira parte do código pode conter também outros


comandos, diretivas de compilação, protótipos de funções, declaração de constantes
e variáveis globais, referências a arquivos externos, entre outros. Alguns desses
elementos serão apresentados oportunamente no decorrer do livro.
Na listagem acima, a diretiva #include na linha 1 tem a função de adicionar ao
programa as funcionalidades contidas na biblioteca iostream. Uma das vantagens
do C++ é a sua capacidade de importar bibliotecas prontas, o que facilita muito a
construção dos programas e economiza muito o esforço e o tempo do programador.
A biblioteca iostream é padrão do C++ . A partir dela são declarados no código
os objetos utilizados para estabelecer uma comunicação com usuário através dos
dispositivos padrões de entrada e saída.
Em outras palavras, a iostream habilita a utilização do teclado e do monitor de
vídeo do computador para as operações comuns de entrada e saída de dados, e por

18
++
Princípios de programação em C

esse motivo está presente no início de praticamente todos os programas escritos


em C++ . Deve-se ficar atento ao fato de a linguagem C++ fazer distinção entre
caracteres maiúsculos e minúsculos. Assim, se por engano o programador digitar
#Include, com a primeira letra em maiúsculo, será gerado um erro em tempo de
execução ao compilar o programa.
Para algumas bibliotecas, como a iostream, é necessário informar o ”espaço de
nomes” (namespace) ao qual as funções dessa biblioteca estão associadas. Isso
permite ao programador acessar direta e explicitamente as funções da biblioteca,
economizando algumas linhas de programação. Por isso, na terceira linha do pro-
grama anterior, foi incluído o namespace std logo no início do código. Por definição,
o C++ utiliza o namespace std para definir todas as funções da biblioteca padrão.
A segunda seção do código começa na linha 5 e vai até a linha 9, e é o programa
propriamente dito. É dentro dessa seção que serão programadas todas as funcio-
nalidades do programa, e aquilo que esperamos que ele faça ao ser executado pelo
usuário. Todo programa em C++ começa com a instrução int main().
A função int main() é um bloco de códigos do tipo função, um assunto que
será abordado em detalhes no Capítulo 8, seção 8.1.2 (p.154). Neste momento o
importante é saber que as funções são blocos de código que devem retornar algum
valor e, neste caso, por ser uma função do tipo inteiro (int) essa função retornará um
valor inteiro. É por isso que foi utilizado o comando return 0 na linha 8, indicando
que ao seu término de execução, a função retornará o valor zero. Na linha 7 do
código foi utilizado o objeto cout da biblioteca padrão (iostream) para imprimir na
tela do computador a expressão ”Hello world!”.
O objeto cout significa ”console output” e não é uma palavra-chave do C++ .
Sua sintaxe e modo de utilização serão abordados mais adiante no decorrer deste
Capítulo 3. A linha 7 termina com o objeto endl (end line), que serve para forçar a
impressão do texto ”Hello world!” na tela do computador e reposicionar o cursor no
início da sua próxima linha.

3.1.2 O uso de chaves e o marcador de final de linha em C++


Nos programas em C++ todos os blocos de instruções ficam entre um par conjugado
de chaves (”{” e ”}”). As chaves tem o mesmo papel delimitador que o BEGIN...END
em outras linguagens de programação.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 // Os comandos em ’’ int main () ’’ devem ser
5 // colocados entre as chaves mostradas nas
6 // linhas 3 e 8
7 return 0;
8 }

19
++
Princípios de programação em C

Assim, na estrutura de um programa C++ , as chaves são símbolos gráficos que


delimitam os blocos de código, como apresentado nas linhas do exemplo a seguir.
Observe que é muito comum ocorrerem erros de compilação causados pelo fato
de o programador se esquecer de inserir no código uma das chaves que formam o
par. Erros causados pelo esquecimento do ponto e vírgula no final das linhas de
programação também ocorrem muito frequentemente.
Em muitas situações as chaves ficam aninhadas no código, ou seja, um bloco
de códigos que é delimitado por um par de chaves pode ficar dentro de um outro
bloco de códigos, também delimitado por um par de chaves, como mostrado entre
as linhas 9 e 11, no comando if do programa apresentado a seguir.
Em C++ o número máximo permitido para estruturas aninhadas é relativamente
grande, cerca de 256 (BECKER, 2011).
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 int x = 10;
8 if ( x == 10)
9 {
10 cout << " Valor igual a 10 " << endl ;
11 }
12 return 0;
13 }

3.1.3 Inserção de comentários e espaços em branco no código


O programador poderá, a seu critério, adicionar comentários ao código C++ de modo
a torná-lo mais claro, explicativo e inteligível, e isso faz parte das Boas Práticas
de Programação. Espaços em branco podem ser colocados livremente entre os
comandos, operadores matemáticos e operadores de comparação, e servem para
auxiliar o programador na formatação do código. Também é permitido saltar linhas
ou deixar linhas em branco.
O uso da tecla TAB para fazer o recuo de blocos de texto um pouco para a
direita é conhecido por indentação, e serve para tornar o código mais fácil de ser
lido e compreendido. Os comentários serão desprezados pelo compilador e servirão
apenas para documentar os códigos. Os modos mais comuns de fazer os comentários
são:

• Comentários inline: ocupam uma única linha do código. Começam com a barra
dupla ’//’ e vão até o término da linha. Opcionalmente pode-se colocar um
ponto e vírgula para indicar o seu final.

20
++
Princípios de programação em C

• Comentários multiline: Começam com ’/*’ e terminam com ’*/’. Todo o texto
colocado entre esses marcadores será considerado comentário e, portanto, des-
prezado pelo compilador.

3.1.3.1 Exemplo de comentário inline

1 # include < iostream >


2

3 using namespace std ;


4

5 int main () {
6 int x = 10; // Exemplo de comentario inline ;
7 if ( x == 10) {
8 cout << " Valor igual a 10 " << endl ;
9 } return 0;
10 }

3.1.3.2 Exemplo de comentários multiline

1 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2 /* Programa para exemplificar o uso de comentarios multili */
3 /* ne no codigo C ++ - Universidade Federal de Lavras / UFLA */
4 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
5 # include < iostream >
6

7 using namespace std ;


8

9 int main () { /* Blocos de comentarios multiline tam */


10 int x = 10; /* bem podem ser inseridos como mostra */
11 if ( x == 10) { /* do aqui , no meio do codigo . */
12 cout << " Valor igual a 10 " << endl ;
13 } return 0;
14 }

3.1.4 Instrução de retorno para o sistema operacional


A função return() inserida no final do código apresentado nos exemplos anteriores
faz com que a função int main() termine. Na forma como é utilizada, com o valor
zero sendo passado como argumento, essa instrução é considerada um status de
saída do programa, e retorno ao sistema operacional. O valor zero nessa instrução
corresponde a um status de sucesso (EXIT_SUCCESS), e tem o mesmo significado
que ”o sofware funcionou corretamente!”.

21
++
Princípios de programação em C

3.2 Declaração de variáveis de memória


Os programas de computador necessitam em algum momento de armazenar infor-
mações de diferentes tipos como, por exemplo, dados inseridos pelo usuário do pro-
grama, resultados de cálculos numéricos, valores temporários para serem posterior-
mente processados, etc.
Todas essas informações ficam armazenadas em variáveis de memória, que são
espaços ou regiões alocados na memória física do computador, dentro das quais pode-
mos guardar temporariamente informações de diferentes tipos: caracteres, números,
textos, etc.
As variáveis são identificadas basicamente pelo seu nome, tipo e por um endereço
na memória do computador. Em C++ só é possível armazenar um dado de cada vez
em uma variável de memória, com exceção a algumas classes especiais de variáveis
como, por exemplo, os vetores e as matrizes.
Declarar o nome e o tipo da variável é uma atribuição do programador, enquanto
que o endereço da variável é definido automaticamente pelo compilador.
A declaração de uma variável em C++ é feita especificando-se o tipo e um nome
para a variável.
Os tipos mais comuns permitidos em C++ estão apresentados na Tabela 3.1,
p.24, e os nomes das variáveis devem ser representativos do tipo de informação que
será armazenada em seu interior. Por exemplo, em uma variável para armazenar
dados de temperatura, um possível nome para essa variável pode ser ’Temper’.
A escolha do nome da variável fica inteiramente por conta do programador, mas
algumas regras devem ser observadas:

• Os nomes das variáveis podem conter caracteres maiúsculos ou minúsculos,


intercalados ou não, mas não pode haver espaços entre eles.

• As variáveis não podem ter o mesmo nome de instruções ou palavras reservadas


da linguagem C++ (ver Tabela 17.1, p.311).

• Devem começar com um caractere alfanumérico ou com um símbolo de under-


line (’_’).

• Podemos inserir numerais no nome da variável, mas desde que esse não seja
o primeiro caractere do nome. Exemplo: ”Tanque2” é um nome de variável
permitido, enquanto que ”2Motor” não é permitido, e irá gerar um erro de
compilação, impossibilitando a execução do programa.

No exemplo apresentado a seguir são declaradas (criadas) três variáveis dentro


do código, uma do tipo int chamada ”UFC”, uma do tipo float chamada ”pH” e outra
do tipo double chamada ”Aw”.
1 # include < iostream >
2 using namespace std ;

22
++
Princípios de programação em C

4 int main () {
5 int UFC ; /* Unidades formadoras de colonia */
6 float pH ; /* Potencial hidrogenionico */
7 double Aw ; /* Atividade de agua */
8 return 0; /* Retorno ao sistema operacional */
9 }

Ao declarar uma variável o programador deverá estar ciente sobre qual valor será
colocado em seu interior. Na linha 5 do exemplo acima, a instrução int faz com
que seja reservado um espaço na memória física do computador para a criação de
uma variável chamada ”UFC”, que deverá receber obrigatoriamente algum valor do
tipo inteiro, porém nesse programa, nenhum valor numérico foi atribuído à variável
UFC, e isso pode gerar um grande problema, visto que um valor arbitrário qualquer,
originalmente presente no mesmo endereço da memória onde UFC foi criada, poderá
ser atribuído a essa variável.
Assim, ao declarar uma variável o programador deverá sempre ficar atento ao seu
conteúdo e, se possível, inicializá-la com algum valor conhecido. No fragmento de
código apresentado a seguir as variáveis são inicializadas com valores numéricos no
mesmo instante em que são declaradas.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int UFC = 250; /* Unidades formadoras de colonia */
6 float pH = 6.82; /* Potencial hidrogenionico */
7 double Aw = 0.86; /* Atividade de agua */
8

9 return 0; /* Retorno ao sistema operacional */


10 }

É possível declarar mais de uma variável, ao mesmo tempo, em uma mesma linha
de código, como apresentado a seguir. Nesse código são declaradas três variáveis do
tipo inteiro: a, b e c.
1 int a , b , c ;

Outra forma de ’inicializar’ é atribuir diretamente valores às variáveis quando na


sua declaração. A forma apresentada na linha 2 a seguir não faz o uso do sinal de
igual, mas sim de parêntesis, enquanto que a declaração de variáveis do tipo char
(linha 5) exige que o caractere seja colocado entre um par de apóstrofos.
1 int a = 8 , b = 6 , c = 12 , d = 0;
2 int Quantidade (125) ;
3 double j = 6.25 , k = 11.27 , w = 0.00;
4 bool Imprimir = false ;
5 char Letra = ’a ’;

23
++
Princípios de programação em C

Declarações especiais, como para as variáveis do tipo vetor e matriz, serão apre-
sentadas oportunamente, no Capítulo 10, a partir da p.172.

3.3 Tipos de valores que podem ser atribuídos às va-


riáveis
Os tipos de dados mais comumente permitidos para as variáveis em C++ , a quanti-
dade de espaços em bytes ocupados na memória e os intervalos de valores permitidos
para cada tipo estão apresentados na Tabela 3.1 a seguir.
Além dos tipos apresentados nesta tabela, há também outros tipos, como aqueles
personalizados, que fazem uso do comando typedef, que será visto no Capítulo 4,
p.76. Uma outra forma de trabalhar com variáveis é a que faz o uso de estruturas,
assunto esse que será abordado no Capítulo 12, p.224.

Tabela 3.1: Tipos de dados mais comuns permitidos em C++ , bytes ocupados na
memória do computador e seus intervalos de valores numéricos.
Tipo de dado Bytes na memória Intervalo permitido de valores
short int 2 -32.768 a 32.768
signed int 2 -32.768 a 32.768
signed short int 2 -32.768 a 32.768
wchar_t 2 -32.768 a 32.768
signed wchar_t 2 -32.768 a 32.768
unsigned short int 2 0 a 65.535
unsigned wchar_t 2 0 a 65.535
int 4 -2.147.483.648 a 2.147.483.648
long int 4 -2.147.483.648 a 2.147.483.648
signed long int 4 -2.147.483.648 a 2.147.483.648
unsigned int 4 0 a 4.294.967.295
unsigned long int 4 0 a 4.294.967.295
char 1 -128 a 127
signed char 1 -128 a 127
unsigned char 1 0 a 255
bool 1 true ou false
float 4 1,2 × 10−38 a 3,4× 10+38
double 8 2,2 × 10−308 a 1,8× 10+308
long double 8 2,2 × 10−308 a 1,8× 10+308
Fonte: Elaborada pelos autores, adaptado de GREGOIRE (2014).

24
++
Princípios de programação em C

3.4 Escopo de variáveis: as declarações local e global


Há variáveis que podem ser acessadas a partir de qualquer parte do programa, en-
quanto outras só podem ser acessadas dentro de uma função, procedimento ou
bloco de códigos, e só serão acessíveis e terão funcionalidade dentro daquele bloco
de códigos onde foram declaradas.
Para entender melhor como isso funciona, observe o bloco de códigos apresentado
a seguir. Nele é apresentado um exemplo de código C++ com declarações do tipo
’local’ e ’global’.
1 # include < iostream >
2 using namespace std ;
3

4 double Tempo = 0.00; /* Tempo de cozimento do produto */


5 double Let = 0.00; /* Letalidade acumulada */
6 int Qtd = 50; /* Qtd de latas no esterilizador */
7

8 int main () {
9 float pH = 6.82; /* Potencial hidrogenionico */
10 double Aw = 0.86; /* Atividade de agua */
11 return 0; /* Retorno ao sistema operacional */
12 }

No bloco de códigos acima, as variáveis declaradas dentro da função int main()


são ’variáveis locais’ (linhas 9 a 11), e só podem ser acessadas dentro do bloco de
códigos onde elas foram declaradas, enquanto que as variáveis declaradas fora da
int main() (linhas 4 a 6) são ’variáveis globais’, cujo conteúdo pode ser acessado
e modificado em qualquer parte do programa. No código apresentado a seguir, as
variáveis x, y e z, declaradas na linha 13, somente estarão acessíveis dentro do bloco
de códigos delimitado pelo par de chaves, entre as linhas 12-16.
1 # include < iostream >
2 using namespace std ;
3

4 double Tempo = 0.00; /* Tempo de cozimento */


5 double Let = 0.00; /* Letalidade acumulada */
6 int Qtd = 50; /* Qtd de latas no esterilizador */
7

8 int main () {
9 float pH = 6.82; /* Potencial hidrogenionico */
10 double Aw = 0.86; /* Atividade de agua */
11

12 {
13 int x , y , z ;
14 x = 8; y = 9; z = 6;
15 pH = 4.25; Let = 6.85;
16 }

25
++
Princípios de programação em C

17

18 x = 11; /* Erro de compilacao */


19 return 0;
20 }

A variável pH, declarada na linha 9, estará acessível na linha 15 e portanto poderá


ter seu valor alterado de 6,82 (atribuído na linha 9) para o valor de 4,25 (atribuído
na linha 15). O mesmo ocorre para a variável Let, que poderá ter seu valor alterado
para 6,85 (linha 15) devido ao fato de esta variável ter sido declarada fora do bloco
delimitado pelas chaves, entre as linhas 12-16. Let é uma variável global, declarada
fora do int main(), e pode ser acessada e ter o seu valor modificado em qualquer
parte do programa.
Entretanto, haverá um erro de compilação em tempo real ao executar o programa,
visto que a modificação do valor da variável x na linha 18 não será possível, devido
ao fato de a variável x ter o seu escopo válido apenas dentro do bloco de códigos
onde foi declarada, ou seja, entre as linhas 12-16. A variável x é, portanto, uma
’variável local’ ao bloco de códigos delimitado pelas chaves entre as linhas 12 e 16,
e só pode ser acessada dentro desse bloco onde foi declarada.

3.5 Entradas e saídas de dados padrões do programa


Em quase todos os programas de computador é necessário que o usuário disponha
de recursos para entrada e saída de dados. Na maioria das vezes a entrada de dados
é feita a partir do teclado do computador, enquanto que as saídas são direcionadas
para a tela do seu monitor de vídeo.
Outras formas de entrada podem ser cliques do mouse ou toques de dedo em
posições específicas da tela do computador, entrada de dados por meio de equi-
pamentos conectados à porta paralela, serial ou USB, bluetooth, entrada de sinais
elétricos pela placa de som, etc. Como saídas, além do monitor de vídeo, há aque-
las referentes às impressoras, arquivos de dados, placas de controladores e outros
equipamentos conectados ao computador.
Neste tópico serão utilizadas duas formas de entradas e de saídas de dados dos
programas C++ :

• Entrada e saída padrão C++ : faz o uso da biblioteca iostream, por meio dos
objetos cin e cout.

• Entrada e saída padrão C: faz o uso da biblioteca stdio.h, por meio das funções
scanf() e printf(). Por uma questão de compatibilidade, todas as funcionalida-
des do C foram mantidas no C++ e por isso essas funções ainda são utilizadas
por muitos programadores, sendo oportuno apresentá-las aqui.

3.5.1 Entrada e saída de dados: uso da biblioteca stdio.h

26
++
Princípios de programação em C

3.5.1.1 As funções printf() e scanf() da linguagem C


A função printf() é usada para para imprimir dados na tela do computador. A função
scanf() é usada para ler dados a partir do teclado do computador.

A função printf(): Na sua forma mais simples, a função printf() é usada da seguinte
maneira:
1 # include < stdio .h >
2 int main () {
3 printf ( " Engenharia de Alimentos " ) ;
4 return 0;
5 }

O código acima irá imprimir o texto passado como argumento da função printf()
na tela do computador, e o cursor ficará piscando imediatamente após a letra ’s’ que
está no final do texto. Outras frases ou textos também podem ser enviados para a
tela do computador, como apresentado a seguir, entretanto o comando printf() fará
a impressão de modo serial, ou seja, não saltará nenhum espaço entre os textos que
foram enviados para a tela (Figura 3.1).
1 # include < stdio .h >
2 int main () {
3 printf ( " Engenharia de Alimentos " ) ;
4 printf ( " Universidade Federal de Lavras " ) ;
5 printf ( " Departamento de Ciencia dos Alimentos " ) ;
6 return 0;
7 }

Exemplo - +
+

Engenharia de AlimentosUniversidade Federal de LavrasDepartamento de Ciencia dos


Alimentos
Process returned 0 (0x0) execution time : 0.001 s
Press ENTER to continue.

Figura 3.1: Tela do terminal do Windows com a saída dos comandos printf() envi-
ados em sequência. (Fonte: autores)

Para evitar o encadeamento sequencial dos textos na tela, podemos inserir um


caractere de quebra de linha (”\n”) no final dos textos a serem enviados pela função
printf(), como mostrado a seguir. O caractere de quebra de linha fará com que o
cursor seja deslocado para o início da próxima linha na tela do computador.
1 # include < stdio .h >
2 int main () {

27
++
Princípios de programação em C

3 printf ( " Engenharia de Alimentos \ n " ) ;


4 printf ( " Universidade Federal de Lavras \ n " ) ;
5 printf ( " Departamento de Ciencia dos Alimentos \ n \ n \ n " ) ;
6 return 0;
7 }

Exemplo - +

+
Engenharia de Alimentos
Universidade Federal de Lavras
Departamento de Ciencia dos Alimentos

Process returned 0 (0x0) execution time : 0.001 s


Press ENTER to continue.

Figura 3.2: Tela do terminal do Windows com a saída dos comandos printf() envi-
ados com caractere de quebra automática de linha. (Fonte: autores)

Além do caractere de quebra de linha, podemos utilizar também caracteres que


permitem a inserção de valores dentro do texto a ser enviado para a tela. Considere
o código apresentado a seguir.
1 # include < stdio .h >
2 int main () {
3 float pH = 4.5;
4 printf ( " O pH para um alimento seguro : % f \ n " , pH ) ;
5 return 0;
6 }

Na linha 4 do código acima, os caracteres ”%f” inseridos dentro do texto dizem


para o compilador que nesta posição deverá ser inserido o valor de uma variável do
tipo float. Essa variável é o pH, passado como argumento no final do comando
printf(), após a vírgula, e o resultado é o que está apresentado a seguir.

Exemplo - +
+

O pH para um alimento seguro: 4.500000

Process returned 0 (0x0) execution time : 0.001 s


Press ENTER to continue.

Figura 3.3: Exemplo do uso de um caractere de formatação para inserir valor de


ponto flutuante na string a ser enviada para a tela do computador pela função
printf(). (Fonte: autores)

28
++
Princípios de programação em C

Variáveis de outros tipos também podem ser passadas como argumento para o
comando printf(). Além disso, o comando printf() aceita mais de um argumento por
vez, como apresentado nos exemplos do código a seguir.
Deve-se observar também que para cada de tipo de dado, é necessário informar
o caractere de formatação correto, caso contrário, poderá haver algum erro de com-
pilação, erro em tempo de execução do programa, ou mesmo acontecer de alguns
caracteres estranhos serem apresentados na tela do computador, na mesma posição
onde deveria ser exibido o valor desejado. A seguir, um exemplo um pouco mais
detalhado, mostrando a utilização do comando printf().
1 # include < stdio .h >
2 int main () {
3 float pHLote = 4.5; int QtdLatas = 22;
4 double Preco = 425.36; char TipoLata = ’S ’;
5 float Tempo = 15.2; float Temper = 121.5;
6 float Vazao = 3.2512; char Filial [] = " Jardim Botanico " ;
7

8 printf ( " CARACTERIZACAO DO LOTE :\ n \ n " ) ;


9 printf ( " Nome da filial ........: % s \ n " , Filial ) ;
10 printf ( " Tipo de lata ..........: % c \ n " , TipoLata ) ;
11 printf ( " Quantidade de latas ...: % d \ n " , QtdLatas ) ;
12 printf ( " pH medio do lote ......: % f \ n " , pHLote ) ;
13 printf ( " Preco medio do lote ...: R$ % lf \ n " , Preco ) ;
14 printf ( " \ n \ nBINOMIO DE ESTERILIZACAO :\ n \ n " ) ;
15 printf ( " Vazao do vapor ........: %.2 f m ^3/ s \ n " , Vazao ) ;
16 printf ( " Tempo : % f ( s ) \ t Temper : % f ( C ) \ n " , Tempo , Temper ) ;
17

18 return 0;
19 }

Uma particularidade dos marcadores de formatação ’%f’ e ’%lf’ é que eles permi-
tem, de uma forma bastante simples, formatar o número de casas decimais a serem
exibidas em resultados numéricos como, por exemplo, no valor da variável vazão do
vapor, na linha 15 do código. Neste caso, o valor ’.2’ que aparece entre os caracteres
’%’ e ’f’ serve para indicar que o valor da vazão do vapor deverá ser expresso com
duas casas decimais. A função printf() se encarregará de fazer os devidos arredon-
damentos numéricos no valor de saída. Exemplos complementares de formatação
utilizando o printf() estão apresentados nos Anexos deste livro, seção 17.4, p. 316.

29
++
Princípios de programação em C

Exemplo - +

+
CARACTERIZACAO DO LOTE:

Nome da filial........: Jardim Botanico


Tipo de lata..........: S
Quantidade de latas...: 22
pH medio do lote......: 4.500000
Preco medio do lote...: R$ 425.360000

BINOMIO DE ESTERILIZACAO:

Vazao do vapor........: 3.250000 m^3/s


Tempo: 15.200000 (s) Temper.: 121.500000 (C)

Process returned 0 (0x0) execution time : 0.001 s


Press ENTER to continue.

Figura 3.4: Saídas do código com exemplos de formatação utilizando a função


printf(). (Fonte: autores)

Os principais caracteres de formação, para diferentes tipos de dados, estão apre-


sentados na Tabela 3.2, p.32. Há muitos outros caracteres além daqueles apresen-
tados nessa Tabela, e o leitor que for utilizar as funções printf() e scanf() deverá
verificar em outras fontes de consulta, de modo a obter tabelas mais completas de
caracteres e símbolos especificadores de formação.

A função scanf(): Na sua forma mais simples, a função scanf() é usada da seguinte
maneira:
1 # include < stdio .h >
2 int main () {
3 int Numero ;
4

5 printf ( " Digite um numero : " ) ;


6 scanf ( " % d " , & Numero ) ;
7 printf ( " O numero digitado foi : % d \ n \ n " , Numero ) ;
8 return 0;
9 }

Na linha 3 do código acima é declarada uma variável inteira com o nome ”Nu-
mero”. Na linha 6, o primeiro parâmetro da função scanf() é o especificador de
formatação ”%d”, que informa que a função receberá, a partir do teclado do compu-
tador, um valor numérico do tipo inteiro. O segundo argumento da função scanf()
é &Numero.
O símbolo ”&” é sempre colocado na frente do nome da variável ao utilizar a fun-
ção scanf() para fazer a leitura de valores numéricos e caracteres. Outros exemplos

30
++
Princípios de programação em C

de uso da função scanf() estão apresentados no código a seguir.


1 # include < stdio .h >
2

3 int main () {
4 int Numero ; float Preco ;
5 double Volume ; char Letra ;
6 char Nome [31]; /* Ate 30 caracteres */
7

8 printf ( " Digite um numero : "); scanf ( " % d " , & Numero ) ;
9 printf ( " Digite o preco ..: "); scanf ( " % f " , & Preco ) ;
10 printf ( " Digite o volume .: "); scanf ( " % lf " , & Volume ) ;
11 printf ( " Digite uma letra : "); scanf ( " % c " , & Letra ) ;
12 printf ( " Digite um nome ..: "); scanf ( " % s " , Nome ) ;
13

14 printf ( " \ n \ n " ) ;


15 printf ( " INFORMACOES DIGITADAS :\ n " ) ;
16 printf ( " Numero ....: % d \ n " , Numero ) ;
17 printf ( " Preco .....: % f \ n " , Preco ) ;
18 printf ( " Volume ....: % lf \ n " , Volume ) ;
19 printf ( " Letra .....: % c \ n " , Letra ) ;
20 printf ( " Nome ......: % s \ n " , Nome ) ;
21 return 0;
22 }

Para as variáveis do tipo char há três observações a serem feitas:

• Para a leitura de um único caractere: No caractere especificador de formato


utilizado na função scanf(), é necessário colocar um espaço antes do símbolo
de percentagem, como apresentado aqui: ” %c”.

• Para a leitura de uma string de texto, é necessário especificar qual a quantidade


máxima de caracteres poderão ser colocados na string. O valor a ser informado
é sempre (n + 1), ou seja, para uma string de 30 caracteres, deve-se informar
31 ao declarar a variável, como mostrado na linha 6 do código do programa no
exemplo anterior.

• A função scanf() não consegue ler vetores de caracteres que contenham espa-
ços em branco em seu interior como, por exemplo, nos espaços presentes nos
nomes de pessoas, de ruas, etc.
Para essa situação pode-se utilizar a função fgets() como exemplificado a se-
guir.
Nesse exemplo, deve-se ficar atento ao fato de a função fgets() fazer a leitura
de todo vetor de caracteres, inclusive o caractere <ENTER> digitado no final
do nome. Assim, o printf() na linha 3 irá saltar uma linha imediatamente após
imprimir na tela o nome armazenado na variável ’cNome’.

31
++
Princípios de programação em C

1 char cNome [60]; // Variavel do tipo ’ caractere ’


2 printf ( " Nome ..: " ) ; fgets ( cNome , sizeof ( cNome ) , stdin ) ;
3 printf ( " Nome ..: % s " , cNome ) ;

Os resultados obtidos ao executar o programa estão mostrados na Figura 3.5,


para dados arbitrários informados pelo usuário.

Exemplo - +

+
Digite um numero: 226
Digite o preco..: 1454.26
Digite o volume.: 158.44
Digite uma letra: H
Digite um nome..: Pectina

INFORMACOES DIGITADAS:
Numero....: 226
Preco.....: 1454.260010
Volume....: 158.440000
Letra.....: H
Nome......: Pectina

Process returned 0 (0x0) execution time : 37.135 s


Press ENTER to continue.

Figura 3.5: Saídas dos exemplos de usos da função scanf(). (Fonte: autores)

3.5.1.2 Principais caracteres de formatação utilizados pelas funções printf()


e scanf()
Na Tabela 3.2 apresentada a seguir estão listados alguns caracteres de formatação
comumente utilizados pelas funções printf() e scanf() da linguagem C. Para uma
tabela mais completa, o leitor poderá consultar BRONSON (1993), além de outros
livros apresentados na seção de Referências Bibliográficas, p.323.
Tabela 3.2: Caracteres especificadores de formato C/C++ utilizados pelas funções
printf() e scanf().
Especificador Tipo de dado Descrição/Função
%c char Formatar um único caractere
%s char[] Formatar uma string/texto
%f float Formatar valores numéricos do tipo float
%lf double Formatar valores numéricos do tipo double
%d int Formatar valores numéricos do tipo int
\t – Caractere TAB (de tabulação/espaçamento)
Fonte: Elaborada pelos autores. Adaptado de SIERRA (2007).

32
++
Princípios de programação em C

3.5.2 Entrada e saída de dados: uso da biblioteca iostream


3.5.2.1 Os objetos cin e cout do C++
O objeto cin é usado para ler dados a partir do teclado do computador, e representa
o stream de entrada no C++ . Os dados são lidos sem espaços e sem tabulações,
como mostrado mais a diante nos exemplos desta seção.
O objeto cout representa o stream de saída no C++ , podendo também ser com-
preendido como uma espécie de sequência ou ”fluxo” de dados a serem impressos
na tela do computador. Para utilizar o objeto cout é necessário também o uso do
operador de inserção (), que insere dados dentro do stream. Para utilizar o objeto
cin é necessário também o uso do operador de extração (), que extrai dados do
stream.
Os objetos cin e cout: Na sua forma mais simples, os objetos cin e cout são
usados da seguinte maneira:
1 # include < iostream > /* Obrigatorio para cin e cout */
2 using namespace std ; /* Obrigatorio para cin e cout */
3 int main () {
4 int Numero = 0;
5 cout << " Digite um Numero : " ; /* Mensagem na tela */
6 cin >> Numero ; /* Leitura pelo teclado */
7 cout << endl ; /* Salta linha na tela */
8 cout << " Numero digitado : " << Numero << endl ;
9 return 0;
10 }

Na linha 4 do bloco de códigos anterior, é feita a declaração de uma variável


inteira denominada ’Numero’. Observe que em C++ os nomes das variáveis não
podem ser acentuados.
O objeto cout na linha 5 tem a função de exibir na tela do computador uma
mensagem para o usuário, solicitando que ele digite um número. Evidentemente é
necessário que o valor digitado seja inteiro, caso contrário o compilador irá truncar
esse numeral, sem fazer arredondamentos, e desprezará qualquer valor decimal que
tenha sido digitado.
Se, por exemplo, o usuário digitar 5.89, a variável ’Numero’ irá reter apenas a
parte inteira do valor digitado, antes do ponto decimal, e o seu conteúdo será o
número 5. Nesse caso, podemos dizer que houve uma conversão de um valor do
tipo float (ou double) para o tipo inteiro, obtida pelo truncamento de toda a parte
decimal que compõe o numeral. A conversão de valores armazenados entre diferentes
tipos de variáveis é um assunto que será abordado em mais detalhes no Capítulo 4,
a partir da p.84.
O objeto cin na linha 6 fará o cursor piscar na tela do computador, aguardando
a digitação de um valor inteiro para ser colocado na variável ’Numero’. Na linha 7 a

33
++
Princípios de programação em C

instrução endl é enviada para a tela do computador, e isso fará com que o cursor se
movimente para o início da próxima linha.
Na linha 8 o objeto cout incialmente imprime uma mensagem na tela do com-
putador (”Numero digitado”) e, em seguida, utiliza um outro operador de inserção
() para imprimir o valor da variável ’Numero’ na tela e, no final da linha 8 uma
nova instrução endl é enviada para a tela, de modo a reposicionar o cursor no início
da próxima linha.
Os objetos cin e cout podem ser utilizados para operações de entrada e saída
de duas ou mais variáveis simultaneamente, como mostrado nos exemplos a seguir.
Nesses exemplos observe que é o ’ponto e vírgula’ que define o final de uma linha
de instruções em C++ .
1 # include < iostream > /* Obrigatorio para cin e cout */
2 using namespace std ; /* Obrigatorio para cin e cout */
3 int main () {
4

5 int Num1 , Num2 , Num3 ;


6

7 cout << " Digite um Num1 : "; cin >> Num1 ;


8 cout << " Digite um Num2 : "; cin >> Num2 ;
9 cout << " Digite um Num3 : "; cin >> Num3 ;
10 cout << endl ;
11 cout << " Num1 digitado .: " << Num1 << endl ;
12 cout << " Num2 digitado .: " << Num2 << endl ;
13 cout << " Num3 digitado .: " << Num3 << endl ;
14 return 0;
15 }

1 # include < iostream > /* Obrigatorio para cin e cout */


2

3 using namespace std ; /* Obrigatorio para cin e cout */


4

5 int main ()
6 {
7 float pH , Tempo , Temper ;
8

9 cout << " Informe pH , Tempo e Temperatura : " << endl ;


10

11 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
12 /* A entrada de dados sera feita digitando - se cada va */
13 /* lor solicitado e , em seguida , pressiona - se a tecla */
14 /* ENTER para confirmar a leitura a partir do teclado */
15 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
16

17 cin >> pH >> Tempo >> Temper ;


18

34
++
Princípios de programação em C

19 cout << endl ;


20 cout << " Os valores lidos foram : " << endl ;
21 cout << " Valor do pH ...........: " << pH << endl ;
22 cout << " Valor do tempo ........: " << Tempo << endl ;
23 cout << " Valor da Temperatura ..: " << Temper << endl ;
24 cout << flush ; /* Esvazia o buffer de saida , sem im */
25 return 0; /* primir nada na tela do computador */
26 }

1 # include < iostream > /* Obrigatorio para cin e cout */


2

3 using namespace std ; /* Obrigatorio para cin e cout */


4

5 int main ()
6 {
7 int Numero ;
8

9 cout << " Informe um Numero : " ; cin >> Numero ;


10

11 cout << " Valor hexadecimal : " << hex << Numero << endl ;
12 cout << " Valor octal ......: " << oct << Numero << endl ;
13 cout << " Base decimal .....: " << dec << Numero << endl ;
14

15 return 0;
16 }

Nos códigos acima, as palavras hex, oct e dec fazem a mudança de base do
numeral digitado para as bases hexadecimal, octal e decimal.
1 # include < iomanip > /* Para uso de setiosflags () */
2 # include < iostream > /* Obrigatorio para cin e cout */
3

4 using namespace std ; /* Obrigatorio para cin e cout */


5

6 int main ()
7 {
8

9 float Temperatura ;
10

11 Temperatura = 121.58746587;
12

13 /* - -[ Fixa em uma casa decimal ] - - - - - - - - - - - - - - - - - - - - - - - - - */


14

15 cout . precision (1) ;


16 cout << setiosflags ( ios :: fixed ) ;
17

18 cout << " Temperatura : " << Temperatura << endl ;


19

35
++
Princípios de programação em C

20 /* - -[ Fixa em duas casas decimais ] - - - - - - - - - - - - - - - - - - - - - - */


21

22 cout . precision (2) ;


23 cout << setiosflags ( ios :: fixed ) ;
24

25 cout << " Temperatura : " << Temperatura << endl ;


26

27 /* - -[ Fixa em quatro casas decimais ] - - - - - - - - - - - - - - - - - - - - */


28

29 cout . precision (4) ;


30 cout << setiosflags ( ios :: fixed ) ;
31

32 cout << " Temperatura : " << Temperatura << endl ;


33

34 return 0;
35 }

No exemplo apresentado acima, as funções setprecision() e setiosflags() da bi-


blioteca iomanip foram utilizadas para definir o número de casas decimais a serem
utilizadas antes de imprimir na tela o valor da variável ’Temperatura’.
A entrada de valores do tipo texto é feita com o uso da função-membro getline()
do objeto cin. Valores do tipo texto também são conhecidos como ’strings de
caracteres’, e são utilizados em situações nas quais é necessário armazenar dados não
numéricos, dados que não sejam utilizados para a realização de cálculos matemáticos
como, por exemplo, nomes, endereços, cidades, telefones, CEP, etc.
Detalhes sobre a manipulação de variáveis dos tipos char e string serão apresen-
tados no Capítulo 4, a partir da p.56.
1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 char Nome [80];
7 cout << " Digite Nome completo : " << endl ;
8 cin . getline ( Nome , 80) ;
9

10 cout << endl ;


11 cout << " Nome completo digitado : " << endl << Nome << endl ;
12 return 0;
13 }

1 # include < iostream >


2 # include < iomanip >
3

4 using namespace std ;


5

36
++
Princípios de programação em C

6 int main ()
7 {
8

9 char Aluno [80];


10 float Prova1 , Prova2 , Prova3 , Media ;
11

12 cout << " Nome do aluno ...: " ;


13 cin . getline ( Aluno , 80) ;
14

15 cout << " Valor da Prova 1: " ; cin >> Prova1 ;


16 cout << " Valor da Prova 2: " ; cin >> Prova2 ;
17 cout << " Valor da Prova 3: " ; cin >> Prova3 ;
18

19 Media = ( Prova1 + Prova2 + Prova3 ) / 3;


20

21 cout . precision (2) ;


22 cout << setiosflags ( ios :: fixed ) ;
23

24 cout << endl ;


25 cout << " Nome do aluno ...: " << Aluno << endl ;
26 cout << " Media das provas : " << Media << endl ;
27 return 0;
28 }

O código acima utiliza os objetos cin e cout para ler e apresentar os valores das
variáveis no cálculo da nota média de três provas de um estudante. Na Figura 3.6 a
seguir está a saída que esse programa produz no terminal do Linux ao ser executado.

Exemplo - + +
Nome do aluno...: Bjarne Silva
Valor da Prova 1: 64.28
Valor da Prova 2: 82.47
Valor da Prova 3: 98.77

Nome do aluno...: Bjarne Silva


Media das provas: 81.84

Process returned 0 (0x0) execution time : 34.632 s


Press ENTER to continue.

Figura 3.6: Exemplo de uso dos objetos cin e cout para leitura das notas das provas
de um estudante, cálculo da média e exibição de seu valor no terminal do Linux.
(Fonte: autores)

Nos exemplos anteriores vimos o uso do caractere de formatação ”\n” para fazer
o salto de linha e posicionamento do cursor no início da nova linha. Vimos também

37
++
Princípios de programação em C

que o caractere ”\t” (Tabelas 3.2 e 3.3) pode ser utilizado para promover um espa-
çamento padrão no texto, correspondendo ao mesmo efeito que teríamos com o uso
da tecla TAB.
Além do ”\n” e do ”\t” há também outros caracteres de formatação, denominados
de ”sequências de escapes”, que podem ser utilizadas em conjunto com as funções
printf() e scanf(), e também com os objetos cin e cout. Na Tabela 3.3 apresentada
a seguir estão listados alguns desses caracteres. Fica como exercício para o leitor a
tarefa de utilizá-los na realização de alguns testes de programação.

Tabela 3.3: Tabela de códigos conhecidos como ’sequências de escapes’, utilizadas


pelos objetos cin e cout do C/C++ .
Sequências de escapes Descrição
\n Salto de linha e posicionamento no início da nova linha
\r Início da linha (retorno)
\t Tabulação horizontal (o mesmo que a tecla TAB)
\v Tabulação vertical
\b Deleção reversa de caracteres na linha
\f Nova página (alimentação da página)
\a Alerta (beep sonoro no auto-falante do computador)
\’ Faz uma aspas simples
\” Faz aspas duplas
\? Faz um sinal de interrogação (?)
\\ Faz uma contra-barra (\)
Fonte: Elaborada pelos autores. Adaptado de GREGOIRE (2014).

3.6 Inserção de caracteres da língua portuguesa nos


programas C++
Nos exemplos apresentados até aqui, e também em outros que se estendem ao longo
dos próximos capítulos, todos os caracteres da língua portuguesa, como ’é’, ’ç’, e
’è’, foram suprimidos, visto que ao utilizá-los no objeto cout, a impressão na tela do
computador poderia se mostrar na forma de outros caracteres, estranhos e diferentes
daqueles que foram utilizados.
Há, contudo, uma biblioteca padrão da linguagem C/C++ que pode ser utilizada
caso o programador queira inserir os caracteres da língua portuguesa em seus pro-
gramas. Essa biblioteca é a locale e um exemplo de sua utilização está apresentado
a seguir.
1 # include < iostream >
2 # include < locale > // Biblioteca para lingua portuguesa
3 using namespace std ;
4

38
++
Princípios de programação em C

5 int main () {
6 setlocale ( LC_ALL , " portuguese " ) ; // Funcao para habilitar
7 return (0) ; // caracteres da lingua
8 } // portuguesa

3.7 Depuração nos códigos de programas C++


No Capítulo 2, seção 2.4.3, p.13, vimos que o compilador exibe as mensagens de erros
de compilação na barra de mensagens do Code::Blocks. A discussão apresentada no
Capítulo 2 tratou basicamente sobre como identificar as linhas contendo os erros
de digitação e os erros de sintaxe do programa. Nesta seção será apresentado
um recurso do Code::Blocks que permite inspecionar, em tempo de execução do
programa, os valores contidos nas variáveis, de modo a identificar um outro tipo de
erro bastante comum, os ’erros de lógica’ de programação.
Para conhecer a ferramenta de debugger do Code::Blocks, vamos analisar o pro-
grama apresentado a seguir. Esse programa é bem simples, e utiliza os objetos cin
e cout da biblioteca iostream para ler o valor de quatro variáveis a partir do teclado,
sendo que cada variável possui um tipo específico.
Ao iniciar um programa, o compilador avalia quais as variáveis foram declaradas
no código e aloca espaço na memória para essas variáveis. O compilador porém
não inicializa essas variáveis com valores nulos ou zeros, ou seja, se na posição
de memória onde uma variável foi criada já houver dados residuais de algum outro
software que tenha utilizado aquela posição anteriormente, então a variável recém
criada dentro do programa C++ poderá herdar aqueles resíduos. Chamamos esses
resíduos informalmente de ’lixo’.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 int x;
8 float y;
9 char z;
10 double w;
11

12 cout << " Valor inteiro ...: "; cin >> x;


13 cout << " Precisao simples : "; cin >> y;
14 cout << " Caractere .......: "; cin >> z;
15 cout << " Dupla precisao ..: "; cin >> w;
16

17 return 0;
18 }

39
++
Princípios de programação em C

Para a maioria das situações, o C++ não verifica o conteúdo das variáveis,
ficando essa tarefa exclusivamente a cargo do programador, que deverá manter ano-
tações e um controle rigoroso sobre quais variáveis foram criadas dentro de seu
código e quais valores há nelas em qualquer parte do programa.
O procedimento de depuração do código será apresentado a seguir tendo, como
exemplo, o código apresentado acima, e o seu passo-a-passo será ilustrado por meio
de algumas de figuras.
A seguir, na Figura 3.7, há uma coluna vertical (na lateral esquerda da figura)
contendo a enumeração sequencial que identifica as linhas de código do programa.
Essa coluna de enumeração é útil porque auxiliará o programador na inserção de
pontos de interrupção (breakpoints) nos quais o programa deverá obrigatoriamente
realizar uma pausa, de modo a permitir ao programador inspecionar os valores con-
tidos em cada uma de suas variáveis durante a execução do programa.
Na Figura 3.7, inicialmente vamos colocar um breakpoint em cada uma das linhas
com os números 12 e 17.
Os breakpoints são pontos de parada, ou seja, interrupções que podemos solicitar
ao compilador de modo que quando o programa estiver sendo executado este será
pausado ao chegar nessas linhas.
Para adicionar um breakpoint a uma linha, basta clicar nessa linha com o botão
direito do mouse e escolher a opção ”Add breakpoint”, na primeira linha do menu
popup que irá aparecer, como mostrado na Figura 3.7.

40
++
Princípios de programação em C

Figura 3.7: Menu popup para inserção de breakpoints nas linhas de um programa
por meio da IDE do Code::Blocks. (Fonte: autores)

A inserção dos breakpoints será confirmada por meio de bolinhas vermelhas, ao


lado direito dos respectivos numerais que identificam as linhas do código, como
mostrado na Figura 3.8.
Para utilizar o debugger do Code::Blocks também é necessário selecionar a aba
Debugger, como mostrado na parte inferior da Figura 3.7. Também é necessário
arrastar e trazer para uma região de mais fácil acesso a barra flutuante de ferramentas
”Debugger Toolbar” (Figura 3.7).
Uma forma mais simples de adicionar ou remover um breakpoint em uma linha
de código é clicar com o mouse e inserir o cursor em qualquer posição dessa linha e
usar a tecla F5.

41
++
Princípios de programação em C

Figura 3.8: Identificação de linhas do código que servirão como pontos de parada
(breakpoints) durante a execução do programa. (Fonte: autores)

O próximo passo consiste em iniciar a execução do programa em modo de de-


bugger. Para isso basta clicar no primeiro botão da barra flutuante de ferramentas
”Debugger Toolbar”. Esse botão é identificado com um ícone vermelho em formato
de triângulo apontando para a direita (Figura 3.8)
Uma mensagem será exibida, questionando ao programador se ele deseja salvar,
ou não, as alterações na disposição dos elementos da IDE do Code::Blocks, como
mostrado na Figura 3.9. Clique em Sim para salvar as alterações.

Figura 3.9: Mensagem de questionamento ao programador sobre salvar, ou não, as


alterações feitas na IDE do Code::Blocks. (Fonte: autores)

Após clicar em Sim na mensagem acima, a janela do terminal irá aparecer e


o programa comecará a ser executado, porém, em modo passo-a-passo (modo de
depuração). Neste momento é uma boa opção dispor, ao lado uma da outra, as
janela do Code::Blocks e do terminal, como mostrado na Figura 3.10.

42
++
Princípios de programação em C

Figura 3.10: Disposição lado a lado das janelas do terminal do Windows e do


Code::Blocks durante os procedimentos de debug (depuração) do código. (Fonte:
autores)

Para inspecionar o valor das variáveis, o programador poderá clicar no botão


”Debugging windows” (Figura 3.11) e selecionar a opção ”Watches”. Isso abrirá a
janela de ”Watches” apresentada na Figura 3.12.
A janela Watches é basicamente uma tabela flutuante, similar à uma pequena
planilha eletrônica, que exibe em tempo real de execução os valores atualmente
contidos nas variáveis do programa.
Nessa janela pode-se observar que algumas variáveis possuem valores completa-
mente arbitrários, considerados lixos, que estavam ocupando os endereços da me-
mória antes de o programa começar a ser executado.
Como apresentado nos exemplos vistos até aqui, o programador poderá, a qual-
quer momento, modificar os valores das variáveis de memória durante a execução do
programa, bastando, para isso, utilizar o objeto cin para leitura de dados digitados
a partir do teclado, ou utilizar o operador de atribuição (’=’) para atribuir um novo
valor a qualquer uma das variáveis.

43
++
Princípios de programação em C

Figura 3.11: Botão de comandos ”Debugging windows” utilizado para abrir a janela
”Watches” do Code::Blocks. (Fonte: autores)

Figura 3.12: Exemplo de execução de um programa passo-a-passo por meio de


debugging e detalhes da janela ”Watches” do Code::Blocks. (Fonte: autores)

O quarto botão na Debugger Toolbar é o ”Step into” (Figura 3.12). O progra-


mador pode clicar nesse botão sucessivas vezes para que o programa seja executado
passo-a-passo. Em cada passo de execução o compilador fará a leitura de uma única
linha do código.
Nas situações em que o valor de uma variável deva ser lido pelo objeto cin, o
usuário deverá clicar, selecionar a janela de terminal (à direita na Figura 3.12) e
digitar os valores. Todos os valores digitados serão imediatamente atualizados na
janela de inspeção ”Watches”, como mostrado na Figura 3.13.

44
++
Princípios de programação em C

Para a variável ’z’, que é do tipo char, a janela ”Watches” informa dois valores.
Primeiro valor é o numeral 77, que corresponde ao código ASCII do caractere M
(maiúsculo), digitado arbitrariamente neste exemplo, e depois a letra M, que é o
conteúdo armazenado na variável z. Nas Tabelas 17.2 a 17.5 (p.312 – 315) estão
listados os códigos dos caracteres ASCII discutidos nos exemplos deste livro.

Program Console - +

+
warning: GDB: Failed to set controlling terminal: Operação não permitida
Valor inteiro...: 225
Precisao simples: 6.045 Whatches

+
Caractere.......: M Function arguments
Dupla precisao..: 12.0054878
Locals
x 225
y 6.04500008
z 77 'M
w 12.005487799999

Figura 3.13: Inspeção de variáveis a partir da janela ”Watches” do Code::Blocks e a


entrada dos dados digitados pelo programador. (Fonte: autores)

O término do processo de debugging é feito clicando-se no botão Stop debugger,


como mostrado na Figura 3.14.

Figura 3.14: Barra flutuante de ferramentas ”Debugger Toolbar” e o botão Stop


degugger, utilizado para interromper o processo de debugging. (Fonte: autores)

A mensagem ”warning: GDB: Failed to set...” na Figura 3.13 não tem nenhuma
relação ou interferência no processo de debugging. Essa mensagem informa apenas
que o software de debugger do Code::Blocks (o GDB) não teve permissão para
acesso a uma pasta no Linux, sistema operacional onde foi instalado o Code::Blocks
utilizado para trabalhar com os exemplos deste capítulo. Essa mensagem pode,
portanto, ser desconsiderada, e não deverá aparecer no terminal caso o sistema
operacional seja o Microsoft Windows.
O código utilizado para exemplo de debugging apresentado nesta seção é re-
lativamente simples, e possui apenas quatro variáveis. O recurso de debugging do
Code::Blocks se torna especialmente útil quando o programa apresenta erros de lógica
ou há um número muito grande de variáveis de memória para serem inspecionadas,

45
++
Princípios de programação em C

em especial nas situações em que o programador tem dificuldades para localizar e


identificar em que parte do código o erro está ocorrendo.
O processo de debugging não é uma exclusividade do Code::Blocks, visto que
muitos outros compiladores e IDE de programação apresentam recursos para a exe-
cução desse procedimento. Neste capítulo as saídas dos programas no console foram
apresentadas na forma de prints das telas, e isso foi feito com o objetivo de mostrar
ao leitor o modo como o Code::Blocks apresenta os resultados dos processamentos
dos dados feitos pelos programas construídos em C++ .
A partir do próximo capítulo essas saídas serão apresentadas de modo mais sim-
ples, na forma de textos ou comentários dentro dos programas, em geral identificadas
na cor vermelha, uma forma de economizar espaço no texto e deixá-lo menos sobre-
carregado com figuras.

3.8 Atividades para fixação da aprendizagem


1. Comentários no código C++

(a) Explique o que são ’comentários’ no código C++ . Qual a sua finalidade?
Em que situações são utilizados?
(b) Qual a diferença entre comentários inline e comentários multiline? Dê
um exemplo.
(c) Escreva um pequeno programa em C++ e mostre como ele pode ser do-
cumentado por meio de comentários.

2. Variáveis de memória

(a) O que são variáveis de memória? Qual a finalidade de utilizá-las?


(b) ’As variáveis de memória possuem um endereço’. Que endereço é esse?
Explique melhor essa afirmativa.
(c) Explique como deve ser a declaração de variáveis para armazenar dados
dos casos listados a seguir. Em cada situação, especifique corretamente
o tipo de variável e atribua corretamente um nome a ela.
i. O valor atual da temperatura de um forno.
ii. O valor da quantidade de latas que entram em uma autoclave.
iii. A quantidade, em número de mols, de um reagente químico em uma
reação de neutralização.
iv. O estado de operação de uma máquina (ligada ou desligada).
v. Um caractere alfanumérico.

3. Tipo de dado e escopo de variáveis de memória

46
++
Princípios de programação em C

(a) O que você entende por ’tipo’ de uma variável? Explique.


(b) No que se refere aos ’tipos’ das variáveis, o que ocorre se for colocado
um valor numérico com casas decimais em uma variável do tipo inteiro?
(c) O que é ’escopo’ de uma variável? Qual a diferença entre a declaração
local e a declaração global de uma variável? Explique.

4. Leitura e gravação com printf() e scanf()

(a) Escreva um programa que imprima na tela do computador os dados pes-


soais de cada membro de seu grupo:

i. Nome, v. e-mail,
ii. Endereço, vi. idade,
iii. Cidade, vii. Curso e
iv. telefone, viii. Período da graduação.

(b) Declare corretamente variáveis para armazenar as seguintes informações:

i. Tempo = 15,5 vi. Custo = 1195,00


ii. Temperatura = 121,1 vii. Preço = 1553,50
iii. pH = 4,5 viii. Margem de lucro = 0,2308
iv. Acidez = 18.2 ix. Markup = 0,3
v. Lote = "882-BMR-46" x. Lucro = 358,50

Em seguida, faça um programa utilizando a função ’printf()’, que imprima


esses valores na tela do computador, juntamente com a sua descrição.
(c) Crie um programa que leia, a partir do teclado, as informações listadas
a seguir. Assim que o usuário digitar os dados solicitados, o programa
deverá imprimir seus valores na tela do computador.

i. Descrição do produto vi. Estatus de liberação do lote (li-


ii. Qtd de pacotes berado/retido)
iii. Preço unitário vii. Temperatura máxima durante o
iv. Massa total (kg) transporte
v. Número do lote viii. Nome da transportadora

5. Leitura e gravação com cin() e cout()

(a) Crie um programa que leia, a partir do teclado, cinco números inteiros,
dois números do tipo float, três do tipo double e dois caracteres. Em
seguida, imprima na tela todos os valores digitados, um por linha.

47
++
Princípios de programação em C

(b) Crie um programa que leia o número do lote de um produto (valor inteiro),
e codifique o valor lido para hexadecimal.
(c) Crie um programa que leia, a partir do teclado, quatro valores de tempe-
ratura. Os valores lidos serão digitados pelo usuário com 5 (cinco) casas
decimais. O programa deverá imprimir os valores na tela do computador,
um valor por linha, com apenas duas casas decimais.
(d) Crie um programa em que o usuário informe, a partir do teclado, os dados
de um determinado produto. Após a entrada de dados, o programa deverá
imprimi-los na tela do computador. Os dados a serem processados são:
• Dados do produto
i. Descrição do produto. (char[40])
ii. Classe. (standard, gourmet, max premium) (char[14])
iii. Destino.(mercado nacional, exportação) (char[20])
iv. Número da nota fiscal. (char[12])
v. Nome da transportadora. (char[40])
vi. Quantidade atual em estoque (int)
vii. Quantidade mínima em estoque (int)
viii. Código de barras produto. (char[30])
ix. Preço unitário, em R$ (double)
x. Vida de prateleira, em dias. (int)
• Dados do processamento
i. Número do Lote. (char[8])
ii. Qtd. de embalagens por lote (int)
iii. Código do tipo de embalagem. (int)
iv. Responsável técnico pelo processamento do produto. (char[60])
v. Tempo de cozimento, em min. (float)
vi. Temperatura de cozimento, em Celsius. (float)
vii. Código do conservante químico (int)
viii. Concentração de conservante (float)
ix. Pressão do vapor (float)
x. Temperatura da água de resfriamento (float)

6. Utilização do Debugger do Code::Blocks

(a) Utilize o debugger do Code::Blocks para verificar o valor final das variáveis
x1 , x2 , y1 , y2 , z1 , z2 , w1 e w2 no programa apresentado a seguir. Em seu
relatório final coloque os ’prints’ da janela Watches do debugger.

48
++
Princípios de programação em C

1 # include < iostream >


2 using namespace std ;
3 int main () {
4 int x1 , x2 , y1 , y2 , z1 , z2 , w1 , w2 ;
5

6 x1 = 15; x2 = 125 - x1 ;
7 y1 = (3 * x2 ) - (2 * x1 ) ; y2 = x1 + x2 + y1 ;
8 z1 = x2 + y2 - x1 ; z2 = (2 * z1 ) + (4 * x2 ) ;
9 x1 = x1 - (2 * z1 ) ; x2 = x1 + (2 * x2 ) ;
10 w2 = x2 + x1 - z1 ; w1 = x1 + z2 - y2 + z1 ;
11 x2 = x1 + x2 ;
12 w2 = 4 + (6 * y2 ) - (2 * z1 ) + 5;
13 return 0;
14 }

49
Capítulo 4

Constantes e variáveis de memória

Conteúdo do capítulo
4.1 Os tipos de dados mais comumente utilizados em C++ . 51
4.1.1 Variáveis booleanas e variáveis inteiras . . . . . . . . . . . 51
4.1.2 Os tipos float e double . . . . . . . . . . . . . . . . . . . . 54
4.1.3 Variáveis do tipo string nos padrões C e C++ . . . . . . . 56
4.1.3.1 Variáveis string no padrão C . . . . . . . . . . . 56
4.1.3.1.1 Saídas formatadas com o sprintf(): . . . 61
4.1.3.2 Variáveis string no padrão C++ . . . . . . . . . . 62
4.1.4 Enumerações . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.1.5 Variáveis especiais para armazenamento de data e hora . . 71
4.1.6 O comando typedef para tipos de dados personalizados . . 76
4.1.7 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.1.8 Definição de macros por meio da diretiva #define . . . . . 81
4.2 Os argumentos argc e argv da função int main() . . . . 82
4.3 Comandos de atribuição e comparação de valores . . . . 84
4.3.1 Comandos de atribuição simples e múltipla . . . . . . . . 84
4.3.2 Operador de comparação de valores . . . . . . . . . . . . . 84
4.4 Operadores matemáticos, regras de precedência, con-
versão entre tipos e castings . . . . . . . . . . . . . . . . . 84
4.4.1 Conversão entre tipos de dados . . . . . . . . . . . . . . . 86
4.5 Operadores lógicos e relacionais . . . . . . . . . . . . . . . 89
4.6 Operadores numéricos de incremento e de decremento . 90
4.7 Declaração de variáveis com a instrução register . . . . . 91
4.8 Atividades para fixação da aprendizagem . . . . . . . . . 91

50
++
Princípios de programação em C

Assim como em outras linguagens de programação, todos os valores temporários


utilizados durante a execução de um programa C++ são armazenados em variáveis de
memória. Alguns conceitos sobre os principais tipos de variáveis e como elas devem
ser declaradas já foram abordados anteriormente no Capítulo 3, seção 3.2, p.22.
O conteúdo deste Capítulo 4 é uma complementação do capítulo anterior, em que
serão abordados detalhes adicionais sobre a declaração e uso dos tipos mais comuns
de variáveis. Este capítulo também introduz o uso de operadores lógicos, relacionais,
e outros operadores que podem ser adicionados aos códigos, com diferentes objetivos
e finalidades, conferindo enorme flexibilidade ao programador.

4.1 Os tipos de dados mais comumente utilizados em


C++
4.1.1 Variáveis booleanas e variáveis inteiras
A variável booleana pode armazenar exclusivamente dois tipos de valores: false (nível
lógico 0) ou true (nível lógico 1). Esse tipo de variável é especialmente útil em alguns
trechos de código para tomadas de decisões acerca de situações como, por exemplo,
para saber se o limite máximo de uma variável de processo foi alcançado ou não,
para interromper laços de repetição, e para comparações numéricas, como mostrado
nos exemplos a seguir.
O código abaixo mostra como podemos utilizar uma variável booleana em um
programa para verificar se um tanque de armazenamento de água está cheio ou não.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 bool TanqueCheio = false ;
8 int VolMax = 20;
9 int VolAtual = 0;
10

11 cout << " Volume atual do tanque ..: " ; cin >> VolAtual ;
12 cout << endl ;
13 TanqueCheio = ( VolAtual >= VolMax ) ;
14 cout << " Tanque esta cheio \? " << TanqueCheio << endl ;
15

16 return 0;
17 }

A variável ’TanqueCheio’, declarada na linha 7, irá armazenar o valor ’zero’


(false), caso o tanque esteja com volume abaixo do seu limite máximo (na va-

51
++
Princípios de programação em C

riável ’VolMax’), e armazenar o valor 1 (um, true) caso o atual volume do tanque
seja maior ou igual ao limite máximo. O valor atual do volume do tanque é um
numeral inteiro, que deverá ser informado pelo programador em tempo de execução
do programa.
No próximo exemplo é mostrada a utilização de uma variável booleana para a
interrupção de um laço de repetição while(). Não se preocupe nesse momento com
os comandos desconhecidos, como while() e if(), eles serão apresentados oportuna-
mente.
Nesse código, o comando while() irá executar indefinidamente todo o bloco de
instruções entre as linhas 11 e 19, até que seja alcançado um critério de parada. Esse
critério é dado pela variável ’Continua’, que assumirá o valor ”false” (ou zero) quando
a variável i assumir o valor 11 (onze). A cada vez que o comando while() executar
o bloco de instruções entre as linhas 11 e 19, a variável inteira i será incrementada
em uma unidade, como mostrado na linha 13.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 bool Continua = true ;
8 int i = 1;
9

10 while ( Continua )
11 {
12 cout << " Linha ..: " << i << endl ;
13 i = i + 1;
14

15 if (i >10)
16 {
17 Continua = false ;
18 }
19 }
20 return 0;
21 }

A instrução int é reservada para a declaração de variáveis do tipo inteiro, per-


mitindo somente valores numéricos inteiros nessas variáveis. Valores com casas
decimais atribuídos a variáveis inteiras serão truncados, como discutido no Capítulo
3, Seção 3.5.2.1, p.33.
No que se refere à declaração de variáveis inteiras, isto é feito exatamente do
mesmo modo como apresentado no Capítulo 3, porém aqui nota-se que podem ser
acrescentados os seguintes modificadores de tipos:

• short: É utilizado para modificar o tipo int para que esse fique com um tama-

52
++
Princípios de programação em C

nho menor, especialmente quando não houver necessidade de trabalhar com


números grandes, o que traz economia no uso da memória do computador.

• long: Ao contrário do modificador short, o long faz com que o tipo int es-
tenda sua capacidade de armazenamento, podendo armazenar números ainda
maiores.

• signed: Esse é um modificador que já é padrão (default) na linguagem C++ .


Seu uso serve para atribuir às variáveis a capacidade de armazenar tanto nu-
merais positivos quanto negativos.

• unsigned: Faz exatamente o contrário do signed. Esse modificador faz com


que as variáveis possam trabalhar apenas com valores numéricos positivos. O
bit que seria utilizado para armazenar o sinal algébrico do numeral se torna
disponível, aumentando ainda mais a capacidade de armazenamento da variável.

O código a seguir mostra como o programador pode utilizar a função sizeof()


para verificar o quanto, em bytes, que uma variável ocupa na memória computador.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int x1 ; // -2147483648 a 2147483647;
6 short int x2 ; // -32768 a 32767;
7 long int x3 ; // -2147483648 a 2147483647;
8 signed int x4 ; // -2147483648 a 2147483647;
9 unsigned int x5 ; // 0 a 4294967295;
10 short signed int x6 ; // -32768 a 32767;
11 long signed int x7 ; // -2147483648 a 2147483647;
12 short unsigned int x8 ; // 0 a 65535;
13 long unsigned int x9 ; // 0 a 4294967295;
14

15 cout << sizeof ( x1 ) << " bytes " << endl ;


16 cout << sizeof ( x2 ) << " bytes " << endl ;
17 cout << sizeof ( x3 ) << " bytes " << endl ;
18 cout << sizeof ( x4 ) << " bytes " << endl ;
19 cout << sizeof ( x5 ) << " bytes " << endl ;
20 cout << sizeof ( x6 ) << " bytes " << endl ;
21 cout << sizeof ( x7 ) << " bytes " << endl ;
22 cout << sizeof ( x8 ) << " bytes " << endl ;
23 cout << sizeof ( x9 ) << " bytes " << endl ;
24

25 return 0;
26 }

53
++
Princípios de programação em C

4.1.2 Os tipos float e double


Os tipos float e double são utilizados para armazenar valores numéricos não inteiros,
contendo uma ou mais casas decimais. A diferença básica entre eles, está no fato
de o double ocupar mais espaço na memória do computador e oferecer uma maior
precisão numérica.
O float ocupa 4 bytes, enquanto que o tipo double ocupa 8 bytes na memória
do computador. Em geral, o tipo float permite uma precisão de até seis ou sete
algarismos significativos, enquanto que o tipo double permite uma precisão maior,
de 15 ou 16 algarismos significativos, podendo chegar a 18 ou 19 quando declarado
como long double (8 bytes), mas essa é uma característica que depende, sobretudo,
de qual compilador C++ está sendo utilizado, versão, sistema operacional, arquitetura
do equipamento, etc.
As faixas de valores que podem ser atribuídos às variáveis do tipo double e float
já foram apresentadas anteriormente na Tabela 3.1, p.24. No que se refere à forma
como são declarados e utilizados em código, não há diferenças entre eles.
A seguir um exemplo das saídas apresentadas na tela do computador ao compa-
rarmos os valores armazenados em variáveis dos tipos float e double.
1 # include < iomanip >
2 # include < iostream >
3

4 using namespace std ;


5

6 int main ()
7 {
8

9 double dblPi = 3.14159265358979323846264338327950288;


10 float fltPi = 3.14159265358979323846264338327950288;
11

12 cout . precision (10) ;


13 cout << setiosflags ( ios :: fixed ) ;
14

15 cout << dblPi << endl ; // Saida : 3.1415926536


16 cout << fltPi << endl ; // Saida : 3.1415927410
17

18 return 0;
19 }

Em C++ , ao trabalhar com números que tenham partes fracionárias, é importante


lembrar que o separador de decimais é o ’ponto’, e não a vírgula. Opcionalmente
o programador poderá modificar as configurações no Painel de Controle do MS
Windows de modo a definir o ’ponto’ como separador de casas decimais para todos
os programas instalados em seu computador. Também é importante lembrar que ao
atribuir valores inteiros à variáveis do tipo int, não é permitida a utilização de ponto
decimal.

54
++
Princípios de programação em C

O código apresentado a seguir mostra a forma correta de atribuir valores inteiros


e valores fracionários aos tipos int, double e float.
1 int i = 0; // Correto ( sem decimais )
2 int j = 0.00 // Errado ! ( com decimais )
3 float w = 3.14; // Correto
4 double s = 5.15; // Correto

Ao tentar dividir um numeral por zero, o compilador irá gerar uma mensagem
com o texto inf e a apresentará na tela do computador, indicando que esse valor
tende a infinito. A tentativa de dividir zero por zero fará com que o compilador gere
uma mensagem com o texto -nan (not a number ), indicando uma indeterminação
matemática, como mostrado no exemplo a seguir. Os erros apresentados pelo com-
pilador não interrompem a execução do programa, e são erros que podem ocorrer
na realização de cálculos matemáticos e numéricos envolvendo o uso de variáveis do
tipo float e double.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7

8 double NumPos = 3.14159; // Numerador positivo ;


9 double NumNeg = -3.14159; // Numerador negativo ;
10 double Den = 0.00; // Denominador igual a zero ;
11

12 double Res1 = NumPos / Den ;


13 double Res2 = NumNeg / Den ;
14 double Res3 = Den / Den ;
15

16 cout << Res1 << endl ; // Saida : + inf


17 cout << Res2 << endl ; // Saida : - inf
18 cout << Res3 << endl ; // Saida : - nan
19

20 return 0;
21 }

Três considerações acerca de variáveis dos tipos double e float em problemas e


cálculos de engenharia:
• Nunca faça testes comparativos de igualdade envolvendo valores de ponto flu-
tuante de tipos diferentes, como mostrado no exemplo a seguir. Deixe essas
comparações para serem feitas com numerais inteiros (tipo int). Mesmo que
esses números sejam aparentemente iguais, pode ocorrer de os últimos bits
utilizados internamente em sua representação sejam diferentes, e o teste com-
parativo de igualdade poderá falhar.

55
++
Princípios de programação em C

1 double x = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9 5 0 2 8 8 ;
2 float y = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9 5 0 2 8 8 ;
3 ...
4 if ( x == y ) {...}

• Os cálculos envolvendo variáveis do tipo float geralmente apresentam pequenos


erros de arredondamento na quinta ou sexta casa decimal sendo, portanto,
sempre recomendada a utilização do tipo double quando houver necessidade de
cálculos mais precisos. A Tabela 4.1 a seguir mostra, em termos comparativos,
a precisão dos tipos float e double.

Tabela 4.1: Comparação da precisão dos tipos float e double em C++ .


Escala Precisão do float Precisão do double
Tamanho de uma sala micrômetro raio de um próton
Circunferência da Terra 2,4 metros 1 nanômetro
Distância até o sol 10 km largura de um fio de cabelo humano
Duração de um dia 5 milissegundos 1 picossegundo
Duração de um século 3 minutos 1 microssegundo
Tempo desde o Big Bang 1 milênio 1 minuto
Fonte: Elaborada pelos autores. Adaptado de ERNERFELDT (2017).

• Ao trabalhar com números muito grandes ou muito pequenos, uma boa es-
tratégia é reescaloná-los com o auxílio da função logaritmo. Por exemplo, ao
invés de dividir diretamente um número W , exageradamente grande, por um
número R, também exageradamente grande (W/R), calcule log(W )−log(R),
e aplique exp() ao resultado final (COOK, 2014). Detalhes sobre as funções
log() e exp() serão apresentados no Capítulo 7, seção 7.1, a partir da p.135.

4.1.3 Variáveis do tipo string nos padrões C e C++


4.1.3.1 Variáveis string no padrão C
Variáveis do tipo caractere (char) são totalmente compatíveis com o C++ , e podem
ser utilizadas para armazenar caracteres e textos de tamanhos variados, dependendo
do modo como são declaradas. Quando usadas para armazenar caracteres, estes
deverão estar entre aspas simples como, por exemplo ’W’ ou ’w’. Deve-se observar
que o C++ diferencia caracteres maiúsculos de minúsculos. A declaração e uso de
variáveis do tipo caractere é feita como apresentado a seguir:
1 char Letra1 = ’R ’; // Declaracao com atribuicao de valor
2 char Letra2 ; // Declaracao sem atribuicao de valor
3 Letra2 = ’M ’;

56
++
Princípios de programação em C

4 cout << Letra1 << endl ;


5 cout << Letra2 << endl ;

É permitido também armazenar diretamente os valores dos caracteres ASCII nas


variáveis do tipo char, como apresentado a seguir. A saída na tela do computador
será a sequência de caracteres: UFLA.
1 char a = 85 , b =70 , c =76 , d =65; // a = ’ U ’, b = ’ F ’;
2 cout << a << b << c << d << endl ; // c = ’ L ’, d = ’ A ’;

O exemplo a seguir mostra que é possível verificar que outros caracteres, como
o espaço em branco (linha 2) e o salto de linha (’\n’, na linha 4), também podem
ser incluídos em variáveis caractere.
1 char a = ’A ’ ;
2 char b = ’ ’ ;
3 char c = ’D ’ ;
4 char d = ’\ n ’;
5 char e = ’P ’ ;
6

7 cout << a << b << c << d << e << endl ;

Uma variável char pode ser declarada e simultaneamente atribuída de múltiplos


caracteres. Para armazenar, por exemplo, a palavra ’Maria’, que contém cinco ca-
racteres, deve-se declarar um vetor de caracteres com (n + 1) posições, ou seja, seis
caracteres. Isso é necessário porque em todo ’vetor de caracteres’ a última posição
é ocupada pelo ’\0’, caractere nulo que indica o final da cadeia de caracteres, como
mostrado na Figura 4.1.
1 char Nome [6] = " Maria " ; // Incializacao explicita ;
2 cout << Nome << endl ;

Primeiro índice Caractere nulo

Pos[0] Pos[1] Pos[2] Pos[3] Pos[4] Pos[5] Índices

M a r i a '\0'

Vetor de caracteres com 6 posições

Figura 4.1: Vetor de caracteres de seis posições. O caractere nulo vem sempre na
última posição. (Fonte: autores)

Além da inicialização explícita, como apresentado acima, podemos inicializar um


vetor de caracteres dispondo seus elementos entre aspas simples, e dentro de um
par de chaves, como apresentado a seguir:
1 char Nome [6] = { ’M ’ , ’a ’ , ’r ’ , ’i ’ , ’a ’ , ’ \0 ’ };
2 cout << Nome << endl ;

57
++
Princípios de programação em C

É possível também declarar um vetor de caracteres sem informar o seu tamanho,


e nesse caso o compilador determinará automaticamente a quantidade de caracteres
a serem reservados para a variável, que no caso apresentado a seguir será (5+1) = 6,
considerando o caractere nulo (’\0’) no final da sequência de caracteres.
1 char Nome [] = " Maria " ;
2 cout << Nome << endl ;

A leitura de um vetor de caracteres sem espaços em branco é feito pelo objeto


cin da biblioteca padrão.
1 char Nome [6];
2 cout << " Informe nome ..: " ;
3 cin >> Nome ;
4 cout << Nome << endl ;

Eventualmente podem ocorrer erros de leitura de dados a partir do teclado ao


utilizar o objeto cin. Isso acontece porque o cin considera que tudo aquilo que vem
do teclado é uma informação de entrada, inclusive o <ENTER>. Assim, quando o
usuário digita um valor, e logo em seguida tecla <ENTER>, não somente o valor
digitado será lido pelo cin, mas o <ENTER> também será lido para dentro da
variável, e isso poderá interferir na leitura do próximo valor a ser digitado pelo usuário.
Para contornar esse problema é recomendado utilizar a instrução ’cin.ignore()’
imediatamente após cada cin, como apresentado no exemplo a seguir. Neste exem-
plo, a leitura do vetor de caracteres contendo espaços em branco é feita pela função
get do objeto cin.
1 char Nome [31];
2 cout << " Informe nome ..: " ; // Informe nome contendo espacos
3 cin . get ( Nome , 31) ; // Le strings contendo espacos
4 cin . ignore () ; // Recomendado apos cada cin
5 cout << Nome << endl ;

É permitido ler, modificar ou até mesmo comparar o conteúdo de qualquer po-


sição dos vetores de caracteres. No código a seguir, é feita a comparação do valor
armazenado na terceira posição (Pos[2]) de dois vetores de caracteres.
1 char Nome1 [6] = " Paula " ; char Nome2 [6] = " Maria " ;
2

3 if ( Nome1 [2] == Nome2 [2]) {


4 cout << " Sao iguais " << endl ;
5 } else {
6 cout << " Sao diferentes " << endl ;
7 }

58
++
Princípios de programação em C

Pos[0] Pos[1] Pos[2] Pos[3] Pos[4] Pos[5]

P a u l a '\0'

M a r i a '\0'

Figura 4.2: Comparação entre os elementos da terceira posição de dois vetores de


caracteres. (Fonte: autores)

A instrução if() e o operador de comparação (’==’) utilizados no código anterior


serão explicados em mais detalhes nas próximas seções e capítulos.
Com a utilização da biblioteca cstring também é permitido copiar o conteúdo de
um vetor de caracteres para um outro vetor de caracteres. Isso é feito pela função
strcpy, como mostrado nas linhas 11 e 14 do exemplo a seguir.
1 # include < iostream >
2 # include < cstring > // strcpy () ;
3

4 using namespace std ;


5

6 int main ()
7 {
8 char Nome1 [6] = " Paula " ;
9 char Nome2 [6] = " \0 " ;
10

11 strcpy ( Nome2 , " Carla " ) ;


12 cout << Nome2 << endl ;
13

14 strcpy ( Nome2 , Nome1 ) ;


15 cout << Nome2 << endl ;
16

17 return 0;
18 }

A função strncpy utilizada no próximo exemplo permite copiar os dois primeiros


caracteres da variável ’Nome1’ para a variável ’Nome2’. Outras quantidades de
caracteres poderiam ser copiados, alterando-se o valor do último parâmetro da função
strncpy, no final da linha 10.
1 # include < iostream >
2 # include < cstring > // strncpy () ;
3 using namespace std ;
4

5 int main ()
6 {
7 char Nome1 [6] = " Paula " ;
8 char Nome2 [6] = " \0 " ;

59
++
Princípios de programação em C

10 strncpy ( Nome2 , Nome1 , 2) ; // 2 = Qtd de caracteres a co


11 cout << Nome2 << endl ; // piar de Nome1 para Nome2
12

13 return 0;
14 }

A função strcat da biblioteca cstring serve para concatenar (juntar) os caracteres


de duas ou mais variáveis, como mostrado a seguir.
1 char Texto1 [] = " Temperatura " ;
2 char Texto2 [] = " De " ;
3 char Texto3 [] = " Referencia " ;
4 char Texto4 [30] = { ’ \0 ’ };
5

6 strcat ( Texto4 , Texto1 ) ;


7 cout << Texto4 << endl ; // Temperatura
8

9 strcat ( Texto4 , Texto2 ) ;


10 cout << Texto4 << endl ; // TemperaturaDe
11

12 strcat ( Texto4 , Texto3 ) ;


13 cout << Texto4 << endl ; // T e m p e r a t u r a D e R e f e r e n c i a

A função strlen no código a seguir permite avaliar o tamanho (quantidade de


caracteres) de um vetor de caracteres.
1 char Nome [20] = " Carlos da Silva " ;
2 int Tamanho = strlen ( Nome ) ;
3 cout << Tamanho << endl ; // Saida : 15

A função strcmp permite comparar duas strings. Esta função possui a sintaxe
apresentada a seguir, e retorna os seguintes possíveis valores:
1 int strcmp ( char * s1 , char * s2 ) ;

• Menor que zero: se s1 for menor que s2.

• Igual a zero: se s1 e s2 são iguais.

• Maior que zero: se s1 for maior que s2.

A comparação é feita no primeiro caractere que diferir nas duas strings.


1 char Texto1 [5] = " abcd " ;
2 char Texto2 [5] = " abtw " ;
3

4 int Compara = strcmp ( Texto1 , Texto2 ) ;


5

6 cout << Compara << endl ;

60
++
Princípios de programação em C

No código anterior, ’Texto1’ é menor que ’Texto2’, pois a terceira letra (’c’)
em ’Texto1’ vem antes da terceira letra (’t’) em ’Texto2’, e a função strcmp irá
retornar algum valor menor do que zero.
É importante notar que a função strcmp faz diferenciação de caracteres maiús-
culos e minúsculos. Assim, as strings ’Aw’ e ’aw’ serão consideradas diferentes por
essa função. Várias outras funções para busca de substrings, cópia, comparação e
separação de fragmentos de texto, baseadas no uso de delimitadores, estão definidas
na biblioteca cstring.
A biblioteca cctype também possui um número de funções para conversão e testes
em caracteres individuais nos vetores de caracteres como, por exemplo, conversão
para maiúsculo e minúsculo, checagem para verificar se o caractere é numérico ou
alfanumérico, e muitas outras funções.

4.1.3.1.1 Saídas formatadas com o sprintf(): A função sprintf() da biblioteca


cstdio é usada para imprimir um texto qualquer dentro de um vetor de caracteres.
No exemplo a seguir é mostrado como essa função, em conjunto com a strcat, pode
ser utilizada para imprimir saídas formatadas de resultados de cálculos numéricos na
tela do computador.
1 # include < iostream >
2 # include < cstring > // Para strcat () ;
3 # include < cstdio > // Para sprintf () ;
4 using namespace std ;
5

6 int main () {
7 double Pressao = 142.147852; // Seis casas decimais
8 float pH = 4.256581; // Seis casas decimais
9 char Msg1 [30] = { ’ \0 ’ };
10 char Msg2 [30] = { ’ \0 ’ };
11 char Msg3 [30] = { ’ \0 ’ };
12 char MsgFinal [30];
13

14 sprintf ( Msg1 , " % s " , " Pressao no reator : " ) ;


15 sprintf ( Msg2 , " %.2 lf " , Pressao ) ; // Duas casas decimais
16 sprintf ( Msg3 , " %.2 f " , pH ) ; // Duas casas decimais
17

18 strcat ( MsgFinal , Msg1 ) ; // strcat -> funcao pa


19 strcat ( MsgFinal , Msg2 ) ; // ra concatenacao de
20 strcat ( MsgFinal , " e pH : " ) ; // strings
21 strcat ( MsgFinal , Msg3 ) ;
22

23 cout << MsgFinal << endl ;


24

25 return 0;
26 }

61
++
Princípios de programação em C

A saída apresentada na tela do computador será:


1 /*
2 Pressao no reator : 142.15 e pH : 4.26
3 */

4.1.3.2 Variáveis string no padrão C++


Diferentemente da linguagem C, que processa strings por meio de um vetor de
caracteres, o C++ possui uma biblioteca específica para a manipulação de strings.
Essa biblioteca deve ser incluída no código da seguinte forma:
1 # include < string >

A declaração de uma variável string é feita por meio da palavra reservada string,
como exemplificado a seguir:
1 string Nome ; // Declara a variavel string ’ Nome ’

O exemplo a seguir mostra como é feita a declaração de variáveis string e como


são realizados os procedimentos de entrada e saída nessas variáveis a partir dos
objetos cin, com o uso de ’getline.cin()’, e cout. Neste exemplo, nota-se que o
compilador C++ se encarrega da tarefa de reservar a quantidade necessária de espaços
na memória para as variáveis do tipo string.
1 # include < iostream >
2 # include < string >
3

4 using namespace std ;


5

6 int main () {
7

8 string Aluno1 = " Jose da Silva " ; // Atribuicao direta ;


9 string Aluno2 ( " Maria da Silva " ) ; // Outra forma direta ;
10 string Aluno3 ; // Atribuicao indireta ;
11

12 cout << " Nome do Aluno3 ..: " ;


13

14 getline ( cin , Aluno3 ) ; // Le o nome do Aluno 3;


15

16 cout << endl ;


17 cout << " Aluno 1..: " << Aluno1 << endl ;
18 cout << " Aluno 2..: " << Aluno2 << endl ;
19 cout << " Aluno 3..: " << Aluno3 << endl ;
20

21 return 0;
22 }

62
++
Princípios de programação em C

De modo análogo à forma de manipulação de strings em C, a biblioteca string


do C++ permite o acesso individual aos caracteres de uma string. Em C o acesso a
um caractere é feito por meio do indexador [n], em que n é a posição do caractere
a ser acessado para leitura ou alteração de seu valor (ver detalhes na seção 4.1.3.1,
a partir da página 56). Em C++ o acesso a um caractere individual é feito por meio
do operador at.
No código a seguir, além do operador at, o método size() permite obter o com-
primento da string, em número de caracteres, e a união (ou concatenação) de duas
ou mais strings pode ser feita pelo operador +. O código do exemplo mostra também
como o conteúdo de uma strings pode ser facilmente copiado para dentro de outra
string, por meio do operador de atribuição (=). O método clear() é utilizado para
limpar o conteúdo de uma string, enquanto que o método insert() permite inserir
um ou mais caracteres a partir de alguma posição dentro de uma string.
1 # include < iostream >
2 # include < string >
3

4 using namespace std ;


5

6 int main () {
7

8 string Nome = " Fulano " ;


9 string Sobrenome ;
10

11 string Tel1 = " 35 -99999 -8888 " ;


12 string Tel2 ;
13

14 // Imprime o tamanho da string ;


15 cout << " Tamanho : " << Nome . size () << endl ;
16

17 // Troca o primeiro caractere da string ( posicao zero ) ;


18 // por uma letra ’G ’ maiuscula ;
19 Nome [0] = ’G ’;
20 cout << " Nome ...: " << Nome << endl ;
21

22 // Usa o operador ’ at ’ para modificar a posicao 2 da string ;


23 // O caractere na posicao 2 sera substituido por ’# ’;
24 Nome . at (2) = ’# ’;
25 cout << " Nome ...: " << Nome << endl ;
26

27 // Faz a concatenacao de strings com o operador ’+ ’;


28 // Um espaco em branco tambem podera ser concatenado ;
29 // junto com a string ;
30 Sobrenome = " da Silva " ;
31 cout << " Nome ...: " << Nome + " " + Sobrenome << endl ;
32

63
++
Princípios de programação em C

33 // Copia o conteudo de ’ Tel1 ’ para dentro de ’ Tel2 ’;


34 Tel2 = Tel1 ;
35 cout << " Tel2 ...: " << Tel2 << endl ;
36

37 // Limpa o conteudo de Tel2 ;


38 Tel2 . clear () ;
39

40 // Insere o texto ’ WWW ’ a partir da segunda posicao de ’ Tel1 ’


41 Tel1 . insert (2 , " WWW " ) ;
42 cout << " Tel1 ...: " << Tel1 << endl ;
43

44 return 0;
45 }

Ao ser executado, o exemplo acima irá reproduzir na tela do computador a saída


apresentada a seguir.
1 /*
2 Tamanho : 6
3 Nome ...: Gulano
4 Nome ...: Gu # ano
5 Nome ...: Gu # ano da Silva
6 Tel2 ...: 35 -99999 -8888
7 Tel1 ...: 35 WWW -99999 -8888
8 */

Há uma outra forma de concatenar strings, porém, usando o método append,


como mostrado a seguir.
1 string Texto1 = " Primeiro " ;
2 string Texto2 = " Segundo " ;
3

4 Texto1 . append ( Texto2 ) ; // Concatena Texto2 com Texto1


5

6 cout << " Texto 1.: " << Texto1 << endl ;
7

8 /*
9 Saida : PrimeiroSegundo
10 */

É possível inicializar uma string com uma sequência de caracteres. No código a


seguir a variável ’Texto’ é inicializada com uma sequência de dez caracteres ’A’.
1 string Texto (10 , ’A ’) ; // Saida : AAAAAAAAAA

A seguir é mostrado como a variável ’Texto2’ pode ser inicializada a partir de


um fragmento de texto contido na variável ’Texto1’. O fragmento lido a partir de
’Texto1’ começa na posição três e se estende por quatro caracteres.

64
++
Princípios de programação em C

1 string Texto1 = " Processos Industriais " ;


2 string Texto2 ( Texto1 , 3 , 4) ;
3

4 cout << Texto2 << endl ; // Saida : cess

A comparação direta entre duas strings pode ser feita com os operadores listados
na Tabela 4.2. As comparações referem-se à ordenação alfabética. Assim, por
exemplo, ao comparar str1 = ’Ana’ e str2 = ’Maria’, o teste comparativo indicará
que ’Ana’ é menor do que ’Maria’, devido ao fato de ’Ana’ vir antes de ’Maria’
quando estes nomes são dispostos em ordem alfabética.

Tabela 4.2: Operadores de comparação de strings em C++ .


Operador Descrição
== Compara se as strings são iguais
!= Compara se as strings são diferentes
> Compara se uma string é maior que a outra
>= Compara se uma string é maior ou igual a outra
< Compara se uma string é menor que a outra
>= Compara se uma string é maior ou igual a outra
compare Retorna 0 (zero) se ambas strings são iguais
Retorna valor menor que 0 se str1 < str2
Retorna valor maior que 0 se str1 > str2
Fonte: Elaborada pelos autores. Adaptado de DAVIS (2014).

O exemplo a seguir mostra como variáveis do tipo string podem ter seus valores
comparados com a utilização dos operadores apresentados na Tabela 4.2.
1 # include < iostream > // Exemplos de comparacao de strings
2 # include < string >
3 using namespace std ;
4

5 int main () {
6

7 string Aluno1 = " Ana Paula " ;


8 string Aluno2 = " Paula Silva " ;
9

10 if ( Aluno1 == Aluno2 )
11 {
12 cout << " Os nomes sao iguais " << endl ;
13 }
14 else if ( Aluno1 < Aluno2 )
15 {
16 cout << " Aluno1 < Aluno2 " << endl ;
17 }

65
++
Princípios de programação em C

18 else if ( Aluno1 > Aluno2 )


19 {
20 cout << " Aluno1 > Aluno2 " << endl ;
21 }
22

23 return 0;
24 }

Neste momento o uso do if()...else() ainda não é importante. Os detalhes de sua


utilização serão explicados mais adiante.
1 # include < iostream > // Exemplo de uso do metodo ’ compare ’
2 # include < string > // para comparar strings
3

4 using namespace std ;


5

6 int main () {
7

8 string Aluno1 = " Ana Paula " ;


9 string Aluno2 = " Paula Silva " ;
10

11 if ( Aluno1 . compare ( Aluno2 ) == 0) {


12 cout << " Os nomes sao iguais " << endl ;
13 }
14 else if ( Aluno1 . compare ( Aluno2 ) < 0) {
15 cout << " Aluno1 < Aluno2 " << endl ;
16 }
17 else if ( Aluno1 . compare ( Aluno2 ) > 0) {
18 cout << " Aluno1 > Aluno2 " << endl ;
19 }
20

21 return 0;
22 }

O método swap, na linha 8 do próximo exemplo, permite alternar e trocar simul-


taneamente o conteúdo de duas variáveis do tipo string.
1 string Aluno1 = " Ana Paula " ;
2 string Aluno2 = " Paula Silva " ;
3

4 cout << " Aluno 1..: " << Aluno1 << endl ; // Ana Paula
5 cout << " Aluno 2..: " << Aluno2 << endl ; // Paula Silva
6

7 cout << endl ;


8 Aluno1 . swap ( Aluno2 ) ; // Troca os conteudos das variaveis
9

10 cout << " Aluno 1..: " << Aluno1 << endl ; // Paula Silva
11 cout << " Aluno 2..: " << Aluno2 << endl ; // Ana Paula

66
++
Princípios de programação em C

O método insert, na linha 3 do próximo exemplo, mostra como este comando


pode ser utilizado para inserir o conteúdo da variável ’Texto2’ na variável ’Texto1’,
a partir da posição 5 (quinta posição).
1 string Texto1 = " Primeiro " ;
2 string Texto2 = " Segundo " ;
3 Texto1 . insert (5 , Texto2 ) ;
4 cout << " Texto 1.: " << Texto1 << endl ; // PrimeSegundoiro

O método erase, na linha 2 do próximo exemplo, mostra como este comando


pode ser utilizado para excluir, a partir da terceira posição, uma sequência de quatro
caracteres na variável ’Texto1’.
1 string Texto1 = " Primeiro " ;
2 Texto1 . erase (3 , 4) ;
3 cout << " Texto 1.: " << Texto1 << endl ; // Saida : Prio

O método find, na linha 2 do próximo exemplo, mostra como este comando pode
ser utilizado para procurar um fragmento de texto dentro de uma string e indicar
qual a posição onde ele começa.
Neste exemplo, o find foi utilizado para procurar a substring ”ind” dentro de
’Texto1’, começando a busca a partir da segunda posição. Caso nenhuma ocorrência
da subtring seja localizada dentro da string, o find retornará um valor string::npos,
que corresponde ao maior valor numérico que pode ser armazenado em um unsigned
int.
1 string Texto1 = " Processos industriais " ;
2 cout << " Posicao : " << Texto1 . find ( " ind " , 2) << endl ;
3 // Saida : Posicao : 10

O método substr é utilizado para extrair uma substring a partir de uma string.
Para utilizá-lo é necessário informar a posição inicial a partir da qual a substring
deverá ser extraída e o seu comprimento, como mostrado a seguir.
1 string Texto1 = " Processos industriais " ;
2 cout << " Substring : " << Texto1 . substr (10 , 3) << endl ;
3 // Saida : Substring : ind

Para fazer saídas formatadas de resultados de cálculos numéricos, é possível


concatenar o conteúdo de variáveis do tipo string com o conteúdo de vetores de
caracteres. O código a seguir faz o uso da função sprintf() da biblioteca cstdio e de
um vetor de caracteres (’vTemp[]’) para uso temporário.
1 # include < iostream >
2 # include < cstdio > // Para a funcao ’ sprintf ’;
3 # include < string >
4 using namespace std ;
5

6 int main () {

67
++
Princípios de programação em C

7 double pH = 6.278975;
8 string Texto1 = " Valor do pH ..: " ;
9 char vTemp [10]; // Vetor temporario
10

11 sprintf ( vTemp , " %2.2 lf " , pH ) ; // Imprime no vetor


12 Texto1 = Texto1 + vTemp ; // Faz a concatenacao
13 cout << Texto1 << endl ; // Valor do pH ..: 6.28
14

15 return 0;
16 }

4.1.4 Enumerações
Enumerações correspondem a um tipo de dado que é definido pelo programador, e
que consiste em atribuir valores do tipo inteiro a nomes pré-definidos. Para decla-
rar uma enumeração utiliza-se a palavra reservada enum, como mostrado a seguir.
Neste exemplo, observe que a enumeração é do tipo ’Escala’, porém é a variável
inteira ’Nota’ que será utilizada no corpo do programa para armazenar os valores de
escores sensoriais.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main () {
6

7 enum Escala { D e s g o s t e i _ E x t r e m a m e n t e = 1,
8 Desgostei_Muito = 2,
9 Desgostei_Moderadamente = 3,
10 Desgostei_Ligeiramente = 4,
11 Indiferente = 5,
12 G os t e i _L i g ei r a me n t e = 6,
13 Gostei_Moderadamente = 7,
14 Gostei_Muito = 8,
15 G os t e i _E x t re m a me n t e = 9} Nota ;
16

17 Nota = Gostei_Muito ; // Nota : Variavel inteira ;


18

19 cout << " Escore sensorial : " << Nota << endl ;
20 /* Saida : Escore sensorial : 8 */
21

22 return 0;
23 }

As enumerações facilitam a organização do programa e a forma como algumas


decisões podem ser tomadas, em especial quando utilizado em conjunto com os

68
++
Princípios de programação em C

desvios condicionais if() e switch(). O exemplo a seguir mostra como utilizar uma
enumeração para decidir sobre a escolha de algum tipo de fruta. Neste exemplo, a
variável ’Escolha’ é declarada explicitamente como int no código.
1 enum Frutas { Banana , Goiaba , Pera , Morango };
2 int Escolha = Morango ;
3

4 if ( Escolha == Morango ) {
5 cout << " Fruta escolhida : morango " << endl ;
6 } else {
7 cout << " Fruta escolhida : " << Escolha << endl ;
8 }

O próximo exemplo mostra a utilização de enumerações com a instrução switch().


Neste momento o leitor não necessita se preocupar com essa instrução, visto que ela
será abordada em mais detalhes no Capítulo 5, Seção 5.1.4, p.103. Deve-se apenas
observar o modo como a enumeração é utilizada para representar os diferentes tipos
de processamento térmico que podem ser aplicados a um alimento.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 enum ProcTermico { Esterilizacao ,
5 Pasteurizacao ,
6 Branqueamento ,
7 Termizacao };
8 ProcTermico TipoTT ; // Instancia a variavel ’ TipoTT ’
9 TipoTT = Branqueamento ;
10

11 switch ( TipoTT ) {
12 case Esterilizacao :
13 cout << " Processo : Esterilizacao " ;
14 break ;
15 case Pasteurizacao :
16 cout << " Processo : Pasteurizacao " ;
17 break ;
18 case Branqueamento :
19 cout << " Processo : Branqueamento " ;
20 break ;
21 case Termizacao :
22 cout << " Processo : Termizacao " ;
23 break ;
24 default :
25 cout << " Valor indefinido " ;
26 }
27 return 0;
28 }

69
++
Princípios de programação em C

As enumerações podem também ser utilizadas juntamente com laços de repeti-


ção do tipo for() ou while(), como mostrado no exemplo a seguir. Por enquanto
o leitor não deve se preocupar com o comando for(), ele é utilizado no próximo
exemplo apenas para ilustrar como todos os elementos de uma enumeração podem
ser automaticamente percorridos e listados na tela, caso isso seja de interesse do
programador. Laços de repetição, como o for(), serão abordados em mais detalhes
no Capítulo 6, Seção 6.1.1, a partir da p.112.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 enum Meses { janeiro = 1,
6 fevereiro = 2,
7 marco = 3,
8 abril = 4,
9 maio = 5,
10 junho = 6,
11 julho = 7,
12 agosto = 8,
13 setembro = 9,
14 outubro = 10 ,
15 novembro = 11 ,
16 dezembro = 12};
17 int i ;
18

19 for ( i = janeiro ; i <= dezembro ; i ++)


20 {
21 cout << i << " " ;
22 }
23 return 0; // Saida : 1 2 3 4 5 6 7 8 9 10 11 12
24 }

Algumas situações de uso frequente das enumerações na codificação de progra-


mas para processos nas indústrias de alimentos estão exemplificadas a seguir:
1 enum Situacao { Funcionando = 1 , Falha = 0 , Paralisado = 2};
2 enum Semana { Seg , Ter , Qua , Qui , Sex , Sab , Dom };
3 enum Turno { manha , tarde , noite };
4 enum Riscos { fisicos , quimicos , microbiologicos };
5 enum Genero { masculino , feminino };
6 enum Cor { vermelho , verde , azul };
7 enum Cafe { mole , duro , rio , riado };
8 enum Defeitos { ardido , verde , concha , quebrado };
9 enum Carne { PSE = 1 , DFD = 2};
10 enum Direcao { norte , sul , leste , oeste };
11 enum Exportadores { Brasil , Italia , Argentina };

70
++
Princípios de programação em C

4.1.5 Variáveis especiais para armazenamento de data e hora


A forma mais simples de armazenar datas consiste em declarar três variáveis inteiras,
uma para o dia, outra para o mês e outra para o ano, como mostrado no próximo
exemplo.
Nessa situação, cabe ao programador definir em código os limites permitidos
para cada uma dessas variáveis como, por exemplo, inserir uma restrição que deve
ser aplicada à variável mês para que somente valores inteiros compreendidos entre 1
e 12 possam ser digitados pelo usuário. O mesmo é válido para a variável dia, que
deverá conter valores inteiros compreendidos entre 1 e 31.
Deve-se ressaltar que este é um método muito simples, que não envolve a iden-
tificação de anos bissextos, e também não estão previstos cálculos de diferenças
ou somas de datas, número de semanas, dias trabalhados, etc. Essas funcionali-
dades devem ser construídas passo-a-passo pelo programador, de acordo com suas
necessidades. Exemplos de programas para manipulação de datas e hora podem ser
facilmente encontrados em livros, artigos técnicos e outras fontes de consulta.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int dia , mes , ano ;
6 cout << " Dia : " ; cin >> dia ; cin . ignore () ;
7 cout << " Mes : " ; cin >> mes ; cin . ignore () ;
8 cout << " Ano : " ; cin >> ano ; cin . ignore () ;
9 cout << endl << dia <<" / " << mes <<" / " << ano << endl ;
10 return 0;
11 }

Variáveis do tipo vetor de inteiros (Capítulo 10, Seção 9.1, p.172) também podem
ser empregadas para o armazenamento de datas, assim como estruturas de dados
(Capítulo 12, Seção 10.9, p.224).
Da mesma forma que para as datas, os valores referentes a horas também podem
ser armazenados em variáveis inteiras, vetores de inteiros e estruturas de dados. O
código a seguir é o mesmo apresentado anteriormente, com ligeiras modificações.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int hora , min , seg ;
6 cout << " Hora : " ; cin >> hora ; cin . ignore () ;
7 cout << " Min .: " ; cin >> min ; cin . ignore () ;
8 cout << " Seg .: " ; cin >> seg ; cin . ignore () ;
9 cout << endl << hora <<" : " << min <<" : " << seg << endl ;
10 return 0;
11 }

71
++
Princípios de programação em C

Em algumas situações é necessário exibir na tela, ou armazenar em uma variável,


a data ou a hora atual do computador, informada pelo sistema operacional. Em C++
a biblioteca ctime disponibiliza algumas funções que permitem manipular valores de
data e hora.
De uma forma mais simplificada, pode-se dizer que essa biblioteca define um
novo tipo de dado chamado ’time_t’, que permite declarar variáveis com a finalidade
específica de armazenar valores de datas e horas. A função time() da biblioteca ctime
lê a hora atual do sistema operacional, e a função ctime() converte os valores de
data e hora para uma string (vetor de caracteres). A função strcpy() da biblioteca
cstring pode ser utilizada para copiar a saída da função ctime() para dentro de um
vetor de caracteres.
O exemplo a seguir mostra como essa biblioteca pode ser utilizada para imprimir
a data e a hora atual do sistema operacional na tela do computador.
1 # include < iostream >
2 # include < ctime >
3 # include < cstring > // Para usar a funcao ’ strcpy ’
4

5 using namespace std ;


6

7 int main ()
8 {
9

10 time_t HoraAtual ; // Declara a variavel ’ HoraAtual ’;


11

12 HoraAtual = time ( NULL ) ; // Usa a funcao time () para ler a


13 // hora do sistema operacional e
14 // coloca em ’ HoraAtual ;
15

16 char DataHora [30]; // Cria um vetor de caracteres ;


17

18 strcpy ( DataHora , ctime (& HoraAtual ) ) ; // Converte as infor


19 // macoes de data e
20 // hora em uma string
21 // de caracteres ;
22

23 cout << " Hoje : " << DataHora << endl ;


24

25 return 0; // Saida : Hoje : Sun Oct 13 19:24:46 2019


26

27 }

A biblioteca ctime define quatro tipos básicos que podem ser utilizados na mani-
pulação de data e hora: tm, clock_t, time_t e size_t. A estrutura tm definida em
ctime é padrão das linguagens C/C++ , e mantém informações sobre a data e a hora
do sistema operacional. Ela é composta pelos seguintes elementos:

72
++
Princípios de programação em C

1 struct tm {
2 int tm_sec ; // segundos de minutos , de 0 ate 61
3 int tm_min ; // minutos de hora , de 0 ate 59
4 int tm_hour ; // horas do dia , de 0 a 24
5 int tm_mday ; // dia do mes , de 1 a 31
6 int tm_mon ; // mes do ano , de 0 a 11
7 int tm_year ; // ano desde 1900
8 int tm_wday ; // dias , desde domingo
9 int tm_yday ; // dias , desde primeiro de janeiro
10 int tm_isdst ; // horas de horario de verao
11 }

Essa estrutura1 tm é uma forma computacional de representação do tempo, que


se baseia na separação de seus componentes, sendo conhecida como broken-down
time. A separação é feita em dias, meses, anos, etc... Além da estrutura tm, a
biblioteca ctime define também algumas funções:

• time_t time(time_t *time): esta função retorna a hora atual do sistema


operacional, expresso na forma de número de segundos decorridos desde o
instante 00:00:00 UTC do dia 1 de janeiro de 1970. Curiosamente, a represen-
tação de datas pelo computador é feita tendo uma data fixa como referência
que, neste caso, é o 01/01/1970. Embora seja de fácil compreensão, é um
modo bastante diferente da maneira pela qual os seres humanos processam as
informações de datas.

• struct tm *localtime(const time_t *time): Retorna um ponteiro 2 para a


estrutura tm representando o tempo (data e hora) local.

• char *ctime(const time_t *time): esta função retorna um ponteiro para


uma string na forma: ’dia mês ano horas:minutos:segundos ano’

• clock_t clock(void): retorna o valor aproximado do tempo decorrido desde o


instante em que o programa atual começou a ser executado.

• char * asctime (const struct tm * time): retorna um ponteiro para uma


string que contém informação armazenada na estrutura tm. O conteúdo da
string estará na forma ’dia mês ano horas:minutos:segundos ano’.

• struct tm *gmtime(const time_t *time): retorna um ponteiro para o tempo


armazenado em uma estrutura tm. Esse tempo é representado como UTC
(Coordinated Universal Time), que é o tempo médio no meridiano de Greenwich
(GTM - Greenwich Mean Time).
1
Structs (ou estruturas) são elementos especiais para armazenamento de dados em variáveis.
Esse assunto será abordado no Capítulo 10.
2
Ponteiros serão discutidos em mais detalhes no Capítulo 9, Seção 10.1, p.199.

73
++
Princípios de programação em C

• time_t mktime(struct tm *time): converte uma estrutura do tipo broken-


down time para uma forma mais simples, do tipo time_t, considerando apenas
os dados de tempo. É uma função que auxilia na conversão de valores de data
e hora, de modo a torná-los adequados para entrada em outras funções.

• double difftime ( time_t time2, time_t time1 ): retorna a diferença de


segundos entre os instantes de tempo time1 e time2.

• size_t strftime(): esta função serve para formatar a data e a hora antes de
apresentá-las na tela ou armazená-las em uma variável.

A seguir são apresentados exemplos de utilização de algumas dessas funções da


biblioteca ctime.
1 # include < iostream >
2 # include < ctime >
3 using namespace std ;
4

5 int main () {
6

7 // Pega a data e hora atual do sistema operacional


8 time_t agora = time (0) ;
9 cout << " Numero de segundos desde 01 jan 1970: " ;
10 cout << agora << endl ;
11

12 // Cria uma variavel chamada ’ LocTime ’ ( tempo local )


13 // na forma de um ponteiro , com a mesma estrutura de
14 // tm , e contendo os dados do tempo atual ;
15 tm * LocTime = localtime (& agora ) ;
16

17 // Lista os componentes da estrutura LocTime ;


18

19 cout << " Ano ...: " << 1900 + LocTime - > tm_year << endl ;
20 cout << " Mes ...: " << 1 + LocTime - > tm_mon << endl ;
21 cout << " Dia ...: " << LocTime - > tm_mday << endl ;
22 cout << 1 + LocTime - > tm_min << " : " ;
23 cout << 1 + LocTime - > tm_sec << endl ;
24 }
25 // ======================================================
26 // Saida :
27 // ------------------------------------------------------
28 // Numero de segundos desde 01 jan 1970: 1571409569
29 // Ano ...: 2019
30 // Mes ...: 10
31 // Dia ...: 18
32 // Hora ..: 12:40:30
33 // ======================================================

74
++
Princípios de programação em C

Em algumas situações é necessário realizar uma pausa no programa com duração


por um tempo finito e determinado. Essas pausas são especialmente úteis quando
na exibição de mensagens na tela para informar algo ao usuário. Em ambiente Linux
isso pode ser feito com a funções sleep() e usleep(), da biblioteca unistd.h.

• sleep(<tempo em n segundos>): faz uma pausa no programa com duração


de n segundos, em que n é sempre um numeral inteiro;

• usleep(<tempo em m microsegundos>): faz uma pausa no programa com


duração de m microsegundos, em que m é sempre um numeral inteiro;

No Microsoft Windows, a função Sleep() da biblioteca windows.h tem a mesma


finalidade, porém, a pausa é feita com base na quantidade de milissegundos que são
passados como argumento para a função. Os comandos que vêm logo após a pausa
são executados normalmente pelo processador.
1 # include < iostream >
2 # include < unistd .h > // Exemplo para o ambiente Linux
3

4 using namespace std ;


5

6 int main () {
7 cout << " Texto 1 " << endl ;
8 sleep (5) ; // Espera 5 segundos ;
9 cout << " Texto 2 " << endl ;
10 usleep (500000) ; // Espera 500 mil microsegundos ;
11 cout << " Texto 3 " << endl ;
12

13 return 0;
14 }

1 # include < windows .h > // Exemplo para o ambiente Windows


2 Sleep (1000) ; // Espera 1 ( um ) segundo : 1000 ms

Há outras bibliotecas, que estendem os recursos de programação de funções do


tempo, tornando possível a construção de programas para a contagem de tempo
com alta resolução. Um exemplo é a biblioteca chrono, que permite a realização de
pausas, contagem de tempo e intervalos de tempo com precisão de nanossegundos.
Essa alta resolução é especialmente útil na construção de cronômetros ou programas
para contagem precisa do tempo em processos industriais, como cinética de reações
químicas, etc.
Uma outra maneira de pausar um programa é por meio da função ’cin.get()’ do
objeto cin. Ao utilizar essa função, o programa será temporariamente suspenso e
só dará continuidade em sua execução quando o usuário pressionar alguma tecla. O
código a seguir mostra como essa função pode ser utilizada para pausar um programa.

75
++
Princípios de programação em C

1 # include < iostream >


2

3 using namespace std ;


4

5 int main ()
6 {
7 cout << " Pressione uma tecla para continuar " << endl ;
8 cin . get () ; // Aguarda o pressionar de alguma tecla ;
9

10 cout << " Fim " << endl ;


11 return 0;
12 }

4.1.6 O comando typedef para tipos de dados personalizados


O comando typedef permite atribuir ’apelidos’ aos tipos básicos do C++ e declarar
variáveis com esses apelidos, o que pode tornar o código mais inteligível e de fácil
compreensão pelo programador. Por exemplo, é possível apelidar o tipo float para
’Velocidade’, e declarar variáveis como sendo do tipo ’Velocidade’.
1 # include < iostream >
2

3 typedef float Velocidade ; // Renomeia o tipo ’ float ’


4

5 using namespace std ;


6

7 int main ()
8 {
9

10 Velocidade v1 = 1.25; // Declara a variavel ’ v1 ’


11 Velocidade v2 = 8.64; // Declara a variavel ’ v2 ’
12

13 cout << " Velocidade 1: " << v1 << endl ;


14 cout << " Velocidade 2: " << v2 << endl ;
15

16 return 0;
17 }

Na construção de programas para fins específicos como, por exemplo, para cál-
culos de pagamentos de funcionários, fornecedores, controles de estoque, gestão de
frotas de veículos, peças ou contabilidade (próximo exemplo), o código fica visivel-
mente mais simples e compreensível pelo programador.
Outros tipos de dados também podem ser renomeados com o comando typedef, e
sua aplicação vai além dos exemplos mostrados aqui, visto que ele pode ser utilizado
em estruturas, classes, e outros recursos do C++ que estão fora do escopo deste

76
++
Princípios de programação em C

livro-texto.
1 # include < iostream >
2

3 typedef double Moeda ; // Renomeia o tipo ’ double ’


4

5 using namespace std ;


6

7 int main ()
8 {
9

10 Moeda Salario = 6250.75;


11 Moeda Desconto = 1164.23;
12

13 Moeda PgtoTotal ;
14

15 PgtoTotal = ( Salario - Desconto ) ;


16

17 cout << " Salario ...: " << Salario << endl ;
18 cout << " Desconto ..: " << Desconto << endl ;
19 cout << " Pgto Total : " << PgtoTotal << endl ;
20

21 return 0;
22 }

4.1.7 Constantes
Em C++ as ’constantes’ são muito parecidas com as variáveis, porém com a carac-
terística de o seu valor permanecer inalterado durante toda a execução do programa.
As constantes podem ser de valores numéricos e também de valores não numéricos,
como strings, por exemplo. Qualquer tentativa de modificar o valor de uma cons-
tante irá gerar, em tempo de execução, um erro no programa. Há basicamente duas
formas de declarar uma constante:

• #define: usado para declarar constantes no início do programa. As constantes


declaradas com #define são constantes globais e poderão ser acessadas por
qualquer função, em qualquer parte do programa. Ao usar #define é necessário
informar o valor da constante.

• const: usado para declarar constantes dentro do programa principal, ou dentro


de procedimentos e funções. As constantes declaradas com const têm o seu
escopo restrito ao procedimento dentro do qual elas são declaradas.

As ’constantes globais’ são definidas antes da função int main(), como no exem-
plo a seguir:

77
++
Princípios de programação em C

1 # include < iostream >


2

3 # define Pi 3.14159
4 # define g 9.80665
5 # define R 8.31446
6 # define Erro1 " Erro ao ler os dados ! "
7 # define Erro2 " Erro ao gravar os dados "
8 # define ICMS 0.18
9

10 using namespace std ;


11

12 int main () {
13 float Raio = 2.25;
14 float Area = Pi * Raio * Raio ;
15 float Massa = 5.0;
16 float Dens = Massa / ( Raio * Area ) ; // Altura = Raio ;
17 float Preco = 2500.00;
18 float Imposto = Preco * ICMS ;
19

20 cout << " Densidade ...........: " << Dens << endl ;
21 cout << " Constante dos gases .: " << R << endl ;
22 cout << " Imposto da compra ...: " << Imposto << endl ;
23 cout << " Mensagem ............: " << Erro1 << endl ;
24

25 return 0;
26 }

As ’constantes locais’ são declaradas dentro do corpo do programa principal


(dentro de int main()) e no interior de procedimentos e funções. Para a declaração
local é necessário especificar o tipo de valor a ser considerado constante (linhas de
8 a 15 no exemplo a seguir).
1 # include < iostream >
2 # include < string >
3

4 using namespace std ;


5

6 int main () {
7

8 const float Pi = 3.14159;


9 const float g = 9.80665;
10 const float R = 8.31446;
11 const int Max = 100;
12

13 const string Erro1 = " Erro ao ler os dados ! " ;


14 const string Erro2 = " Erro ao gravar os dados " ;
15 const string Erro3 = " Erro ao excluir os dados " ;

78
++
Princípios de programação em C

16

17 float Raio = 2.25;


18 float Area = Pi * Raio * Raio ;
19

20 float Massa = 5.0;


21 float Dens = Massa / ( Raio * Area ) ; // Altura = Raio ;
22

23 cout << " Densidade ...........: " << Dens << endl ;
24 cout << " Constante dos gases .: " << R << endl ;
25 cout << " Mensagem ............: " << Erro1 << endl ;
26

27 return 0;
28 }

A declaração de constantes facilita a operação com dados do tipo vetor de ca-


racteres, visto que se houver alterações no tamanho total da string, essa alteração
poderá será feita em um único local do programa como, por exemplo, na linha 2 do
código apresentado a seguir.
1 # include < iostream >
2 # define TamMax 30 // Modificar apenas aqui !
3

4 using namespace std ;


5

6 int main () {
7

8 char vAmostra [ TamMax ]; // Nome da amostra ;


9 char vLab [ TamMax ]; // Nome do laboratorio ;
10 char vTec [ TamMax ]; // Nome do tecnico analista ;
11

12 cout << " Amostra ....: " ; cin . get ( vAmostra , TamMax ) ;
13 cin . ignore () ;
14

15 cout << " Laboratorio : " ; cin . get ( vLab , TamMax ) ;


16 cin . ignore () ;
17

18 cout << " Analista ...: " ; cin . get ( vTec , TamMax ) ;
19 cin . ignore () ;
20

21 return 0;
22 }

Como boa prática de programação, em geral, declara-se as constantes com no-


mes significativos, simples, curtos e autoexplicativos. É comum que os nomes de
constantes sejam escritos sempre com letras maiúsculas. Uma das vantagens de tra-
balhar com constantes, e declará-las logo no início do programa, é que caso o valor
da constante tenha que ser alterado, essa alteração ocorre apenas em um único local

79
++
Princípios de programação em C

do código, que é na linha onde a constante foi declarada.


Quando for necessário trabalhar com um número muito grande de constantes, a
melhor alternativa consiste em colocá-las em um arquivo externo, e referenciar3 esse
arquivo a partir do programa principal.
O código a seguir mostra como deve ser o conteúdo de um arquivo externo
intitulado arbitrariamente de ’Constantes.h’, usado para armazenar os valores de
constantes numéricas. Qualquer outro nome poderia ser dado a esse arquivo, mas
deve-se observar que sua extensão deve ser .h, e que ele deverá ser colocado na
mesma pasta ou diretório onde se encontra o arquivo executável (.exe) do programa
no qual as constantes são utilizadas.
1 // Conteudo do arquivo " Constantes . h "
2 # ifndef C O N S T A N T E S _ H _ I N C L U D E D
3 # define C O N S T A N T E S _ H _ I N C L U D E D
4

5 # define AVOGADRO 6.022 E23


6 # define GRAVIDADE 9.80665
7 # define BOLTZMANN 1.3806488 E -23
8 # define VELOCLUZ 299792458
9 # define PI 3.14159265359
10 # define PLANK 6.62606896 E -34
11 # define PERMISSIVIDADE 8.854187817 E -12
12 # define COULOMB 8.9875517874 E9
13

14 # endif

No código acima, as constantes são declaradas nas linhas de 5 até 12. Os


comandos nas linhas 2 e 3 são conhecidos como header guard, e são obrigatórios.
Servem para evitar um problema relacionado à dupla inclusão (ou dupla referenciação)
de arquivos externos (arquivos .h), o que pode gerar um erro de compilação do
programa. O comando na linha 14 indica o final do arquivo externo ’Constantes.h’.
Mais detalhes da criação de arquivos externos serão apresentados no Capítulo 13.
A referenciação de um arquivo externo de constantes é algo bem simples, e está
exemplificada no programa apresentado a seguir.
1 # include < iostream >
2 # include " Constantes . h " // Arquivo externo de constantes
3

4 using namespace std ;


5

6 int main () {
7 cout << " Valor do PI : " << PI << endl ;
8 return 0;
9 }

3
É o mesmo que incluir ou ’chamar’ o arquivo externo para dentro do programa principal, por meio
de uma referência ao seu nome e à sua localização no computador.

80
++
Princípios de programação em C

O Code::Blocks possui um recurso bastante útil e intuitivo para auxiliar na criação


de arquivos externos (arquivos com extensão .h). Esse recurso gera automaticamente
o arquivo .h e inclui os comandos de header guard no início do arquivo, bem como
o comando ’#endif’ ao seu final. O acesso ao módulo construtor de arquivos .h é
feito por meio do seguinte menu de opções.

Menu File → New → From template... → Files (opçãos na lateral esquerda da


janela ’New from template’) → C/C++ header → Go.

4.1.8 Definição de macros por meio da diretiva #define


Além do #define poder ser utilizado para declarar constantes, ele permite também
que algumas funcionalidades de ’macro’ possam ser adicionadas ao programa. Em
geral essas macros são ’automações’ para procedimentos simples como, por exemplo,
para o cálculo da área de um retângulo, como mostrado na linha 2 do exemplo a
seguir:
1 # include < iostream >
2 # define AreaRet (b , h ) ( b * h ) // macro para calculo da area ;
3

4 using namespace std ;


5

6 int main ()
7 {
8 float Base = 5.25;
9 float Altura = 6.24;
10 float Area = AreaRet ( Base , Altura ) ;
11 cout << " Area do retangulo : " << Area << endl ;
12 return 0;
13 }

A macro no próximo exemplo é utilizada para decidir qual é o maior, ou o menor,


entre dois valores passados como argumentos.
1 # include < iostream >
2 # define Maior (a , b ) (a > b ? a : b )
3 # define Menor (a , b ) (a < b ? a : b )
4

5 using namespace std ;


6

7 int main () {
8 float Valor1 = 7.56;
9 float Valor2 = 8.87;
10 cout << " Maior valor : " << Maior ( Valor1 , Valor2 ) << endl ;
11 cout << " Menor valor : " << Menor ( Valor1 , Valor2 ) << endl ;
12 return 0;
13 }

81
++
Princípios de programação em C

Outros exemplos de macros estão apresentados a seguir.


1 # define Quadrado ( x ) ( x ) *( x ) // Quadrado de x
2 # define Cubo ( x ) ( x ) *( x ) *( x ) // Cubo de x
3 # define Soma (x , y ) ( x ) +( y ) // Soma x e y
4 # define Divide (a , b ) ( a ) /( b ) // Divisao a / b
5 # define Media (a , b ) ( ( a ) + ( b ) ) / 2 // Media
6 # define Modulo ( x ) ((( x ) < 0) ? -( x ) : ( x ) ) // Modulo de x
7 # define AreaCirc ( r ) 3.141516 * ( r ) * ( r ) // Area circulo
8 # define AreaTrap (B ,b , h ) ((( B ) + ( b ) ) *( h ) ) /2 // Area trapezio
9 # define RadTOGrau ( x ) (( x ) * 57.29578) // Rad -> Grau
10 # define Print ( i ) ( cout << i << endl ) // Imprime ’i ’
11 # define SWAP (a , b ) { double temp =( a ) ;( a ) =( b ) ;( b ) = temp ;} // SWAP

Muitas macros já vêm pré-definidas pelo compilador C++ e podem ser acessadas
sem nenhuma declaração prévia. Algumas dessas macros estão apresentadas no
código a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5

6 cout << " Data atual ..........: " << __DATE__ << endl ;
7 cout << " Hora atual ..........: " << __TIME__ << endl ;
8 cout << " Nome do arquivo .....: " << __FILE__ << endl ;
9 cout << " Linha atual .........: " << __LINE__ << endl ;
10 cout << " Compilador ANSI C ...: " << __STDC__ << endl ;
11 cout << " Versao do compilador : " << __VERSION__ << endl ;
12 cout << " C ou C ++............: " << __cplusplus << endl ;
13 return 0;
14 }

Além das macros apresentadas nas linhas 6 e 7 do código acima, alguns recursos
para manipulação de data e hora já foram abordados anteriormente neste capítulo,
na seção 4.1.5, p.71.

4.2 Os argumentos argc e argv da função int main()


Em algumas situações é necessário passar argumentos para um programa a partir da
linha de comandos, pelo terminal do Windows ou do Linux, logo quando o programa
é inicializado. Nesse caso, os parâmetros são passados para a função int main() a
partir de argc e argv.

• argc: é um valor inteiro que informa para a int main() a quantidade de argu-
mentos que serão passados no prompt de comandos ao chamar o programa.

82
++
Princípios de programação em C

• argv: é um vetor de caracteres que contém os argumentos passados para a


int main().
A posição argv[0] armazena o nome do programa que foi executado no prompt
de comandos, e assim, argc deve assumir valor maior ou igual a 1 (um). Ao
passar os argumentos na linha de comandos, esses devem ser separados por
espaços ou por caracteres de tabulação (tecla TAB do teclado).

O exemplo a seguir mostra como podemos passar para um programa dois nume-
rais a partir do prompt de comandos e processar internamente esses valores numé-
ricos.
1 # include < iostream >
2 # include < cstdlib > // Para a funcao atof ;
3

4 # define Maior (a , b ) (a > b ? a : b )


5

6 using namespace std ;


7

8 int main ( int argc , char * argv [ ])


9 {
10

11 float Valor1 = atof ( argv [1]) ; // Recebe o primeiro valor ;


12 float Valor2 = atof ( argv [2]) ; // Recebe o segundo valor ;
13

14 cout << " Maior valor ....: " << Maior ( Valor1 , Valor2 ) <<
endl ;
15 cout << " Qtd . argumentos : " << argc << endl ;
16

17 return 0;
18 }

No código acima, a função atof() da biblioteca cstdlib serve para converter para
float a informação alfanumérica armazenada nas posições 1 e 2 de argv. Para a
conversão de valores inteiros deve-se utilizar a função atoi(). A seguir é mostrado
um exemplo de como esse código é executado na linha de comandos do terminal do
MS Windows e a sua saída correspondente.
1 C :\ > Teste . exe 9.668 6.478 < ENTER >
2 Maior valor ....: 9.668
3 Qtd . argumentos : 3

No ambiente Linux, o programa pode ser executado da seguinte maneira:


1 ~ $ ./ teste 9.668 6.478 < ENTER >
2 Maior valor ....: 9.668
3 Qtd . argumentos : 3

83
++
Princípios de programação em C

4.3 Comandos de atribuição e comparação de valores


4.3.1 Comandos de atribuição simples e múltipla
O caractere de atribuição (’=’) é utilizado para atribuir valores às variáveis, con-
forme apresentado e discutido em exemplos anteriores. Na forma como foi utilizado,
esse tipo de atribuição é chamado de atribuição simples. Entretanto o símbolo de
igualdade pode também ser utilizado para atribuição múltipla, como mostrado no
próximo exemplo.
1 int v1 , v2 , v3 , v4 , v5 ; // Declara 5 variaveis inteiras ;
2 float w1 , w2 , w3 ; // Declara 3 variaveis float ;
3

4 v1 = v2 = v3 = 22; // Atribuicao multipla ;


5 v4 = ( v5 = 68) ; // Atribuicao multipla ;
6 w1 = w2 = ( w3 = 5.25) ; // Atribuicao multipla ;

4.3.2 Operador de comparação de valores


Em C++ o símbolo duplo de igualdade (’==’) não tem a função de atribuição. Esse
símbolo serve para comparar se dois valores são, ou não, iguais entre si. No código
a seguir esse operador verifica se o valor da variável ’w1’ é numericamente igual ao
valor da variável ’w2’.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 double w1 = 10.668; double w2 = 16.628;
5 if ( w1 == w2 ) { // Compara os valores w1 e w2 ;
6 cout << " Os valores w1 e w2 sao iguais " << endl ;
7 } else {
8 cout << " Os valores w1 e w2 sao diferentes " << endl ;
9 }
10 return 0;
11 }

O operador de comparação é muito utilizado em testes lógicos, em especial


aqueles feitos com o comando if(), inicialmente apresentado no Capítulo 3, Seção
3.1.2, p.20, e discutido em mais detalhes no Capítulo 5.

4.4 Operadores matemáticos, regras de precedência,


conversão entre tipos e castings
Os operadores matemáticos básicos do C++ estão apresentados na Tabela 4.3. No
Capítulo 7 serão discutidos detalhes mais aprofundados de operações e o usos de

84
++
Princípios de programação em C

funções matemáticas pré-definidas na biblioteca cmath do C++ .

Tabela 4.3: Operadores matemáticos básicos do C/C++ .


Operador Descrição
+ Adição
- Subtração
* Multiplicação
\ Divisão
% Resto da divisão entre dois valores inteiros
Fonte: Elaborada pelos autores.

Em geral discute-se sobre a precedência4 das operações matemáticas ao utili-


zar os operadores da Tabela 4.3. Essas regras de precedência não serão abordadas
em detalhes aqui, pois envolvem conceitos mais avançados de programação, como
árvores binárias, parametrização de equações matemáticas e notação polonesa re-
versa, entre outros. Entretanto, na prática, o leitor poderá se valer de um método
mnemônico bem simples, conhecido como PEMDAS (Parêntesis, Expoentes e raí-
zes, Multiplicação, Divisão, Adição e Subtração), que opera sempre da esquerda
para a direita, para identificar a ordem execução das operações em uma expressão
 √ 
matemática. Assim, por exemplo, na expressão: 5 + 3 × 4 − 7 2
+ 36/5 .

Avaliação 1:) 3 × 4 − 72 = (3 × (4 − 49)) = (3 × −45) = −135




√ 
Avaliação 2:) 36/5 = (6/5) = 1, 2

Avaliação 3:) 5 + (−135) + 1, 2 = −128, 8 ← resultado final.

No exemplo a seguir pode-se observar o efeito da ordem de utilização dos parên-


tesis sobre os resultados de cálculos matemáticos em C++ .
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 float w1 , w2 , w3 , w4 ;
5 w1 = 6.25; w2 = 9.47; w3 = 7.59; w4 = 1.36;
6 cout << " Resp 1: " << ( w1 / w2 ) + ( w3 / w4 ) << endl ;
7 cout << " Resp 2: " << w1 / ( w2 + w3 ) / w4 << endl ;
8 cout << " Resp 3: " << ( w1 / w2 + w3 ) / w4 << endl ;
9 cout << " Resp 4: " << w1 / ( w2 + w3 / w4 ) << endl ;
10 return 0;
11 }
4
Ordem, prioridade ou sequência com que as operações matemáticas são avaliadas e resolvidas
pela Unidade Lógica Aritmética do processador do computador.

85
++
Princípios de programação em C

12 // Saidas : Resp 1: 6.24086 Resp 2: 0.269378


13 // Resp 3: 6.06616 Resp 4: 0.415258

4.4.1 Conversão entre tipos de dados


Para alguns tipos de dados pode haver a necessidade de convertê-los em outros
tipos, antes que estes possam efetivamente ser utilizados dentro de um programa.
As conversões mais utilizadas entre os tipos de dados são as que estão listadas a
seguir.

• vetor de caracteres → inteiro: esta conversão utiliza a função atoi() (con-


versão alfanumérico para inteiro) da biblioteca cstdlib:
1 # include < iostream >
2 # include < cstdlib >
3 using namespace std ;
4

5 int main () {
6

7 char vValor1 [10] , vValor2 [10];


8 cout << " Digite inteiro 1: " ; cin . getline ( vValor1 , 10) ;
9 cout << " Digite inteiro 2: " ; cin . getline ( vValor2 , 10) ;
10

11 int Soma = atoi ( vValor1 ) + atoi ( vValor2 ) ;


12 cout << " Soma ............: " << Soma << endl ;
13 return 0;
14 }

• vetor de caracteres → float ou double: esta conversão utiliza a função atof()


(conversão alfanumérico para ponto flutuante) da biblioteca cstdlib:
1 # include < iostream >
2 # include < cstdlib >
3 using namespace std ;
4

5 int main () {
6 char vValor1 [10] , vValor2 [10];
7 cout << " Digite float 1: " ; cin . getline ( vValor1 , 10) ;
8 cout << " Digite float 2: " ; cin . getline ( vValor2 , 10) ;
9

10 float Soma = atof ( vValor1 ) + atof ( vValor2 ) ;


11

12 cout << " Soma ..........: " << Soma << endl ;
13 return 0;
14 }

86
++
Princípios de programação em C

• inteiro → float ou double: A conversão de um valor inteiro para os tipos float


ou double é feita simplesmente atribuindo-se o valor inteiro às variáveis float
ou double.
1 # include < iostream >
2 # include < cstdlib >
3

4 using namespace std ;


5

6 int main () {
7

8 int ValorInt = 125;


9 float ValorFlt = ValorInt ;
10 double ValorDbl = ValorInt ;
11

12 cout << " Valor inteiro : " << ValorInt << endl ;
13 cout << " Valor float ..: " << ValorFlt << endl ;
14 cout << " Valor double .: " << ValorDbl << endl ;
15

16 return 0;
17 }

• double/float → inteiro: Esse tipo de conversão envolve duas novidades. A


primeira é que é necessário forçar a conversão do tipo double/float para o tipo
inteiro, e isso é feito com o casting (int), colocado no lado direito do sinal
de igual (linha 10, do exemplo a seguir). A outra novidade é que antes de o
valor ser convertido é necessário arredondá-lo com o uso da função round() da
biblioteca cmath.
1 # include < iostream >
2 # include < cmath >
3

4 using namespace std ;


5

6 int main () {
7 int ValorInt ;
8 double ValorDbl = 7.745;
9

10 ValorInt = ( int ) ( round ( ValorDbl ) ) ;


11

12 cout << " Valor double .: " << ValorDbl << endl ; // 7.745
13 cout << " Valor inteiro : " << ValorInt << endl ; // 8
14

15 return 0;
16 }

87
++
Princípios de programação em C

Caso a função round() não seja utilizada, o casting (int) fará a conversão do valor
float/double para inteiro, tomando apenas a sua parte inteira, ou seja, antes do ponto
decimal, e todos os numerais que vêm após a casa decimal serão descartados.
1 ValorInt = ( int ) ( ValorDbl ) ;
2 cout << " Valor double .: " << ValorDbl << endl ; // 7.745
3 cout << " Valor inteiro : " << ValorInt << endl ; // 7

Os castings podem ser utilizados sempre que houver necessidade de forçar a


conversão de tipos. No exemplo a seguir, o valor armazenado em uma variável do
tipo float é convertido em um valor do tipo double com o casting (double).
1 float ValorFlt = 9.125;
2 double ValorDbl ;
3 ValorDbl = ( double ) ( ValorFlt ) ;

A seguir um exemplo do uso de castings para forçar a conversão de diferentes


tipos para double ao realizar cálculos com variáveis numéricas.
1 # include < iostream >
2 # include < cmath >
3

4 using namespace std ;


5

6 int main () {
7

8 float Pressao = 101325;


9 double ConstGases = 0.082057;
10 int NumMols = 2;
11 float Kelvin = 273.15;
12 double Volume ;
13

14 Volume = ( ( double ) NumMols * ConstGases * ( double ) Kelvin ) ;


15 Volume = Volume / ( ( double ) Pressao ) ;
16

17 cout << " Volume ..: " << Volume << endl ; //
18

19 return 0; // Saida : 0.000442415


20 }

Ainda no que se refere à conversão de tipos, as variáveis declaradas como string


herdam recursos típicos da biblioteca cstring, como, por exemplo, facilidades para
realizar conversões de numerais para strings e vice-versa, que podem ser feitos com
as seguintes funções:

• stoi: Converte string para integer

• stol: Converte string para long integer

88
++
Princípios de programação em C

• stoul: Converte string para unsigned integer

• stoll: Converte string para long integer

• stoull: Converte string para unsigned long integer

• stof: Converte string para float

• stod: Converte string para double

• stold: Converte string para long double

• to_string: Converte um valor numérico para string

4.5 Operadores lógicos e relacionais


Os operadores lógicos e relacionais mais utilizados em C++ estão listados na Tabela
4.4. A utilização desses operadores quase sempre é feita com os comandos de
decisão, em especial o if(). Alguns exemplos de utilização desses operadores estão
apresentados após a Tabela 4.4, adaptada de DAVIS (2014).

Tabela 4.4: Operadores lógicos e relacionais do C/C++ .


Operador Descrição
< Menor que
<= Menor ou igual
= Igual (para atribuição de valores)
> Maior que
>= Maior ou igual
== Operador de comparação
!= Diferente (não igual a)
&& Operador lódigo E
|| Operador lódigo OU
! Operador lódigo NÃO
?: Operador condicional ternário
Fonte: Elaborada pelos autores.

1 if ( a > b ) {...}
2 if ( pH <= 4.5) {...}
3 if ( Temper == 82.5) {...}
4 if ( Concentracao != 7.78) {...}
5 if (( pH >= 4.5) && ( Temper <= 85.8) ) {...}
6 if ((( x > L1 ) && ( x < L2 ) ) || (( y < L3 ) && ( y > L4 ) ) ) {...}
7 float ( pH =3.89) , Temper ; pH < 4.25 ? Temper =121: Temper =90;

89
++
Princípios de programação em C

4.6 Operadores numéricos de incremento e de decre-


mento
Os operadores de incremento e de decremento permitem alterar dinamicamente o
valor de uma variável numérica, modificando o seu valor em uma unidade, para mais
ou para menos. Esses operadores são especialmente úteis nos laços de repetição,
como for() e while(), e subrotinas que realizam contagens numéricas, localização de
registros em arquivos de dados, seleção de itens em listas, etc. Os operadores mais
utilizados são:

• x++: (Incremento) Primeiro faz a atribuição e só depois aumenta o valor da


variável x em uma unidade.
1 int a = 30;
2 int valor ;
3 valor = a ++;
4 cout << " Valor : " << valor << endl ; // Valor = 30
5 cout << " a ..... " << a << endl ; // a = 31

• x--: (Decremento) Primeiro faz a atribuição e só depois diminui o valor da


variável x em uma unidade.
1 int a = 30;
2 int valor ;
3 valor = a - -;
4 cout << " Valor : " << valor << endl ; // Valor = 30
5 cout << " a ..... " << a << endl ; // a = 29

• ++x: (Incremento a priori) Primeiro incrementa o valor da variável x e depois


faz a atribuição.
1 int a = 30;
2 int valor ;
3 valor = ++ a ;
4 cout << " Valor : " << valor << endl ; // Valor = 31
5 cout << " a ..... " << a << endl ; // a = 31

• --x: (Decremento a priori) Primeiro decrementa o valor da variável x e depois


faz a atribuição.
1 int a = 30;
2 int valor ;
3 valor = --a ;
4 cout << " Valor : " << valor << endl ; // Valor = 29
5 cout << " a ..... " << a << endl ; // a = 29

90
++
Princípios de programação em C

• Atribuição composta. Exemplos apresentados a seguir:


1 soma += valor ; // soma = soma + valor ;
2 soma += 1; // soma = soma + 1;
3 soma *= 10; // soma = soma * 10;
4 soma *= ++ valor ; // soma = soma * ( valor + 1) ;
5 soma /= -- valor ; // soma = soma / ( valor - 1) ;

4.7 Declaração de variáveis com a instrução register


A instrução register diz ao sistema operacional que ao alocar espaço para uma variável
este deverá fazê-lo em um registro do processador, e não na memória RAM. É o
sistema operacional que irá decidir se isso será feito ou não, em tempo de execução
do programa.
Em geral as variáveis declaradas com register são acessadas mais rapidamente,
entretanto essa forma de declaração poderá gerar erros de execução do programa ao
tentar acessar o endereço da variável por meio de ponteiros. A forma de utilização
da instrução register é a que está apresentada a seguir. Declarar variáveis com a
instrução register pode ser uma boa opção ao trabalhar com laços de repetição do
tipo for() ou while(), discutidos em mais detalhes no Capítulo 6.
1 register int i ;
2 i = 100;

4.8 Atividades para fixação da aprendizagem


1. Variáveis booleanas e variáveis inteiras

(a) Construa um programa no qual o usuário deverá informar a DBO (de-


manda bioquímica de oxigênio, mg/L) e a DQO (demanda química de
oxigênio, mg/L) de uma lagoa de sedimentação de resíduos de uma in-
dústria de alimentos. O programa deve obrigatoriamente conter variáveis
booleanas para decidir se os valores digitados pelo usuário estão, ou não,
acima dos valores máximos permitidos pela legislação.
i. Máximo legal de DBO: até 50 mg/L.
ii. Máximo legal de DQO: até 150 mg/L.
(b) Modifique o programa anterior de modo que ele possa também levar em
consideração os limites máximos dos seguintes resíduos industriais:
i. Temperatura do efluente: máximo 40 graus Celsius.
ii. Materiais sedimentáveis: até 1 ml/L.
iii. Concentração de óleos e graxas: até 50 mg/L.

91
++
Princípios de programação em C

iv. Cobre: até 1 mg/L


v. Zinco: até 5 mg/L
vi. Nitrogênio amoniacal total: até 20 mg/L

2. Indeterminação matemática e valores infinitos

(a) Explique o que são os símbolos apresentados a seguir, e em que tipos de


situações eles podem aparecer durante a execução de alguns programas:
i. +inf
ii. -inf
iii. -nan

3. Variáveis do tipo char

(a) Por que podemos fazer as atribuições mostradas a seguir? A variável


do tipo char não deveria receber somente um valor do tipo caractere?
Explique porque isso é permitido.
1 char vLetra = 65;
2 char vSimb = ’\ n ’

(b) O que é um vetor de caracteres? Explique e dê um exemplo.


(c) Explique como podemos inicializar um vetor de caracteres. Dê dois exem-
plos para cada modo de inicialização apresentado.
(d) Qual a diferença em utilizar o cin e o cin.get? Em que situações eles são
utilizados? Dê um exemplo.
(e) Descreva qual é a finalidade das seguintes funções. Dê um exemplo para
cada uma delas.
i. strcpy, strncpy, strcat, strlen e strcmp

4. Variáveis do tipo string padrão C++

(a) Escreva um programa que utilize variáveis declaradas como ’string’ para ler
o nome de quatro empresas fornecedoras de produtos para uma indústria.
Após a digitação dos nomes pelo usuário, esses devem ser impressos na
tela do computador, juntamente com o tamanho da string que foi digitada.
(b) O que você entende por ’concatenação de strings’? Explique e dê dois
exemplos.
(c) Explique para que servem os métodos clear(), insert(), append() e com-
pare() que operam sobre ’strings’. Dê um exemplo da utilização de cada
um desses métodos.

92
++
Princípios de programação em C

(d) Explique para que servem os métodos swap(), erase(), find() e substr()
que operam sobre ’strings’. Dê um exemplo da utilização de cada um
desses métodos.

5. Enumerações

(a) Explique o são as ’enumerações’. Para que servem? Quando são utiliza-
das?
(b) Escreva um programa (à sua escolha!) que obrigatoriamente utilize uma
enumeração para decidir sobre turnos de trabalho em uma indústria: ’ma-
nhã=1’, ’tarde=2’, ’noite=3’.

6. Variáveis para data e hora

(a) O que é UTC (Tempo Universal Coordenado) no fuso horário? Explique.


(b) Qual é o UTC do Brasil? Explique.
(c) Como calcular a hora UTC? Explique e dê dois exemplos.
(d) O que é GMT (Greenwich Mean Time)? Explique e dê um exemplo.
(e) Escreva um programa que imprima na tela do computador a data e a hora
atual.
(f) Modifique o programa da Atividade 1 de modo que ela armazene tam-
bém, além dos valores de DBO, DQO e outros poluentes, a data e a
hora da última análise realizada na lagoa de sedimentação da indústria.
Além disso, acrescente ao programa a função sleep() de modo a manter
por 10 segundos na tela do computador, logo após a digitação dos da-
dos, a seguinte mensagem: ’Verificar o prazo de validade dos sensores de
monitoramento da lagoa!’.

7. Tipos personalizados com typedef

(a) Escreva um programa que utilize o comando typedef para criar os seguin-
tes tipos personalizados:
i. ’Temperatura’, ’Produto’ e ’Lote’.

8. Constantes e macros

(a) Escreva três programas (i, ii e iii) nos quais sejam declaradas e utilizadas
as seguintes constantes:
i. Gravidade, g = 9, 80665, e massa M = 12, 5 kg.
ii. pH crítico, pH = 4, 5, e Temperatura de esterilização Te = 121, 1 o C.
iii. Pressão máxima, PMax = 1, 82 atm, e Força F~ = 16 N.

93
++
Princípios de programação em C

(b) Qual a diferença ao declarar constantes com as instruções #define e


const. Explique e dê dois exemplos de cada uma.
(c) O que são macros? Para que servem? Explique e dê dois exemplos de
utilização.

9. Os argumentos argc e argv do int main()

(a) Escreva um programa com as seguintes características:


i. Que use os parâmetros argc e argv para ler três valores numéricos
a partir do prompt de comandos e imprima esses valores na tela do
computador.
ii. Os valores lidos para dentro do programa devem ficar em variáveis do
tipo int, declaradas com ’atribuição múltipla’ dentro do programa, e
todas inicialmente com valor igual a zero.

10. Operador de comparação

(a) Escreva um programa que leia 5 (cinco) valores inteiros digitados pelo
usuário. Se algum dos valores digitados for exatamente igual à ’-1’, então
o programa deverá exibir uma mensagem para o usuário: ’Programa ter-
minado!’, aguardar 5 segundos (função sleep()) e, em seguida, encerrar
o programa.
(b) Explique qual é a diferença entre o ’operador de atribuição’ e o ’operador
de comparação’ em C++ . Dê um exemplo.

11. Conversão de dados e castings

(a) O que são castings? Para que eles servem? Em que situações são utili-
zados? Dê três exemplos.
(b) O que você entende por ’conversão’ de tipos de dados? Explique e dê
três exemplos.

12. Operadores relacionais

(a) O que são operadores lógicos relacionais? Para que servem? Explique e
dê quatro exemplos de sua utilização.

13. Operadores de incremento e de decremento

(a) Utilize o debugger do Code::Blocks e avalie o que acontece com as va-


riáveis no código a seguir.

94
++
Princípios de programação em C

1 # include < iostream >


2 using namespace std ;
3 int main () {
4 int x1 , x2 , x3 , x4 ;
5 x1 = 6; x2 = x1 ++; x2 ++;
6 x3 = ( x1 ++) - (++ x2 ) ;
7 x4 = x1 + x2 + ( - - x3 ) ;
8 x4 += x2 ; x3 -= x1 ;
9 x1 - -; x1 += ( - - x2 ) ;
10 return 0;
11 }

Responda: Qual o valor final em cada variável? Em seu relatório final


coloque os ’prints’ da janela do debugger, ou uma tabela com os valores
das variáveis em cada uma das linhas do programa.

14. Declaração de variáveis com register

(a) Qual a diferença em declarar uma variável com a instrução ’register’ e


sem essa instrução? Explique e dê um exemplo de como essa declaração
é feita.

95
Capítulo 5

Desvios condicionais

Conteúdo do capítulo
5.1 Desvios condicionais em C++ . . . . . . . . . . . . . . . . 96
5.1.1 Desvio condicional simples . . . . . . . . . . . . . . . . . . 96
5.1.1.1 Uso do operador interrogação (operador ternário) 96
5.1.2 Desvio condicional composto . . . . . . . . . . . . . . . . 98
5.1.3 if ’s aninhados . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.1.4 As instruções switch(), case, break e default . . . . . . . . 103
5.2 Atividades para fixação da aprendizagem . . . . . . . . . 106

5.1 Desvios condicionais em C++


Os desvios condicionais compreendem um grupo de instruções utilizadas para verificar
se uma condição é verdadeira ou falsa, e a partir dai, permitir a tomada de decisões
dentro do programa. Embora sejam bastantes simples, os desvios condicionais são
muito versáteis, e oferecem ao programador toda a funcionalidade para avaliar os va-
lores das variáveis em diferentes situações. Alguns dos desvios condicionais tratados
neste capítulo já foram apresentados anteriormente na forma de exemplos.

5.1.1 Desvio condicional simples


5.1.1.1 Uso do operador interrogação (operador ternário)
Talvez o desvio condicional mais simples seja aquele que faz o uso do operador ’ ?’
(interrogação), conhecido por ’operador ternário’. Com esse operador pode-se tomar
decisões simples. Sua sintaxe está apresentada a seguir.

<Condição>?<Verdadeiro>:<Falso>

96
++
Princípios de programação em C

O que esse comando faz é avaliar a condição colocada antes do símbolo de


interrogação. Se a condição for verdadeira, será executada a instrução passada
como parâmetro <Verdadeiro>. Se a condição for falsa, será executada a condição
<Falso>. Os exemplos a seguir mostram como utilizar o operador ternário para a
tomada de decisões.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main () {
6

7 int x ;
8

9 cout << " Digite um valor ..: " ;


10 cin >> nValor ;
11 cin . ignore () ;
12

13 ( x >= 10) ? ( cout << " X >= 10 " ) : ( cout << " X < 10 " ) ;
14

15 return 0;
16 }

1 # include < iostream >


2 # include < cstring >
3

4 using namespace std ;


5

6 int main () {
7

8 float pH ; // Valor do pH do alimento


9 string Seguranca ; // String ’ SIM ’ ou ’ NAO ’
10

11 cout << " Informe o pH .: " ;


12 cin >> pH ;
13 cin . ignore () ;
14

15 ( pH < 4.5) ? ( Seguranca = " SIM " ) : ( Seguranca = " NAO " ) ;
16

17 cout << " Pode ser consumido ? " << Seguranca << endl ;
18

19 return 0;
20 }

97
++
Princípios de programação em C

5.1.2 Desvio condicional composto


O desvio condicional composto faz o uso do comando if()...else() para a tomada de
decisões. É a estrutura de testes condicionais mais comum em praticamente todas
as linguagens de programação. A sua sintaxe está apresentada logo a seguir.

if(<Condição>)
{
instruções;
}
else
{
instruções;
}
A ’<condição>’ é um parâmetro que deve ser obrigatoriamente informado ao
utilizar o comando if()...else(). O par de chaves delimita o espaço dentro do qual
as instruções devem ser inseridas, para serem executadas caso a condição seja ver-
dadeira. O ’else’ não é obrigatório, mas se for utilizado serve para especificar uma
tomada de decisão alternativa, caso a condição seja falsa. Os operadores de compa-
ração utilizados pelo comando if()...else() são os mesmo que já foram apresentados
anteriormente na Tabela 4.2, p.89.
1 x = 10;
2

3 if ( x >= 45)
4 {
5 cout << " Temperatura maior ou igual a 45 Celsius " << endl ;
6 }
7 else
8 {
9 cout << " Temperatura menor que 45 Celsius " << endl ;
10 }

No exemplo acima, caso a condição avaliada seja verdadeira (temperatura >= 45


Celsius), então será executado o bloco de instruções compreendido entre as linhas
4 e 6. Caso contrário, será executado o bloco de instruções compreendido entre as
linhas 8 e 10.
Aqui vale ressaltar que o bloco de códigos entre as linhas 4 e 6 poderia ser
composto por um número maior de instruções, se estendendo por muitas linhas. O
mesmo é válido para o bloco de códigos que está compreendido entre as linhas 8 e
10, que poderia ser composto por mais instruções, se estendendo também por muitas
linhas de programação.
As condições podem ser compostas por diferentes operadores de comparação,
e nesta situação deverão ser agrupadas dentro de parêntesis, como mostrado nos
exemplos a seguir. Alguns exemplos do uso de operadores lógicos relacionais já

98
++
Princípios de programação em C

foram apresentados e discutidos anteriormente no Capítulo 4 (Seção 4.5, p.89, e


também na Tabela 4.4, p.89). Esses operadores serão amplamente utilizados em
muitos exemplos de programas apresentados neste livro.
1 if ( ( Seguro == false ) && ( Temper < 65 ) && ( pH <= 4.5) )
2 { ... instrucoes ;}

1 if ( ( x < 6) && ( y >= x ) && ( ( y <= 60) || ( z != y ) ) )


2 { ... instrucoes ;}

1 if ( !( x > 5) )
2 { ... instrucoes ;}

A condição a ser avaliada também poderá ser uma função, uma subrotina ou
mesmo uma macro declarada com #define, como no exemplo a seguir.
1 # include < iostream >
2 # define Soma (x , y ) ( x ) +( y )
3

4 using namespace std ;


5

6 int main () {
7

8 float Valor1 , Valor2 ;


9

10 cout << " Valor 1.: " ;


11 cin >> Valor1 ;
12 cin . ignore () ;
13

14 cout << " Valor 2.: " ;


15 cin >> Valor2 ;
16 cin . ignore () ;
17

18

19 if ( Soma ( Valor1 , Valor2 ) >= 100 )


20 {
21 cout << " A soma resulta em valor maior ou igual a 100 " ;
22 }
23 else
24 {
25 cout << " A soma resulta em valor menor que 100 " ;
26 }
27

28 return 0;
29 }

Caso seja do interesse do programador, a cláusula ’else’ também poderá espe-


cificar alguma condição a ser avaliada. Isso é especialmente útil ao tomar decisões

99
++
Princípios de programação em C

baseadas em faixas de valores numéricos dentro das quais pode haver exceções.
No exemplo a seguir a condição será verdadeira se os valores de x estiverem
dentro da faixa que vai de 10 a 110, inclusive esses valores extremos, situação essa
na qual o processador irá executar os comandos compreendidos entre as linhas 2 e
4. Caso o valor de x esteja fora desse intervalo, então o processador irá executar
o bloco alternativo de códigos, compreendido entre as linhas 6 e 8, mas esse bloco
alternativo somente será executado se o valor de x for diferente de 120.
1 if ( ( x >= 10) && ( x <= 110) )
2 {
3 ... instrucoes aqui ;
4 }
5 else if ( ( x != 120) )
6 {
7 ... instrucoes aqui ;
8 }

É permitido ter mais de uma cláusula ’else’, como mostrado no código a seguir.
O compilador avaliará todas as cláusulas ’else’, uma por vez, e sairá imediatamente
do comando if()...else() assim que encontrar algum ’else’ que possa ser executado.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5

6 double x = 25; double y = 63; double z ;


7

8 if ( ( ( x + y ) > 40 ) && ( (y - x ) < 100) ) // Verdadeiro ! Nao


9 { // avaliara as ou
10 z = 121.15; // tras condicoes .
11 }
12 else if ( ( x + y ) != 77 ) // Nao avaliado
13 {
14 z = 93;
15 }
16 else // Nao avaliado
17 {
18 z = (x+y);
19 }
20 cout << " x + y .......: " << ( x + y ) << endl ; // 88
21 cout << " Valor de z : " << z << endl ; // 121.15
22 return 0;
23 }

No exemplo a seguir, apenas a condição (x > 20) é que será executada. Ao ter-
minar de executar o bloco contido entre as linhas 12 e 14, o processador abandonará

100
++
Princípios de programação em C

os comandos if()...else() e saltará para a próxima linha, imediatamente após a linha


de número 17.
1 double x = 25;
2

3 if ( x > 100) { // Sera avaliado


4 cout << " x > 100 " << endl ;
5 }
6 else if ( x < 10) { // Sera avaliado
7 cout << " x < 10 " << endl ;
8 }
9 else if ( x > 85) { // Sera avaliado
10 cout << " x > 85 " << endl ;
11 }
12 else if ( x > 20) { // Apenas este bloco
13 cout << " x > 20 " << endl ; // sera executado
14 }
15 else if ( x == 25) { // Esta condicao nao
16 cout << " x = 25 " << endl ; // sera avaliada
17 }

5.1.3 if’s aninhados


É permitido a inserção de um bloco if()...else() dentro de um outro bloco if()...else(),
compondo assim uma ’estrutura aninhada’ de if’s. A quantidade de if’s aninhados
é restrita apenas ao limite do compilador, que para o GNU GCC utilizado pelo
Code::Blocks é de 256 níveis (limite máximo de if’s aninhados). Ao utilizar if’s
aninhados o programador deve ficar atento à logica de programação, às condições
que deverão ser avaliadas, os limites avaliados e os operadores de comparação.
Ao trabalhar com if’s aninhados é muito comum a ocorrência de erros de lógica
e, para esse tipo de erro, o processo de compilação não irá gerar erros de execução,
e o programa será compilado normalmente. O C++ não fará nenhuma análise para
verificar se as condições são possíveis, ou não, de serem testadas, sendo que essa
atribuição fica exclusivamente por conta do programador.
Caso o programa apresente mal funcionamento, tome decisões erradas ou forneça
valores estranhos como resultados, então o programador deverá fazer uma análise
passo-a-passo do seu código. Uma boa estratégia consiste em utilizar alguma ferra-
menta de depuração de código, como aquela que foi apresentada no final do Capítulo
3, Seção 3.7, p.39.
O exemplo apresentado a seguir mostra como os if’s podem ser aninhados. Para
facilitar a visualização dos níveis de aninhamento é comum fazer um recuo do texto,
deslocando em cada linha os comandos um pouco mais para a direita. Isso pode ser
feito com a tecla TAB, ou mesmo acrescentando alguns espaços antes do início de
cada linha. Um erro bastante comum ao trabalhar com if()...else(), e qualquer outro

101
++
Princípios de programação em C

comando de desvio condicional, é o programador se esquecer de fechar um colchete.


Nesse caso será gerado um erro de compilação e o programa não será gerado pelo
compilador.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5

6 float pH = 4.2; // pH ;
7 float ConcX = 0.50; // Concentracao de X ;
8 float ConcY = 1.25; // Concentracao de Y ;
9 float DQO = 0.00; // Demanda oxigenio ;
10

11 if ( pH < 4.5)
12 {
13 if ( ( ConcX > 0.25) && ( ConcX <= 045) )
14 {
15 DQO = 2.47 * ConcY ;
16 }
17 else
18 {
19 DQO = 0.58 * ConcY ;
20

21 if ( DQO > 8)
22 {
23 DQO = 6.25;
24 }
25 else
26 {
27 DQO = 4.82;
28 }
29 }
30 }
31 else
32 {
33 DQO = 1.26;
34 }
35

36 cout << " pH ....: " << pH << endl ; // 4.2


37 cout << " ConcX .: " << ConcX << endl ; // 0.5
38 cout << " ConcY .: " << ConcY << endl ; // 1.25
39 cout << " DQO ...: " << DQO << endl ; // 3.0875
40

41 return 0;
42 }

102
++
Princípios de programação em C

5.1.4 As instruções switch(), case, break e default


A instrução switch já foi apresentada anteriormente no Capítulo 4, Seção 4.1.4,
p.69). Essa instrução permite a tomada de decisões baseada no valor de uma variável.
É uma estrutura diferente do if()...else() devido ao fato de não aceitar operadores
de comparação. Outra diferença é que o switch avalia todos os blocos condicionais
em sequência, ou seja, se a condição verdadeira estiver no primeiro bloco do switch,
todos os demais blocos também serão avaliados, independentemente do número de
blocos que compõem o switch. A sua sintaxe básica é a que está apresentada a
seguir.
switch(<variável>)
{
case <constante 1>:
instruções;
break;
case <constante 2>:
instruções;
break;
case <constante n>:
instruções;
break;
[default]:
instruções;
}
O exemplo a seguir mostra como utilizar o swich para construir um simples menu
de opções em um programa para conversão de valores de temperatura.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 int Escolha ; double Temper ;
5

6 cout << " ===[ CONVERSAO DE TEMPERATURA ]=== " << endl ;
7 cout << " 1 - De Celsius para Kelvin " << endl ;
8 cout << " 2 - De Kelvin para Celsius " << endl ;
9 cout << " 3 - De Celsius para Fahrenheit " << endl ;
10 cout << " = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = " << endl ;
11 cout << " --> DIGITE 1 , 2 ou 3 ou outra le " << endl ;
12 cout << " tra para sair " << endl ;
13 cout << " = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = " << endl ;
14 cout << " --> ESCOLHA .: " ;
15 cin >> Escolha ; // Le a tecla digitada pelo
16 cin . ignore () ; // usuario : 1 , 2 ou 3
17 cout << endl ;

103
++
Princípios de programação em C

18

19 switch ( Escolha )
20 {
21 case 1:
22 cout << " Temperatura em Celsius .: ";
23 cin >> Temper ;
24 Temper += 273.15;
25 cout << " Temperatura em Kelvin ..: " << Temper << endl ;
26 break ;
27 case 2:
28 cout << " Temperatura em Kelvin ..: ";
29 cin >> Temper ;
30 Temper -= 273.15;
31 cout << " Temperatura em Celsius .: " << Temper << endl ;
32 break ;
33 case 3:
34 cout << " Temperatura em Celsius .: ";
35 cin >> Temper ;
36 Temper = ( Temper * 1.8) + 32;
37 cout << " Temperatura Fahrenheit .: " << Temper << endl ;
38 break ;
39

40 default :
41 cout << " Terminado ! " << endl << endl ;
42 }
43 return 0;
44 }

No programa acima, o bloco identificado por ’default’ (na linha 40) será execu-
tado se o usuário informar qualquer outro valor diferente dos valores 1, 2 ou 3 no
menu de opções.
O switch pode ser combinado com quaisquer outros elementos e comandos da
programação C++ com o objetivo de aumentar as funcionalidades de um programa.
No exemplo a seguir o switch é utilizado para avaliar o tipo de parâmetro passado
como argumento na linha de comando do programa por meio de argc e argv.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ( int argc , char * argv [] )


6 {
7 switch (* argv [1])
8 {
9 case ’a ’:
10 cout << " O parametro foi <a > " ;
11 break ;

104
++
Princípios de programação em C

12 case ’b ’:
13 cout << " O parametro foi <b > " ;
14 break ;
15 case ’c ’:
16 cout << " O parametro foi <c > " ;
17 break ;
18 default :
19 cout << " Parametro desconhecido " << endl << endl ;
20 }
21 return 0;
22 }

No exemplo a seguir o switch é usado em conjunto com uma enumeração (ver


detalhes sobre enumerações no Capítulo 4, Seção 4.1.4, p.68), permitindo ao usuário
escolher uma determinada opção de cor.
1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 int CodCor ;
7 enum Cor { Verde = 1,
8 Azul = 2,
9 Branco = 3,
10 Amarelo = 4};
11

12 cout << " Informe codigo da cor [1 a 4].: " ;


13 cin >> CodCor ;
14 cin . ignore () ;
15

16 switch ( CodCor )
17 {
18 case Verde :
19 cout << " Escolheu cor VERDE " << endl ; break ;
20 case Azul :
21 cout << " Escolheu cor AZUL " << endl ; break ;
22 case Branco :
23 cout << " Escolheu cor BRANCA " << endl ; break ;
24 case Amarelo :
25 cout << " Escolheu cor AMARELA " << endl ; break ;
26 default :
27 cout << " Cor invalida ! Tente outra " << endl << endl ;
28 }
29

30 return 0;
31 }

105
++
Princípios de programação em C

5.2 Atividades para fixação da aprendizagem


1. Usos do operador ternário

(a) O que é o operador ternário ’ ?’. Como ele deve ser utilizado? Dê quatro
exemplos de sua utilização.

2. Usos dos desvios condicionais (simples e composto)

(a) Escreva um programa que solicite ao usuário a entrada de dois valores


numéricos inteiros. Utilize o comando if() para decidir qual dos dois va-
lores digitados é maior. Use o objeto cout para imprimir na tela apenas
o maior entre os valores digitados.
(b) Escreva um programa que solicite ao usuário o valor do pH e da atividade
de água (aw ) de um alimento enlatado particular. O programa deve de-
cidir sobre a segurança microbiológica do alimento, e imprimir na tela o
resultado de sua análise, com base nos seguintes critérios:
i. Se: pH ≥ 4,5 e aw ≥ 0,98, Então: ’alimento com altíssimo risco
microbiológico’.
ii. Caso contrário se: pH ≥ 4,5 e (0,86 ≤ aw < 0,98), Então: ’alimento
com alto risco microbiológico’.
iii. Caso contrário se: pH ≥ 4,5 e (aw < 0,86), Então: ’alimento com
alto risco microbiológico’.
iv. Caso contrário se: pH < 4,5 e (0,72 ≤ aw < 0,86), Então: ’alimento
com moderado risco microbiológico’.
v. Caso contrário se: pH < 4,5 e (0,60 ≤ aw < 0,72), Então: ’alimento
com baixo risco microbiológico’.
vi. Caso contrário se: pH < 4,5 e aw < 0,60, Então: ’alimento com
muito baixo risco microbiológico’.
(c) Escreva um programa que solicite ao usuário o valor de quatro proprie-
dades do escoamento de um fluido em uma tubulação de secção circular
operando completamente cheia:
i. Densidade do fluido (ρ, em kg/m3 ).
ii. Velocidade média do escoamento (v̄ , em m/s).
iii. Diâmetro do tubo no qual o fluido escoa (D, em m).
iv. Viscosidade dinâmica do fluido (µ, em kg/(m × s)).
Em seguida, o programa deverá calcular o Número de Reynolds para
esse escoamento conforme a Equação 5.1

ρ × v̄ × D
NRey = (5.1)
µ

106
++
Princípios de programação em C

O programa deverá avaliar o valor de NRey e informar para o usuário


qual é o regime de escoamento do fluido, conforme o seguinte critério:
A. NRey ≤ 2100: Regime de escoamento ’laminar’.
B. NRey ≥ 4000: Regime de escoamento ’turbulento’.
C. 2100 < NRey < 4000: Regime de escoamento ’de transição’.
(d) Escreva um programa que solicite ao usuário as medidas dos três lados
de um triângulo. Declare as variáveis como sendo do tipo double. O
programa deverá utilizar o desvio condicional composto para classificar o
triângulo entre as seguintes classes:
i. Triângulo equilátero: quando possui os três lados com medidas
iguais.
ii. Triângulo isósceles: quando possui dois lados com medidas iguais.
iii. Triângulo escaleno: quando possui os três lados com medidas dife-
rentes.
(e) Modifique o programa anterior de modo a acrescentar mais uma funciona-
lidade a ele: o programa deverá também solicitar ao usuário que digite os
valores de seus três ângulos internos (tipo double), e classificar o triângulo
também quanto à medida de seus ângulos:
i. Triângulo acutângulo: quando possui todos os ângulos com as me-
didas inferiores a 90 graus.
ii. Triângulo retângulo: quando possui um ângulo com medida igual a
90 graus.
iii. Triângulo obtusângulo: quando possui um ângulo obtuso, maior que
90 graus.
(f) Escreva um programa que solicite ao usuário o valor ta temperatura ótima
de crescimento de um microrganismo (tipo float) e em seguida faça a
classificação do microrganismo de acordo com os seguintes critérios:
i. Psicrófilos: microrganismos têm o ótimo de crescimento em tempe-
raturas entre 0 e 20 graus Celsius.
ii. Psicrotróficos: microrganismos têm o ótimo de crescimento em tem-
peraturas entre 0 e 7 graus Celsius.
iii. Mesófilos: microrganismos têm o ótimo de crescimento em tempe-
raturas entre 25 a 40 graus Celsius.
iv. Termófilos: microrganismos têm o ótimo de crescimento em tempe-
raturas entre 45 e 65 graus Celsius.
v. Termodúricos: microrganismos têm o ótimo de crescimento em tem-
peraturas acima de 80 graus Celsius.
vi. Não classificado: microrganismos cuja temperatura ótima de cresci-
mento não se enquadra nas classificações acima (usar ’else()...if()’).

107
++
Princípios de programação em C

(g) Escreva um programa que solicite ao usuário as seguintes informações


sobre a qualidade do leite cru que chega à plataforma de recepção de
uma indústria de laticínios:

i. Acidez Dornic x. Amido


ii. Teste do Alizarol xi. Formol
iii. Índice crioscópico xii. Álcool
iv. Resíduos de antibióticos xiii. Sacarose
v. pH xiv. Peróxidos
vi. Densidade xv. Alcalinos
vii. Redutase xvi. Extrato seco total
viii. Gordura xvii. Extrato seco desengordurado
ix. Cloretos xviii. Contagem de células somáticas

O programa deverá verificar o valor que o usuário digitar para cada um


dos itens acima, comparar com os valores de referência da legislação e
imprimir na tela resultados do tipo: ’atende à legislação’ ou ’não atende
à legislação’, para cada um dos itens avaliados.
Obs: Esse programa para Análise de Conformidade do Leite deverá será
feito com base nos limites legais, estabelecidos pelas atuais portarias do
Ministério da Agricultura (MAPA), que deverão ser consultadas e estuda-
das antes da elaboração do programa.

3. Uso de operadores condicionais

(a) Escreva um programa que decida sobre as condições de execução de um


processo industrial hipotético. Os critérios estão listados a seguir:
i. Se (Temper ≥ 45,0 e pH < 6,3) ou (Temper ≤ 48,0 e Dens ≥
1.350,0) Então: imprimir na tela ’Usar desidratação osmótica’.
ii. Caso contrário se (Temper ≥ 52,0 e pH < 5,2) ou (Temper ≤
56,0 e Dens ≥ 1.259,0) Então: imprimir na tela ’Usar secador de
bandejas’.
iii. Caso contrário se (Temper ≥ 60,0) ou (pH < 4,5 ou pH > 3,2)
ou (Dens > 997,4 e Dens ≤ 1.115,9) Então: imprimir na tela ’usar
secador solar’.

4. Uso de if’s aninhados

(a) Avalie o programa a seguir com o debugger do Code::Blocks e informe


o valor final das variáveis a, b, c e d. Em seu relatório final coloque os
’prints’ da janela do debugger.

108
++
Princípios de programação em C

1 # include < iostream >


2 using namespace std ;
3 int main () {
4 int a , b , c , d ;
5 b = 42; c = 26; d = 13;
6 if (( ( b > 16) && ( b < 64) ) || (( c - d ) > 125) ) {
7 a = 14; c = 3* a ;
8 } else if ( ( a > 13) || ((2* c ) > 0) ) {
9 b = 3* a ; c = -42* d ; d ++;
10 } else if ( c < 0) {
11 a += (b - -) + ( c ++) + ( - - d ) ; b = a ++; c -= 3* b ;
12 }
13 return 0;
14 }

(b) Sem utilizar o debugger do Code::Blocks, verifique o valor final de cada


variável do exemplo a seguir. Em seu relatório final, coloque o passo-a-
passo de como obteve o valor de cada variável durante a execução do
programa, desde o início até o seu final.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4 int x , y , z , k , w ;
5 x = 15; z = 26;
6 if ( z > x ) {
7 y = 65; w = 96;
8 if (( x < w ) && (( z + y ) < (2* w ) ) ) {
9 k = 165; w += x ; --x ;
10 if ( x < 18) {
11 w ++; y - -; --w ; z -= x ;
12 } else {
13 w - -; y ++; ++ w ; z += x ;
14 if (( z <= 100) || ( z >= 100) ) {
15 z ++;
16 } else {
17 if (( x + y + z ) < 100) {
18 x ++; z - -; w += (++ k ) + ( - - y ) + z ;
19 }
20 }
21 }
22 }
23 }
24 return 0;
25 }

109
++
Princípios de programação em C

5. Uso do switch(), case, break e default

(a) Escreva um programa que tenha o menu principal de um programa para o


gerenciamento do estoque de materiais de um Laboratório de Desenvolvi-
mento de Novos Produtos, (DNP). O menu deve ser igual ao apresentado
a seguir. Nas configurações do terminal (Linux ou MS Windows), altere
as dimensões da tela para 80x25 (80 colunas e 25 linhas), de modo a
acomodar corretamente todas as linhas e colunas do programa.
O programa deverá ler, a partir do teclado, a opção escolhida pelo usuário.
Para isso, utilize o comando switch(). O programa deverá aceitar que
o usuário digite apenas as letras (em maiúsculo) apresentadas no lado
esquerdo de cada opção do menu. Caso o usuário digite uma opção
inválida, o programa deverá limpar a tela (ver funções para limpar a tela
no Capítulo 8, Seção 8.1.2.6, p.163) e apresentar o menu de opções
novamente.

==========================================================
CTRL DE ESTOQUE DE MATERIAIS - LABORATORIO DE DNP - UFLA
==========================================================
>>>> MENU PRINCIPAL DO MODULO DE CTRL DE ESTOQUE:
----------------------------------------------------------
[A] - INCLUSAO DE NOVOS PRODUTOS
[X] - EXCLUSAO DE PRODUTOS <BUSCA POR CODIGO DE BARRAS>
[D] - EXCLUSAO DE PRODUTOS <BUSCA POR DESCRICAO>
[M] - ALTERACAO DE DADOS DE CADASTRO DO PRODUTO

>>>> REGISTRO DE ENTRADA OU SAIDA DE PRODUTOS DO ESTOQUE:


----------------------------------------------------------
[E] - REGISTRO DE ENTRADA DE PRODUTOS NO ESTOQUE
[S] - REGISTRO DE SAIDA DE PRODUTOS DO ESTOQUE

>>>> RELATORIOS GERENCIAIS:


----------------------------------------------------------
[P] - LISTAGEM DAS ENTRADAS E SAIDAS [POR DATA/PERIODO]
[N] - LISTAGEM DE PRODUTOS [POR NUM. DA NOTA FISCAL]
[T] - LISTAGEM DE PRODUTOS [POR TRANSPORTADORA]
[F] - LISTAGEM DE PRODUTOS [POR FORNECEDOR]
[L] - LISTAGEM DE PRODUTOS EM QTD MINIMA [LOW STOCK]
[V] - LISTAGEM DE PRODUTOS PROXIMOS AO VENCTO [POR DIAS]

>>> ESCOLHA UMA OPCAO [Q PARA SAIR]..:


==========================================================

110
Capítulo 6

Laços de repetição e tratamento de


exceções

Conteúdo do capítulo
6.1 Laços de repetição em C++ . . . . . . . . . . . . . . . . . . 111
6.1.1 O laço ’for()’ . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.1.2 O laço ’while{}’ . . . . . . . . . . . . . . . . . . . . . . . 117
6.1.3 O laço ’do while{}’ . . . . . . . . . . . . . . . . . . . . . . 118
6.1.4 Laços aninhados e os comandos break e continue . . . . . 119
6.1.5 O temido salto incondicional goto . . . . . . . . . . . . . . 122
6.2 O tratamento de exceções com try, throw e catch . . . . 123
6.3 Atividades para fixação da aprendizagem . . . . . . . . . 126

6.1 Laços de repetição em C++


Os laços de repetição são estruturas presentes em praticamente todas as linguagens
de programação e sua finalidade é fazer com que um bloco de instruções seja repetido
indefinidamente ou por um certo número de vezes.
Essas estruturas são utilizadas com diferentes finalidades como, por exemplo,
para percorrer uma lista de nomes até que algum nome específico seja localizado.
Servem para percorrer as diferentes células em uma matriz ou vetor para fins de
leitura ou gravação de informações, e até mesmo para executar um bloco de códigos
por uma quantidade muito grande de vezes, até que algum critério de parada seja
estabelecido.
Neste capítulo serão apresentados os principais laços de repetição da linguagem
C/C++ . O leitor deverá estar bem familiarizado com as sintaxes desses laços e
se habituar a utilizar seus recursos, em função da elevada frequência com que são
utilizados em praticamente todos os tipos de programas.

111
++
Princípios de programação em C

6.1.1 O laço ’for()’


O comando for() é usado quando o programador necessita repetir um determinado
bloco de instruções por um número definido de vezes. O bloco de instruções será
repetido até que alguma condição de interrupção se torne verdadeira. A sua sintaxe
está descrita a seguir.

for([variável]; [condição]; [incremento ou decremento])


{
instruções;
}

Variável: É uma variável inteira ou de ponto flutuante que será utilizada como con-
tador durante os ciclos de repetição.

Condição: A [condição] refere-se a algum critério lógico capaz de assinalar a inter-


rupção do comando for().

Incremento/decremento: Nesta seção do comando for() é definida a forma como


será feito o incremento ou decremento da ’variável contadora’.

Para compreender o funcionamento do comando for(), suponha que o programa-


dor queira listar na tela do computador os números de 1 a 10, em ordem crescente,
sendo um número por linha. A forma mais simples de fazer isso é como está no
código a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 cout << " 1 " << endl ;
6 cout << " 2 " << endl ;
7 cout << " 3 " << endl ;
8 cout << " 4 " << endl ;
9 cout << " 5 " << endl ;
10 cout << " 6 " << endl ;
11 cout << " 7 " << endl ;
12 cout << " 8 " << endl ;
13 cout << " 9 " << endl ;
14 cout << " 10 " << endl ;
15 return 0;
16 }

Entretanto se o objetivo fosse listar na tela os números de 1 a 100, o programador


certamente teria um grande trabalho, e o programa poderia ficar excessivamente
extenso. A situação seria ainda pior se o objetivo fosse listar desde 1 (um) até

112
++
Princípios de programação em C

valores muito maiores, como 1 × 108 , por exemplo. Neste caso a construção do
programa se tornaria uma tarefa impraticável.
O comando for() permite reescrever o mesmo programa acima, porém de uma
forma mais elegante e simplificada, como mostrado a seguir.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7

8 int i ; // i = Variavel contadora


9

10 for ( i =1; i <11; i = i +1) // O bloco de instrucoes sera


11 { // repetido enquanto a varia
12 cout << i << endl ; // vel ’i ’ estiver assumindo
13 } // diferentes valores , desde
14 // i =1 ate i =10. Em cada repe
15 return 0; // ticao a variavel i sera in
16 } // crementada de uma unidade .

Uma possível interpretação para o comando for() entre as linhas 10 e 13 do código


acima é: ”imprima na tela o valor de i, conforme especificado pela instrução na linha
12. O valor de i será inicializado com o valor 1 (um, i=1) e será incrementado em
cada ciclo iterativo (i=i+1), até chegar ao valor 10 (i < 11)”.
Se o programador quisesse listar na tela valores de i , desde 1 até 1000, bastaria,
portanto, modificar o critério de parada:
1 for ( i =1; i <1001; i = i +1)

Ou então:
1 for ( i =1; i <=1000; i = i +1)

Ao invés de usar a forma i=i+1 para fazer o incremento da variável i , é mais


comum utilizar a notação i++, como discutido anteriormente no Capítulo 4 (seção
4.6, página 90), e o comando for() do exemplo acima poderá ser reescrito como
apresentado a seguir.
1 for ( i =1; i <=1000; i ++)

Se a intenção do programador fosse listar na tela do computador os números de 1


a 1000, porém na ordem inversa, ou seja, do maior para o menor, então o ’operador
de decremento’ deveria ser utilizado.
1 for ( i =1000; i >0; i - -)

113
++
Princípios de programação em C

O programador deve ficar atento para não extrapolar os limites numéricos permi-
tidos para o tipo da ’variável contadora’ utilizada dentro do for(). Faixas de valores
para diferentes tipos de dados estão listados na Tabela 3.1, p.24.
Os valores de início e fim de um laço for() podem ser obtidos como resultado
de algum cálculo, serem valores constantes, definidos com #define ou const, ou
mesmo serem informados a partir do teclado.
1 int inicio = 1; int fim = 1000; int i = 0;
2

3 for ( i = inicio ; i <= fim ; i ++)


4 {
5 cout << i << endl ;
6 }

A ’variável contadora’ do laço for() não necessita, obrigatoriamente, ser incre-


mentada ou decrementada de uma unidade. Se a intenção do programador fosse
listar na tela os números de 1 a 1000 mas saltando de 2 em 2, então o incremento
seria i += 2 (ou i=i+2). Se fosse para saltar de 10 em 10, então o incremento seria
i += 10 (i=i+10), e assim por diante.
Diferentemente do exemplo acima, a variável contadora poderá ser declarada
dentro do comando for(), como mostrado na linha 1 (um) do código a seguir. Nesse
caso ela será uma variável local, e seu escopo será apenas o bloco de instruções
definido pelo comando for().
A declaração da variável contadora também poderá ser feita com a instrução
register (linha 2 (dois) do exemplo a seguir), caso o programador tenha a intenção de
declará-la em um registrador do processador (ver detalhes sobre a instrução register
no Capítulo 4, Seção 4.7, p.91).
1 for ( int i =0; i <=20; i ++) {...}
2 for ( register int i =0; i <=20; i ++) {...}

É possível fazer com o que laço for() execute quase infinitamente um bloco de
instruções. Para isso basta colocar alguma condição de parada que nunca se torne
verdadeira, ou então não especificar nenhuma condição de parada, como mostrado
a seguir.
1 for ( int i =0; ; i ++) {...} // laco for () infinito

Neste caso a interrupção do laço for() ocorrerá quando a variável contadora


chegar ao limite máximo permitido para o tipo int (ver Tabela 3.1, p.24), valor esse
considerado muito grande, ou ’infinito’, para a maioria das aplicações práticas.
Uma outra forma de fazer um laço for() infinito, consiste em não informar nenhum
parâmetro para o laço. Nesse caso o comando for() irá conter apenas os caracteres
de ponto e vírgula (’;’) dentro do par de parêntesis que compõe a sua sintaxe.
Durante a execução do programa esse laço pode ser interrompido manualmente pela
combinação das teclas CTRL+C, a partir do teclado.

114
++
Princípios de programação em C

1 long int i = 1;
2 for ( ; ; ) { // laco for () infinito
3 cout << i << endl ;
4 i ++;
5 }

O critério de parada poderá ser uma condição particular para alguma situação
específica. No Capítulo 4, Seção 4.1.3.1, p.57, discutiu-se que as strings do tipo
’vetor de caracteres’ terminam com o símbolo ’\0’. Assim, o comando for() pode ser
utilizado para percorrer todas as posições de um vetor de caracteres e parar apenas
quando o símbolo ’\0’ for encontrado. O próximo exemplo mostra como isso pode
ser feito.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 char vNome [80];
6 cout << " Digite seu nome .: " ; cin . getline ( vNome , 80) ;
7

8 for ( register int i =0; vNome [ i ] != ’ \0 ’; i ++) {


9 cout << vNome [ i ] << endl ;
10 }
11 return 0;
12 }

Se a declaração de uma variável do tipo string for feita com a instrução string, da
biblioteca string 1 , então o comando for() pode ser utilizado para percorrer todos os
caracteres contidos na variável, conforme mostrado a seguir. Neste caso é utilizado
o método size() para obter o tamanho total do texto contido na variável ’Aluno’.
O método size() já foi apresentado anteriormente2 ao discutir diferentes formas de
trabalhar com variáveis do tipo string.
1 # include < iostream >
2 # include < string >
3 using namespace std ;
4

5 int main () {
6 string Aluno = " Jose da Silva " ;
7 for ( register int i = 0; i < Aluno . size () ; i ++) {
8 cout << Aluno [ i ] << endl ;
9 }
10 return 0;
11 }

1
Ver Capítulo 4, Seção 4.1.3.2, p.62
2
Ver Capítulo 4, Seção 4.1.3.2, p.63

115
++
Princípios de programação em C

O comando break é utilizado para forçar a interrupção da execução de um laço


for(). Isso é especialmente útil quando é necessário sair do ciclo de repetições quando
uma dada condição se tornar verdadeira. No exemplo a seguir o for() está progra-
mado para fazer 10 ciclos de repetição, porém, quando a variável i for igual à 6
(seis) o laço será abruptamente interrompido e o programa continuará normalmente,
seguido os códigos que vêm após a linha 8 (após o laço for()). Assim, o comando
break é, portanto, uma forma de imediatamente interromper e saltar para fora de
um laço for().
1 for ( int i = 0; i < 10; i ++)
2 {
3 if ( i == 6)
4 {
5 break ;
6 }
7 cout << i << endl ;
8 }

Há também uma forma de saltar iterações dentro de um laço for(), e isso é feito
pelo comando continue. Esse comando quebra uma iteração do ciclo e vai para a
próxima iteração. No exemplo a seguir, o laço for() está programado para fazer 10
iterações e listar na tela o valor da variável i para cada uma dessas iterações, exceto
quando i assumir os valores 3 ou 5.
1 for ( int i = 1; i <= 10; ++ i )
2 {
3 if ( i == 3 || i == 5) { // Salta se : i =3 ou i =5
4 continue ;
5 }
6 cout << i << endl ;
7 }

O comando continue pode ser utilizado em várias outras situações dentro do laço
for(). No exemplo a seguir apenas os numerais ímpares de 1 a 100 serão listados
na tela do computador. Para fazer o for() saltar os números pares, foi utilizado o
continue e o operador ’%’, que calcula o resto da divisão entre dois números.
1 for ( int i = 1; i <= 100; i ++)
2 {
3 if ( i % 2 == 0) // Se o resto da divisao de i por 2
4 { // for igual a zero , entao nao faz
5 continue ; // nada , e salta para proxima iteracao
6 } // Imprime apenas os numeros impares
7 else
8 {
9 cout << i << endl ;
10 }
11 }

116
++
Princípios de programação em C

No próximo exemplo todos os números inteiros informados pelo usuário serão


somados e armazenados na variável ’vSoma’. O laço for() será interrompido e apre-
sentará o resultado final da soma apenas quando o usuário digitar o numeral zero,
um critério de parada estabelecido arbitrariamente pelo programador.
1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 int vSoma = 0;
7

8 for ( ; ; )
9 {
10 cout << " Digite valor inteiro [ ou 0 para sair ]: " ;
11 int vNumero ;
12 cin >> vNumero ;
13 cin . ignore () ;
14

15 if ( vNumero == 0) // Sai do laco for ()


16 {
17 break ;
18 }
19 vSoma += vNumero ;
20 }
21 cout << " Total ..: " << vSoma << endl ;
22 return 0;
23 }

6.1.2 O laço ’while{}’


O laço while() é semelhante ao laço for(). A diferença entre eles é que a condição
de interrupção ou término do while() deve ser estabelecida logo no início do laço.
Ao ser definida no início, o processador primeiro testa a condição, e o bloco de
códigos contido no while() somente será executado se a condição for verdadeira.
Dependendo da condição a ser testada, e se essa for falsa, poderá ocorrer de o bloco
de códigos não ser executado nenhuma vez. Nessa situação, a sintaxe do while() é
a que está apresentada a seguir.

while([condição])
{
instruções;
}
A seguir é apresentado um exemplo de uso do while() com teste a priori. O bloco
de códigos dentro do while() será executado enquanto a condição avaliada na linha

117
++
Princípios de programação em C

8 for verdadeira.
1 # include < iostream >
2 # include < string >
3 using namespace std ;
4

5 int main () {
6 int i =0;
7

8 while ( i < 20) // Primeiro testa se i < 20


9 { // antes de entrar no laco
10 i = i +1;
11 cout << i << endl ;
12 }
13

14 return 0;
15 }

6.1.3 O laço ’do while{}’


Outra possibilidade de uso do comando while() é quando o teste condicional é re-
alizado no final do laço. Nesta situação, o while() será chamado de ’do while()’, e
executado pelo menos uma vez. A sintaxe para o teste a posteriori é a que está a
seguir.
do
{
instruções;
} while (condição);

1 # include < iostream >


2

3 using namespace std ;


4

5 int main () {
6 int i =0;
7

8 do // Primeiro entra no laco . O teste


9 { // condicional vai ser realizado
10 i = i +1; // apenas no final do laco .
11 cout << i << endl ;
12 } while ( i < 20) ;
13

14 return 0;
15 }

118
++
Princípios de programação em C

Qualquer comando ou combinação dos comandos vistos até agora poderá ser
utilizado dentro do while(). Variáveis declaradas dentro de um while() serão válidas
apenas dentro do while() no qual elas foram declaradas3 .

6.1.4 Laços aninhados e os comandos break e continue


De modo semelhante ao que ocorre no laço for(), o while() também permite que
outros laços while(), ou mesmo laços for() sejam colocados em seu interior, caracte-
rizando uma estrutura de laços aninhados. A seguir um exemplo de como isso ocorre
nos programas em C++ .
1 # include < iostream > // Tabela de dados gerados
2 using namespace std ; // a partir de uma equacao
3

4 int main ()
5 {
6

7 int x = 0; int y = 0; float z = 0; int vLinha = 1;


8

9 while ( x < 20)


10 {
11 while ( y < 20)
12 {
13 z = (3 * ( x + 1) ) + (5 * ( y + 6) ) ;
14 cout << " Linha : " << vLinha << ’\ t ’
15 << x << ’\ t ’ << y << ’\ t ’ << z << endl ;
16 y ++; vLinha ++;
17 }
18 x ++; y = 0;
19 }
20 return 0;
21 }

Os comandos break e continue são utilizados para interromper ou saltar iterações


dentro de um laço while(), da mesma forma que foi feito para o laço for(). No
exemplo a seguir, o usuário irá digitar quantos numerais desejar para serem somados.
O processo continuará até que algum número negativo seja digitado e, quando isso
ocorrer, o laço while() será interrompido com o comando break, e o programa saltará
imediatamente para a linha 30. Na linha 32 o cout se encarregará de apresentar na
tela do computador o resultado final da soma dos números digitados.
Para mostrar o efeito do comando continue dentro do while(), o programa não
aceitará que valores maiores do que 100 (cem) sejam incluídos na soma (linha 17).
Assim, se o usuário digitar algum valor maior que 100, então esse valor será ignorado,
e o controle do ciclo iterativo do while() voltará para a linha 12.
3
Ver declaração de variáveis locais e variáveis globais no Capítulo 3, seção 3.4, p.25.

119
++
Princípios de programação em C

1 # include < iostream >


2 # include < iomanip >
3 using namespace std ;
4

5 int main ()
6 {
7

8 double Numero = 0.00; double Soma = 0.00;


9

10 while ( true ) // Executa o while indefinidamente


11 {
12 cout << " Digite um numero ..: " ;
13 cin >> Numero ; cin . ignore () ;
14

15 if ( Numero > 100) // Nao inclui na soma numeros que se


16 { // maiores do que 100.
17 continue ;
18 }
19

20 if ( Numero < 0.00)


21 {
22 break ; // Termina a entrada de dados se o
23 } // usuario digitar algum valor ne
24 else // gativo
25 {
26 Soma += Numero ;
27 }
28 }
29

30 cout . precision (6) ; // Resultados com 6 casas decimais


31 cout << setiosflags ( ios :: fixed ) ;
32 cout << " Soma ...: " << Soma ;
33 return 0;
34 }

No próximo exemplo o while() é empregado para fazer um ciclo de iterações ao


compor um menu de entrada de dados de um programa. Caso o usuário não informe
corretamente o valor de entrada, o menu de opções será novamente apresentado ao
usuário, permitindo a digitação de um novo valor.
Neste caso, antes de reapresentar o menu ao usuário para a digitação de um
novo valor, o programa deveria primeiro limpar a tela do computador e reposicionar
o cursor na sua primeira linha e primeira coluna, mas os comandos para limpar a tela
serão discutidos em mais detalhes somente no Capitulo 8 (seção 8.1.2.6, página 163),
portanto, neste momento, embora apresentado aqui, não é importante se preocupar
com esse tipo de funcionalidade, visto que será discutido mais adiante. Por enquanto

120
++
Princípios de programação em C

o importante é compreender o funcionamento do comando while() e como ele pode


ser usado em conjunto com outros comandos como, por exemplo, com o switch.
1 # include < iostream >
2 # include < stdlib .h > // Para usar a funcao " system () "
3 using namespace std ; // system (" clear ") -> Linux
4 // system (" cls ") -> Windows
5 int main ()
6 {
7

8 int Escolha ;
9

10 do
11 {
12 system ( " clear " ) ; // Limpa a tela
13 cout << " ====[ PROCESSAMENTO TERMICO ]==== " << endl ;
14 cout << " \ t [1] - Branqueamento " << endl ;
15 cout << " \ t [2] - Pasteurizacao " << endl ;
16 cout << " \ t [3] - Esterilizacao " << endl ;
17 cout << " = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = " << endl ;
18 cout << " Digite aqui ..: " ;
19 cin >> Escolha ;
20 cin . ignore () ;
21 } while (( Escolha <1) ||( Escolha >3) ) ;
22

23 switch ( Escolha )
24 {
25 case 1:
26 {
27 cout << " Voce escolheu BRANQUEAMENTO " << endl ;
28 break ;
29 }
30 case 2:
31 {
32 cout << " Voce escolheu PASTEURIZACAO " << endl ;
33 break ;
34 }
35 case 3:
36 {
37 cout << " Voce escolheu ESTERILIZACAO " << endl ;
38 break ;
39 }
40 }
41 return (0) ;
42 }

121
++
Princípios de programação em C

6.1.5 O temido salto incondicional goto


A instrução goto permite fazer um salto absoluto incondicional para qualquer outra
linha do programa. O problema de utilizar essa instrução é que ela, embora útil em
algumas situações, ignora completamente qualquer nível de aninhamento ou sequên-
cia lógica do programa, podendo saltar abruptamente para fora de qualquer laço
for(), while(), do while(), procedimento ou função. O local de destino do salto deve
ser identificado por um ’apelido’ (um label), que deverá ser utilizado pela instrução
goto. O nome desse label deve seguir os mesmos cuidados tomados ao dar nomes
para variáveis de memória (ver Capítulo 3, p.22) e além disso deve vir seguido de
dois pontos (’:’).
Deve-se sempre que possível evitar a utilização do goto dentro dos programas,
visto que é uma instrução que pode facilmente levar a loops infinitos caso o pro-
gramador não esteja muito ciente de sua utilização. Como vantagem o goto pode
tornar o código mais fácil de ser construído e implementado em algumas situações
muito particulares. Há programadores que abusam da quantidade de goto em seus
códigos, mas em geral os programas assim construídos são muito difíceis de serem
lidos ou serem submetidos a qualquer tipo de manutenção por uma outra equipe de
programadores. Como se costuma dizer, ’goto is bad!’ e portanto deve ser evitado
ou utilizado sempre com muita cautela. Uma boa prática consiste em substituir o
goto por instruções lógicas convenientes.
1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 int i =0;
7

8 for ( i =0; i <100; i ++)


9 {
10 cout << i << endl ;
11

12 if (i >=60)
13 {
14 goto Termina ; // Vai imediatamente para a linha 19
15 }
16

17 }
18

19 Termina :
20 cout << " Termina o programa abruptamente " << endl ;
21

22 return 0;
23 }

122
++
Princípios de programação em C

6.2 O tratamento de exceções com try, throw e catch


Em muitas situações podem ocorrer erros críticos durante a execução de um pro-
grama. Em C/C++ esses erros nem sempre são fáceis de serem identificados, pois
em sua maioria se devem a erros de lógica, e não de sintaxe ou de digitação, como
a falta de um ponto e vírgula no final de um comando.
Os erros mais comuns em C/C++ são aqueles relacionados a falhas na abertura de
arquivos, overflow nos limites permitidos para as variáveis, falha de hardware, divisão
por zero, acesso a índices inválidos em matrizes e vetores, utilização de objetos que
ainda não tenham sido inicializados, etc.
Para tratar a ocorrência de erros (exception handling, em inglês) o programador
pode se utilizar de um recurso do C++ que é composto por três instruções: try,
catch e throw.
• try: Representa um bloco de códigos dentro do qual pode surgir uma exceção
(um erro) durante a execução do programa.
• catch: Representa um bloco de códigos que deverá ser executado quando
ocorrer uma exceção.
• throw: É usado para ’lançar’ uma exceção. Também é usado para listar as
exceções lançadas por alguma função.
Para compreender melhor como o C++ faz o tratamento de exceções, façamos
a análise do código apresentado a seguir. Nesse programa é evidente que poderá
ocorrer um erro em tempo de execução ao tentar fazer uma divisão por zero, caso
em algum momento o valor zero seja digitado e atribuído à variável ’Den’.
1 # include < iostream >
2 using namespace std ;
3 int main () {
4

5 float Num , Den ;


6

7 cout << " Digite numerador ..: " ;


8 cin >> Num ;
9 cin . ignore () ;
10

11 cout << " Digite denominador : " ;


12 cin >> Den ;
13 cin . ignore () ;
14

15 cout << " Resultado .........: " ;


16 cout << ( Num / Den ) ;
17

18 return (0) ;
19 }

123
++
Princípios de programação em C

Para tentar resolver esse problema e tratar a possibilidade de ocorrência de uma


divisão por zero, o programador pode utilizar os comandos try, catch e throw como
no código a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5

6 float Num , Den ;


7

8 cout << " Digite numerador ..: " ;


9 cin >> Num ;
10 cin . ignore () ;
11

12 cout << " Digite denominador : " ;


13 cin >> Den ;
14 cin . ignore () ;
15

16 cout << " Resultado .........: " ;


17

18 try
19 {
20 if ( Den == 0)
21 {
22 throw 1; // Lanca uma excecao com valor
23 } // igual a 1 caso o denominador
24 else // seja igual a zero
25 {
26 cout << ( Num / Den ) ;
27 }
28 }
29 catch ( int erro ) // Gera uma mensagem descrevendo
30 { // o tipo de erro quando a exce
31 if ( erro == 1) // cao lancada for igual a 1
32 {
33 cout << " Erro de divisao por zero " << endl ;
34 }
35 }
36

37 return (0) ;
38 }

Dentro do bloco try (entre as linhas 18 e 28) é feito um teste lógico para verificar
se o denominador é igual à zero (linha 20). Caso essa condição seja verdadeira
e o denominador for igual a zero, então será ’lançada’ na linha 22 uma exceção
(um erro) com valor igual a ’1’ (um). Se a condição especificada na linha 20 for

124
++
Princípios de programação em C

falsa e o denominador for algum valor numérico diferente de zero, então não haverá
necessidade de lançar nenhuma exceção, e o comando dentro do bloco else (entre
as linhas 25 e 27) será executado normalmente, e o resultado da divisão Num/Den
será impresso na tela (linha 26).
Caso o denominador seja igual a zero e uma exceção tenha sido lançada (throw )
na linha 22, então essa exceção será capturada pelo bloco catch na linha 29, e o
número da exceção que foi lançada na linha 22 será passada como argumento para
o catch (linha 29). Dentro do bloco catch o erro será avaliado pelo comando if()
(na linha 31) e uma mensagem apropriada, referente ao erro de ’divisão por zero’
será exibida na tela do computador (linha 33), sem que ocorra nenhuma interrupção
ou fechamento forçado do programa.
Neste exemplo, apenas uma única exceção foi tratada, entretanto o programador
poderá avaliar, a seu critério, um número maior de exceções, bastando, para isso,
acrescentar mais condições a serem avaliadas dentro do bloco catch do código. O
exemplo a seguir mostra como isso pode ser feito quando o programador também
deseja impedir que denominadores sejam digitados com sinal negativo.
1 try
2 {
3 if ( Den == 0)
4 {
5 throw 1; // Lanca a primeira excecao
6 }
7 else
8 {
9 if ( Den < 0)
10 {
11 throw 2; // Lanca a segunda excecao
12 }
13 else
14 {
15 cout << ( Num / Den ) ;
16 }
17 }
18 }
19 catch ( int erro )
20 {
21 if ( erro == 1)
22 {
23 cout << " Erro de divisao por zero " << endl ;
24 }
25 if ( erro == 2)
26 {
27 cout << " Numeros negativos nao permitidos " << endl ;
28 }
29 }

125
++
Princípios de programação em C

6.3 Atividades para fixação da aprendizagem


1. O laço for()

(a) Escreva um programa que gere uma listagem dos valores de temperatura
entre 35 e 63 graus Celsius, e suas respectivas conversões para as escalas
Kelvin, Fahrenheit e Rankine, conforme o modelo apresentado a seguir.
As temperaturas devem ter incrementos de 0.001 graus Celsius, e devem
ser apresentadas na tela com três casas decimais. Para facilitar a leitura
do relatório, o início de cada linha deve ter uma enumeração sequencial,
começando de ’0001’. O relatório deve apresentar apenas 18 linhas por
página na tela do computador. No rodapé da tela deve haver uma opção
para o usuário encerrar o programa ou continuar a exibição da próxima
página da listagem.

===========================================================
TABELA DE CONVERSAO - ESCALAS DE TEMPERATURA
===========================================================

-----------------------------------------------------------
[Pg. 01] [Emitido em: 21/11/2019 - 13:52:00]
-------+---------------------------------------------------
| CELSIUS KELVIN FAHRENHEIT RANKINE
-------+---------------------------------------------------
0001 | 35.000 308.150 95.000 554.701
0002 | 35.001 308.151 95.002 554.672
0003 | 35.002 308.152 95.004 554.674
.... | ...... ....... ...... .......
0018 | 35.017 308.167 95.031 554.701
-------+--------------------------------------------------

>> Tecle <P> para exibir a proxima tela da tabela de dados


>> Tecle <Q> para fechar o programa
>> OPCAO....:
==========================================================

(b) Modifique o programa anterior, de modo que o usuário possa informar,


em tempo de execução do programa, qual é o valor inicial e qual o valor
final para a tabela de dados de temperatura.
(c) Escreva um programa que utilize o laço for() para contar desde zero
até cem milhões. O programa deverá imprimir na tela a hora atual do
sistema, imediatamente antes e após o laço for(). Apenas os valores de
’hora’, antes e após o for(), devem ser impressos na tela. Para utilizar

126
++
Princípios de programação em C

uma variável numérica inteira muito grande, esta deve ser dimensionada
como ’long int’. O objetivo do programa é estimar, em segundos, o tempo
que o computador gasta para contar desde zero até cem milhões.
(d) Escreva um programa que gere valores de x, y , z e w nas faixas de valores
especificados a seguir. Esses dados serão utilizados pela Equação 6.1 para
calcular o valor de φ. Os dados de todas as variáveis deverão ser impressos
na tela conforme o seguinte exemplo de relatório, que deverá apresentar
apenas 18 linhas por página na tela do computador. No rodapé da tela
deve haver uma opção para o usuário encerrar o programa ou continuar a
exibição da próxima página da listagem.

 
sen(3 ∗ x) 1
+ 1, 125 ∗ (z 0,08 ) + √ (6.1)
 
φ(x, y , z, w ) = 3
2 + cos(y ) w

x ∈ [2; 18], y ∈ [5; 9], z ∈ [7; 11], w ∈ [2; 6]. Todas as variáveis deverão
ter incremento de 0,01 dentro do laço for().

===========================================================
TABELA DE DADOS DA EQUAÇÃO PHI(x, y, z, w)
===========================================================

-----------------------------------------------------------
[Pg. 01] [Emitido em: 21/11/2019 - 20:06:07]
-------+--------------------------------+------------------
| x y z w | PHI(x, y, z, w)
-------+--------------------------------+------------------
0001 | 2.00 5.00 7.00 2.00 | 1.985846
0002 | 2.00 5.00 7.00 2.01 | 1.984527
0003 | 2.00 5.00 7.00 2.02 | 1.983218
.... | .... .... .... .... | ........
-------+--------------------------------+------------------

>> Tecle <P> para exibir a proxima tela da tabela de dados


>> Tecle <Q> para fechar o programa
>> OPCAO....:
===========================================================

(e) Escreva um programa que imprima na tela do computador os números de


1000 até 0, saltando de 5 em 5. Os números devem ser dispostos na tela
em 5 colunas.
(f) Escreva um programa que imprima na tela os valores de x (x ∈ [−10; 10]),
y (x), z(x), w (x) e r (x), conforme as equações de 1 a 4, a seguir:

127
++
Princípios de programação em C

1) y (x) = sin(x 2 ) + cos(x 3 )


1
2) z(y ) = y 2 + p 3
y2
3) w (z) = z 2 + 3.125z 1,22
4) r (x, y , z) = x + y − 6.25z
Os valores de x, y (x) e z(x) devem ser impressos em três colunas, uma
ao lado da outra, e todos os valores devem apresentar 6 casas decimais.
(g) Utilize o debugger do C++ para avaliar qual o valor final das variáveis x,
y e z durante a execução do programa a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int x , y , z ;
6 x = y = z = 104;
7

8 for ( x =0; x <50; x ++) {


9 for ( y =12; y >2; y - -) {
10 if (( x + y ) <16) {
11 z = 164;
12 }
13 else if (( x + y ) > 14) {
14 z = 236;
15 for ( int i =4; i <20; i ++) {
16 z -= ( x ++) + (2* y - -) ;
17 }
18 } else {
19 for ( int i =4; i <20; i ++) {
20 z += (x - -) + ( y ++) ;
21 }
22 }
23 }
24 }
25 return 0;
26 }

(h) A integração numérica de uma função matemática, y = f (x) é frequen-


temente realizada fazendo-se aproximações acumulativas das áreas (Ai )
de figuras geométricas mais simples.

128
++
Princípios de programação em C

y
y=f(x)

A1 A2 A3 A4 A5 A6 A7 A8

a x
b

Figura 6.1: Representação gráfica da integração numérica da função y = f (x), no


intervalo [a; b]. (Fonte: autores)

Na Figura 6.1, a área abaixo da curva descrita por y = f (x) é feita


pela soma das áreas de uma série de retângulos dispostos paralelamente
em um intervalo [a; b]. A Regra de 1/3 de Simpson (Equações 6.2 a
6.4) é frequentemente utilizada para a integração numérica de funções
matemáticas, como aquela apresentada na Figura 6.1.

Para a Regra de 1/3 de Simpson:


• A Equação 6.2 é a integral a ser avaliada no intervalo [a; b]

Z b
I= f (x)dx (6.2)
a

• m é o número de subintervalos sob a curva, e h é a largura de cada


um dos retângulos, considerada constante e igual para todos eles.

b−a
m= (6.3)
h
• O valor aproximado da integral I é dado pela Equação 6.4.

h
I= [f0 + 4 (f1 + f3 + f5 + · · · + fm−1 ) + 2 (f2 + f4 + f6 + · · · + fm )]
3
(6.4)

129
++
Princípios de programação em C

– Para cada uma das integrais apresentadas a seguir, escreva um


programa que utilize a Regra de 1/3 de Simpson para estimar o
seu valor numérico, considerando os intervalos de integração de
cada função. No cálculo de cada integral faça, no mínimo, 10.000
subintervalos (m = 10000).
 
Z 15 T (t) − 121, 1
i. F0 = e 2,303 10 9.6 dt
0
Em que: T (t) = 108, 250 + 0, 252 ∗ e (0,175t)
 
Z 6
ii. V = π 8 − x 2 dx


Z0 2 h i
2
iii. V = π 2x − x 2 − (2 − x)2 dx
Z1 8  
9
iv. V = π 2

64 − x dx
0 64
(i) Com a finalidade de determinar aproximadamente o volume de molho que
pode ser colocado em um frasco de polietileno, você utilizou uma régua
milimetrada e fez algumas medições, subdividindo o comprimento longi-
tudinal do frasco em 10 subintervalos (x1 a x10 ), conforme apresentado
na Figura 6.2. Com auxílio de uma planilha de cálculos (Microsoft Ex-
cel, por exemplo) você ajustou uma função de interpolação a cada um
dos intervalos, de modo que os polinômios representassem corretamente
o semi-contorno da embalagem (curva em azul). Os dados obtidos de sua
medição estão apresentados na Tabela 6.1.

0
x

x1 x2 x3 x4 x5 x6 x7 x8 x9 x10

Figura 6.2: Representação gráfica da segmentação de um frasco de polietileno para


acondicionamento de molho de alho. (Fonte: autores)

130
++
Princípios de programação em C

Tabela 6.1: Dados coletados a partir de medições feitas em um frasco de polietileno,


utilizado para acondicionamento de molho de alho. As medidas estão em milímetros.
Intervalo Posição em x (em mm) Função de interpolação R2
(em x) Inicial (a) Final (b) (y em mm) (%)
0 a x1 0,0000 1,4577 y1 (x) = 12, 81174 x − 0, 74458 97,51
x1 a x2 1,4577 5,0452 y2 (x) = 5, 077884 ln(x) + 16, 442899 93,46
x2 a x3 5,0452 11,0243 y3 (x) = 23, 9460 100,00
x3 a x4 11,0243 12,8382 y4 (x) = −0, 737829 x + 32, 235079 97,76
x4 a x5 12,8382 66,2115 y5 (x) = 22, 7374 100,00
x5 a x6 66,2115 68,7187 y6 (x) = 0, 476020 x − 8, 864935 95,54
x6 a x7 68,7187 74,1581 y7 (x) = 23, 7971 100,00
x7 a x8 74,1581 82,6735 y8 (x) = −0, 468403 x + 58, 933352 94,63
x8 a x9 82,6735 92,9997 y9 (x) = 5006609420, 49 x (−4,39015927989) 97,15
x9 a x10 92,9997 130,2822 y10 (x) = 133, 992234819 x (−0,539175754749) 95,81
Fonte: Elaborada pelos autores.

Com base nos dados da Tabela 6.1, e da Equação 6.5 (’integral do vo-
lume’), faça um programa que calcule a soma dos volumes dos sólidos
de revolução de todos os subintervalos (a até b), de modo a estimar,
aproximadamente, o volume total de molho que pode ser colocado no
frasco.

Z b
V =π [y (x)]2 dx (6.5)
a

2. O laço while()

(a) Faça um programa que leia, a partir do teclado, números reais maiores
do que zero. Quando o usuário digitar o zero, então o programa deverá
apresentar na tela do computado a quantidade total de números digitados,
a média desses números, o maior e o menor deles.
(b) Faça um programa que leia, a partir do teclado, uma senha, composta por
4 (quatro) números inteiros. O programa deverá verificar se a senha está
correta e, caso não esteja, deverá apresentar a mensagem ’Senha incor-
reta!’. Caso a senha esteja correta, então o programa deverá apresentar
a mensagem ’Acesso autorizado’.
(c) Faça um programa para simular uma urna eletrônica de votação para a
escolha da ’Rainha do Rodeio de Lavras, MG’. Os nomes (fictícios) das
candidatas devem ser apresentados na tela:
• 1 - Luiza (Veterinaria)
• 2 - Cristine (Eng. Alimentos)
• 3 - Sophia (Eng. Ctrl. e Automação)

131
++
Princípios de programação em C

• 4 - Carla (Eng. Biomateriais)


• 5 - Sandra (Eng. Agricola)
• 6 - NULO
• 7 - BRANCO
O programa deverá contabilizar todos os votos. Ao digitar a letra ’Q’
(maiúsculo), o programa devera encerrar a votação e listar na tela as
seguintes informações:
• Quantidade total de votos
• Número de votos para cada candidata
• Porcentagem de votos para cada candidata
• Quantidade de votos nulos
• Porcentagem de votos nulos
• Quantidade de votos brancos
• Porcentagem de votos brancos
• Identificação da candidata vencedora do concurso
(d) Escreva um programa que leia um número inteiro (n) a partir do teclado.
O programa deverá escrever a soma de todos os números, desde 1 até n
e apresentar o resultado na tela do computador.
(e) Escreva um programa que leia um número inteiro (n) a partir do teclado.
O programa deverá escrever a soma de todos os números pares, desde 2
até n e apresentar o resultado na tela do computador.
(f) Escreva um programa contendo um menu de 4 (quatro) opções na tela.
• 1 - Depósito de dinheiro
• 2 - Saque de dinheiro
• 3 - Consulta saldo atual
• 4 - Sair do programa
A cada vez que o usuário escolher a opção ’depósito’ ou ’saque’, o pro-
grama deverá perguntar o valor, que deverá ser digitado a partir do te-
clado. Quando o usuário escolher a opção ’Consulta’, o programa deverá
mostrar o valor atualizado na tela do computador. Inicialmente há R$
0,00 na conta.
(g) Faça um programa que leia, a partir do teclado, o peso e a altura de uma
pessoa, e calcule o seu ’índice de massa corporal’ (Equação)

Peso
IMC = (6.6)
(Altura)2

132
++
Princípios de programação em C

O programa deve apresentar na tela o resultado do IMC e interpretá-lo


adequadamente, com base nos valores de referência encontrados na lite-
ratura. O programa deverá também ter um menu inicial, com os seguintes
dados:
• 1 - Calcular IMC
• 2 - Sair do programa
Sempre que apresentar os resultados de cálculo de um IMC, o programa
deverá retornar ao menu inicial e apresentá-lo novamente na tela do com-
putador.
(h) No processo de esterilização comercial de um alimento enlatado, observou-
se que a destruição térmica de células vegetativas tem um tempo de meia
vida igual a 8 segundos. Faça um programa no qual seja necessário in-
formar a massa (em gramas) do alimento, e a quantidade inicial de mi-
crorganismos (UFC/g). O programa deverá calcular o tempo necessário,
em segundos, de duração do tratamento térmico, para que a quantidade
residual de células vegetativas seja menor do que 10−12 UFC/g.
(i) A instrução goto é deve ser usada com bastante cuidado porque ela pode
fazer um salto absoluto e incondicional para qualquer outra linha do pro-
grama. O código apresentado a seguir possui uma função utilizada para
verificar se um número é par ou ímpar. Discuta sobre a utilização do goto
nessa função. Com qual finalidade ele foi utilizado? Ele saltou algum
comando ou estrutura importante? Reescreva a função originalmente
apresentada no código, mas sem utilizar o goto.
1 # include < iostream >
2 using namespace std ;
3 void ChecarParInpar ( int Num ) ;
4 int main () {
5 int x = 363;
6 ChecarParInpar ( x ) ;
7 return 0;
8 }
9 void ChecarParInpar ( int Num ) {
10 if ( Num % 2 == 0) {
11 goto NumPar ;
12 } else {
13 goto NumImpar ;
14 }
15 NumPar :
16 cout << " Numero par ...: " << Num << endl ; return ;
17 NumImpar :
18 cout << " Numero impar .: " << Num << endl ; return ;
19 }

133
Capítulo 7

Biblioteca padrão de funções para


cálculos matemáticos

Conteúdo do capítulo
7.1 A biblioteca cmath . . . . . . . . . . . . . . . . . . . . . . . 135
7.1.1 Funções trigonométricas . . . . . . . . . . . . . . . . . . . 135
7.1.2 Funções hiperbólicas . . . . . . . . . . . . . . . . . . . . . 136
7.1.3 Funções exponenciais e logarítmicas . . . . . . . . . . . . 136
7.1.4 Função Erro e função Gamma . . . . . . . . . . . . . . . . 138
7.1.5 Funções de truncamento e arredondamento . . . . . . . . 139
7.1.6 Operações com números complexos . . . . . . . . . . . . . 141
7.2 Bibliotecas para cálculos numéricos avançados . . . . . . 143
7.3 Macros pré-definidas na biblioteca <math.h> . . . . . . 144
7.4 Atividades para fixação da aprendizagem . . . . . . . . . 145

Este capítulo traz informações importantes para os estudantes de ciências exatas,


pois nele são apresentadas algumas das funções matemáticas básicas contidas na
biblioteca padrão cmath do C++ .
Apesar de as funções dessa biblioteca atenderem a uma boa parte das necessi-
dades básicas dos estudantes, que frequentemente necessitam de realizar cálculos
matemáticos, a cmath não dispõe de funcionalidades para a realização de cálculos
numéricos como, por exemplo, algoritmos para inverter matrizes, calcular determi-
nantes, resolver sistemas de equações lineares, etc.
Na cmath infelizmente também não há funções para cálculos de integrais, deriva-
das, expansão em série de Taylor, Fourier ou Transformadas de Laplace, gradientes
e divergentes. Entretanto, há inúmeras outras bibliotecas de C++ que oferecem es-
sas funcionalidades, sendo que muitas delas são gratuitas e podem ser facilmente
encontradas na Internet, disponíveis para download.

134
++
Princípios de programação em C

7.1 A biblioteca cmath


A seguir estão listadas as principais funções da biblioteca cmath e alguns exemplos
de sua utilização.

7.1.1 Funções trigonométricas


• cos: Retorna, em radianos, o cosseno de um ângulo. Exemplo:
1 # include < iostream >
2 # include < cmath >
3 using namespace std ;
4

5 int main () {
6 float Valor = 18.53;
7 cout << " Cos ..: " << cos ( Valor ) ; // 0.949375
8 return (0) ;
9 }

• sin: Retorna, em radianos, o seno de um ângulo. Exemplo:


1 float Valor = 18.53;
2 cout << " Seno ..: " << sin ( Valor ) ; // -0.314144

• tan: Retorna, em radianos, a tangente de um ângulo. Exemplo:


1 float Valor = 18.53;
2 cout << " Tangente : " << tan ( Valor ) ; // -0.330896

• acos: Retorna, em radianos, o valor principal do arco-cosseno de um ângulo.


Exemplo:
1 float Valor = 0.53;
2 cout << " Arco - cosseno : " << acos ( Valor ) ; // 1.0122

• asin: Retorna, em radianos, o valor principal do arco-seno de um ângulo.


Exemplo:
1 float Valor = 0.53;
2 cout << " Arco - seno : " << asin ( Valor ) ; // 0.558601

• atan: Retorna, em radianos, o valor principal do arco-tangente de um ângulo.


Exemplo:
1 float Valor = 0.53;
2 cout << " Arco - tangente : " << atan ( Valor ) ; // 0.487359

135
++
Princípios de programação em C

7.1.2 Funções hiperbólicas


• cosh: Retorna, em radianos, o cosseno hiperbólico de um ângulo. Exemplo:
1 float Valor = 0.53;
2 cout << " Cos hiperbolico : " << cosh ( Valor ) ; // 1.14377

• sinh: Retorna, em radianos, o seno hiperbólico de um ângulo. Exemplo:


1 float Valor = 0.53;
2 cout << " Seno hiperbolico : " << sinh ( Valor ) ; // 0.555164

• tanh: Retorna, em radianos, a tangente hiperbólica de um ângulo. Exemplo:


1 float Valor = 0.53;
2 cout << " Tan hiperbolica : " << tanh ( Valor ) ; // 0.485381

• acosh: Retorna, em radianos, o arco-cosseno hiperbólico não negativo de um


ângulo. Exemplo:
1 float Valor = 10.53;
2 cout << " Arco - cos hiperb : " << acosh ( Valor ) ; // 3.04511

• asinh: Retorna, em radianos, o arco-seno hiperbólico de um ângulo. Exemplo:


1 float Valor = 10.53;
2 cout << " Arco - sen hiperb : " << asinh ( Valor ) ; // 3.04962

• atanh: Retorna, em radianos, o arco-tangente hiperbólico de um ângulo.


Exemplo:
1 float Valor = 0.53;
2 cout << " Arco - tan hiperb : " << atanh ( Valor ) ; // 0.590145

7.1.3 Funções exponenciais e logarítmicas


• exp: Retorna o valor de e x . Exemplo:
1 float Valor = 1.5;
2 cout << " Exponencial .: " << exp ( Valor ) ; // 4.48169

• log: Retorna o valor de ln(x). Exemplo:


1 float Valor = 1.5;
2 cout << " ln .: " << log ( Valor ) ; // 0.405465

• log10: Retorna o valor de log(x) na base 10. Exemplo:

136
++
Princípios de programação em C

1 float Valor = 1.5;


2 cout << " log .: " << log10 ( Valor ) ; // 0.176091

• frexp: ’Quebra’ (decompõe) um número de ponto flutuante em duas partes:


um fator de multiplicação e um termo do tipo ’2 elevado a um expoente’.
Exemplo:
1 # include < stdio .h >
2 # include < cmath >
3

4 int main () {
5

6 double Valor , Res ;


7 int Expoente ;
8

9 Valor = 81.0;
10 Res = frexp ( Valor , & Expoente ) ;
11 printf ( " % f = % f * 2^% d \ n " , Valor , Res , Expoente ) ;
12 return (0) ; // 81.000000 = 0.632812 * 2^7
13 }

• modf: ’Quebra’ (decompõe) um número de ponto flutuante em duas partes:


uma parte inteira e uma parte fracionária. Exemplo:
1 # include < stdio .h >
2 # include < cmath >
3

4 int main () {
5

6 double Valor , PartFrac , PartInt ;


7

8 Valor = 3.14159265;
9 PartFrac = modf ( Valor , & PartInt ) ;
10 printf ( " % f =%2.8 f + %2.8 f \ n " , Valor , PartInt , PartFrac ) ;
11

12 return (0) ; // 3.14159265 = 3.00000000 + 0.14159265


13 }

• pow: Retorna o valor de bx , uma base b elevada a um expoente x. Exemplo:


1 // (4.2) ^(3.5) = 151.835
2 cout << " Potencia : " << pow (4.2 , 3.5) ;

• sqrt: Retorna o valor da raiz quadrada de x. Exemplo:

137
++
Princípios de programação em C

1 float Valor = 1.5;


2 cout << " Raiz : " << sqrt ( Valor ) ; // 1.22474

• cbrt: Retorna o valor da raiz cúbica de x. Exemplo:


1 float Valor = 1.5;
2 cout << " Raiz cubica : " << cbrt ( Valor ) ; // 1.14471

• hypot: Retorna o valor da hipotenusa de um triângulo retângulo. Exemplo:


1 float Cateto1 = 4.8;
2 float Cateto2 = 6.2;
3 float Hipot = hypot ( Cateto1 , Cateto2 ) ;
4 cout << " Hipotenusa : " << Hipot ; // 7.84092

7.1.4 Função Erro e função Gamma


• erf: Retorna o valor da função erro para uma variável x. Exemplo:
1 float Valor = 2.6;
2 float FuncErro = erf ( Valor ) ;
3 cout << " Funcao Erro : " << FuncErro ; // 0.999764

• erfc: Retorna o valor complementar da função erro para uma variável x. Exem-
plo:
1 float Valor = 2.6;
2 float FuncErroC = erfc ( Valor ) ; // 0.000236035
3 cout << " Funcao Erro Compl : " << FuncErroC ;

• tgamma: Retorna o valor da função gamma para uma variável x. Exemplo:


1 float Valor = 2.6;
2 float Gamma = tgamma ( Valor ) ;
3 cout << " Funcao gamma : " << Gamma ; // 1.42962

• lgamma: Retorna o valor em módulo do logaritmo natural da função gamma


para uma variável x. Exemplo:
1 float Valor = 2.6;
2 float lGamma = lgamma ( Valor ) ;
3 cout << " Funcao log - gamma : " << lGamma ; // 0.357412

138
++
Princípios de programação em C

7.1.5 Funções de truncamento e arredondamento


• ceil: Arredonda para cima o valor de x. O valor obtido será o próximo inteiro
que não seja menor do que x. Exemplo:
1 float Valor1 = 2.045;
2 float Valor2 = 1.875;
3 float Valor3 = 0.345;
4 cout << " Ceil Valor 1: " << ceil ( Valor1 ) << endl ; // 3
5 cout << " Ceil Valor 2: " << ceil ( Valor2 ) << endl ; // 2
6 cout << " Ceil Valor 3: " << ceil ( Valor3 ) << endl ; // 1

• floor: Arredonda para baixo o valor de x. O valor obtido será o maior valor
inteiro que não seja maior do que x. Exemplo:
1 float Vr1 = 2.045; float Vr2 = 1.875; float Vr3 = 0.345;
2 cout << " Floor Valor 1: " << floor ( Vr1 ) << endl ; // 2
3 cout << " Floor Valor 2: " << floor ( Vr2 ) << endl ; // 1
4 cout << " Floor Valor 3: " << floor ( Vr3 ) << endl ; // 0

• fmod: Retorna o restante da divisão entre dois números de ponto flutuante.


Exemplo:
1 double Num = 2.045;
2 double Den = 1.875;
3 double Resto = fmod ( Num , Den ) ;
4

5 cout . precision (6) ;


6 cout << " Resto da divisao : " << Resto << endl ; // 0.17

• trunc: Trunca o valor de x. O valor de x será arredondado para o valor inteiro


mais próximo a ele, mas que não seja maior do que x. Exemplo:
1 double Valor1 = 2.045; double Valor2 = 1.875;
2 double Valor3 = 0.128; double Valor4 = 5.001;
3 double Valor5 = 4.998;
4

5 Valor1 = trunc ( Valor1 ) ; Valor2 = trunc ( Valor2 ) ;


6 Valor3 = trunc ( Valor3 ) ; Valor4 = trunc ( Valor4 ) ;
7 Valor5 = trunc ( Valor5 ) ;
8

9 cout . precision (6) ;


10 cout << " Trunc Valor 1: " << Valor1 << endl ; // 2
11 cout << " Trunc Valor 2: " << Valor2 << endl ; // 1
12 cout << " Trunc Valor 3: " << Valor3 << endl ; // 0
13 cout << " Trunc Valor 4: " << Valor4 << endl ; // 5
14 cout << " Trunc Valor 5: " << Valor5 << endl ; // 4

139
++
Princípios de programação em C

• round: Arredonda o valor de x para o valor inteiro mais próximo a ele. Exemplo:
1 double Valor1 = 2.045;
2 double Valor2 = 1.875;
3 double Valor3 = 0.128;
4 double Valor4 = 5.001;
5 double Valor5 = 4.998;
6 double Valor6 = 2.500;
7

8 Valor1 = round ( Valor1 ) ;


9 Valor2 = round ( Valor2 ) ;
10 Valor3 = round ( Valor3 ) ;
11 Valor4 = round ( Valor4 ) ;
12 Valor5 = round ( Valor5 ) ;
13 Valor6 = round ( Valor6 ) ;
14

15 cout . precision (6) ;


16 cout << " Round Valor 1: " << Valor1 << endl ; // 2
17 cout << " Round Valor 2: " << Valor2 << endl ; // 2
18 cout << " Round Valor 3: " << Valor3 << endl ; // 0
19 cout << " Round Valor 4: " << Valor4 << endl ; // 5
20 cout << " Round Valor 5: " << Valor5 << endl ; // 5
21 cout << " Round Valor 6: " << Valor6 << endl ; // 3

• fabs: Calcula o valor absoluto de x. Exemplo:


1 double Vr1 = -2.045;
2 double Vr2 = -1.875;
3

4 cout . precision (6) ;


5 cout << " fabs Valor 1: " << fabs ( Vr1 ) << endl ; // 2.045
6 cout << " fabs Valor 2: " << fabs ( Vr2 ) << endl ; // 1.875

• isfinite: Verifica se x possui um valor finito. Esta função retorna 0 (zero) ou


1 (um), indicando um estado de falso ou verdadeiro. Exemplo:
1 # define ff ( x ) isfinite ( x ) // Para ajustar margens ...
2 ...
3 cout << " (0.0) ........: " << ff (0.0) << endl ;
4 cout << " (1.0/0.0) ....: " << ff (1.0/0.0) << endl ;
5 cout << " ( -1.0/0.0) ...: " << ff ( -1.0/0.0) << endl ;
6 cout << " sqrt ( -1.0) ...: " << ff ( sqrt ( -1.0) ) << endl ;
7 cout << " cbrt ( -1.0) ...: " << ff ( cbrt ( -1.0) ) << endl ;
8 cout << " exp (1.5) .....: " << ff ( exp (1.5) ) << endl ;
9 cout << " pow (2.0 ,3.0) .: " << ff ( pow (2.0 , 3.0) ) << endl ;
10 cout << " pow ( -2.0 ,3.0) : " << ff ( pow ( -2.0 , 3.0) ) << endl ;
11

12 // 1 0 0 0 1 1 1 1

140
++
Princípios de programação em C

• isinf: Verifica se x possui um valor infinito. Esta função retorna 0 (zero) ou 1


(um), indicando um estado de falso ou verdadeiro. Exemplo:
1 cout << " (1.0/0.0) : " << isinf (1.0/0.0) << endl ; // 1

• isnan: Retorna verdadeiro (1) se x não for um número. Para caracteres ASCII
individuais, a função leva em consideração o seu valor correspondente na tabela
ASCII e, portanto, são considerados valores numéricos. Exemplo:
1 char vChar = ’c ’;
2 int vNum1 = 10;
3 double vNum2 = sqrt ( -1) ;
4

5 cout << " vChar .: " << isnan ( vChar ) << endl ; // 0
6 cout << " vNum1 .: " << isnan ( vNum1 ) << endl ; // 0
7 cout << " vNum2 .: " << isnan ( vNum2 ) << endl ; // 1

7.1.6 Operações com números complexos


Eventualmente o programador poderá se deparar com situações nas quais necessite
realizar cálculos com números complexos.
A biblioteca complex, que é padrão do C++ , implementa várias funções para
essa finalidade. Ao utilizá-la, a declaração de um número complexo deve ser feita
conforme a seguinte sintaxe:
1 # include < complex >
2 ...
3 complex < double > NomeVariavel ( Parte Real , Parte imaginaria ) ;

Alguns exemplos de como utilizar as funções da biblioteca complex estão apre-


sentados a seguir.

• real: Retorna a parte real do número complexo. Exemplo:


1 # include < iostream >
2 # include < cmath >
3 # include < complex >
4

5 using namespace std ;


6

7 int main () {
8 complex < double > NumComplexo (10.25 , 15.82) ;
9 cout << " Parte real ..: " << real ( NumComplexo ) << endl ;
10 return (0) ;
11 }

• imag: Retorna a parte imaginária do número complexo. Exemplo:

141
++
Princípios de programação em C

1 complex < double > NumCplxo (10.25 , 15.82) ;


2 cout << " Parte imaginaria : " << imag ( NumCplxo ) << endl ;

• abs: Retorna o módulo de um número complexo. Exemplo:


1 complex < double > NumComplexo (10.25 , 15.82) ;
2 cout << " Modulo : " << abs ( NumComplexo ) << endl ;

• arg: Retorna o ângulo de fase (ou componente angular) de um número com-


plexo. Exemplo:
1 complex < double > NumComplexo (3 , 4) ;
2 cout << " Angulo de fase : " << arg ( NumComplexo ) << endl ;

• norm: Retorna à norma de um número complexo. Exemplo


1 complex < double > NumComplexo (3 , 4) ;
2 cout << " Norma : " << norm ( NumComplexo ) << endl ;

• conj: Retorna o conjugado complexo de um número complexo. Exemplo:


1 complex < double > NumComplexo (3 , 4) ;
2 cout << " Conjugado : " << conj ( NumComplexo ) << endl ;

• polar: Retorna à forma polar do número complexo. Exemplo:


1 double Magnitude = 2;
2 double AngFase = 0.5;
3 complex < double > NumComplexo ( Magnitude , AngFase ) ;
4 cout << " Forma polar : " << polar ( NumComplexo ) << endl ;

• Soma e subtração: Operações algébricas de soma e subtração de variáveis


complexas podem ser realizadas com a utilização dos operadores matemáticos
convencionais. Exemplo:
1 # include < iostream >
2 # include < cmath >
3 # include < complex >
4 using namespace std ;
5 int main () {
6 complex < double > NumCplx1 (16.22 , 80.07) ;
7 complex < double > NumCplx2 (40.13 , 9.36) ;
8 complex < double > Resp (0 , 0) ;
9 Resp = NumCplx1 + NumCplx2 ;
10 cout << " Soma .: " << Resp << endl ; // ( 56.35 , 89.43)
11

142
++
Princípios de programação em C

12 Resp = NumCplx1 - NumCplx2 ;


13 cout << " Subt .: " << Resp << endl ; // ( -23.91 , 70.71)
14

15 return 0;
16 }

Além dessas funções básicas, a biblioteca complex possui também várias outras
funções para a manipulação de números complexos, entre elas funções trigonomé-
tricas, hiperbólicas, exponenciais, logarítmicas, etc.

7.2 Bibliotecas para cálculos numéricos avançados


A GSL (GNU Scientific Library ) é uma biblioteca de distribuição livre para as lin-
guagens C/C++ . Ela implementa mais de 1.000 funções matemáticas, que cobrem
uma ampla faixa de necessidades em cálculos numéricos envolvidos nos problemas
de engenharia e outras ciências exatas. O download da GSL pode ser feito a partir
do seguinte endereço eletrônico na Internet:
https://www.gnu.org/software/gsl/

Entre as funcionalidades da GSL, algumas estão destacadas a seguir:

• Números complexos • Vetores e matrizes


• Funções especiais • Ordenação
• Permutações • Álgebra linear
• Autovalores e autovetores • Transformada rápida de Fourier
• Quadratura numérica • Números aleatórios
• Sequências Quasi-Random • Distribuições aleatórias
• Estatísticas • Histogramas
• Simulated Annealing • Integração pelo método de Monte
• Interpolação Carlo

• Aproximação por Chebyshev • Equações diferenciais

• Otimização • Diferenciação numérica

• Constantes físicas • Raízes de equações

• Transformada discreta de Wavelet • Método de mínimos quadrados

• Raízes de polinômios • Interpolação por splines

143
++
Princípios de programação em C

Exemplos da utilização da GSL, e de outras bibliotecas numéricas disponíveis


na Internet, estão fora do escopo deste livro visto que, em geral, a utilização das
funções contidas nessas bibliotecas exige do programador conhecimentos um pouco
mais avançados de C++ como, por exemplo, a declaração de ponteiros para variáveis
e alocação dinâmica de memória, entre outros recursos. De uma forma genérica
pode-se dizer que os recursos contidos na cmath já são suficientes para realizar a
maioria dos cálculos básicos presentes nos problemas de engenharia e outras ciências
exatas.

7.3 Macros pré-definidas na biblioteca <math.h>


Além biblioteca cmath do C++ , há também a biblioteca math.h, padrão da linguagem
C, que tem praticamente as mesmas funções presentes em cmath. Em math.h estão
pré-definidas algumas macros que podem ser úteis na realização de cálculos. As
principais macros estão apresentadas na Tabela 7.1 a seguir.
Tabela 7.1: Macros pré-definidas na biblioteca math.h.
Macro Descrição Valor
M_E Número de Euler 2.71828182845904523540
M_LOG2E Logaritmo de e na base 2 1.44269504088896340740
M_LOG10E Logaritmo de e na base 10 0.43429448190325182765
M_LN2 Logaritmo natural de 2 (ln(2)) 0.69314718055994530942
M_LN10 Logaritmo natural de 10 (ln(10)) 2.30258509299404568402
M_PI Valor de π 3.14159265358979323846
M_PI_2 Valor de π/2 1.57079632679489661923
M_PI_4 Valor de π/4 0.78539816339744830962
M_1_PI Valor de 1/π 0.31830988618379067154
M_2_PI Valor de 2/π 0.63661977236758134308

M_2_SQRTPI Valor de 2/ √ π 1.12837916709551257390
M_SQRT2 Valor de 2√ 1.41421356237309504880
M_SQRT1_2 Valor de 1/ 2 0.70710678118654752440
Fonte: Elaborada pelos autores.

Exemplo de aplicação:
1 # include < iostream >
2 # include < iomanip >
3 # include < math .h >
4 using namespace std ;
5 int main () {
6 cout . precision (19) ;
7 cout << " O valor de Pi : " << M_PI << endl ;
8 return (0) ;
9 }

144
++
Princípios de programação em C

7.4 Atividades para fixação da aprendizagem


1. Cálculos matemáticos simples com a biblioteca cmath
Faça um programa que solicite ao usuário a digitação das variáveis de entrada,
faça o cálculo e retorne o resultado das expressões matemáticas apresentadas
a seguir, algumas obtidas de DAVIS (1955). Se necessário, implemente o
método iterativo de Newton-Raphson (RUGGIERO e LOPES, 1996) para obter
a solução desejada.

(a)
s
L
θ = 2π (7.1)
g

Na Equação 7.1, θ é o tempo de uma oscilação completa de um pêndulo,


em segundos. L é o comprimento do pêndulo, em metros. g é a aceleração
da gravidade, 9, 80665 m/s 2
(b)

R = 2, 315 × V 0,5759 (7.2)

Na Equação 7.2, R é a taxa de escoamento de um líquido, em cm3 /mi n,


através de um cubo de espuma (água + 0,25% de lauril sulfato de sódio).
V é o volume do líquido em 1 cm3 de espuma.
(c)

V = 0, 01054 S 2,303 + 2, 08 (7.3)

Na Equação 7.3, V é a velocidade de perfuração de uma rocha, em


cm/mi n. S é a distância de perfuração, em metros, por cada homem
em um turno de trabalho.
(d)

T = 3724e 2,303×(−0,01977 B) (7.4)

Na Equação 7.4, B é a percentagem de benzeno em uma solução aquosa.


T é o efeito da percentagem de benzeno sobre a resistência à tração de
uma borracha sintética, dado em lbf /in2 .
(e)

S = 7, 894e 0,1939t − 4, 82 (7.5)

Na Equação 7.5, S é concentração de uma solução saturada de clorato


de potássio em água, expressa em percentagem (ou g/100g). t é a
temperatura da solução, em graus Celsius.

145
++
Princípios de programação em C

(f)
p − 12
C= + 16, 95 (7.6)
0, 040 − 0, 0644p

Na Equação 7.6, C é a massa (em lbm ) dos produtos totais de combustão


do carvão. p é a percentagem de CO2 nos gases de combustão.
(g)

log (Re)[log (Re) − 0, 602] [log(Re)]3


1
C = 0, 1755−1, 736 log (Re)− 1,52 + −
Re +9 Re + 5, 5 2660 − Re
(7.7)

Na Equação 7.7, C é a constante teórica para um medidor de vazão do


tipo placa de orifício. Re é o número de Reynolds para o escoamento no
interior do medidor de vazão.
(h)

P = 6, 35 + 15, 80 sinh (0, 0009N − 1, 08) (7.8)

Na Equação 7.8, P é a potência de um motor diesel de 6 (seis) cilindros,


em Hp. N é a quantidade de rotações do eixo principal do motor, em
r pm.
(i)
   
p2 ∆H 1 1
2, 303 × log =− − (7.9)
p1 R T2 T1

A Equação 7.9 descreve o estado termodinâmico, que correlaciona dados


de pressão de vapor de uma substância pura na pressão p1 , na tempera-
tura T1 , com os dados de pressão de vapor, p2 , na temperatura T2 . As
temperaturas são dadas em Kelvin. Os valores de pressão são dados em
atmosferas. ∆H é a entalpia (ou calor) de vaporização da substância,
dado em kJ/mol. R é uma constante, que vale 8, 3145 Jmol −1 K −1 .
O programa deverá calcular p2 na temperatura T2 . As demais variáveis
são digitadas pelo usuário do programa.
(j)

log (x) − log (x1 )


= a + b log (x) (7.10)
log (y ) − log (y1 )

O programa deverá calcular o valor de x na Equação 7.10, e imprimir seu


valor na tela do computador. As demais variáveis serão digitadas pelo
usuário do programa.

146
++
Princípios de programação em C

(k)
! i=60,i6
i=120
X 4, 125 + [6 ∗ (i 1,125 )] X=42  22 − i

F = p + √ (7.11)
i=1 2, 226i + 3e (1,224) i=2
5 + 2i

Para a Equação 7.11, o programa deverá calcular o valor de F e imprimir


o resultado na tela.
(l)
4557 − 65, 3W
log (p) = 10, 9528−0, 009725W −0, 000868W 2 − (7.12)
t + 273
A Equação 7.12 trata da solubilidade do cloreto de hidrogênio em água.
Nessa equação, p é a pressão parcial do cloreto de hidrogênio (0,1 a 100
mmHg). W é a percentagem de cloreto de hidrogênio em solução (de 15
a 35%). t é a temperatura, de 0 a 100 graus Celsius.
Faça um programa no qual o usuário informe o valor de p e a tempera-
tura, t, como dados de entrada. O valor de W deverá ser calculado e
apresentado na tela.
(m)
δ + 4, 70t 2,06 (10−7 ) − 1, 0015
X= (7.13)
0, 001516 − 3, 40t(10−6 )
Para uma solução aquosa de etileno glicol, X é a percentagem de glicol
por volume (de 10 a 60%). δ é a massa específica a 60 graus Fahrenheit,
relativa a água, de 0,99 a 1,09. t é a temperatura entre 20 e 180 graus
Fahrenheit.
Faça um programa que calcule o valor de δ em função das outras variáveis,
que deverão ser digitadas pelo usuário do programa.
(n)

p e 3,542−0,02512t + 1 − 100 sinh−1 {[76, 264 − 21, 844 log (t + 25)]}

S=
(7.14)

Na Equação 7.14, S é a massa (gramas) de amônia que se dissolve em


1 kg de água, na temperatura t (t entre 0 e 50 graus Celsius). p é a
pressão parcial da amônia, em mmHg, com p entre 20 e 1000 mmHg.
Faça um programa que calcule o valor de p e apresente o resultado na
tela. Os valores das demais variáveis serão informados pelo usuário do
programa.
(o) Escreva um programa para calcular o ângulo formado por dois vetores de
coordenadas a~ =< x1 , y1 , z1 > e ~b =< x2 , y2 , z2 >. O ângulo deve ser
expresso em graus. As coordenadas dos dois vetores deverão ser digitadas
pelo usuário do programa.

147
++
Princípios de programação em C

(p) Escreva um programa que calcule o ’módulo’ do vetor resultante (|z|) da


soma vetorial: z~ = a~ + ~b + c~ + d.
~ Cada um desses vetores possui duas
coordenadas espaciais do tipo double, < x, y >, que deverão ser digitadas
pelo usuário do programa.
(q) Escreva um programa que calcule o ’produto escalar’ entre dois vetores:
~r e ~s. Cada um desses vetores possui três coordenadas espaciais do tipo
double, < x, y , z >, que deverão ser digitadas pelo usuário do programa.
(r) Escreva um programa que contenha uma função para calcular o valor de
π, de acordo com uma expansão em série, dada pela Equação 7.15. A
função terá como parâmetro apenas o valor k, correspondendo ao número
de iterações descritas pela Equação 7.15. Liste na tela do computador
os valores de π obtidos ao testar k entre 3 e 100. Analise e discuta
os resultados obtidos comparando-os com o valor de π com 20 casas
decimais: π = 3, 14159265358979323846.

∞  
X 1 4 2 1 1
π= − − − (7.15)
k=0
16k 8k + 1 8k + 4 8k + 5 8k + 6

(s) Modifique o programa anterior, de modo que ele possa também calcular o
valor de π por meio da Equação 7.16. Esta equação deverá ser resolvida
pela regra de 1/3 de Simpson (ver Equações 6.2 a 6.4, p.129).

Z 1 p 
π =2× 1 − x 2 dx (7.16)
−1

(t) Modifique o programa anterior de modo que ao invés de pi , a função


possa ser utilizada para calcular os resultados das seguintes séries1 :
i.

X xn
x
e = , para: x = 0, 325 (7.17)
n=0
n!

ii.

X (−1)n 2n+1
sen(x) = x , para: x = 0, 05 (7.18)
n=0
(2n + 1)!

iii.

X (−1)n
cos(x) = x 2n , para: x = 0, 25 (7.19)
n=0
(2n)!

1
Uma função recursiva para o cálculo do fatorial de um número inteiro não negativo está descrita
no Capítulo 8, p.162.

148
Capítulo 8

Procedimentos e funções em C++

Conteúdo do capítulo
8.1 A segmentação do código em procedimentos e funções . 149
8.1.1 Procedimentos em C++ . . . . . . . . . . . . . . . . . . . 152
8.1.1.1 Passagem de parâmetros para procedimentos e
funções em C++ . . . . . . . . . . . . . . . . . . 152
8.1.1.2 Protótipos de procedimentos e de funções . . . . 153
8.1.2 Particularidades sobre procedimentos e funções em C++ . 154
8.1.2.1 Funções inline . . . . . . . . . . . . . . . . . . . 156
8.1.2.2 Sobrecarga de procedimentos e funções . . . . . 156
8.1.2.3 Domínio de funções em cálculos matemáticos . . 158
8.1.2.4 Parâmetros padrões de procedimentos e funções 160
8.1.2.5 Recursividade . . . . . . . . . . . . . . . . . . . 162
8.1.2.6 Funções para limpar e posicionar o cursor na tela 163
8.2 Atividades para fixação da aprendizagem . . . . . . . . . 165

8.1 A segmentação do código em procedimentos e


funções
Com o objetivo de aumentar a eficiência, reusabilidade e funcionalidade de um pro-
grama, os seus códigos em C++ podem ser reorganizados e segmentados em blocos
menores, separados do programa principal. De uma forma bem resumida, pode-
se dizer que os procedimentos (procedures) e as funções (functions) apresentados
neste capítulo são ’blocos de instruções projetados para cumprir uma tarefa bem
específica’.
A vantagem de fazer a segmentação do código é que todas as suas partes re-
petitivas poderão ser reescritas na forma de procedimentos ou funções, diminuindo

149
++
Princípios de programação em C

bastante o tamanho do código e a complexidade do fluxo de informações dentro do


programa. Além disso, os procedimentos e funções facilitam muito a manutenção
do código, principalmente quando houver necessidade de localizar erros ou alterar o
modo como os cálculos e tarefas repetitivas são realizadas.
Para compreender como os procedimentos e funções podem ser utilizados em
um programa, façamos a análise do código a seguir.
1 # include < iostream >
2 # include < math .h >
3

4 using namespace std ;


5

6 void Linha ( void ) // Procedimento para desenhar


7 { // uma linha na tela
8 cout << " - - - - - - - - - - - - - - - - - - - - - - - - - - - - " << endl ;
9 }
10

11 int main ()
12 {
13 Linha () ; // Chamado aqui (1 a vez )
14 cout << " O valor de Pi ....: " << M_PI << endl ;
15 cout << " Numero de Euler ..: " << M_E << endl ;
16 cout << " Raiz de 2........: " << M_SQRT2 << endl ;
17 Linha () ; // Chamado aqui (2 a vez )
18 cout << " Pi /2.............: " << M_PI_2 << endl ;
19 cout << " Pi /4.............: " << M_PI_4 << endl ;
20 cout << " Ln (2) ............: " << M_LN2 << endl ;
21 Linha () ; // Chamado aqui (3 a vez )
22

23 return (0) ;
24 }

No código acima foi construído um procedimento entre as linhas 6 e 9. Esse


procedimento começa com a palavra reservada void (do inglês, ’vazio’) e logo em
seguida vem o seu nome, que neste caso é ’Linha’. É um procedimento simples,
que tem unicamente a função de desenhar uma linha na tela do computador. Logo
após o nome do procedimento há um par de parêntesis dentro do qual está a palavra
void. Esse par de parêntesis tem a função de receber valores externos (parâmetros
externos) que podem ser repassados para serem processados no interior do procedi-
mento.
Entretanto, neste exemplo, nenhum parâmetro foi passado para ele, e por isso
dentro do par de parêntesis há apenas a palavra reservada void do C++ . Observe
que esse procedimento foi ’chamado’ nas linhas 13, 17 e 21, e exatamente nesses
locais onde foi chamado, o que ele vai fazer é tão somente desenhar uma linha na
tela, como programado na linha 8 do código. As instruções entre as linhas 6 e 9
deste exemplo são típicas de um ’procedimento’, que nada mais é do que um bloco

150
++
Princípios de programação em C

de códigos que pode ser chamado várias vezes dentro do programa, mas que ao ser
executado ele não retorna nenhum valor, apenas executa um bloco de instruções.
No próximo exemplo temos uma situação um pouco diferente. Temos um proce-
dimento que irá retornar um valor. Todo procedimento que retorna algum tipo de
valor é chamado de ’função’. Assim, basicamente, pode-se dizer que o que diferencia
uma ’função’ de um ’procedimento’ é o fato de a função sempre retornar um valor.
1 # include < iostream >
2

3 using namespace std ;


4

5 float Soma ( float x , float y ) // Funcao declarada aqui


6 {
7 float Resp ;
8 Resp = x + y ;
9 return Resp ; // A funcao retorna um
10 } // valor do tipo float
11

12 // - -[ Programa principal ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13

14 int main ()
15 {
16 float Valor1 = 32.25;
17 float Valor2 = 63.28;
18 float Valor3 = 11.29;
19 float Valor4 = 16.19;
20

21 float Total1 ;
22 float Total2 ;
23 float Total3 ;
24

25 Total1 = Soma ( Valor1 , Valor2 ) ; // Primeira chamada


26 Total2 = Soma ( Valor3 , Valor4 ) ; // Segunda chamada
27 Total3 = Soma ( Total1 , Total2 ) ; // Terceira chamada
28

29 cout << " Total 1..: " << Total1 << endl ;
30 cout << " Total 2..: " << Total2 << endl ;
31 cout << " Total 3..: " << Total3 << endl ;
32

33 return (0) ;
34 }

Na linha 5 (cinco) do exemplo acima, foi construída a função Soma, cuja finali-
dade é somar dois valores, x e y , do tipo float que são passados externamente como
argumentos para a função. A passagem de valores para dentro de uma função é
feita especificando-se, dentro do par de parêntesis, as variáveis que serão passadas
e os seus respectivos tipos.

151
++
Princípios de programação em C

Logo no início da linha cinco, antes mesmo do nome da função, há a palavra


float, que indica o tipo de valor que a função deverá retornar, ou seja, o resultado
da soma (x + y ) a ser feita pela função deverá retornar um valor do tipo float. O
corpo da função é todo o bloco de códigos que está compreendido entre as linhas
7, 8 e 9. Na linha 7 foi declarada uma variável do tipo float com o nome de ’Resp’.
Essa é uma variável local, e tem seu escopo definido apenas dentro da função onde
ela foi criada, e não pode ser acessada do lado de fora desta função. É uma variável
de uso temporário, que será utilizada apenas para armazenar o valor resultante da
soma (x + y ).
Na linha 8 está o código que irá fazer a soma dos valores x e y e armazenar o
resultado na variável Resp. Na linha 9 a palavra reservada return serve para informar
que a função Soma deverá retornar o valor que está na variável Resp. Observe
que a função Soma poderá ser chamada (utilizada) quantas vezes forem necessárias
dentro do programa. Neste exemplo, a função Soma foi chamada nas linhas 25, 26
e 27 do programa. Observe também, na linha 25, que o valor retornado pela função
foi colocado na variável ’Total1’. O mesmo ocorre nas linhas 26 e 27, em que os
valores retornados pela função são colocados nas variáveis ’Total2’ e ’Total3’.
O tema ’funções’ não é uma novidade para nós, visto que já estávamos habitu-
ados com a função int main(), presente em todos os programas C++ apresentados
anteriormente neste livro. Para a função int main(), esta sempre retorna um valor
inteiro. A instrução ’return 0’ no final de todos os programas indica, portanto, que a
função int main() deve retornar o valor zero, que para o processador é o mesmo que
dizer ’saia do programa e retorne ao sistema operacional’. Uma restrição inerente à
instrução return é que em todas as funções esta instrução deverá sempre tornar a
apenas um único valor.
Muitas outras funções também já foram apresentadas anteriormente. As funções
matemáticas sqrt(), pow() e log() da biblioteca cmath são exemplos disso.

8.1.1 Procedimentos em C++


Há algumas observações importantes a serem feitas a respeito dos procedimentos
em C++ . A primeira refere-se ao fato de que a declaração de procedimentos deve
sempre começar com a palavra reservada void, indicando que o procedimento é um
tipo de bloco de instruções que não retorna nenhum valor.
Outra observação importante é que os procedimentos, assim como as funções,
devem sempre ser declarados logo no início do programa, antes da função int main().

8.1.1.1 Passagem de parâmetros para procedimentos e funções em C++


Os parâmetros passados para um procedimento ou função devem ser declarados
entre parêntesis. Os nomes e os tipos de parâmetros são especificados como no
exemplo apresentado na linha abaixo.
1 void foo ( int Valor1 , int Valor2 ) {...}

152
++
Princípios de programação em C

Neste exemplo, o procedimento arbitrariamente denominado ’foo’ recebe dois


parâmetros do tipo inteiro, especificados entre parêntesis, que serão utilizados no
interior do procedimento para alguma finalidade específica como, por exemplo, para
a realização de algum cálculo. Esse procedimento não retorna nenhum valor, visto
que ele foi declarado com a palavra reservada void antes do no seu nome. Observe
que esse procedimento poderia ter maior número de parâmetros, e esses parâmetros
serem de tipos diferentes, o que é bastante comum.
Obviamente o programador poderia optar por escrever uma função ao invés de
um procedimento, de modo a obter algum valor lógico, como 1 ou 0, informando,
por exemplo, se as operações no interior da função foram realizadas corretamente
ou não, como apresentado no exemplo a seguir.
O exemplo nas linhas abaixo mostra uma função que retorna um valor do tipo
booleano (’verdadeiro’ ou ’falso’) indicando o status de falha ou sucesso obtido ao
chamar essa função em alguma parte do programa.
1 bool foo ( int Valor1 , int Valor2 )
2 { // A funcao retorna ’ true ’ caso
3 bool Sucesso = false ; // as operacoes no interior da
4 ... // funcao foram processados cor
5 return Sucesso ; // retamente , e retorna ’ false ’
6 } // caso ocorra algo de errado .

Os valores passados como argumentos para um procedimento ou função podem


ser utilizados normalmente em seu interior, mas não são acessíveis do lado de fora
desse procedimento (ou função). No exemplo acima, a variável ’Sucesso’ só é válida
dentro do procedimento ’foo()’.
No Capítulo 10 essa característica será ampliada com a utilização de ’ponteiros’,
em que será estudada a passagem de parâmetros por referência, situação na qual
os valores das variáveis que estejam dentro de um procedimento ou função poderão
modificar valores em variáveis que estejam externas a esses.

8.1.1.2 Protótipos de procedimentos e de funções


Em geral os procedimentos são declarados antes da função int main(). Essa regra
geral pode ser quebrada, fazendo-se a declaração do procedimento em alguma outra
parte do código como, por exemplo, ao seu final.
Caso o programador opte por fazer a declaração do procedimento em algum
outro local que não seja antes da função int main(), ele deverá deixar o ’protótipo’
(a sua declaração) do procedimento (ou da função) antes do int main(). O exemplo
a seguir mostra como isso pode ser feito para uma função.
O ’protótipo’ de um procedimento ou função nada mais é do que a própria
declaração do procedimento (ou função), mas sem as instruções que compõem o
interior desse procedimento (ou função), como mostrado na linha 6 do exemplo a
seguir.

153
++
Princípios de programação em C

1 # include < iostream >


2 using namespace std ;
3

4 // - -[ Prototipos das funcoes ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


5

6 float Soma ( float x , float y ) ; // O prototipo vem aqui


7

9 // - -[ Programa principal ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10

11 int main ()
12 {
13 float Valor1 = 32.25; float Valor2 = 63.28;
14 float Total ;
15

16 Total = Soma ( Valor1 , Valor2 ) ;


17 cout << " Total .: " << Total << endl ;
18 return (0) ;
19 }
20

21 // - -[ Secao reservada para declaracao de funcoes ] - - - - - - - - - - - - -


22

23 float Soma ( float x , float y ) // Funcao declarada aqui


24 {
25 float Resp ;
26 Resp = x + y ;
27 return Resp ;
28 }

8.1.2 Particularidades sobre procedimentos e funções em C++


Como discutido anteriormente as funções são blocos de códigos que retornam algum
tipo de valor, que pode ser numérico, alfanumérico ou booleano. Diferentemente de
um procedimento, que não possui a palavra reservada return em seu interior, as
funções devem ter, obrigatoriamente, essa instrução de retorno de valor.
O programador poderá escrever quantas funções desejar em seu programa, para
diferentes finalidades, sendo que uma função poderá, eventualmente, chamar uma
outra função, sempre que necessário, mas não é permitido declarar (construir) uma
função dentro de outra.
O exemplo a seguir mostra como uma função pode chamar outra função em seu
interior.
1 # include < iostream >
2 using namespace std ;
3

154
++
Princípios de programação em C

4 // - -[ Prototipos de funcoes ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5 void Linha ( void ) ;
6 float F a r e n h e i t P a r a C e l s i u s ( float F ) ;
7 float ListaNaTela ( float F ) ;
8

9 int main () {
10 float nFarenheit = 365.82;
11 cout << " Celsius .: " << ListaNaTela ( nFarenheit ) << endl ;
12 Linha () ;
13 return (0) ;
14 }
15

16 // - -[ Secao para declaracao de funcoes ] - - - - - - - - - - - - - - - - - -


17

18 void Linha ( void )


19 {
20 for ( int i =0; i <30; i ++) {
21 cout << " -" ;
22 }
23 cout << endl ;
24 }
25

26 float F a r e n h e i t P a r a C e l s i u s ( float F )
27 {
28 float nCelsius ;
29 nCelsius = ( F - 32.0) / (1.80) ;
30 return nCelsius ;
31 }
32

33 float ListaNaTela ( float F )


34 {
35 Linha () ; // Chama a funcao Linha () aqui
36 float Resp = F a r e n h e i t P a r a C e l s i u s ( F ) ;
37 return Resp ;
38 }

No Capítulo 4, Seção 4.1.7, p.80, vimos que é possível criar um arquivo externo,
com a extensão .h, no qual as constantes de um programa podem ser colocadas.
Da mesma forma que para as constantes, é mais conveniente colocar todas as
funções e procedimentos de um programa em um ou mais arquivos externos, e
referenciá-los no programa principal. Essa é uma prática muito recomendada, além
de permitir uma maior portabilidade e reaproveitamento de funções, que poderão ser
reutilizadas por diferentes programas, além de tornar menor os códigos do programa
principal. O Capítulo 13 mostrará exemplos de como isso pode ser feito.

155
++
Princípios de programação em C

8.1.2.1 Funções inline


Quando um procedimento ou uma função é ’chamada’ em algum local de um pro-
grama, o que ocorre internamente é que a sequência normal de operações do pro-
grama se desvia, vai até onde aquele procedimento (ou função) está, executa o seu
código e retorna imediatamente após a linha na qual ocorreu a chamada.
Tudo isso demora um certo tempo para acontecer. Se ocorrerem muitas cha-
madas à uma função, então o programa se tornará um pouco mais lento em sua
execução, podendo, inclusive, ser penalizado em sua eficiência.
Uma forma de melhorar a eficiência do programa é utilizar a instrução inline antes
da declaração da função, como mostrado no código a seguir.
1 inline float ListaNaTela ( float F ) {...}

Quando o programa é compilado, a instrução inline faz uma cópia do procedi-


mento (ou função), e efetivamente substitui essa cópia dentro do código, exatamente
nos locais onde ocorrem as chamadas. Assim, a sequência normal de operações do
programa não terá que se desviar para outro local, e seguirá linearmente em suas
atividades, refletindo em um ganho substancial de velocidade em sua execução.
Se por um lado há o aumento na velocidade de execução, por outro lado há um
aumento no tamanho do arquivo executável do programa, o que é uma característica
pouco atrativa. Essa disputa ’velocidade’ versus ’tamanho do arquivo executável’
não é tão importante para os computadores atuais, visto que a grande maioria deles
é capaz de fazer centenas de chamadas a um procedimento (ou função) em uma
fração de segundo, e há espaço de sobra, tanto em capacidade de memória (memória
RAM), quanto nos discos físicos de armazenamento permanente (hard disk) desses
computadores.

8.1.2.2 Sobrecarga de procedimentos e funções


Curiosamente em C++ podemos ter dois ou mais procedimentos (ou funções) com o
mesmo nome. Embora pareça estranho, isso é muito comum, e bastante utilizado em
uma modalidade de programação conhecida como POO (Programação Orientada a
Objetos). Um exemplo de funções diferentes, mas que compartilham o mesmo
nome, está apresentado no código a seguir. Neste exemplo a função Soma pode ser
utilizada tanto para operar com números inteiros quando com valores não inteiros.
1 # include < iostream >
2 using namespace std ;
3

4 // - -[ Prototipos das funcoes ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


5

6 inline float Soma ( float x , int y ) ; // Funcao 1


7 inline int Soma ( int x , int y ) ; // Funcao 2
8 inline double Soma ( double v1 , int v2 ) ; // Funcao 3
9

156
++
Princípios de programação em C

10 // - -[ Programa principal ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
11

12 int main ()
13 {
14 float fV1 = 32.25;
15 int iV2 = 44;
16 double dV3 = 1.45;
17 float Resp1 = Soma ( fV1 , iV2 ) ;
18 int Resp2 = Soma ( iV2 , iV2 ) ;
19 double Resp3 = Soma ( dV3 , iV2 ) ;
20

21 cout << " Soma 1: " << Resp1 << endl ; // 76.25
22 cout << " Soma 2: " << Resp2 << endl ; // 88
23 cout << " Soma 3: " << Resp3 << endl ; // 45.45
24 return (0) ;
25 }
26

27 // - -[ Secao reservada para declaracao de funcoes ] - - - - - - - - - - - - -


28

29 inline float Soma ( float x , int y )


30 {
31 float Total = x + ( float ) y ; // casting
32 return Total ;
33 }
34

35 inline int Soma ( int x , int y )


36 {
37 int Total = x + y ;
38 return Total ;
39 }
40

41 inline double Soma ( double v1 , int v2 )


42 {
43 double Total = v1 + ( double ) v2 ; // casting
44 return Total ;
45 }

Basicamente, o que diferenciará uma função da outra que possua o mesmo nome
são os seus parâmetros e tipo de retorno. Designa-se por ’sobrecarga da função’ o
fato de termos diferentes funções (ou ’sobrecarga do procedimento’, para procedi-
mentos) com o mesmo nome.
No Code::Blocks, ao inserir o nome de um procedimento ou função sobrecar-
regada, automaticamente será aberto um menu de contexto, permitindo escolher
qual função será utilizada, como mostrado na Figura 8.1. Não é necessário se pre-
ocupar com qual função deverá ser escolhida, visto que isso será feito pelo próprio
compilador, em função dos tipos das variáveis passadas como argumentos para a

157
++
Princípios de programação em C

função.

Figura 8.1: Menu de contexto do Code::Blocks para funções sobrecarregadas.


(Fonte: autores)

8.1.2.3 Domínio de funções em cálculos matemáticos


Uma das principais aplicações e usos de funções em cálculos de engenharia está na
facilidade com a qual as funções matemáticas podem ser inseridas e avaliadas nos
programas C++ . Entretanto, em muitas situações podem ocorrer erros de execução
do programa, causados principalmente quando a Unidade Lógica Aritmética do com-
putador tenta executar alguma operação ilegal como, por exemplo, calcular a raiz
quadrada ou o logaritmo de um número negativo. O ’tratamento de exceções’ é um
instrumento importante em situações dessa natureza, e já foi devidamente abordado
e discutido no Capítulo 6. Neste tópico o objetivo é alertar ao leitor sobre a necessi-
dade de sempre avaliar e restringir corretamente os intervalos permitidos de valores
a serem passados como argumentos para as funções, a fim de evitar possíveis erros
ou travamentos do programa durante a sua execução.
A Equação 8.1 apresentada a seguir é utilizada apenas para exemplificar e ilustrar
o modo como o programador pode avaliar o domínio de uma função matemática, e
restringir a faixa de valores permitidos para os seus parâmetros, antes de efetivamente
implementá-la em um programa C++ .
s
x 2 − 4x − 5
f (x) = (8.1)
4 − 4x + x 2
Para que a função descrita pela Equação 8.1 possa ser corretamente avaliada
pelo processador matemático do computador é necessário que tudo aquilo que se

158
++
Princípios de programação em C

encontra sob o símbolo de radical (√) seja obrigatoriamente maior ou igual a zero,
como mostrado na Equação 8.2.

x 2 − 4x − 5
 
≥0 (8.2)
4 − 4x + x 2

Para avaliar o domímio da Equação 8.2 é necessário considerar separadamente


o numerador, y1 (x) = x 2 − 4x − 5, e o denominador, y2 (x) = 4 − 4x + x 2 , dessa
inequação.

Estudo do sinal de y1 (x) = x 2 − 4x − 5: Para a primeira função, y1 (x), a sua


concavidade é voltada para cima, com os valores positivos desta função localizados
nos intervalos x ≤ −1 e x ≥ 5, como mostrado na Figura 8.2 a seguir. Nas discussões
apresentadas nesta seção, a equação de segundo grau tem o formato utilizado na
maioria dos livros de matemática: y (x) = ax 2 +bx +c, com suas raízes representadas
por r1 e r2 .

+ +

-1 5 x
a = 1, (a > 0) -
∆ = 36
r1 = −1, r2 = 5

Figura 8.2: Estudo do sinal da função y1 (x). (Fonte: autores)

Estudo do sinal de y2 (x) = 4 − 4x + x 2 : Para a segunda função, y2 (x), a sua


concavidade é voltada para cima, com os valores positivos desta função localizados
no intervalo x ∈ [−∞, +∞], como mostrado na Figura 8.3 a seguir.

a = 1, (a > 0) + + +

∆=0 x
2
r1 = r2 = 2
Figura 8.3: Estudo do sinal da função y2 (x). (Fonte: autores)

159
++
Princípios de programação em C
 
y1 (x)
Estudo do domínio de : O estudo do domínio da inequação 8.2 deve levar
y2 (x)
y1 (x)
em consideração uma análise dos intervalos dos sinais da razão , conforme
y2 (x)
apresentado na Figura 8.4.

+ - - +
y(x):
1 -1 5 x
+ + + +
y(x):
2 2 x
y(x) + - - +
1
:
y(x) -1 2 5 x
2

Figura 8.4: Estudo do sinal da inequação descrita pela Equação 8.2. (Fonte: autores)

Com base nos intervalos permitidos de valores para a Equação 8.2, apresentado
na Figura 8.4, conclui-se que os valores permitidos para a função 8.1 são: x ≤ −1 e
x ≥ 5. Caso o programador não fique atento a essas restrições e utilize valores fora
da faixa permitida, o programa implementado em C++ poderá não funcionar e gerar
erros em tempo de execução.

8.1.2.4 Parâmetros padrões de procedimentos e funções


Valores padrões podem ser previamente definidos para um ou mais argumentos de
uma função. Assim, quando a função é chamada dentro do código de um programa
o programador pode optar por especificar, ou não, aquele parâmetro e, caso não
especifique, o valor default será utilizado pelo programa. Para exemplificar como
isso funciona, observe a função apresentada a seguir.
1 double Soma ( double x , double y , double z = 0 , double w = 0)
2 {
3 return ( x + y + z + w ) ;
4 }

Os dois últimos parâmetros da função acima possuem valores padrões (default)


e por isso ela pode ser chamada de diferentes formas dentro do código:
1 cout << Soma (2 , 5) << endl ;
2 cout << Soma (2 , 5 , 8) << endl ;
3 cout << Soma (2 , 5 , 8 , 9) << endl ;

Deve-se observar a partir do protótipo (ou cabeçalho) da função que, uma vez
que um parâmetro tenha um valor padrão, então todos os parâmetros subsequentes
a ele também deverão possuir algum valor padrão.

160
++
Princípios de programação em C

1 int Func1 ( int a , int b , int c , int d ) ; // Correto ;


2 int Func2 ( int a , int b =2 , int c , int d ) ; // Errado ;
3 int Func3 ( int a =1 , int b , int c =2 , int d ) ; // Errado ;
4 int Func4 ( int a , int b , int c =2 , int d =1) ; // Correto ;
5 int Func5 ( int a =2 , int b =3 , int c =2 , int d =1) ; // Correto ;

A seguir um código completo de exemplo de aplicação:


1 # include < iostream >
2

3 using namespace std ;


4

5 int Soma ( int a , int b , int c = 2 , int d = 4)


6 {
7 return ( a + b + c + d ) ;
8 }
9

10 int main ()
11 {
12

13 cout << Soma (3 ,3) << endl ; // Saida : 12


14 cout << Soma (3 ,3 ,3) << endl ; // Saida : 13
15 cout << Soma (3 ,3 ,3 ,3) << endl ; // Saida : 12
16

17 return 0;
18 }

Os parâmetros default também podem ser utilizados para outros tipos de variá-
veis, além do double, int e float. No código a seguir um exemplo de como uma
variável do tipo string pode receber um valor padrão em uma função.
1 # include < iostream >
2 # include < cstring >
3 using namespace std ;
4

5 void PrintCidade ( string NomeCidade = " Rio de Janeiro " ) {


6 cout << NomeCidade << endl ;
7 }
8

9 int main () {
10

11 PrintCidade ( " Lavras " ) ;


12 PrintCidade ( " Ijaci " ) ;
13 PrintCidade () ; // Usa o default ;
14 PrintCidade ( " Nepomuceno " ) ;
15 return 0;
16 }

161
++
Princípios de programação em C

8.1.2.5 Recursividade
Recursividade é uma propriedade que permite que uma função chame a si mesma.
O objetivo da recursão é quebrar ou subdividir um problema maior em problemas
menores, dentro de um ciclo iterativo, até que alguma condição de interrupção do
ciclo possa ser alcançada.
Não é algo muito comum trabalhar com funções recursivas em problemas de
engenharia, visto que nem sempre é fácil identificar quando podemos escrever uma
solução para um dado problema em função desse próprio problema. Porém, há inú-
meras aplicações de funções recursivas na resolução de problemas de inteligência
computacional, otimização combinatória, logística de transportes, localização de fa-
cilidades, pesquisa operacional, análise de dados em árvores binárias, algoritmos de
ordenação de dados (Quick sort, Merge sort, etc.), jogos (Puzzle, Chess, Candy
Crush, etc), métodos de busca de sequências de DNA e RNA em bancos de dados
de sequenciamento genético (bioinformática), entre outras aplicações.
No que se refere ao processo recursivo, em cada nova chamada à função, o sis-
tema operacional irá criar na memória do computador uma nova ocorrência dessa
função, com instruções, comandos e variáveis completamente independentes de ocor-
rências anteriores. A função será executada iterativamente, em ciclos, até que al-
guma condição de parada seja estabelecida. Deve-se observar que se esse critério
de interrupção não for bem estabelecido há o risco eminente de a função entrar em
um loop infinito. Além disso, se o loop recursivo for muito grande, então haverá a
necessidade de alocar uma quantidade maior de espaço na memória do computador
para instanciar novas ocorrências dos comandos e variáveis da função, o que não é
uma boa opção.
Na grande maioria das situações, a solução tradicional (sem apelar para recur-
sividade) é suficiente para resolver a quase totalidade dos problemas e, por isso, a
recursividade é apresentada aqui apenas para fins didáticos. No exemplo a seguir é
declarada uma função recursiva para calcular o fatorial (n!) de um número.
1 # include < iostream >
2 using namespace std ;
3

4 // - -[ Prototipo da funcao ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5

6 inline long int fatorial ( long int n )


7 {
8

9 if ( ( n == 1) || ( n == 0) ) {
10 return 1;
11 } else
12 {
13 return ( fatorial (n -1) * n ) ; // Aqui a funcao chama ela
14 } // mesma , de modo recursivo
15 }

162
++
Princípios de programação em C

16

17 // - -[ Programa principal ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18

19 int main ()
20 {
21

22 long int Numero = 0;


23

24 cout << " Informe um numero inteiro ..: " ;


25 cin >> Numero ;
26 cin . ignore () ;
27

28 cout << " O fatorial de " << Numero << " vale : " ;
29 cout << fatorial ( Numero ) << endl ;
30

31 return 0;
32 }

8.1.2.6 Funções para limpar e posicionar o cursor na tela


Na linguagem C++ padrão não há um comando específico que permita limpar a tela
do computador.
Para implementar essa funcionalidade, há várias opções, sendo que uma delas é
utilizar função ’system()’ da biblioteca stdlib.h e, a partir desta função, executar um
comando externo, do próprio sistema operacional, para limpar a tela.
1 # include < stdlib .h >
2 ...
3 system ( " clear " ) ; // Linux ( tudo em minusculos )
4 system ( " cls " ) ; // MS Windows

Bibliotecas gratuitas disponíveis na Internet, como a NCurses1 e a WinBGI2 ,


implementam funções gráficas em C++ para a manipulação da cor dos caracteres na
tela, modificação da posição do cursor, construção de janelas, campos de entrada de
dados, e também para limpar a tela, entre outras, e seu uso é bastante recomendado,
visto que facilitam muito algumas tarefas do programador.
O posicionamento do cursor na tela dependerá, sobretudo, do sistema operacional
que está sendo utilizado pelo programador.
Em geral, a tela do console do MS Windows, assim como do terminal do Linux,
é organizada em linhas e colunas, com a coordenada <0,0> localizada no canto
superior esquedo da tela, conforme apresentado na Figura 8.5.
1
Disponível para download em: https://www.gnu.org/software/ncurses/
2
Disponível para download em: https://www.cs.colorado.edu/main/bgi/install.html

163
++
Princípios de programação em C

0
0

Elemento de coordenada (x,y)

Figura 8.5: Sistema de coordenadas do terminal do Linux e do console do MS


Windows. (Fonte: autores)

A posição do cursor deve ser informada, portanto, na forma de um par de coor-


denadas do tipo <Linha, Coluna>.
• MS Windows: No MS Windows, pode-se criar uma função para o posicio-
namento do cursor na tela, mas para fazer isso é necessário chamar a função
’SetConsoleCursorPosition()’, que pertence a API do MS Windows. A API
(Application Programming Interface) compreende um conjunto de bibliotecas,
funções e procedimentos internos do MS Windows.
1 # include < windows .h >
2 ...
3 void gotoxy ( int column , int line )
4 {
5 COORD coord ;
6 coord . X = column ;
7 coord . Y = line ;
8 SetConsoleCursorPosition (
9 GetStdHandle ( ST D_OUTP UT_HAN DLE ) ,
10 coord
11 );
12 }

O programador pode utilizar as funcionalidades da API em seus programas,


sendo que todos os componentes da API são bem documentados, e podem ser
acessados por diferentes linguagens de programação, como MS Visual Basic,
C++ e C#, entre outras.
• Linux: No Linux o posicionamento do cursor na tela é feito pelo envio de ’ca-
racteres de controle’ (ou ’sequências de escapes’) para o terminal. A sequên-
cia ’\033[<L>;<C>f’ tem a função de movimentar o cursor para a linha ’L’

164
++
Princípios de programação em C

e coluna ’C’. O programador também poderá utilizar a sequência ’\033[2J’


no Linux para limpar a tela, ao invés de usar o system("clear") apresentado
anteriormente.
1 # include < iostream >
2 ...
3 void gotoxy ( unsigned x , unsigned y )
4 {
5 cout << " \033[ " << y << " d \033[ " << x << ’G ’;
6 }

A seguir um exemplo de como limpar a tela e posicionar o cursor na coordenada


<Linha=10, Coluna=1> no terminal do Linux.
1 # include < iostream >
2 # include < stdlib .h >
3 using namespace std ;
4

5 // - -[ Prototipos das funcoes ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


6

7 void GotoXY ( unsigned int x , unsigned int y ) ;


8 void LimpaTela ( void ) ;
9

10 // - -[ Programa principal ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
11

12 int main () {
13 LimpaTela () ;
14 GotoXY (1 ,10) ; // Imprime na coluna 1 e linha 10
15 cout << " Teste " << endl ;
16 return 0;
17 }
18

19 // - -[ Implementacoes das funcoes ] - - - - - - - - - - - - - - - - - - - - - - - - - - - -


20

21 void GotoXY ( unsigned x , unsigned y ) {


22 cout << " \033[ " << y << " d \033[ " << x << ’G ’;
23 }
24 void LimpaTela ( void ) {
25 cout << " \033[2 J " ;
26 }

8.2 Atividades para fixação da aprendizagem


1. Procedimentos e funções
Para os casos apresentados a seguir, escreva a função, o programa em C++ ,
e mostre os valores obtidos com a utilização de dados arbitrários de entrada

165
++
Princípios de programação em C

digitados pelo usuário. Algumas equações apresentadas nesta seção foram


obtidas de DAVIS (1955).

(a) Escreva o programa e a função C++ para calcular o C(p), com p do tipo
double, conforme a Equação 8.3.

p − 12
C(p) = + 16, 95 (8.3)
0, 040 − 0, 0644p

(b) Escreva o programa e a função C++ para calcular o y (a, b, c, d, x), todos
do tipo float, conforme a Equação 8.4.

y = a + bx + 10c+dx (8.4)

(c) Escreva o programa e a função C++ para calcular o B(c), em que c é do


tipo float, conforme a Equação 8.5.

26
B = 366 − 4, 638c + + 0, 01064(100,04084c )
e 0,14(27,5−c) + e 0,14(c−27,5)
(8.5)

(d) Escreva o programa e a função C++ para calcular o valor de L(n, D, d),
em que D e d são variáveis são do tipo float. L representa o comprimento
total de um rolo de papel. n é o número inteiro de voltas (600 a 5.000).
D é o diâmetro do rolo (14 a 34 in). d é o diâmetro do rolo oco interno,
que serve apenas de suporte do papel enrolado a ele (diâmetro de 2 a 6
in).

πn (D + d)
L= (8.6)
24
(e) Escreva o programa e a função C++ para calcular o valor de pH(V, t) de
uma solução na qual está mergulhado um eletrodo de calomelano, usado
juntamente com uma solução saturada de cloreto de potássio. Na Equa-
ção 8.7, V é o potencial em volts (0,2 a 1,2 volts), e t é a temperatura
(10 a 60 graus Celsius).
V − 0, 2458 − 0, 0002t
pH = (8.7)
0, 000198 (t + 273)

(f) Analise a função apresentada a seguir. O que ela faz? Explique detalha-
damente como é o seu funcionamento.

166
++
Princípios de programação em C

1 long int fact ( long int n )


2 {
3 long int ff = 1;
4 long int i = 0;
5

6 for ( i =1; i <= n ; i ++)


7 {
8 ff = ff * i ;
9 }
10

11 return ( ff ) ;
12 }

(g) Analise a função apresentada a seguir. O que ela faz? Explique deta-
lhadamente como é o seu funcionamento. Como essa função pode ser
utilizada dentro de um programa C++ . Dê um exemplo.
1 void RepCh ( char ch , int qtd )
2 {
3 for ( register int i =0; i < qtd ; i ++)
4 {
5 cout << ch ;
6 }
7 cout << endl ;
8 }

(h) Faça um balanço de massa em um tacho aberto, de modo a calcular a


quantidade de doce de leite (M) que pode ser obtida a partir da concen-
tração de uma mistura de leite (L), açúcar (A) e bicarbonato de sódio
(B), com pureza (z). Obtenha a função capaz de calcular uma estima-
tiva para a massa final de doce de leite (M) e a quantidade de água (W )
removida no processo de concentração. Escreva um programa em C++
para implementar as funções obtidas:

M = f (L, A, B, z, bi , bf ) (8.8)

W = f (L, A, B, z, bi , bf ) (8.9)

Nas equações acima, bi e bf são os valores inicial e final de graus Brix da


mistura no tacho aberto.
(i) É possível escrever uma função que retorne um vetor, ao invés de retornar
um único valor? Se sim, explique e dê um exemplo.
(j) É possível escrever uma função que retorne uma matriz, ao invés de re-
tornar um único valor? Se sim, explique e dê um exemplo.

167
++
Princípios de programação em C

(k) As propriedades termofísicas de um alimento podem ser estimadas por


meio das equações apresentas na Tabela 8.1 a seguir, adaptada de IBARZ
e BARBOSA-CÁNOVAS (2003).

Tabela 8.1: Modelos empíricos para cálculo de propriedades termofísicas de alimen-


tos.
Propriedade Componente Equação
k(W/m ◦ C) Carboidrato k = 0, 20141 + 1, 3874 × 10−3 T − 4, 3312 × 10−6 T 2
Cinzas K = 0, 32962 + 1, 4011 × 10−3 T − 2, 9069 × 10−6 T 2
Fibra K = 0, 18331 + 1, 2497 × 10−3 T − 3, 1683 × 10−6 T 2
Gordura K = 0, 18071 + 2, 7604 × 10−3 T − 1, 7749 × 10−7 T 2
Proteína K = 0, 17881 + 1, 1958 × 10−3 T − 2, 7178 × 10−6 T 2
α106 (m2 /s) Carboidrato α = 8, 0842 × 10−2 + 5, 3052 × 10−4 T − 2, 3218 × 10−6 T 2
Cinzas α = 1, 2461 × 10−1 + 3, 7321 × 10−4 T − 1, 2244 × 10−6 T 2
Fibra α = 7, 3976 × 10−2 + 5, 1902 × 10−4 T − 2, 2202 × 10−6 T 2
Gordura α = 9, 8777 × 10−2 + 1, 2569 × 10−4 T − 3, 8286 × 10−8 T 2
Proteína α = 6, 8714 × 10−2 + 4, 7578 × 10−4 T − 1, 4646 × 10−6 T 2
ρ(kg/m ) 3
Carboidrato ρ = 1, 5991 × 103 − 0, 31046T
Cinzas ρ = 2, 4238 × 103 − 0, 28063T
Fibra ρ = 1, 3115 × 103 − 0, 36589T
Gordura ρ = 9, 2559 × 102 − 0, 41757T
Proteína ρ = 1, 3299 × 103 − 0, 51840T
Ĉp (kJ/kg ◦ C) Carboidrato Ĉp = 1, 5488 + 1, 9625 × 10−3 T − 5, 9399 × 10−6 T 2
Cinzas Ĉp = 1, 0926 + 1, 8896 × 10−3 T − 3, 6817 × 10−6 T 2
Fibra Ĉp = 1, 8459 + 1, 8306 × 10−3 T − 4, 6509 × 10−6 T 2
Gordura Ĉp = 1, 9842 + 1, 4733 × 10−3 T − 4, 8008 × 10−6 T 2
Proteína Ĉp = 2, 0082 + 1, 2089 × 10−3 T − 1, 3129 × 10−6 T 2
Fonte: Elaborada pelos autores. Adaptada de IBARZ e BARBOSA-CÁNOVAS (2003).

Escreva um programa que utilize essas funções para estimar as proprieda-


des termofísicas de um alimento em função de sua composição química.
(l) O programa implementado a seguir executa o Método de Interpolação
Polinomial de Lagrange sobre um par de vetores de dados numéricos
reais x, y (RUGGIERO e LOPES (1996)).
Utilize esse programa e obtenha o valor interpolado para o pH (y ), quando
a concentração de ácido cítrico em uma solução é igual a x = [C6 H8 O7 ] =
1, 50 (Mols/litro).
Reescreva o programa, convertendo-o em um procedimento para Interpo-
lação Polinomial de Lagrange, com o seguinte nome: void Lagrange(void).

x=[C6 H8 O7 ] 0,32 0,78 1,47 1,50 1,82 2,47


y=pH 6,75 5,62 4,93 ? 4,17 3,91

168
++
Princípios de programação em C

1 # include < iostream >


2 using namespace std ;
3 int main () {
4 float x [100] , y [100] , xp , yp =0 , p ; int i , j , n ;
5 /* - -[ Tela de entrada de dados ] - - - - - - - - - - - - - - - - - - */
6 cout << " Quantidade de dados .: " ; cin >> n ;
7 cout << endl << endl ;
8 cout << " Informe os dados : " << endl << endl ;
9 for ( i =1; i <= n ; i ++) {
10 cout << " x [ " << i << " ] = " ; cin >> x [ i ];
11 cout << " y [ " << i << " ] = " ; cin >> y [ i ];
12 cout << endl ;
13 }
14 cout << " Informe o x para interpolacao ..: " ;
15 cin >> xp ;
16 /* - -[ Metodo de interpolacao de Lagrange ] - - - - - - - - - */
17 for ( i =1; i <= n ; i ++) {
18 p =1;
19 for ( j =1; j <= n ; j ++) {
20 if ( i != j ) {
21 p = p * ( xp - x [ j ]) /( x [ i ] - x [ j ]) ;
22 }
23 }
24 yp = yp + p * y [ i ];
25 }
26 cout << endl << " Valor interpolado para : "
27 << xp << " >---> " << yp ;
28 cout << endl ;
29 return 0;
30 }

2. Funções inline

(a) O que são funções inline? Qual a vantagem de utilizá-las? Como é feita
a declaração de uma função inline?
(b) Escreva uma função inline que retorne a média geométrica dos valores
contidos em um vetor de 10 elementos.
(c) (FGV-SP) A curva de aprendizagem é um conceito criado por psicólogos
que constataram a relação existente entre a eficiência de um indivíduo e
a quantidade de treinamento ou experiência possuída por este indivíduo.
Um exemplo de Curva de Aprendizagem é dado pela seguinte expressão
(Equação 8.10).

Q(t) = 700 − 400e −0,5t (8.10)

169
++
Princípios de programação em C

Na Equação 8.10, Q é a quantidade de peças produzidas mensalmente por


um funcionário, t refere-se a meses de experiência, e = 2, 718281828.
Escreva um programa no qual a Equação 8.10 seja uma função inline,
para calcular quantas peças um funcionário com n meses de experiência
(n meses de treinamento) deverá produzir mensalmente. n é um valor
inteiro a ser informado pelo usuário do programa.
(d) Escreva um programa no qual as ’fórmulas de equivalência’ dadas pelas
Equações 8.11 listadas a seguir, estejam na forma de funções inline. Essas
equações são amplamente utilizadas em análises de viabilidade econômica
de projetos agroindustriais (DUFFY, 2006; HEWLETT-PACKARD, 2003;
SANTOS, 2001). Observe que algumas dessas funções possuem o mesmo
nome e são, portanto, funções sobrecarregadas. Nas Equações 8.11:
• n é o número de períodos de capitalização. É uma variável do tipo
int.
• i é a taxa efetiva de juros por período de capitalização. É uma variável
do tipo double.
• P V é o valor presente do capital. É uma variável do tipo double.
• P MT é o valor da parcela (valor da prestação) que incide sobre cada
período de capitalização. É uma variável do tipo double.
• F V é o valor futuro do capital acumulado ao final de n períodos de
capitalização, com a taxa de juros i . É uma variável do tipo double.




 F V = P V (1 + i )n




  

 1
PV = FV

(1 + i )n









  n 

 (1 + i ) − 1
F V = P MT


i





Equações =   (8.11)
 i
P MT = F V


(1 + i )n − 1








(1 + i )n − 1

  

P V = P MT


i (1 + i )n








  n 
i (1 + i )


P MT = P V


(1 + i )n − 1

3. Sobrecarga de funções

170
++
Princípios de programação em C

(a) O que é ’sobrecarga de funções’? Explique e dê dois exemplos.


(b) Escreva três funções sobrecarregadas, que tenham como parâmetro de
entrada um vetor de 8 elementos. A primeira função deverá retornar a
’média aritmética’ dos valores presentes no vetor. A segunda deverá retor-
nar a ’média harmônica’, e a terceira deverá retornar a ’média geométrica’
dos dados.
(c) Escreva um programa que tenha funções denominadas ’Converte()’ (to-
das com o mesmo nome) para converter valores de quantidade de calor,
energia e trabalho, conforme as unidades de medida especificadas na pá-
gina 315 (Capítulo 17, Anexos).

4. Recursividade

(a) O que é recursividade de uma função? Explique e dê três exemplos.


(b) Escreva uma função recursiva para calcular x n , em que x e n são dois
números inteiros.
(c) Escreva uma função recursiva para calcular a soma dos valores de todos
elementos de um vetor

171
Capítulo 9

Vetores e matrizes

Conteúdo do capítulo
9.1 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
9.1.1 Declaração e utilização de vetores . . . . . . . . . . . . . . 173
9.1.2 A classe vector . . . . . . . . . . . . . . . . . . . . . . . . 178
9.1.3 Pilhas de memória . . . . . . . . . . . . . . . . . . . . . . 179
9.2 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
9.2.1 Declaração de matrizes e operações sobre seus elementos . 184
9.2.2 Matrizes de strings de caracteres . . . . . . . . . . . . . . 186
9.2.3 Operações numéricas e algébricas com matrizes . . . . . . 186
9.2.3.1 Soma e subtração de matrizes . . . . . . . . . . . 186
9.2.3.2 Multiplicação de matrizes . . . . . . . . . . . . . 188
9.2.3.3 Transposição de uma matriz . . . . . . . . . . . 190
9.2.3.4 Outras operações algébricas com matrizes . . . . 192
9.3 Atividades para fixação da aprendizagem . . . . . . . . . 193

9.1 Vetores
Vetores (do inglês arrays) compreendem variáveis subdivididas em elementos dispos-
tos em série na memória do computador, sendo que todos os elementos devem ser
do mesmo tipo (int, float, etc), e cada posição pode ser acessada por meio de um
índice numérico. Na Figura 9.1 está a representação gráfica de um vetor de dez
elementos, sendo que o primeiro índice é o zero, o segundo índice é um, e assim por
diante.
Muitos problemas práticos no campo das ciências exatas são resolvidos com a
utilização de vetores. Entre os que aparecem mais frequentemente, estão aqueles

172
++
Princípios de programação em C

relacionados com a realização de cálculos estatísticos, ordenação de dados numéri-


cos e alfanuméricos; organização, busca e localização de informações, estruturas de
registros em tabelas de bancos de dados, análise de filas, pilhas, listas, etc.
Neste livro, o assunto ’vetor de caracteres’ já foi abordado anteriormente, no
Capítulo 4, Seção 4.1.3.1, p.56).
O conteúdo sobre vetores tratado aqui no Capítulo 9 é essencialmente o mesmo
do Capítulo 4, porém, diferentemente dos ’vetores de caracteres’, os ’vetores numé-
ricos’ apresentados aqui não tem a sua última posição ocupada pelo ’caractere nulo’
(’\0’), sempre presente na última posição de uma string de caracteres.

Elemento
(no índice 8)

Primeiro índice

0 1 2 3 4 5 6 7 8 9 Índices

Vetor de comprimento igual a 10

Figura 9.1: Representação gráfica de um vetor na memória RAM do computador.


(Fonte: autores)

9.1.1 Declaração e utilização de vetores


A declaração de um vetor é semelhante àquela feita para outros tipos de variáveis,
exceto pelo fato de haver um par de colchetes indicando a dimensão do vetor. No
código a seguir é feita a declaração de um vetor de 10 posições (índices de 0 a 9)
chamado ’nMeuVetor’. A letra ’n’ na primeira posição do nome do vetor é para
indicar que se trata de uma variável numérica.
Cada posição do vetor pode ser acessada pelo seu respectivo índice e receber va-
lores do tipo inteiro. Vetores de outros tipos de dados também podem ser declarados
da mesma forma como, por exemplo, vetor de float, double, etc.
1 int nMeuVetor [10]; // < Tipo > < Nome > [ Qtd . de elementos ]

Para atribuir valores às posições do vetor é necessário que o valor seja do mesmo
tipo suportado pelo vetor. Além disso é necessário informar qual posição do vetor
deverá ser acessada. Assim, por exemplo, para armazenar o valor 36 à primeira
posição do vetor ’nMeuVetor’, a seguinte notação deve ser utilizada:
1 int nMeuVetor [0] = 36;

O programa a seguir mostra que a leitura do valor armazenado em uma posição


qualquer do vetor também é feita a partir do índice especificando a posição desejada.
1 int nValor = nMeuVetor [0];

173
++
Princípios de programação em C

O próximo exemplo mostra mais detalhadamente como armazenar valores nas


posições de um vetor de double, e como fazer sua leitura a partir do objeto cout para
apresentá-los na tela. Neste exemplo o comando for() foi utilizado para percorrer
todos os elementos do vetor.
1 # include < iostream >
2 # include < iomanip >
3 using namespace std ;
4

5 int main () {
6

7 double vProvas [8];


8

9 vProvas [0] = 62.47;


10 vProvas [1] = 86.25;
11 vProvas [2] = 87.65;
12 vProvas [3] = 92.68;
13 vProvas [4] = 88.14;
14 vProvas [5] = 63.15;
15 vProvas [6] = 74.47;
16 vProvas [7] = 56.57;
17

18 for ( int i =0; i <8; i ++)


19 {
20 cout << " Nota [ " << i << " ].: " << vProvas [ i ] << endl ;
21 }
22

23 return 0;
24 }

Um vetor pode ser declarado como mostrado na linha 7 do exemplo acima, sem
nenhum valor atribuído aos seus elementos. Neste caso, cada elemento poderá
conter algum valor arbitrário, vulgarmente chamado de ’lixo de memória’, que já
estava anteriormente guardado na mesma posição da memória onde agora aquele
elemento ocupa. Alternativamente pode-se inicializar o vetor com valores numéricos
como apresentado a seguir.
1 double vProvas [4] = {62.47 , 86.25 , 87.65 , 92.68};

O vetor também pode ser inicializado com zeros em todos os seus elementos.
1 double vProvas [10] = {0}; // Inicializa com zeros

Assim como para valores numéricos, os vetores também podem conter strings.
1 # include < iostream >
2 # include < cstring >
3

4 using namespace std ;

174
++
Princípios de programação em C

6 int main ()
7 {
8 string Carros [4] = { " Volvo " , " BMW " , " Ford " , " Mazda " };
9

10 for ( int i =0; i <4; i ++)


11 {
12 cout << " Modelo .: " << Carros [ i ] << endl ;
13 }
14 return 0;
15 }

Para modificar o valor de um elemento do vetor, basta acessar o conteúdo desse


elemento a partir de seu índice.
1 Carros [2] = " Fusca " ; // Modifica o conteudo da terceira
2 // posicao do vetor

A função getline() pode ser usada para fazer a leitura de strings a partir do
teclado, como no exemplo a seguir.
1 # include < iostream >
2 # include < cstring >
3 using namespace std ;
4

5 int main () {
6 string Nome [3];
7

8 getline ( cin , Nome [0]) ; // A entrada de dados deve ser


9 getline ( cin , Nome [1]) ; // feita a partir do teclado
10 getline ( cin , Nome [2]) ;
11

12 cout << Nome [0] << endl ;


13 cout << Nome [1] << endl ;
14 cout << Nome [2] << endl ;
15

16 return 0;
17 }

Um vetor pode ser inicializado sem que o seu tamanho seja especificado. No
código abaixo, nenhum tamanho foi informado para o vetor ’Carros’. O seu tamanho
será, portanto, igual ao número de elementos utilizados em sua inicialização que,
neste caso, é quatro.
1 string Carros [] = { " Volvo " , " BMW " , " Ford " , " Mazda " };

A inicialização parcial de um vetor também é possível. No exemplo a seguir


apenas os elementos das posições [0] e [1] foram inicializados. Os demais elementos
foram acrescentados após a inicialização, nas linhas de 9 a 12.

175
++
Princípios de programação em C

1 # include < iostream >


2 # include < cstring >
3 using namespace std ;
4

5 int main () {
6

7 string Carros [6] = { " Volvo " , " BMW " };


8

9 Carros [2] = " Fusca " ;


10 Carros [3] = " Ferrari " ;
11 Carros [4] = " Honda " ;
12 Carros [5] = " Ford " ;
13

14 for ( int i =0; i <6; i ++) {


15 cout << " Modelo .: " << Carros [ i ] << endl ;
16 }
17 return 0;
18 }

O programador deve, portanto, tomar algum cuidado ao percorrer os elementos de


um vetor. Se algum índice inválido for informado pelo programador, uma mensagem
de erro poderá ocorrer. No exemplo a seguir, o vetor possui apenas duas posições,
[0] e [1], porém o comando for() tenta percorrer o vetor desde a posição 0 até a
posição 5, extrapolando suas dimensões. Nesse caso uma mensagem de erro será
apresentada na tela: ’Segmentation fault (core dumped)’.
1 string Carros [2] = { " Volvo " , " BMW " };
2

3 for ( int i =0; i <6; i ++) {


4 cout << " Modelo .: " << Carros [ i ] << endl ;
5 }

É importante observar que o compilador C++ não fará nenhuma verificação para
problemas desse tipo durante a compilação. Fazer esse tipo de verificação é uma
tarefa que caberá exclusivamente ao programador. O programa será compilado nor-
malmente, porém ao tentar percorrer elementos que não existam no vetor, uma
mensagem de erro será exibida e o programa poderá ser abortado em tempo de
execução.
O índice ou o tamanho de um vetor também pode ser definido por meio de uma
constante (declarada com #define ou const).
1 # include < iostream >
2

3 # define TAM 5 // Constante


4 # define POS1 1 // Constante
5 # define POS2 3 // Constante
6 using namespace std ;

176
++
Princípios de programação em C

8 int main () {
9 float cNotas [ TAM ];
10

11 cNotas [ POS1 ] = 67.25; cNotas [ POS2 ] = 89.36;


12

13 cout << cNotas [ POS1 ] << endl ; // 67.25;


14 cout << cNotas [ POS2 ] << endl ; // 89.36;
15 return 0;
16 }

O exemplo a seguir mostra como utilizar vetores para calcular a diferença total
entre duas cores de tomate (no padrão L*a*b* de cores) por meio da distância
euclidiana entre suas coordenadas espaciais.
1 # include < iostream >
2 # include < cmath >
3 using namespace std ;
4

5 int main () {
6

7 double CieLab_Cor1 [3] = {43.31 , 47.63 , 14.12}; // Tomate 1


8 double CieLab_Cor2 [3] = {47.34 , 44.58 , 15.16}; // Tomate 2
9 double DeltaCor = 0.00;
10

11 for ( int i =0; i <3; i ++)


12 {
13 DeltaCor += pow (( CieLabCor1 [ i ] - CieLab_Cor2 [ i ]) , 2) ;
14 }
15

16 DeltaCor = sqrt ( DeltaCor ) ;


17 cout << " Distancia .: " << DeltaCor << endl ; // 5.16;
18

19 return 0;
20 }

A vantagem prática da utilização de vetores está no fato de tornar possível a


manipulação de grandes quantidades de valores numéricos, enquanto mantém o có-
digo bastante reduzido. O exemplo a seguir calcula a soma e a média de todos os
números pares, desde zero até 10.000, percorrendo as posições de um vetor com o
comando for(). Neste caso não foi necessário declarar dez mil variáveis , mas apenas
um único vetor com dez mil posições, e acessar cada uma delas por meio de um
índice.
1 # include < iostream >
2 # define TAM 10000 // Constante
3 using namespace std ;
4

177
++
Princípios de programação em C

5 int main () {
6

7 double nNum [ TAM ];


8 double nSoma , nMedia ;
9 int j = 0;
10

11 for ( int i =0; i < TAM ; i ++) { // Preenche pares


12 nNum [ i ] = ( double ) j ;
13 j += 2;
14 }
15

16 nSoma = nMedia = 0.00;


17

18 for ( int i =0; i < TAM ; i ++) { // Calcula soma


19 nSoma += nNum [ i ];
20 }
21

22 nMedia = ( nSoma ) / ( double ) TAM ; // Calcula a media


23

24 cout << " Soma ..: " << nSoma << endl ; // 9.999 e +07;
25 cout << " Media .: " << nMedia << endl ; // 9999;
26 return 0;
27 }

Embora permitido em outras linguagens de programação, como o Microsoft Visual


Basic, em C++ o programador não pode manipular diferentes tipos de dados em um
mesmo vetor. Se o vetor foi declarado como sendo do tipo float, então ele aceitará
somente valores do tipo float em todos os seus elementos, e não outros tipos. Caso
seja necessário atribuir dados de outros tipos aos elementos de um vetor, então é
necessário primeiramente convertê-los1 para o tipo adequado antes de fazer essa
atribuição.

9.1.2 A classe vector


No que se refere a vetores, o C++ possui funcionalidades alternativas, além daquelas
que foram apresentadas até agora. Algumas dessas funcionalidades estão na classe
array, uma biblioteca interna do C++ que permite, por exemplo, redimensionar um
vetor em tempo de execução do programa, além de oferecer recursos para ordenação,
informar sobre o tamanho do vetor, operações com pilhas de dados, avaliar se o vetor
está vazio ou não, entre outras funcionalidades. Para utilizar os recursos da classe
vector é necessária a inclusão da biblioteca ’vector’.
1 # include < vector >

1
Ver detalhes sobre conversão de tipos no Capítulo 4, Seção 4.4, p.84.

178
++
Princípios de programação em C

A declaração de um vetor utilizando essa biblioteca é feita por meio da palavra


reservada vector, a especificação do tipo de dado a ser armazenado no vetor, e o seu
tamanho. O código a seguir mostra um exemplo de como deve ser feita a declaração
de um vetor de inteiros contendo dez elementos.
1 vector < int > MeuVetor (10) ;

Caso o programador tenha interesse em inicializar o ’MeuVetor’ com algum valor


numérico, isso pode ser feito da seguinte forma:
1 vector < int > MeuVetor (10 , 5) ; // Inicializa todos os
2 // elementos com o valor 5

O tamanho total do vetor pode ser obtido com o método size().


1 cout << MeuVetor . size () << endl ;

O tamanho de um vetor pode ser modificado, em tempo de execução do pro-


grama, com o método ’resize()’. Neste caso, o sistema operacional se encarregará
de dinamicamente alocar mais espaço na memória quando o tamanho do vetor au-
mentar, ou então liberar espaços na memória ao diminuir o tamanho do vetor.
1 MeuVetor . resize (15) ;
2 MeuVetor [12] = 125;
3 cout << MeuVetor [12] < < endl ; // 125

O acesso aos elementos de um vetor é feito por meio de seu índice, que deve ser
informado dentro de um par de colchetes. O índice sempre começa a contar a partir
do zero.
1 MeuVetor [1] = 430;
2 int cNum = MeuVetor [1];
3 cout << cNum << endl ;

É possível também inicializar um vetor vazio, bastando, para isso, não informar
o seu tamanho. Para testar se um vetor está vazio, o programador pode utilizar a
função ’empty()’.
1 vector < int > OutroVetor ; // Retorno :
2 cout << OutroVetor . empty () << endl ; // 1 >> vetor vazio
3 // 0 >> vetor nao vazio

9.1.3 Pilhas de memória


O conceito de pilha (Figura 9.2) é muito importante em diversas aplicações cientí-
ficas. São estruturas do tipo ’o último elemento que entra na pilha, é também o
primeiro elemento que sai da pilha’. Elas ajudam a organizar e facilitam a manipula-
ção de certos tipos de dados.

179
++
Princípios de programação em C

A operação de uma pilha é sempre feita por uma de suas extremidades. Alguns
exemplos de típicos do dia-a-dia estão listadas logo a seguir, e podem ser facilmente
implementados em vetores por meio das operações de push (inserir na pilha) e pop
(remover da pilha).

1 2 3 4 5 6 7

Empilhamento 7
6 6
5 5 5
4 4 4 4
3 3 3 3 3
2 2 2 2 2 2
1 1 1 1 1 1 1

7 6 5 4 3 2 1
Esvaziamento da pilha

7
6 6
5 5 5
4 4 4 4
3 3 3 3 3
2 2 2 2 2 2
1 1 1 1 1 1 1

Figura 9.2: Diagrama esquemático do funcionamento básico de uma pilha de me-


mória. (Fonte: autores)

• Pilha de livros, de cd’s, de folhas de papel, sacas de café em um armazém.

• Retirada de mercadorias em um caminhão de entregas.

• Esvaziamento de um meio de transporte coletivo pela retirada de pessoas como,


por exemplo, um trem ou um metrô. Os passageiros que entraram por último, e
que se encontram mais próximos à porta, sairão primeiro, enquanto que aqueles
que entraram primeiro serão os últimos a sair.

• Pilha de instruções na memória de uma calculadora (RPN2 ).

O exemplo apresentado a seguir mostra como adicionar e remover elementos de


uma pilha.
1 # include < iostream >
2 # include < vector >
3 using namespace std ;
4

2
Notação Polonesa Reversa, modo de processamento típico de algumas calculadoras científicas.

180
++
Princípios de programação em C

5 void ImprimeVetor ( void ) ; // Prototipo da funcao


6 // ImprimeVetor ( void )
7 vector < int > IDProduto ; // Vetor de inteiros ( global )
8

9 int main () {
10

11 IDProduto . push_back (16) ; // Insere 16 na posicao zero


12 IDProduto . push_back (11) ; // Insere 11 na posicao um
13 IDProduto . push_back (45) ; // Insere 45 na posicao dois
14 IDProduto . push_back (64) ; // Insere 64 na posicao tres
15 IDProduto . push_back (85) ; // Insere 85 na posicao quatro
16 IDProduto . push_back (69) ; // Insere 69 na posicao cinco
17 ImprimeVetor () ;
18

19 IDProduto . pop_back () ; // Retira dois elementos da pilha


20 IDProduto . pop_back () ;
21 ImprimeVetor () ;
22

23 return 0;
24 }
25

26 void ImprimeVetor ( void ) {


27 for ( register int i =0; i < IDProduto . size () ; i ++) {
28 cout << IDProduto [ i ] << endl ;
29 }
30 cout << endl << endl ;
31 }

A função ’capacity()’ fornece o número de posições (tamanho) do vetor, e caso


o programador tenha necessidade de aumentar ou diminuir o tamanho do vetor, isso
pode ser feito com a função ’reserve()’.
1 cout << IDProduto . capacity () << endl ; // Exibe tamanho atual
2 IDProduto . reserve (100) ; // Aumenta o tamanho
3 // do vetor para 100
4 // posicoes

No exemplo apresentado a seguir a classe vetor é utilizada para armazenar uma


lista de alunos. Os alunos são acrescentados à pilha em uma ordem não alfabética.
Para que strings sejam adicionadas ao vetor, é necessário incluir a biblioteca strings
no início do programa. Para ordenar alfabeticamente a lista dos nomes dos alunos,
é utilizado o comando sort da biblioteca algorithm.
1 # include < iostream > // Biblioteca padrao C ++
2 # include < vector > // Biblioteca para trabalhar com vetores
3 # include < algorithm > // Para usar a funcao ’ sort () ’ ordenacao
4 # include < string > // Para inserir ’ strings ’ nos vetores
5

181
++
Princípios de programação em C

6 using namespace std ;


7

8 void ImprimeVetor ( void ) ; // Prototipo


9 vector < string > Alunos ; // Variavel global
10

11 int main () {
12 Alunos . push_back ( " Paulo " ) ;
13 Alunos . push_back ( " Joaquim " ) ;
14 Alunos . push_back ( " Antonio " ) ;
15 Alunos . push_back ( " Simone " ) ;
16 Alunos . push_back ( " Liliam " ) ;
17 Alunos . push_back ( " Cristine " ) ;
18

19 sort ( Alunos . begin () , Alunos . end () ) ; // Ordenacao do vetor


20 ImprimeVetor () ;
21 return 0;
22 }
23

24 void ImprimeVetor ( void )


25 {
26 for ( register int i =0; i < Alunos . size () ; i ++)
27 {
28 cout << Alunos [ i ] << endl ;
29 }
30 cout << endl << endl ;
31 }

A comparação entre os conteúdos armazenados em dois vetores diferentes pode


ser feita facilmente com o operador ”==”, da classe vector, como mostrado no exem-
plo a seguir. Outros operadores de comparação, como ’>’, ’>=’, ’<’, ’<=’ e ’ !=’
também funcionarão quando utilizados para a comparação de dois vetores.
1 # include < iostream >
2 # include < vector >
3

4 using namespace std ;


5

6 int main () {
7

8 vector < int > Vetor1 (10) ;


9 vector < int > Vetor2 (10) ;
10

11 for ( int i =0; i <10; i ++)


12 {
13 Vetor1 [ i ] = 2* i ;
14 Vetor2 [ i ] = 5* i ;
15 }

182
++
Princípios de programação em C

16

17 if ( Vetor1 == Vetor2 ) {
18 cout << " Os vetores sao iguais " << endl ;
19 } else {
20 cout << " Os vetores sao diferentes " << endl ;
21 }
22

23 return 0;
24 }

O conteúdo de um vetor (’Vetor1’) pode ser simultaneamente trocado (swap)


com o de outro vetor (’Vetor2’) com a função swap().
1 Vetor1 . swap ( Vetor2 ) ;

A exclusão dinâmica de dados de um vetor é feita com a função erase(). Ela pode
ser utilizada para excluir o elemento de uma posição específica como, por exemplo,
para excluir o elemento na quinta posição do vetor.
1 Vetor1 . erase ( Vetor1 . begin () +4) ;

E pode ser utilizada também para excluir uma faixa de valores. No exemplo a
seguir ela irá excluir os três primeiros elementos do vetor.
1 Vetor1 . erase ( Vetor1 . begin () , Vetor1 . begin () +3) ;

Outros recursos para manipulação de pilhas em C++ podem ser obtidos com o
uso da biblioteca padrão stack, mas sua abordagem está fora do escopo deste livro,
e sua utilização fica como um exercício para o leitor.
1 # include < stack >

9.2 Matrizes
Matrizes são muito semelhantes a vetores, porém, diferentemente dos vetores, que
possuem apenas uma dimensão, as matrizes são tipicamente multidimensionais. Ma-
trizes são, portanto, um conjunto de variáveis do mesmo tipo, com um nome em
comum, que podem ser referenciadas e acessadas por um índice.
A Figura 9.3 mostra a configuração típica de dois tipos de matrizes, mais à
esquerda está uma matriz de duas dimensões, com dez (dez) colunas e 8 (oito)
linhas. A configuração mais à direita nesta Figura é uma matriz de três dimensões,
com 6 (seis) colunas, 6 (seis) linhas e 6 (seis) elementos de profundidade.

183
++
Princípios de programação em C

Elemento
(Posição: Col = 5, Lin = 3)

Primeiro índice na coluna

0 1 2 3 4 5 6 7 8 9 Índices

0 Elemento
(Posição: Col = 0, Lin = 0, Prof = 0)
1

2
3
4
5
6

Índices

Matriz de dimensão 10x8 Matriz de dimensão 7x6x5

Figura 9.3: Configuração típica da disposição dos elementos em uma matriz. À


esquerda, uma matriz bidimensional. À direita, uma matriz tridimensional. As siglas
apresentadas na figura são: ’Lin’ (linha), ’Col’ (coluna) e ’Prof’ (profundidade).
(Fonte: autores)

Uma observação a ser feita é que muitos softwares de planilhas eletrônicas, como
o Microsoft Excel e o GNumeric, utilizam a mesma disposição de seus elementos (ou
células) da configuração bidimensional apresentada na Figura 9.3.

9.2.1 Declaração de matrizes e operações sobre seus elementos


A declaração de matrizes é muito semelhante à declaração de vetores, e é feita
especificando-se o seu tipo (int, float, double, etc.), o nome da matriz, e as quan-
tidades de elementos em cada dimensão, devidamente separadas por um par de
colchetes.
A declaração de uma matriz bidimensional de inteiros com 6 colunas e 4 linhas,
e com o nome ’nMatriz1’ é feita da seguinte forma:
1 int nMatriz1 [6][4]; // 6 colunas e 4 linhas

A declaração de uma matriz tridimensional de floats, com o nome ’nMatriz2’,


com 8 linhas, 9 colunas e 15 posições de profundidade é feita assim:
1 int nMatriz2 [9][8][15]; // 9 colunas , 8 linhas e 15
2 // elementos de profundidade

184
++
Princípios de programação em C

Observe que em C++ todos os elementos da matriz devem ser de um mesmo


tipo de dado. Matrizes de dimensões maiores também podem ser declaradas e o
acesso a qualquer elemento em seu interior deve levar em conta todas as dimensões
da matriz. No exemplo a seguir uma matriz com 5 (cinco) dimensões.
1 int nMatriz3 [ 12 ] [ 16 ] [ 9] [ 7 ][ 2 2 ] ; // Uma matriz de inteiros
2 // com cinco dimensoes

Matrizes de muitas dimensões devem ser utilizadas com algum cuidado visto que
podem ocupar muito espaço na memória do computador. No exemplo anterior a
matriz ’nMatriz3’ possui um total de 12 × 16 × 9 × 7 × 22 = 226.112 células.
O preenchimento das posições de uma matriz é feito exatamente da mesma
maneira que para os vetores. É necessário apenas informar a posição do elemento
dentro da matriz, por meio de índices, e utilizar o operador de atribuição ’=’, conforme
mostrado a seguir.

0 1 2 3 4 5 6

0 21 36 97 2 44 21 9

1 60 13 17 5 11 87 14

2 22 83 69 18 1 99 7
3 40 26 31 66 92 3 15

Figura 9.4: Matriz bidimensional de inteiros, com 7 colunas e 4 linhas. (Fonte:


autores)

1 int nMatriz [7][4]; // 7 colunas e 4 linhas ;


2 nMatriz [0][0] = 21;
3 nMatriz [1][0] = 36;
4 ...
5 nMatriz [6][3] = 15;

A leitura do conteúdo do elemento que ocupa alguma posição da matriz é feita


exatamente da mesma forma que para os vetores.
1 int x ,y , z ;
2 x = nMatriz [0][0]; // x recebe 21;
3 y = nMatriz [1][0]; // y recebe 36;
4 z = nMatriz [6][3]; // z recebe 15;

A comparação dos elementos de duas matrizes é feita da mesma forma que a


comparação das posições de elementos de vetores, com o operador de comparação
’==’, bastando, para isso, informar as posições dos elementos a serem comparados.
1 if ( nMatriz1 [2][6] == nMatriz2 [16][25]) {...};

185
++
Princípios de programação em C

9.2.2 Matrizes de strings de caracteres


Matrizes de strings de caracteres também podem ser declaradas, de modo semelhante
às matrizes de valores numéricos. Nesta situação, contudo, o modo de utilização da
matriz é um pouco diferente. No exemplo a seguir, é feita a declaração de uma matriz
de caracteres com o nome ’cFrutas’. Essa matriz possui 4 elementos na primeira
dimensão, correspondente aos nomes de 4 frutas. A segunda dimensão possui 12
posições, correspondendo aos tamanhos dos nomes das frutas, que deverão possuir
até 11 letras. Aqui é importante lembrar que o último caractere do nome de cada
fruta será o ’caractere nulo’ (’\0’).
1 # include < iostream >
2 # include < cstring > // Para usar ’ strcpy () ’
3 using namespace std ;
4 int main () {
5

6 char cFrutas [4][12]; // 4 frutas , cada uma com ate 11


7 // caracteres no seu nome
8 strcpy ( cFrutas [0] , " Melancia " ) ;
9 strcpy ( cFrutas [1] , " Goiaba " ) ;
10 strcpy ( cFrutas [2] , " Morango " ) ;
11 strcpy ( cFrutas [3] , " Abacate " ) ;
12

13 cout << " Fruta 1.: " << cFrutas [0] << endl ; // Melancia
14 cout << " Fruta 2.: " << cFrutas [1] << endl ; // Goiaba
15 cout << " Fruta 3.: " << cFrutas [2] << endl ; // Morango
16 cout << " Fruta 4.: " << cFrutas [3] << endl ; // Abacate
17 return 0;
18 }

9.2.3 Operações numéricas e algébricas com matrizes


9.2.3.1 Soma e subtração de matrizes
Operações algébricas com matrizes podem ser facilmente realizadas ao utilizar índices
e laços de repetição para percorrer todos os elementos da matriz. As operações mais
comuns são a soma e a subtração de matrizes. A soma é descrita pela Equação 9.1.
Os elementos sij da matriz resultante da soma são calculados pela Equação 9.2.

     
a11 a12 · · · a1n b11 b12 · · · b1n s11 s12 · · · s1n
 a21 a22 · · · a2n   b21 b22 · · · b2n   s21 s22 · · · s2n 
.. .. . . . .. + .. .. ... .. = .. .. . . . .. 
     
. . . . . . . . . 

    
am1 am2 · · · amn bm1 bm2 · · · bmn sm1 sm2 · · · smn
(9.1)

186
++
Princípios de programação em C

sij = aij + bij (9.2)

No exemplo a seguir é utilizado o gerador de números aleatórios do computador


para preencher as posições de duas matrizes de dimensões 3x3. A seed utilizada para
a geração dos números aleatórios tem como base a hora atual do computador, obtida
com auxílio da biblioteca ctime. Um laço for() aninhado é utilizado para percorrer as
posições das duas matrizes e fazer a soma de seus elementos, colocando o resultado
na matriz ’nSoma’.
1 # include < iostream >
2 # include < cstdlib > // Para funcoes ’ srand () ’ e ’ rand () ’
3 # include < ctime > // ’ Seed ’ para numeros aleatorios
4 using namespace std ;
5

6 int main () {
7 srand (( unsigned ) time ( NULL ) ) ;
8 int nMin = 0; // Valor minimo para aleatorio
9 int nMax = 100; // Valor maximo para aleatorio
10

11 int nNotas1 [3][3];


12 int nNotas2 [3][3];
13 int nSoma [3][3] = {0};
14

15 int Aleatorio = 0;
16

17 // - -[ Preenche a primeira e a segunda matriz com numeros ] - - - -


18 // - -[ aleatorios gerados por ’ rand () ’ e ’ srand () ’ ]----
19 for ( int Linha =0; Linha <3; Linha ++) {
20 for ( int Coluna =0; Coluna <3; Coluna ++) {
21 Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;
22 nNotas1 [ Linha ][ Coluna ] = Aleatorio ;
23

24 Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;


25 nNotas2 [ Linha ][ Coluna ] = Aleatorio ;
26 }
27 }
28

29 // - -[ Imprime a matriz nNotas1 ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


30 cout << " Matriz nNotas1 : " << endl << endl ;
31 for ( int Linha =0; Linha <3; Linha ++) {
32 cout << nNotas1 [ Linha ][0] << ’\ t ’ <<
33 nNotas1 [ Linha ][1] << ’\ t ’ <<
34 nNotas1 [ Linha ][2] << endl ;
35 }
36 cout << endl << endl ;

187
++
Princípios de programação em C

37

38 // - -[ Imprime a matriz nNotas2 ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


39 cout << " Matriz nNotas2 : " << endl << endl ;
40 for ( int Linha =0; Linha <3; Linha ++) {
41 cout << nNotas2 [ Linha ][0] << ’\ t ’ <<
42 nNotas2 [ Linha ][1] << ’\ t ’ <<
43 nNotas2 [ Linha ][2] << endl ;
44 }
45

46

47 // - -[ Calcula a soma dos elementos de nNotas1 e nNotas2 ] - - - - -


48 for ( int Linha =0; Linha <3; Linha ++) {
49 for ( int Coluna =0; Coluna <3; Coluna ++) {
50 nSoma [ Linha ][ Coluna ] = nNotas1 [ Linha ][ Coluna ] +
51 nNotas2 [ Linha ][ Coluna ];
52 }
53 }
54 cout << endl << endl ;
55

56 // - -[ Imprime a matriz nSoma ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


57 cout << " Soma : " << endl << endl ;
58 for ( int Linha =0; Linha <3; Linha ++) {
59 cout << nSoma [ Linha ][0] << ’\ t ’ <<
60 nSoma [ Linha ][1] << ’\ t ’ <<
61 nSoma [ Linha ][2] << endl ;
62 }
63 return 0;
64 }

Em termos computacionais, a subtração de matrizes é um processo idêntico ao


da soma, sendo que a única diferença está no sinal que aparece no final da linha 50
do código acima que, para a operação de subtração, será o sinal algébrico negativo.
Sendo essa a única diferença no código, então não há necessidade de apresentar um
código de exemplo para a operação de subtração.

9.2.3.2 Multiplicação de matrizes


A multiplicação de uma matriz 2x2 é feita conforme descrito pela Equação 9.3.
Matrizes de dimensões maiores são multiplicadas da mesma forma, e cada elemento
cij da matriz resultante é calculado pela Equação 9.4.

     
a11 a12 b11 b12 (a11 × b11 + a12 × b21 ) (a11 × b12 + a12 × b22 )
+ =
a21 a22 b21 b22 (a21 × b11 + a22 × b21 ) (a21 × b12 + a22 × b22 )
(9.3)

188
++
Princípios de programação em C

n
X
cij = aik × bkj (9.4)
k=1

A seguir o código de um programa que preenche duas matrizes, ’nNotas1’ e


’nNotas2’, com números aleatórios no intervalo de zero a 100. Em seguida é feita
a multiplicação dessas matrizes, de acordo com a Equação 9.4, e o resultado é
colocado na matriz ’nProd’. Deve-se observar que operações algébricas como soma
e subtração exigem que as matrizes a serem somadas ou subtraídas tenham a mesma
dimensão. Para a multiplicação de matrizes é exigido que o número de colunas da
primeira matriz seja igual ao número de linhas da segunda matriz, e para o cálculo
de determinante e inversa de matrizes, essas devem ter o número de linhas igual ao
número de colunas (matrizes quadradas).
1 # include < iostream > // Biblioteca padrao C ++
2 # include < cstdlib > // Para funcoes ’ srand () ’ e ’ rand () ’
3 # include < ctime > // ’ Seed ’ para numeros aleatorios
4 using namespace std ;
5

6 int main () {
7 srand (( unsigned ) time ( NULL ) ) ;
8 int nMin = 0; // Valor minimo para aleatorio
9 int nMax = 100; // Valor maximo para aleatorio
10 int nNotas1 [3][3];
11 int nNotas2 [3][3];
12 int nProd [3][3] = {0};
13 int Aleatorio = 0;
14

15 // - -[ Preenche a primeira e a segunda matriz com numeros ] - - - -


16 // - -[ aleatorios gerados por ’ rand () ’ e ’ srand () ’ ]----
17 for ( int Linha =0; Linha <3; Linha ++) {
18 for ( int Coluna =0; Coluna <3; Coluna ++) {
19 Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;
20 nNotas1 [ Linha ][ Coluna ] = Aleatorio ;
21 Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;
22 nNotas2 [ Linha ][ Coluna ] = Aleatorio ;
23 }
24 }
25

26 // - -[ Imprime a matriz nNotas1 ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


27 cout << " Matriz nNotas1 : " << endl << endl ;
28 for ( int Linha =0; Linha <3; Linha ++) {
29 cout << nNotas1 [ Linha ][0] << ’\ t ’ <<
30 nNotas1 [ Linha ][1] << ’\ t ’ <<
31 nNotas1 [ Linha ][2] << endl ;
32 }

189
++
Princípios de programação em C

33 cout << endl << endl ;


34

35 // - -[ Imprime a matriz nNotas2 ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


36 cout << " Matriz nNotas2 : " << endl << endl ;
37 for ( int Linha =0; Linha <3; Linha ++) {
38 cout << nNotas2 [ Linha ][0] << ’\ t ’ <<
39 nNotas2 [ Linha ][1] << ’\ t ’ <<
40 nNotas2 [ Linha ][2] << endl ;
41 }
42

43 // - -[ Calcula o produto dos elementos de nNotas1 e nNotas2 ] - - -


44 double nElemento = 0.00;
45

46 for ( int Coluna =0; Coluna <3; Coluna ++) {


47 for ( int Linha =0; Linha <3; Linha ++) {
48 for ( int K =0; K <3; K ++) {
49 nElemento = nElemento +
50 ( nNotas1 [ Linha ][ K ] * nNotas2 [ K ][ Coluna ]) ;
51 }
52 nProd [ Linha ][ Coluna ] = nElemento ;
53 nElemento = 0.00;
54 }
55 }
56 cout << endl << endl ;
57

58 // - -[ Imprime a matriz nSoma ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


59 cout << " Soma : " << endl << endl ;
60 for ( int Linha =0; Linha <3; Linha ++) {
61 cout << nProd [ Linha ][0] << ’\ t ’ <<
62 nProd [ Linha ][1] << ’\ t ’ <<
63 nProd [ Linha ][2] << endl ;
64 }
65 return 0;
66 }

9.2.3.3 Transposição de uma matriz


A transposta de uma matriz A = [ai,j ]m,n
i,j=1 é a matriz A = [ai,j ]j,i=1 . A Equação 9.5
T n,m

mostra um exemplo de como é feita a transposição de uma matriz.


   
a1,1 a1,2 · · · a1,n a1,1 a2,1 · · · am,1
 a2,1 a2,2 · · · a2,n   a1,2 a2,2 · · · am,2 
A= .. .. .. ..  ⇔ AT =  .. .. .. .. (9.5)
   
. . . . . . . .

   
am,1 am,2 · · · am,n a1,n a2,n · · · am,n
Os elementos de uma matriz transposta são calculados pela Equação 9.6.

190
++
Princípios de programação em C

AT (9.6)
 
ij
= [A]ji

1 # include < iostream >


2 # include < cstdlib > // Para funcoes ’ srand () ’ e ’ rand () ’
3 # include < ctime > // ’ Seed ’ para numeros aleatorios
4 using namespace std ;
5

6 int main ()
7 {
8 srand (( unsigned ) time ( NULL ) ) ;
9 int nMin = 0; // Valor minimo para aleatorio
10 int nMax = 100; // Valor maximo para aleatorio
11 int nMatriz [5][3]; int nTransp [3][5]; int Aleatorio = 0;
12

13 // - -[ Preenche a matriz com numeros aleatorios ] - - - - - - - - - - - - - -


14 for ( int Linha =0; Linha <3; Linha ++)
15 {
16 for ( int Coluna =0; Coluna <5; Coluna ++) {
17 Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;
18 nMatriz [ Coluna ][ Linha ] = Aleatorio ;
19 }
20 }
21 // - -[ Imprime a matriz nMatriz ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 cout << " Matriz .: " << endl << endl ;
23 for ( int Linha =0; Linha <3; Linha ++)
24 {
25 for ( int Coluna =0; Coluna <5; Coluna ++) {
26 cout << nMatriz [ Coluna ][ Linha ];
27 if ( Coluna == 4) {
28 cout << endl ;
29 } else {
30 cout << ’\ t ’;
31 }
32 }
33 }
34 cout << endl << endl ;
35

36 // - -[ Calcula a transposta ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
37 for ( int Linha =0; Linha <3; Linha ++)
38 {
39 for ( int Coluna =0; Coluna <5; Coluna ++) {
40 nTransp [ Linha ][ Coluna ] = nMatriz [ Coluna ][ Linha ];
41 }
42 }
43 cout << endl << endl ;

191
++
Princípios de programação em C

44

45 // - -[ Imprime a matriz transposta ] - - - - - - - - - - - - - - - - - - - - - - - - - - -


46 for ( int Linha =0; Linha <5; Linha ++)
47 {
48 for ( int Coluna =0; Coluna <3; Coluna ++) {
49 cout << nTransp [ Coluna ][ Linha ];
50 if ( Coluna ==2) {
51 cout << endl ;
52 } else {
53 cout << ’\ t ’;
54 }
55 }
56 }
57 return 0;
58 }

9.2.3.4 Outras operações algébricas com matrizes


• Determinante é uma função matricial que associa um único valor escalar a
uma matriz quadrada. Calcular o valor do determinante é importante porque
permite verificar se uma matriz admite, ou não, a operação de inversão. Se
o determinante de uma matriz é igual a zero, então diz-se que essa matriz é
singular, e não admite inversa.

n×n , também quadrada e de


• A inversa de uma matriz A é uma outra matriz, A−1
mesma ordem da matriz A. Por definição, a matriz inversa possui a seguinte
propriedade (Equação 9.7).

An×n · A−1 −1
n×n = An×n × An×n = In×n (9.7)

Em que In×n é uma matriz identidade.


Em problemas como balanços de massa, análise de malhas de circuitos elétricos,
preparo de formulação para sorvetes, produtos de panificação, resolução de
sistemas de equações e ajuste de modelos estatísticos a dados experimentais,
é necessário o cálculo da inversa de matrizes.
Uma abordagem teórica sobre o cálculo de determinantes e inversas de matrizes
não será feita aqui, pois está fora do escopo deste livro, mas o leitor poderá
encontrar exercícios propostos sobre o cálculo de matrizes inversas, e outros
assuntos relacionados a matrizes em BOLDRINI et al. (1986) e RUGGIERO e
LOPES (1996).

192
++
Princípios de programação em C

9.3 Atividades para fixação da aprendizagem


1. Vetores

(a) Faça um programa no qual seja declarado um vetor R. Esse vetor deve
possuir 10 posições (n = 10 elementos) do tipo double. O programa
deverá fazer as seguintes operações sobre esse vetor:
i. Atribuir valores entre 10,0 e 50,0 aos elementos do vetor. Esses
valores serão digitados a pelo usuário do programa
ii. Calcular a soma e a média aritmética dos elementos do vetor e apre-
sentar os resultados na tela do computador
iii. Calcular a variância amostral (σ̂ 2 , Equação 9.8) dos elementos do
vetor e apresentar o resultado na tela do computador.

i=n
X
(xi − x̄)2
i=1
σ̂ 2 = (9.8)
(n − 1)
iv. Listar na tela todos os elementos do vetor, começando da maior
posição, até a sua primeira posição.
(b) Modifique o programa do exercício anterior, de modo que na tela do com-
putador, além dos valores originalmente contidos nas posições do vetor,
sejam listados também os valores quadráticos (xi2 ) de cada um de seus
elementos.
(c) Escreva um programa que leia a partir do teclado um vetor de 20 posições.
Em seguida, leia também os valores de duas variáveis inteiras, X e Y (com
x, y ∈ [0; 19]). X e Y indicam as posições do vetor, a partir das quais os
valores contidos nessas posições deverão ser lidos e apresentados na tela.
(d) Escreva um programa que leia um vetor de inteiros com 20 posições. Em
seguida, o programa deverá listar na tela a quantidade total de números
pares e de ímpares nesse vetor. O programa deverá também apresentar
na tela qual o maior e o menor valor.
(e) Escreva um programa que leia o valor de 10 medidas de pH. Para isso,
trabalhe com um vetor do tipo float de 10 posições. O programa deverá
listar na tela do computador a média e o desvio-padrão (σ̂, Equação 9.9)
dos valores de pH.

v
u i=n
uX
u
u (xi − x̄)2
t i=1
σ̂ = (9.9)
(n − 1)

193
++
Princípios de programação em C

(f) Escreva um programa que leia o valor de 20 números reais a partir do te-
clado (tipo float ou double), e liste na tela a quantidade total de números
negativos e de números positivos que foram digitados.
(g) Modifique o programa anterior, de modo que ele mostre também a posição
do vetor onde está o maior e o menor valor digitado.
(h) Modifique o programa anterior de modo que ele mostre na tela se há
algum valor duplicado dentro do vetor, ou seja, se há valores repetidos no
vetor. Se houver, o programa deverá indicar as posições onde estão os
valores repetidos.
(i) Modifique o programa anterior de modo que seja atribuído o valor zero à
todos os elementos que possuírem valores negativos.
(j) Escreva um programa que receba, a partir do teclado, os valores dois veto-
res do tipo float, M e N, cada um com 10 elementos. O programa deverá
calcular a diferença quadrática entre os elementos desses dois vetores,
(Mi − Ni )2 , e apresentar na tela a soma total dessas diferenças.
(k) Escreva um programa que leia um número inteiro inicial, uma razão, e
calcule os termos de uma progressão aritmética (PA), armazenando os
seus valores em um vetor de tamanho 20. Ao final, os valores do vetor
deverão ser listados na tela.
(l) Modifique o programa anterior para que o mesmo possa calcular os valores
digitados para uma ’progressão geométrica’ (PG), com o vetor armaze-
nando apenas os 8 primeiros elementos da PG. Ao final, os valores do
vetor deverão ser listados na tela.

2. Matrizes

(a) Escreva um programa que leia uma matriz 6 × 6 de inteiros a partir do


teclado. O programa deverá listar na tela quantos valores maiores do que
20 essa matriz possui.
(b) Modifique o programa anterior de modo a preencher todos os elementos
da diagonal principal com ’1’ (um). Para isso utilize um laço for(). Liste
na tela todos os elementos da matriz.
(c) Modifique o programa anterior de modo que ele passe também a imprimir
na tela a soma dos elementos de cada linha da matriz.
(d) Escreva um programa que leia uma matriz 5 × 5 de inteiros a partir do
teclado. O programa também deverá ler um valor inteiro X a partir do
teclado, e procurar esse valor na matriz. Se encontrado, deverá ser in-
formado na tela do computador a(s) posição(ões) (linha × coluna) na(s)
qual(ais) esse elemento se encontra.

194
++
Princípios de programação em C

(e) Escreva um programa para automaticamente preencher uma matriz W do


tipo double, de tamanho 20×20, com as condições apresentadas a seguir.
O programa deverá listar na tela todos os elementos da matriz.
i. se (i < j): W [i ][j] = 4, 72e |i+j| + (6, 85i ) − (3, 147j)
ii. se (i = j): W [i ][j] = 2, 22i 2 + [cos(i )] − [6, 63 sin(j)]
s
1
iii. se (i > j): W [i ][j] = [8, 124 cos(i )] − [6, 63 sin(j)] +
(i + j)2
(f) Escreva um programa que leia uma matriz 6 × 6 do tipo float e calcule
e imprima na tela a soma dos elementos que estão acima da diagonal
principal.
(g) Modifique o programa anterior para que ele calcule e imprima na tela a
soma dos elementos que estão abaixo da diagonal principal. O programa
deverá também calcular e listar na tela a soma dos elementos que estão
na diagonal principal da matriz.
(h) Escreva um programa que leia uma matriz 4 × 4 de inteiros e imprima na
tela a sua transposta.
(i) Em uma fábrica pretende-se aplicar um formulário para avaliar o nível de
conhecimento dos funcionário com relação aos acidentes de trabalho e ao
uso de equipamentos de proteção individual. Escreva um programa para
ler uma matriz 10x8, referente à 8 questões de múltipla escolha, a serem
respondidas por 10 funcionários de um setor da fábrica. Leia também um
vetor de 10 posições, contendo o gabarito das respostas da avaliação.
O programa deverá analisar as respostas dos funcionários comparando-
as com o gabarito, e emitir o escore de acertos (pontuação) de cada
funcionário.
(j) Escreva um programa que leia duas matrizes 3 × 3 double, M e N, e liste
na tela os resultados a seguir.
i. M +N
ii. M −N
iii. M T e N T (transpostas)
iv. kM + r N, em que k e r são constantes double digitadas pelo usuário
do programa.
v. M × N
vi. M 2
vii. N 2
(k) Dados dois vetores, um contendo a quantidade e outro o preço unitário
de 10 tipos de alimentos enlatados encontrados em um supermercado,
escreva um programa que leia esses vetores a partir do teclado, calcule
os valores descritos a seguir e transporte todas essas informações para

195
++
Princípios de programação em C

dentro uma matriz do tipo double. Ao final o programa deverá listar na


tela os elementos dessa matriz.
i. Preço total por cada alimento enlatado (Quantidade × preço unitá-
rio).
ii. Preço total dos alimentos (todos os alimentos).
iii. Preço médio, considerando todos os alimentos
iv. Listar a quantidade de itens alimentícios cujo preço se encontra abaixo
da média
(l) Nas linhas da matriz A apresentada a seguir estão listados os percentuais
de nutrientes, expressos como g/100g, de cinco tipos de alimentos.
Gor d P r ot F ibr a Ci nzas
Alim. 1
 
8, 5 2, 5 0, 7 0, 01
Alim. 2 6, 2 2, 8 0, 8 0, 02 
A = Alim. 3 4, 1

 3, 1 0, 4 0, 02 
Alim. 4 7, 3

1, 2 0, 1 0, 01 
Alim. 5 9, 2 3, 1 0, 6 0, 07
No vetor C estão listadas as quantidades de energia, em kCal, fornecidas
por cada nutriente, com valores expressos em kCal/100g.
kCal/100g
Gord.
 
850
Prot.  620 
C=
Fibra 
 
410 
Cinzas 920
Escreva um programa que leia os dados da matriz A e do vetor C, e calcule
a quantidade total de energia fornecida por cada alimento. Esses valores
podem ser calculados a partir da multiplicação A×C. Os resultados devem
ser listados na tela para cada alimento.
(m) Modifique o programa anterior, de modo que esse possa ser utilizado
para analisar até 10 alimentos. Os valores ds percentuais de nutrientes
presentes em cada alimento devem ser digitados pelo usuário do programa.
(n) Faça um programa para resolver o sistema linear de equações apresentado
a seguir (Equação 9.10). Utilize o método numérico de Gauss-Jacobi
(RUGGIERO e LOPES (1996), p. 155 – 161). Os valores de x1 , x2 e x3
devem ser apresentados na tela ao término da execução do programa.


12x1 + 4x2 + 3x3 = 46

M = 2x1 + 6x2 + 2x3 = 38 (9.10)

8x1 + 4x2 + 8x3 = 64

(o) Modifique o programa anterior, de modo que os coeficientes (β) das equa-
ções e os termos independentes (φ) possam ser digitados pelo usuário do

196
++
Princípios de programação em C

programa. No código, os valores de β e de φ devem ser declarados como


variáveis do tipo double, podendo receber valores positivos e negativos
(Equação 9.11).


β0 x1 + β1 x2 + β2 x3 = φ0

M = β3 x1 + β4 x2 + β5 x3 = φ1 (9.11)

β6 x1 + β7 x2 + β8 x3 = φ2

(p) Modifique o programa anterior de modo que ele possa ser utilizado para
resolver um sistema linear de equações com 10 variáveis.

3. Pilhas

(a) Considere uma agroindústria que fabrica uma bebida pronta para consumo,
feita à base de soja (extrato solúvel de soja). Nessa indústria há um galpão
no qual os caminhões entram, realizam a pesagem da carga e descarregam
a soja em uma moega.
Em função da grande movimentação diária de caminhões, há uma longa
avenida, que fica próxima ao galpão de descarga de grãos, na qual os
caminhões ficam aguardando a sua vez de descarregar.
Essa avenida é como uma ’rua sem saída’, visto que uma de suas ex-
tremidades está fechada por um muro, e há apenas uma única entrada,
controlada por uma cancela eletrônica, que serve também de saída para
os caminhões. Essa avenida tem capacidade para acomodar até 36 cami-
nhões enfileirados.
A descarga dos caminhões não é feita pela ordem de chegada, mas sim,
em função do tempo em que o produto já se encontra no caminhão, o
tempo total de transporte, decorrido desde o fornecedor de grãos até a
agroindústria.
Assim, se um caminhão é convocado para ser descarregado, então podem
acontecer duas situações:
i. Se o caminhão está próximo ao local de saída da avenida, e sem
nenhum outro caminhão atrás dele para atrapalhar, então ele sai e
vai descarregar sua carga de soja.
ii. Se o caminhão não está próximo ao local de saída da rua, então todos
os caminhões que estão enfileirados bloqueando sua saída deverão ser
manobrados, retirados da avenida, e só depois o caminhão convocado
poderá sair. Após isso, os caminhões que foram manobrados e reti-
rados retornam normalmente para a avenida, na mesma ordem que
estavam, e continuam esperando para serem convocados.

197
++
Princípios de programação em C

Escreva um programa para gerenciar a movimentação de caminhões nessa


longa avenida.
No programa, cada caminhão que passar pela cancela e entrar na avenida
implicará em um lançamento do tipo ’entrada’ (’E’). Cada caminhão que
sair da avenida implicará em um movimento do tipo ’saída’ (’S’).
Tanto nos movimentos de entrada quanto de saída, o programa deverá
registar a placa do caminhão.
Quando um caminhão chegar, o programa deverá verificar se há vagas
na avenida de estacionamento. Se não houver, então uma mensagem do
tipo ’Não há mais vagas. Cai fora!’ deverá ser impressa na tela.
Se houver vagas na avenida, então o caminhão poderá entrar e ocupar
uma vaga (considere que o estacionamento é uma pilha).
Quando um caminhão for convocado para descarga, então o programa de-
verá verificar quantos caminhões deverão ser manobrados e retirados da
avenida, de que modo que o caminhão convocado possa sair e descarregar,
ou seja, deverá ser listado na tela do computador os números das placas
de todos os caminhões que necessitam ser manobrados e serem tempo-
rariamente retirados da avenida. Em cada movimentação de entrada ou
saída de caminhões, o programa deverá imprimir na tela o número total
de vagas desocupadas, livres para estacionamento na avenida.
(b) Escreva um programa que leia um conjunto de 20 valores inteiros digitados
pelo usuário. O programa deverá armazenar os valores positivos em uma
pilha e os valores negativos em outra pilha. Ao final, o programa deverá
listar na tela a média dos valores positivos (primeira pilha) e também a
média dos valores negativos (segunda pilha).
(c) Suponha que uma pilha possua 10 valores: 1, 2, 3, 4, 5, 6, 7, 8, 9 e 10.
Explique qual deve ser a sequência correta de operações de (’E’) push e
(’S’) ’pop’ para que os valores fiquem na seguinte ordem: 3, 8, 1, 6, 9,
5, 4, 10, 2 e 7.
(d) Escreva um programa que utilize o conceito de pilhas para colocar os
caracteres da palavra ’ENGENHARIA’ em ordem invertida, ou seja, ’AI-
RAHNEGNE’.

198
Capítulo 10

Ponteiros e structs

Conteúdo do capítulo
10.1 Ponteiros em C++ . . . . . . . . . . . . . . . . . . . . . . . 199
10.1.1 Declaração e uso de ponteiros . . . . . . . . . . . . . . . . 200
10.2 Ponteiros em procedimentos e funções . . . . . . . . . . . 202
10.2.1 Passagem de parâmetros por valor . . . . . . . . . . . . . 202
10.2.2 Passagem de parâmetros por ponteiros . . . . . . . . . . . 203
10.3 Ponteiro para vetores e matrizes . . . . . . . . . . . . . . 204
10.4 Ponteiros para outros ponteiros . . . . . . . . . . . . . . . 209
10.5 Vetores de ponteiros . . . . . . . . . . . . . . . . . . . . . . 210
10.6 Passagem de vetores e matrizes para procedimentos e
funções por meio de ponteiros . . . . . . . . . . . . . . . . 211
10.7 Alocação dinâmica de memória com as funções mal-
loc(), realloc() e free() . . . . . . . . . . . . . . . . . . . . 214
10.7.1 A função malloc() . . . . . . . . . . . . . . . . . . . . . . 215
10.8 Alocação dinâmica de memória com os operadores new
e delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
10.8.1 O operador new . . . . . . . . . . . . . . . . . . . . . . . 220
10.8.2 O operador delete . . . . . . . . . . . . . . . . . . . . . . 221
10.8.3 Declaração dinâmica de vetores com o operador new . . . 223
10.9 Estruturas de dados com o comando struct{} . . . . . . 224
10.10Atividades para fixação da aprendizagem . . . . . . . . . 233

10.1 Ponteiros em C++


Um ’ponteiro’ é um tipo de variável especial que contém o endereço de uma posição
na memória do computador. Em geral, o conteúdo de um ponteiro é o endereço de

199
++
Princípios de programação em C

uma outra variável, e diz-se que o ponteiro ’aponta’ para essa outra variável.
Para compreender melhor como isso funciona, suponha que uma variável inteira,
’x1’, ocupe a posição 0001 da memória RAM do computador (Tabela 10.1). O
conteúdo de ’x1’ é o numeral hexadecimal 0x02, que é o ’endereço’ que a variável
’x3’ ocupa na memória do computador. Observe que o valor de ’x3’ é 25, um valor
inteiro. Assim, diz-se que: ’A variável x1 (inteiro) é um ponteiro que armazena o
endereço 0x02, que pertence à variável x3 (inteiro) e, portanto, ’x1 aponta para x3’
(x1 → x3).’ (Tabela 10.1).
Em C++ o nome, o tipo e o conteúdo da variável ’x3’ foram definidos pelo
programador, da maneira usual, como mostrado a seguir.
1 int x3 = 25;

O endereço que ’x3’ ocupa na memória do computador é definido automatica-


mente pelo sistema operacional (Linux, MS Windows, ...) quando o programa é
executado, sem a intervenção do programador. É o sistema operacional que se en-
carrega de encontrar alguma posição livre na memória do computador e reservá-la
para a variável ’x3’. Além disso, quando o programa é executado, o valor armazenado
em ’x3’ é convertido internamente para um número em base binária.

Tabela 10.1: Esboço do mapa da memória com a identificação, endereço e conteúdo


das variáveis.
Identificacao da variavel Mapa da memória
Nome Tipo Posicao Endereço Conteúdo
x1 int 0001 0x00 0x02
x2 float 0002 0x01 154.46
x3 int 0003 0x02 25
x4 char 0004 0x03 ’a’
Fonte: Elaborada pelos autores.

10.1.1 Declaração e uso de ponteiros


Para declarar um ponteiro é necessário acrescentar o símbolo de um asterisco ime-
diatamente antes do nome da variável, conforme a sintaxe apresentada a seguir:
tipo * <nome da variável>;
Além de ser utilizado para declarar um ponteiro, o símbolo de asterisco (*) tam-
bém tem a função de referenciar o conteúdo da variável apontada. A referência ao
endereço de memória da variável apontada pelo ponteiro é feita por meio do operador
’&’ (caractere representado pelo símbolo de ’e’ comercial).
O código a seguir mostra como declarar o ponteiro (’x1’) e a variável apontada
por ele, ’x3’, de acordo com os dados apresentados na Tabela 10.1. Observe que o
ponteiro deverá obrigatoriamente ter o mesmo ’tipo de dado’ que a variável para a
qual ele aponta.

200
++
Princípios de programação em C

1 int x3 = 25;
2 int * x1 ; // Ponteiro x1
3 x1 = & x3 ; // x1 aponta para x3

Na linha 1 código anterior, é criada a variável ’x3’ do tipo inteiro. Essa variável
recebe o valor 25. Na linha 2 é declarado ’x1’, um ponteiro do tipo inteiro. Na
declaração do ponteiro foi utilizado o símbolo asterisco para indicar que se trata de
um ponteiro. Na linha 3 foi utilizado o símbolo ’&’ para indicar que a variável ’x1’
aponta para o endereço de memória da variável ’x3’.
O programador poderá, por exemplo, criar uma outra variável, ’nValor’, que re-
ceberá o conteúdo da variável apontada por ’x1’.
1 int nValor ;
2 nValor = * x1 ; // nValor recebe o valor 25

Ao utilizar a variável ’nValor’, como mostrado na linha 2 do exemplo acima, esta


variável receberá o valor numérico armazenado em ’x1’, entretanto ’x1’ não possui
um valor numérico, mas sim o ’endereço de memória’ que aponta para ’x3’.
Dessa forma, o conteúdo de ’x3’, que é o número 25, será armazenado na variável
’nValor’, por que um símbolo de asterisco foi utilizado para fazer ’referência ao
conteúdo’ da variável ’x3’, apontada pelo ponteiro ’x1’.
Em termos práticos, ’x1’ e ’x3’ acessam o mesmo endereço na memória do
computador (0x02), e o asterisco faz referência ao conteúdo armazenado nesse
endereço, que neste exemplo é o número 25.
Um outro exemplo da utilização de ponteiros é dado a seguir. Nele são declaradas
três variáveis do tipo inteiro: ’x’, ’y’ e ’Pnt1’.
1 int x = 4; int y = 16;
2 int * Pnt1 ; Pnt1 = & x ;
3 y = * Pnt1 ; * Pnt1 = 22;

A variável ’Pnt1’ na linha 2 é um ponteiro do tipo inteiro. No final da linha


2 ’Pnt1’ irá apontar para o mesmo endereço de memória da variável ’x’. Assim,
as variáveis ’x’ e ’Pnt1’ compartilham o mesmo endereço de memória e o mesmo
conteúdo.
Na linha 3 a variável ’y’ terá o seu atual conteúdo (o valor 16, atribuído na linha
1) substituído pelo conteúdo (*) do ponteiro ’Pnt1’, e dessa forma, a variável ’y’
receberá o mesmo conteúdo da variável apontada por ’Pnt1’, que é o conteúdo de ’x’,
o valor 4. No final da linha 3, o atual conteúdo (*) da variável apontada por ’Pnt1’
(o valor 4, na variável ’x’) será substituído pelo número 22. Assim, o conteúdo da
variável ’x’ também passará a valer 22, visto que ’Pnt1’ e ’x’ compartilham o mesmo
endereço de memória.
Mais um outro exemplo da utilização de ponteiros é dado a seguir. Este exemplo
foi inserido neste capítulo com o objetivo de mostrar que podem ser declarados

201
++
Princípios de programação em C

ponteiros para qualquer outro tipo de dado, além do inteiro, utilizado nos exemplos
anteriores.
1 double X , Y ;
2 int Z ;
3 double * W ;
4 X = 10.25;
5 Y = 32.63;
6 Z = 73;
7 W = &X;
8 Y = X + (* W ) ;
9 Z = ( int ) ( Y ) ;
10 Z ++;

No final da linha 3 deste exemplo, é declarado um ponteiro do tipo double (’*W’).


Na linha 7 o ponteiro ’W’ passa a apontar para a variável ’X’ e ambas compartilharão
o mesmo conteúdo e endereço de memória.
Na linha 8, o conteúdo de ’W’ (que é o mesmo conteúdo de ’X’, 10,25) é
somado ao valor da variável ’X’ (10,25), resultando em ’20,50’, valor esse atribuído
à variável ’Y’, substituindo o valor que havia sido anteriormente atribuído a essa
variável (32,63).
Na linha 9 um casting força a conversão do valor armazenado em ’Y’ para inteiro.
Nesse caso, o valor armazenado em ’Y’ será truncado, resultando em ’20’, valor esse
que será atribuído à variável ’Z’.
Na linha 10, o valor de ’Z’ é incrementado em uma unidade e passará a valer 21.

10.2 Ponteiros em procedimentos e funções


A passagem de parâmetros para funções e procedimentos, assunto apresentado e
discutido no Capítulo 8, Seção 8.1.1.1, p.152, será revisto nos sub-tópicos apresen-
tados a seguir.
A abordagem feita aqui tem como objetivo a utilização de ponteiros para acres-
centar algumas funcionalidades técnicas às aos procedimentos e funções, de modo a
torná-los mais abrangentes e eficazes na resolução de problemas que eventualmente
possam surgir quando na construção de um programa.

10.2.1 Passagem de parâmetros por valor


Chama-se ’passagem de parâmetros por valor’ o modo de passagem de parâmetros
no qual a função (ou procedimento), ao ser chamada dentro do código, recebe uma
’cópia fiel’ dos valores das variáveis que são passadas a ela como parâmetros.
Todas as atribuições de valores feitas dentro do código não irão alterar o valor
original das variáveis passadas como parâmetros. Para entender melhor como isso
funciona, acompanhe atentamente o código a seguir:

202
++
Princípios de programação em C

1 // - -[ Variaveis globais ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2 int x = 10;
3 int y = 20;
4

5 // - -[ Funcao ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6 void TrocaValor ( int ValorX , int ValorY )
7 {
8 int vTemp ;
9 vTemp = ValorX ;
10 ValorX = ValorY ;
11 ValorY = vTemp ;
12 }
13

14 // - -[ Dentro de ’ int main () ’] - - - - - - - - - - - - - - - - - - - - - - - - - - - -


15 TrocaValor (x , y ) ;
16 cout << " x : " << x << ’\ t ’ << " y : " << y << endl ;

No código acima, quando a função ’TrocaValor()’ é chamada dentro do int


main() (linha 15), uma ’cópia’ fiel dos valores das variáveis ’x’ e ’y’ é passada como
argumentos para essa função.
No interior da função, os valores de ’x’ e ’y’ são trocados entre si, ou seja, a
variável ’x’ passa a valer 20, e a variável ’y’ passa a valer 10. Entretanto nenhuma
modificação ocorre com os valores originalmente presentes nas variáveis ’x’ e ’y’, que
foram declaradas como ’globais’ nas linhas 2 e 3. Dessa forma, ao listar na tela os
valores dessas variáveis com o objeto cout (linha 16), os seus valores permanecerão
inalterados, com x=10 e y=20.
Esta forma de passagem de parâmetros é exatamente a mesma que foi apresen-
tada e discutida nos exemplos do Capítulo 8.

10.2.2 Passagem de parâmetros por ponteiros


Chama-se ’passagem de parâmetros por ponteiros’ o modo de passagem de parâme-
tros no qual a função (ou procedimento), ao ser chamada dentro do código, recebe
uma referência às variáveis passadas a ela como parâmetros.
Não é uma simples ’cópia’ dos valores das variáveis, e as alterações realizadas
dentro da função (ou procedimento) irão efetivamente modificar os valores conti-
dos nas variáveis originais. Para entender melhor como isso funciona, companhe
atentamente o código listado a seguir, exemplo na próxima página.
Na linha 5 desse exemplo, os parâmetros da função foram declarados como pon-
teiros, fazendo com que tanto as variáveis originais (’x’ e ’y’) quanto as variáveis
declaradas como parâmetros da função (’ValorX’ e ’ValorY’) passem a compartilhar
os mesmos endereços de memória e os mesmos conteúdos que as variáveis globais,
externas à função. Assim, qualquer modificação no conteúdo de ’ValorX’, no interior
da função, implicará diretamente em modificações no conteúdo de ’x’.

203
++
Princípios de programação em C

1 // - -[ Variaveis globais ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2 int x = 10; int y = 20;
3

4 // - -[ Funcao ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5 void TrocaValor ( int * ValorX , int * ValorY )
6 {
7 int vTemp ;
8 vTemp = * ValorX ;
9 * ValorX = * ValorY ;
10 * ValorY = vTemp ;
11 }
12 // - -[ Dentro de ’ int main () ’] - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13 TrocaValor (& x , & y ) ;
14 cout << " x : " << x << ’\ t ’ << " y : " << y << endl ;

O mesmo ocorre para as variáveis ’ValorY’ e ’y’. Como resultado desta ’passagem
de parâmetros por ponteiro’, os valores apresentados na tela, pelo uso de cout na
linha 13, são x=20 e y=10. Como pode ser observado, os valores das variáveis ’x’ e
’y’, externas à função ’TrocaValor()’ foram efetivamente trocados entre si, e isso só
foi possível por causa da utilização de ponteiros.

10.3 Ponteiro para vetores e matrizes


Uma forma eficiente de trabalhar com vetores e matrizes é fazer a indexação de seus
elementos por meio de ponteiros. Um ponteiro para um vetor ou uma matriz sempre
apontará para o seu primeiro elemento (índice zero, [0]), e todas as demais posições
são consideradas ’contíguas’ na memória do computador (ver explicações na Figura
10.1, p.208).
Na linha 1 do exemplo a seguir é declarado um ’vetor de inteiros’ com cinco
elementos.
1 int v [5];
2

3 v [0] = 2;
4 v [1] = 4;
5 v [2] = 6;
6 v [3] = 8;
7 v [4] = 10;
8

9 int * p ;
10 p = v;

Na linha 9 é declarado um ponteiro ’p’ do tipo inteiro. Esse ponteiro aponta para
o primeiro elemento do vetor ’v’ (linha 10), ou seja, aponta para a posição ’v[0]’.

204
++
Princípios de programação em C

Para listar na tela o conteúdo e o endereço de memória apontado por ’p’ pode-se
utilizar o objeto cout.
1 cout << p << endl ; // Endereco : 0 x7fff4c8d6ff4
2 cout << * p << endl ; // Conteudo : 2

Para acessar um outro elemento do vetor é necessário apontar para a posição


da memória ocupada por esse elemento. Assim, para acessar a terceira posição do
vetor:
1 p = & v [2];
2 cout << * p << endl ; // Conteudo : 6

Devido ao fato de as posições do vetor (ou matriz) serem consideradas ’contíguas’


na memória do computador, então é possível utilizar os operadores de incremento e
de decremento (p.90) para movimentar o ponteiro entre as suas diferentes posições
indexadas. Exemplo:
1 p = & v [2]; // Aponta para a terceira posicao
2 p ++; // Vai para a quarta posicao , v [3]
3 cout << * p << endl ; // Conteudo : 8

O valor de uma posição do vetor (ou matriz) pode ser modificado com o uso de
ponteiros. Exemplo:
1 int * p ; // Declara o ponteiro ’p ’;
2 p = v; // Aponta para a primeira posicao
3 // de v []. Nao utiliza o simbolo ’& ’
4 cout << * p << endl ; // Imprime o valor de v [0]: 2
5 p = & v [4]; // Aponta para a quinta posicao de
6 // v []
7 * p = 30; // Muda o valor da quinta posicao de
8 // p para 30
9 cout << * p << endl ; // Imprime o valor de p na quinta po
10 // sicao : 30
11 cout << v [4] << endl ; // Imprime o valor de v [] na quinta
12 // posicao : 30

No código acima, uma outra forma de modificar o valor da quinta posição de ’p’
é a que está indicada na linha 4 do código a seguir.
Se ’p’ aponta para a primeira posição do vetor ’v’ (v[0]), então ’(p+4)’ apontará
para a quinta posição de ’v’.
O asterisco antes do parêntesis a linha 4 faz referência ao ’valor numérico’ ar-
mazenado na posição apontada pelo ponteiro.
Se ’p’ aponta para um elemento particular de um vetor, então (p+1) aponta para
o próximo elemento desse vetor. E, de um modo genérico, pode-se dizer que se
’p’ aponta para um elemento particular de um vetor, então (p+i) apontará para o
elemento localizado i posições, a partir da atual posição indexada nesse vetor.

205
++
Princípios de programação em C

1 int * p ;
2 p = v; // Aponta para a primeira posicao
3 // de v []
4 *( p +4) = 80; // Muda o valor da quinta posicao
5 // de p para 80
6

7 cout << * p << endl ; // Imprime o conteudo da posicao


8 // atual de p ( p [0])
9 cout << v [4] << endl ; // Imprime o conteudo da quinta
10 // posicao de v []

Ao fazer a declaração de um ponteiro, há uma importante observação a ser feita


no que se refere à posição do asterisco em relação ao seu nome. As três formas
abaixo estão corretas:
1 int * p ; // Asterisco digitado entre o ’ int ’ e o ’p ’
2 int * p ; // Asterisco digitado a direita de ’ int ’
3 int * p ; // Asterisco digitado a esquerda de ’p ’

Da mesma forma que para outras variáveis, um ponteiro do tipo inteiro pode ser
inicializado como um ’ponteiro nulo’, bastando, para isso, atribuir o valor ’zero’ a
esse ponteiro.
1 int * p = 0;

O programador pode optar em declarar um ponteiro e não apontá-lo para nenhum


local da memória do computador. Isso é feito atribuindo-se a palavra reservada NULL
ao ponteiro. NULL é uma constante, defina na forma de macro, que tem valor igual
a zero.
1 # include < iostream >
2 using namespace std ;
3 int main ()
4 {
5 float z = 36.25;
6 float * w = NULL ;
7

8 cout << " Ender de w ..: " << w << endl ; // 0


9 w = &z;
10 cout << " Valor de W ..: " << * w << endl ; // 36.25
11 cout << " Ender de w ..: " << w << endl ; // 0 x7ffdece8abfc
12 * w = NULL ;
13 cout << " Valor de W ..: " << * w << endl ; // 0
14 cout << " Ender de w ..: " << w << endl ; // 0 x7ffdece8abfc
15

16 return 0;
17 }

206
++
Princípios de programação em C

Entretanto, o programador deve ficar atento ao fato de que não é permitido


assinalar valores literais diretamente a um ponteiro. Caso faça isso será gerada uma
mensagem de erro de compilação.
1 p = 25; // Erro de compilacao se ’p ’ for um ponteiro

Nos códigos em C++ o programador pode declarar ponteiros de diferentes tipos


de dados, como mostrado a seguir:
1 int * ip ; // inteiro
2 char * cp ; // caractere
3 double * dp ; // double
4 float * fp ; // float

Caso seja do interesse do programador, ele poderá listar os endereços de me-


moria apontados por um ponteiro para vetor ’p’ qualquer, bem como o conteúdo
armazenado de cada posição do vetor, como mostrado a seguir.
1 int v [5];
2 v [0] = 2; v [1] = 4;
3 v [2] = 6; v [3] = 8;
4 v [4] = 10;
5

6 int * p ; p = v ;
7

8 for ( int i =0; i <5; i ++)


9 {
10 cout << " v [ " << i << " ]: " << & p [ i ]
11 << ’\ t ’ << *( p + i ) << endl ;
12 }
13

14 // - -[ Saidas :] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
15 //
16 // v [0]: 0 x7ffdefb35770 2
17 // v [1]: 0 x7ffdefb35774 4
18 // v [2]: 0 x7ffdefb35778 6
19 // v [3]: 0 x7ffdefb3577c 8
20 // v [4]: 0 x7ffdefb35780 10
21 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Os valores em hexadecimal apresentados na saída deste programa são os ende-


reços de memória alocados pelos elementos de ’v[]’. Esses endereços dependem,
sobretudo, de características físicas do hardware do computador no qual o programa
está sendo executado, do sistema operacional e da forma como a memória do compu-
tador já se encontra ocupada por causa da execução em paralelo de outros programas,
como processadores de texto, jogos, anti-vírus, planilhas eletrônicas, etc.
Dessa forma, um mesmo programa, ao ser executado diferentes vezes, poderá
ter as suas variáveis ocupando posições completamente diferentes na memória, para

207
++
Princípios de programação em C

cada vez que for executado.


Uma string também pode ser declarada por meio de um ponteiro. No exemplo
a seguir, o compilador criará uma ’string’ com 31 elementos, sendo que o último
elemento será automaticamente atribuído do caractere nulo, ’\0’.
1 char * vTexto = " Universidade Federal de Lavras " ;
2 cout << vTexto << endl ;

Não somente nos vetores, mas também as posições dos elementos nas matrizes
são acessados de modo contíguo por meio de ponteiros.
Assim, a matriz armazenada na memória do computador possui suas células (seus
elementos) dispostos de modo sequencial, semelhante à disposição de um vetor, não
havendo, portanto, nenhuma organização bi-dimensional (linhas × colunas), como
mostrado na Figura 10.1.

0,0
Primeira linha
1,0 da matriz

2,0
3,0
Elementos dispostos de modo contíguo na memória

0,0 1,0 2,0 3,0

Figura 10.1: Sequenciamento contíguo dos elementos de uma matriz na memória


do computador. (Fonte: autores)

No exemplo a seguir uma matriz M, de tamanho 100 × 100, é totalmente pre-


enchida com zeros. O ponteiro ’pos’ inicialmente estará apontando para a primeira
posição da matriz (linha=0 e coluna=0 ), como mostrado na linha 3 do código.
Em seguida, o comando for() é utilizado para incrementar o índice do ponteiro, de
modo a percorrer todos os dez mil elementos da matriz e preenchê-la completamente
com zeros (linhas 6 e 7). Esse é um procedimento muito utilizado para inicializar
matrizes e vetores em C/C++ .
1 int M [100][100]; // Declara uma matriz 100 x 100
2 int * pos ; // Declara o ponteiro ’ pos ’
3 pos = & M [0][0]; // ’ pos ’ aponta para o primeiro
4 // elemento da matriz M
5

6 for ( int i =0; i <10000; i ++) // Preenche todos os elementos


7 { // da matriz M com zeros
8 *( pos + i ) = 0;
9 }

208
++
Princípios de programação em C

Um exemplo simples de uso da indexação contígua das posições de um ponteiro


para string é a função apresentada a seguir, que retorna o tamanho, em quantidade
de caracteres, de uma ’string de caracteres’.
1 int QtdCaracteres ( char * vString )
2 {
3 int nTamanho = 0;
4 while (* vString != ’ \0 ’)
5 {
6 vString ++;
7 nTamanho ++;
8 }
9 return ( nTamanho ) ;
10 }

A utilização da função ’QtdCaracteres()’ é feita simplesmente passando a ela o


conteúdo da string da qual o tamanho deverá ser calculado.
1 int main () {
2 char * Texto = " Universidade Federal de Lavras " ;
3 cout << QtdCaracteres ( Texto ) << endl ; // Saida : 30
4 return 0;
5 }

10.4 Ponteiros para outros ponteiros


O termo ’ponteiro para ponteiro’ refere-se a uma forma de indireção múltipla na
qual um ponteiro aponta para um outro ponteiro. Assim, o primeiro ponteiro con-
tém o endereço de um segundo ponteiro, que aponta para alguma variável, como
esquematizado na Figura 10.2.

Ponteiro Ponteiro Variável

Endereço Endereço Valor

Figura 10.2: Encadeamento ponteiro para ponteiro. (Fonte: autores)

Esse tipo de encadeamento é especialmente útil em algumas aplicações como


análise de estruturas de dados organizadas em árvores binárias, filas, listas encadea-
das, ordenação de registros em arquivos de dados, etc, mas esses assuntos não serão
abordados aqui, pois estão fora do escopo deste livro.
Nesta seção apenas será mostrado como declarar e utilizar um ponteiro que
aponta para outro ponteiro.
Um ’ponteiro para ponteiro’ é declarado colocando-se dois asteriscos antes do
nome do ponteiro, como mostrado a seguir.

209
++
Princípios de programação em C

1 int ** p ;

Para acessar o valor da variável apontada pelo segundo ponteiro é necessária a


utilização de dois asteriscos, como mostrado no código a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 int Temper ; // Variavel ’ Temper ’
7 int * pTemper ; // Ponteiro para ’ Temper ’
8 int ** ppTemper ; // Ponteiro para o ponteiro de ’ Temper ’
9

10 Temper = 90;
11 pTemper = & Temper ;
12 ppTemper = & pTemper ;
13

14 cout << " Valores das variaveis : " << endl ; // Saidas :
15 cout << " Temper ...: " << Temper << endl ; // 90
16 cout << " pTemper ..: " << * pTemper << endl ; // 90
17 cout << " ppTemper .: " << ** ppTemper << endl ; // 90
18

19 return 0;
20 }

Ponteiros que apontam para outros ponteiros também podem ser colocados em
uma sequência maior, encadeada com a adição de mais asteriscos para fazer a sua
declaração.
1 int *p;
2 int ** p ;
3 int *** p ;
4 int **** p ;

10.5 Vetores de ponteiros


O ’vetor de ponteiros’ é um vetor no qual cada um de seus elementos contém um
ponteiro.
Esse recurso é útil para referenciar variáveis que possuam tamanhos diferentes
como, por exemplo, para ordenar alfabeticamente uma lista de nomes de pessoas,
entre outra finalidades. Nessa situação, cada nome possui um comprimento diferente
(em quantidade de caracteres).
Para declarar um ’vetor de ponteiros’ é necessário especificar o seu tipo, nome
e tamanho, além de usar o asterisco para indicar que se trata de um ’vetor de
ponteiros’.

210
++
Princípios de programação em C

1 int * p [10];

No código a seguir um exemplo de uso e declaração de um ’vetor de ponteiros’.


1 # include < iostream >
2 using namespace std ;
3

4 int main ()
5 {
6 char * Frutas [5] = { " Goiaba " ,
7 " Manga " ,
8 " Laranja " ,
9 " Caju " ,
10 " Morango " };
11

12 for ( register int i =0; i <5; i ++)


13 {
14 cout << " Fruta ..: " << *( Frutas + i ) << endl ;
15 }
16

17 return 0;
18 }

10.6 Passagem de vetores e matrizes para procedi-


mentos e funções por meio de ponteiros
Além de ponteiros é possível também a passagem de ’vetores’ e ’matrizes’ para
procedimentos e funções, e para fazer isso, uma das opções é justamente a que faz
o uso de ponteiros.
A vantagem dessa prática está na possibilidade de fazer com que uma função
retorne simultaneamente a mais de um valor, o que pode ser feito modificando
efetivamente os elementos do vetor (ou matriz) passado como argumento (passagem
por referência). Nos exemplos a seguir será mostrado como a passagem de vetores
e matrizes para funções pode ser feita com o uso de ponteiros.
Ao fazer a passagem de um vetor (uma única dimensão) para uma função (ou
procedimento) por meio de ponteiro, na realidade não estamos passando uma cópia
fiel de seus elementos para a função, mas sim, apontando para endereço de memória
em que está localizada a primeira posição do vetor. Além disso é uma prática comum
passar também para a função o tamanho do vetor, como mostrado a seguir.
1 float TemperMedia ( float * vTemper , int n ) ;

Na função ’TemperMedia()’, o primeiro argumento é um ponteiro do tipo float,


enquanto que o segundo argumento é o tamanho ’n’, que é a quantidade de elementos
do vetor.

211
++
Princípios de programação em C

No exemplo a seguir a função ’TemperMedia()’ utiliza um vetor contendo três


valores de temperatura, calcula a média desses valores e retorna o valor calculado.
Vetores com quantidades maiores de elementos poderiam ser passados para a função
bastando, para isso, apenas informar a quantidade correta de elementos desse vetor
no parâmetro ’n’ da função.
1 # include < iostream >
2 using namespace std ;
3

4 // ==[ Prototipo da funcao ] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


5

6 inline float TemperMedia ( float * vTemper , int n ) ;


7

8 // ==[ Programa principal ] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


9

10 int main ()
11 {
12

13 float Temper [3];


14

15 Temper [0] = 42.5;


16 Temper [1] = 44.7;
17 Temper [2] = 47.3;
18

19 cout << " Temper Media .: " << TemperMedia ( Temper , 3) ;


20

21 return 0;
22 }
23

24 // ==[ Implementacao da funcao ] = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


25

26 inline float TemperMedia ( float * vTemper , int n )


27 {
28

29 float nSoma = 0.00;


30 for ( register int i =0; i < n ; i ++)
31 {
32 nSoma += vTemper [ i ];
33 }
34

35 nSoma = ( nSoma / n ) ;
36

37 return nSoma ;
38 }

Para passar uma matriz como argumento de uma função (ou procedimento),
é necessário declarar um ponteiro para a matriz, além de outros dois parâmetros,

212
++
Princípios de programação em C

para informar a quantidade de linhas e de colunas na matriz. No exemplo a seguir


a função ’TemperMedia()’ faz referência a uma matriz contendo nove valores de
temperatura, calcula a sua média e retorna o valor calculado.
1 # include < iostream >
2 using namespace std ;
3

4 float TemperMedia ( float * matrizTemper ,


5 int QtdLinhas ,
6 int QtdColunas ) ;
7

8 int main ()
9 {
10 float mTemper [3][3];
11

12 mTemper [0][0] = 42.5; mTemper [1][0] = 44.7;


13 mTemper [2][0] = 47.3; mTemper [0][1] = 64.1;
14 mTemper [1][1] = 66.9; mTemper [2][1] = 72.2;
15 mTemper [0][2] = 76.6; mTemper [1][2] = 79.4;
16 mTemper [2][2] = 83.2;
17

18 cout << " Temper Media .: " << TemperMedia ( mTemper [0] , 3 , 3) ;
19

20 return 0;
21 }
22

23 float TemperMedia ( float * matrizTemper ,


24 int QtdLinhas ,
25 int QtdColunas ) {
26 float nSoma = 0.00;
27 float nMedia = 0.00;
28 for ( int Lin =0; Lin <( QtdLinhas ) ; Lin ++) {
29 for ( int Col =0; Col <( QtdLinhas ) ; Col ++) {
30 nSoma = nSoma + matrizTemper [ Lin * QtdColunas + Col ];
31 }
32 }
33 nMedia = ( nSoma / ( QtdLinhas * QtdColunas ) ) ;
34

35 return nMedia ;
36 }

A notação ’matrizTemper[Lin * QtdColunas + Col]’, na linha 30 do código


acima, retrata o fato de os elementos serem colocados em uma ordenação contígua
dentro da matriz, como ilustrado pela Figura 10.1, p.208.
A expressão ’Lin * QtdColunas + Col’ irá acessar o elemento desejado dentro
da matrix, cuja posição é indicada pelos pelos comandos for() aninhados.
Há um outro modo de passar uma matriz como argumento de uma função (ou

213
++
Princípios de programação em C

procedimento), porém, sem fazer explicitamente uso de ponteiros, como exemplifi-


cado a seguir. Neste caso, a indexação dos elementos da matriz é feito de modo
direto, como mostrado na linha 23 do código.
1 # include < iostream >
2 using namespace std ;
3 float TemperMedia ( float matrizTemper [3][3]) ;
4

5 int main () {
6 float mTemper [3][3];
7

8 mTemper [0][0] = 42.5; mTemper [1][0] = 44.7;


9 mTemper [2][0] = 47.3; mTemper [0][1] = 64.1;
10 mTemper [1][1] = 66.9; mTemper [2][1] = 72.2;
11 mTemper [0][2] = 76.6; mTemper [1][2] = 79.4;
12 mTemper [2][2] = 83.2;
13

14 cout << " Temper Media .: " << TemperMedia ( mTemper ) ;


15 return 0;
16 }
17

18 float TemperMedia ( float matrizTemper [3][3]) {


19 float nSoma = 0.00;
20 float nMedia = 0.00;
21 for ( int Lin =0; Lin <3; Lin ++) {
22 for ( int Col =0; Col <3; Col ++) {
23 nSoma = nSoma + matrizTemper [ Lin ][ Col ];
24 }
25 }
26 nMedia = ( nSoma / (3 * 3) ) ;
27 return nMedia ;
28 }

10.7 Alocação dinâmica de memória com as funções


malloc(), realloc() e free()
Nos exemplos de códigos apresentados e discutidos ao longo dos capítulos estudados
até aqui, foram mostrados os modos convencionais de fazer a declaração das variáveis
de memória, como exemplificado a seguir:
1 double Temper ;
2 int QtdLatas ;
3 float pH [6];
4 char cLetra ;

214
++
Princípios de programação em C

Em todas essas formas, a alocação de espaço para a as variáveis na memória


RAM do computador é feita de modo estático1 , e a quantidade de memória a ser
reservada para as variáveis é definida pelo sistema operacional (Linux, MS Windows,
etc) no momento em que o programa é efetivamente executado.
Contudo, em muitas situações, é necessário trabalhar com ’alocação dinâmica de
memória’, um recurso do C/C++ , que faz com que a quantidade de memória a ser
reservada para uma variável seja definida pelo usuário do programa, em tempo real
de execução, ou seja, enquanto o programa está sendo executado.
Processos de alocação e liberação dinâmica de memória são feitos por três fun-
ções: malloc(), realloc() e free(). Para utilizar essas funções é necessário incluir a
biblioteca stdlib.h no código fonte do programa.
1 # include < stdlib .h >

10.7.1 A função malloc()


A função ’malloc()’ (memory allocation) aloca espaço para bloco de bytes consecu-
tivos na memória RAM (Random Access Memory ) e retorna um ponteiro do tipo
’void’ para o primeiro byte alocado, caso a alocação tenha sido realizada com sucesso
(PAREWA LABS PVT. Ltd., 2019).
O número de bytes é especificado como argumento da função malloc(). Na linha
9 (nove) do código apresentado a seguir é alocado o espaço de 1 (um) byte, tamanho
suficiente para armazenar um único caractere, que ocupa de 1 (um) byte na memória
do computador.
1 # include < iostream >
2 # include < stdlib .h > // Necessario para uso de ’ malloc () ’
3

4 using namespace std ;


5

6 int main ()
7 {
8 char * cLetra ;
9 cLetra = ( char *) malloc (1) ;
10 cin >> cLetra ;
11 cout << cLetra ;
12 return 0;
13 }

Em algumas situações a função ’sizeof()’ é utilizada para especificar a quantidade


de bytes a serem reservados, com base no tamanho ocupado por algum ’tipo de dado’
padrão da linguagem C++ . A linha 7 (sete) do código a seguir mostra como alocar
espaço para um vetor que tem o mesmo tamanho que 5 (cinco) variáveis inteiras.
1
’Estático’ aqui não tem nenhuma relação com a palavra reservada ’static’ do C/C++ .

215
++
Princípios de programação em C

1 # include < iostream >


2 # include < stdlib .h >
3 using namespace std ;
4

5 int main () {
6 int * nVetor ;
7 nVetor = ( int *) malloc ( sizeof ( int ) *10) ;
8 cout << " Digite os elementos do vetor : " << endl ;
9

10 for ( int i =0; i <10; i ++) {


11 cin >> nVetor [ i ];
12 }
13

14 cout < < " Oe elementos sao : " << endl ;


15 for ( int i =0; i <10; i ++) {
16 cout << nVetor [ i ] < < endl ;
17 }
18 free ( nVetor ) ;
19 return 0;
20 }

A linha 18 do código acima traz uma novidade, que é a função ’free()’, utilizada
para liberar dinamicamente da memória todo o espaço que havia sido reservado para
o vetor ’nVetor’. A função ’free()’ deve ser sempre utilizada para liberar o espaço
de memória, quando esse não for mais utilizado pelo programa.
Embora seja algo que ocorra raramente, nem sempre o sistema operacional con-
segue alocar memória para uma variável quando utilizamos malloc(), e isso pode
ocorrer por diversas razões, entre as quais, pelo fato de haver muitos programas
abertos simultaneamente e acessando a memória, ou algum outro tipo de falha.
Para testar se a alocação de memória ocorreu corretamente, pode-se proceder
da seguinte forma, colocando um teste condicional imediatamente após a linha que
contém a função malloc() (linha 8 do programa anterior).
1 if ( nVetor == NULL )
2 {
3 cout << " \ nErro ! Memoria nao pode ser alocada ! " ;
4 exit (0) ;
5 }

Não apenas o tipo inteiro, mas qualquer outro tipo de dado pode utilizar da
função malloc() para fazer a alocação de espaço na memória. O código a seguir,
mostra como alocar um vetor de double, com tamanho w = 100 na memória do
computador, e preencher todos os seus elementos com o valor 120, 00.
Deve-se observar que o asterisco que aparece entre a variável ’w ’ e a função
sizeof(), na linha 11, é meramente o símbolo de matemático de multiplicação, não
tendo nenhuma relação com o símbolo de ponteiro, que também é um asterisco.

216
++
Princípios de programação em C

1 # include < iostream > // Este exemplo mostra como declarar


2 # include < stdlib .h > // um vetor de tamanho variavel , cu
3 using namespace std ; // jo tamanho pode ser definido pelo
4 // programador ou usuario do progra
5 int main () // ma , em tempo real , ou seja , duran
6 { // te a execucao do programa .
7

8 double * Temper ;
9 int w = 100;
10

11 Temper = ( double *) malloc ( w * sizeof ( double ) ) ;


12

13 if ( Temper == NULL )
14 {
15 cout << " \ nErro ! Memoria nao pode ser alocada ! " ;
16 exit (0) ;
17 }
18

19 for ( int i =0; i < w ; i ++)


20 {
21 Temper [ i ] = 120.00;
22 }
23

24 free ( Temper ) ; // Libera da memoria todo o espaco


25

26 return 0; // ocupado pelo vetor ’ Temper ’


27 }

A função ’realloc()’ da biblioteca stdlib.h é utilizada para fazer o ’redimensio-


namento dinâmico’ do tamanho do bloco de memória alocado, em tempo real de
execução do programa.
O conteúdo que já estava no bloco alocado pela função ’malloc()’ é preservado
ao ampliar o seu tamanho com ’realloc()’. Caso o tamanho do bloco seja diminuído
com o realloc(), o novo bloco terá seu conteúdo truncado, e irá conter apenas parte
dos dados que já estavam presentes no bloco anterior.
A função ’realloc()’ tem como primeiro argumento o endereço de um bloco que
tenha sido previamente alocado por ’malloc()’, e como segundo argumento o novo
tamanho que o bloco deverá ter, seja ele maior ou ou menor que o tamanho do bloco
anterior. O que a função ’realloc()’ faz é alocar um novo bloco, para o qual todo o
conteúdo do bloco anterior é copiado, e ela passa então a apontar para o início do
novo bloco, liberando o espaço ocupado pelo bloco anterior.
Entretanto, caso o novo bloco seja apenas uma extensão do bloco anterior, então
seu conteúdo não é copiado, o novo bloco será apenas uma ampliação do espaço de
memória ocupado pelo bloco anterior, mantendo-se o mesmo endereço original para
a primeira posição do bloco.

217
++
Princípios de programação em C

No código a seguir, é inicialmente alocado um vetor para armazenar 10 valores


de temperatura, mas em tempo de execução do programa, sua capacidade de arma-
zenamento é ampliada para 15 valores de temperatura, e isso é feito com o a função
’realloc()’.
1 # include < iostream >
2 # include < stdlib .h >
3 using namespace std ;
4

5 int main ()
6 {
7 double * Temper ; int w = 10;
8

9 Temper = ( double *) malloc ( w * sizeof ( double ) ) ;


10

11 if ( Temper == NULL )
12 {
13 cout << " \ nErro ! Memoria nao pode ser alocada ! " ;
14 exit (0) ;
15 }
16

17 for ( int i =0; i < w ; i ++) {


18 Temper [ i ] = 60.00;
19 }
20

21 Temper = ( double *) realloc ( Temper , 15 * sizeof ( double ) ) ;


22

23 for ( int i =10; i <15; i ++) // As posicoes restantes do


24 { // vetor sao completadas com
25 Temper [ i ] = 60.00; // 60.00
26 }
27

28 free ( Temper ) ;
29

30 return 0;
31 }

Matrizes de duas dimensões podem ser alocadas dinamicamente como um ’vetor


de vetores’ (Figura 10.3), como no exemplo apresentado a seguir.
Matrizes bidimensionais são amplamente utilizadas em cálculos de engenharia,
em especial para a resolução de sistemas lineares de equações, resolução de balanços
de massa e energia em processos industriais, análises de malhas de circuitos elétricos,
fluxos em rede, logística de transporte e distribuição de mercadorias, métodos nu-
méricos de otimização, entre outras aplicações. Assim, o profissional de engenharia
deverá, estar bastante familiarizado com a manipulação de ponteiros e com os pro-
cedimentos de alocação, realocação e liberação dinâmica de memória para operação
com vetores e matrizes.

218
++
Princípios de programação em C

1 # include < iostream >


2 # include < stdlib .h >
3 using namespace std ;
4

5 int main ()
6 {
7 int m = 3; // Qtd . de linhas
8 int n = 4; // Qtd . de colunas
9

10 double ** M ; // Ponteiro duplo para a matriz


11 M = ( double **) malloc ( m * sizeof ( double *) ) ;
12

13 if ( M == NULL )
14 {
15 cout << " Erro ! Nao foi possivel alocar memoria ! " << endl ;
16 exit (0) ;
17 }
18

19 for ( int i =0; i < m ; i ++)


20 {
21 M [ i ] = ( double *) malloc ( n * sizeof ( double *) ) ;
22 }
23

24 // Preenche os elementos da matriz ;


25 M [0][0] = 25.36; M [0][1] = 14.78;
26 M [0][2] = 60.17; M [0][3] = 16.50;
27 M [1][0] = 44.42; M [1][1] = 87.54;
28 M [1][2] = 13.55; M [1][3] = 11.21;
29 M [2][0] = 51.25; M [2][1] = 44.97;
30 M [2][2] = 10.09; M [2][3] = 98.89;
31

32 // Lista na tela os elementos da matriz


33 for ( int Linha =0; Linha < m ; Linha ++) {
34 for ( int Coluna =0; Coluna < n ; Coluna ++) {
35 cout << M [ Linha ][ Coluna ] << endl ;
36 }
37 }
38

39 // Libera a memoria
40 for ( int i = 0; i < m ; i ++)
41 {
42 free ( M [ i ]) ;
43 }
44 free ( M ) ; return 0;
45 }

219
++
Princípios de programação em C

Uma matriz com m linhas e n colunas, é representada na memória com compu-


tador como um vetor de m elementos, sendo que cada um desses elementos contém
um vetor com n elementos, como representado na Figura 10.3 a seguir.

M[0]

m linhas
M[1]

M[2]
M[3]

n colunas

Figura 10.3: Diagrama esquemático do modo como uma matriz bidimensional do tipo
’vetor de vetores’ está organizada na memória do computador. (Fonte: autores)

No código do exemplo anterior, as situações em que a alocação de memória


não puder ser realizada (teste na linha 13) o programador poderá optar por fechar
imediatamente o programa, com o comando ’exit(0)’ (linha 16), ou então, o que é
mais recomendado, manter o programa em funcionamento, fazendo adequadamente
o tratamento do erro com as funções try, throw e catch, conforme discutido no
Capítulo 6 (p.123).

10.8 Alocação dinâmica de memória com os opera-


dores new e delete
Tanto o C quanto o C++ permitem que a alocação dinâmica de memória seja feita
de uma outra maneira, com o uso dos operadores new e delete.

10.8.1 O operador new


A função do operador new é alocar dinamicamente espaço na memória do computa-
dor para uma variável, vetor ou matriz. Esse operador retorna um ponteiro contendo
o endereço do início do bloco de memória alocado. O código no exemplo a se-
guir mostra como utilizar o operador new para fazer a declaração dinâmica de uma
variável do tipo int.
1 int * a = new int ;

No exemplo acima, *a não é uma variável do tipo inteiro, mas sim um ponteiro,
alocado dinamicamente, e que deverá conter o endereço de uma variável com algum
valor inteiro.
O espaço que o operador new reserva na memória do computador é exatamente
do mesmo tamanho do tipo de dado alocado por ele que, para este exemplo, é o
tamanho do tipo inteiro (4 bytes). Embora no exemplo acima tenha sido declarado

220
++
Princípios de programação em C

um vetor do tipo inteiro, o programador deve ter em mente que outros tipos de
dados poderiam ter sido declarados: float, char, double, um vetor, uma matriz, uma
struct, um número complexo, etc.
A sintaxe básica para a utilização do operador new é a que está mostrada a
seguir:
tipo *ponteiro = new tipo
Nessa sintaxe, o compilador se encarregará de verificar que o tipo de dado utilizado
pelo ponteiro no lado esquerdo do sinal de igual é do mesmo tipo que aquele utilizado
no lado direito do sinal de igual. Caso sejam diferentes ocorrerá um típico erro de
sintaxe, e o compilador irá gerar uma mensagem de erro na tela do computador
durante a compilação do programa. O exemplo apresentado a seguir mostra como
declarar dinamicamente uma variável inteira chamada ’Qtd’.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 int * Qtd = NULL ;
8 * Qtd = new int ;
9

10 * Qtd = 256;
11

12 cout << " Valor ..: " << * Qtd << endl ;
13 delete Qtd ;
14 return (0) ;
15 }

10.8.2 O operador delete


No exemplo anterior o operador ’delete’ foi utilizado na linha 13 para desalocar e
liberar dinamicamente todo o espaço de memória reservado para a variável Qtd. O
programador deve ficar atento ao fato de sempre ter que utilizar o operador delete
para liberar a memória todas as vezes em que fizer uso do operador new.
Outra coisa importante a ser observada na linha 7 do exemplo anterior, logo após
o ponteiro ’Qtd’ ter sido declarado, é que o valor NULL (’nada’) foi atribuído a ele.
Uma curiosidade é que valor NULL é atribuído automaticamente a um ponteiro pelo
sistema operacional sempre que houver uma falha na tentativa do ponteiro alocar
espaço na memória do computador para uma variável. Assim, por exemplo, se houver
falta de memória ao tentar alocar dinamicamente um ponteiro, poderá haver um erro
durante a execução do programa.
Para evitar esse problema, antes de utilizar um ponteiro o programador deverá

221
++
Princípios de programação em C

sempre verificar se o valor NULL foi atribuído a ele durante a execução do programa,
como mostrado no código a seguir.
1 # include < iostream >
2

3 using namespace std ;


4

5 int main ()
6 {
7 int * Qtd = NULL ;
8 Qtd = new int ;
9

10 if ( Qtd == NULL ) // Testa se ha espaco na memoria


11 { // para a alocacao de ’ Qtd ’
12 cout << " Nao ha espaco na memoria " << endl ;
13 return ( -1) ;
14 }
15 else
16 {
17 * Qtd = 256;
18 cout << " Valor ..: " << * Qtd << endl ;
19 delete Qtd ;
20 }
21

22 return 0;
23 }

Observe que a função ’return’ na linha 13 do código acima tem como parâmetro
o valor ’−1’. Essa função foi utilizada com a finalidade de abortar a execução
do programa, em função da impossibilidade de alocação de memória. O correto,
contudo, seria o programador construir alguma subrotina de tratamento de exceção
com as instruções try, throw e catch, apresentadas e discutidas no Çapítulo 6.
Além de servir para abortar o programa, a instrução return também serve para
informar ao programador o tipo de erro ocorrido durante sua execução. O parâmetro
−1 foi utilizado aqui para indicar uma situação na qual a saída do programa tenha
ocorrido mediante o surgimento de algum tipo de erro para o qual não era espe-
rado de ocorrer, afinal os computadores modernos geralmente possuem memória em
quantidade suficiente para a alocação de uma variável inteira. As convenções mais
utilizadas para o parâmetro de return são os seguintes:

Zero: O programa terminou corretamente, sem a ocorrência de erros;

Positivo: Em geral, utiliza-se o valor ’1’ como parâmetro da instrução return. Serve
para indicar que algo de potencialmente errado, mas previsível, ocorreu na
execução do programa como, por exemplo, falha na abertura de um arquivo,
falha na conexão com um servidor remoto, etc.

222
++
Princípios de programação em C

Negativo: Em geral, utiliza-se o valor ’−1’ como parâmetro da instrução return.


Serve para indicar que ocorreu um erro imprevisível, não esperado como, por
exemplo, por falha de alocação de memória, divisão por zero em algum cálculo
numérico, etc

Ao invés de utilizar os valores −1, 0 e 1 como parâmetros para o return, o progra-


mador também tem a opção de utilizar os termos EXIT_SUCESS, já apresentado no
Capítulo 3, p.21, e EXIT_FAILURE, macros pré-definidas na biblioteca cstdlib com
os seguintes valores:
1 # define EXIT_SUCESS 0
2 # define EXIT_FAILURE 1

10.8.3 Declaração dinâmica de vetores com o operador new


Com o operador new fica relativamente simples a declaração e alocação dinâmica de
vetores, como mostrado no próximo exemplo. A sintaxe desse tipo de declaração é
a que está apresentada a seguir.
tipo *ponteiro = new tipo[dimensões]
Exemplo:
1 # include < iostream >
2 using namespace std ;
3

4 int main () {
5 int n ;
6 cout << " Informe a Qtd de latas a processar ..: " ;
7 cin >> n ; cin . ignore () ;
8 cout << endl ;
9

10 int * Lata = NULL ;


11 Lata = new int [ n ]; // Cria um vetor de tamanho va
12 // riavel , com ’n ’ posicoes a
13 if ( Lata == NULL ) // serem informadas pelo usuario
14 {
15 cout << " Nao ha espaco para alocacao de memoria " ;
16 return ( -1) ;
17 }
18 else
19 {
20 for ( register int i =1; i <= n ; i ++)
21 {
22 cout << " Peso da lata [ " << i << " ]..: " ;
23 cin >> Lata [ i ]; cin . ignore () ;
24 }

223
++
Princípios de programação em C

25 cout << endl ;


26 cout << " Pesos digitados : " << endl << endl ;
27

28 for ( register int i =1; i <= n ; i ++)


29 {
30 cout << " Peso da lata " << i << ’\ t ’ << Lata [ i ] << endl ;
31 }
32 delete Lata ; // Libera a memoria ocupada pela variavel
33 } // Lata
34 return 0;
35 }

10.9 Estruturas de dados com o comando struct{}


Considere a seguinte situação: você trabalha em uma indústria de alimentos na qual
a estação de tratamento de resíduos mantém um conjunto de informações a cerca
das características físico-químicas do efluente resultante da higienização CIP (Clean
in Place) de tanques de estocagem de leite pasteurizado.
Uma opção para realizar o registro e a manutenção desses dados consiste em
escrever um programa em C++ no qual são criadas variáveis individuais, uma para
cada parâmetro físico-químico de qualidade do efluente como, por exemplo, pH, con-
dutividade elétrica, turbidez, temperatura, DBO (demanda bioquímica de oxigênio)
e DQO (demanda química de oxigênio). O problema surge quando você neces-
sita de repassar todas essas informações para alguma função dentro do programa
C++ . Nesse caso, você deverá repassar, individualmente, cada uma dessas variáveis
como parâmetro para a função, o que pode ser bastante entediante caso a função
seja chamada no código por um grande número de vezes. Poderia ser bem melhor
se houvesse alguma forma de agrupar todas essas variáveis e repassá-las como um
único parâmetro para a função, por meio de apenas um único nome.
Em C++ há uma forma bastante simples de fazer isso, que é por meio de structs
(estruturas). Uma struct é uma coleção de membros de dados de diferentes tipos,
mas agrupados sob um único nome (GIBBS, 2019). Uma struct para os dados
físico-químicos de exemplo do efluente da estação de tratamento de resíduos pode
ser feita como apresentado a seguir.
1 struct Efluente
2 {
3 float pH ; // pH
4 float Condut ; // Condutividade eletrica
5 int Turbidez ; // Indice de turbidez
6 float Temper ; // Temperatura
7 float DBO ; // Demanda Bioquimica de Oxigenio
8 float DQO ; // Demanda Quimica de Oxigenio
9 };

224
++
Princípios de programação em C

Nessa struct todos os seus membros (variáveis de qualidade físico-química) estão


agrupados sob um mesmo nome: ’Efluente’, indicando que se tratam de dados do
efluente de uma estação de tratamento de resíduos.
O código acima apenas declara uma estrutura de dados denominada ’Efluente’ e
adiciona algumas variáveis membro em seu interior. Para efetivamente utilizar essa
estrutura dentro do programa é necessário instanciá-la, ou seja, declarar uma variável
cujo ’tipo de dado’ seja a struct ’Efluente’.
1 Efluente FichaDeDados ;

Assim, cria-se uma variável chamada ’FichaDeDados’, cujo tipo de dado não é
inteiro, float ou double, mas sim, o tipo ’Efluente’.
Agora é possível atribuir valores aos membros da variável ’FichaDeDados’, e isso
é feito por meio de um ’ponto’, como mostrado a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 struct Efluente {
5 float pH ; // pH
6 float Condut ; // Condutividade eletrica
7 int Turbidez ; // Indice de turbidez
8 float Temper ; // Temperatura
9 float DBO ; // Demanda Bioquimica de Oxigenio
10 float DQO ; // Demanda Quimica de Oxigenio
11 };
12

13 int main ()
14 {
15 Efluente FichaDeDados ;
16

17 FichaDeDados . Condut = 18;


18 FichaDeDados . DBO = 6.25;
19 FichaDeDados . DQO = 3.25;
20 FichaDeDados . pH = 6.5;
21 FichaDeDados . Temper = 22.4;
22 FichaDeDados . Turbidez = 12;
23

24 cout << " Condutividade : " << FichaDeDados . Condut << endl ;
25 cout << " DBO ..........: " << FichaDeDados . DBO << endl ;
26 cout << " DQO ..........: " << FichaDeDados . DQO << endl ;
27 cout << " pH ...........: " << FichaDeDados . pH << endl ;
28 cout << " Temperatura ..: " << FichaDeDados . Temper << endl ;
29 cout << " Turbidez .....: " << FichaDeDados . Turbidez << endl ;
30

31 return 0;
32 }

225
++
Princípios de programação em C

Ao escrever o código do programa no Code::Blocks, sempre que o ponto for di-


gitado após o nome da variável associada à struct, um menu popup será aberto, e
apresentará todos os seus membros, bem como seus respectivos tipos, como mos-
trado na Figura 10.4.

Figura 10.4: Acesso aos membros da struct ’FichaDeDados’ ao teclar um ’ponto’


no editor de códigos do Code::Blocks. (Fonte: autores)

Os valores são atribuídos aos membros da struct da mesma maneira que para
qualquer outro tipo de variável bastando, portanto, utilizar o símbolo convencional
de atribuição de valores (’=’).
Para extrair o valor armazenado em um membro da struct é necessário apenas
referenciar esse membro no código. Exemplo:
1 cout << " Condutividade : " << FichaDeDados . Condut << endl ;

E se houvesse mais de uma estação de tratamento de resíduos? Nesse caso seria


necessário um registro de dados independente para cada uma delas.
Esse é um problema que pode ser facilmente resolvido simplesmente declarando
uma variável do tipo ’Efluente’ para cada uma das estações de tratamento de resí-
duos, como mostrado na linha 15 do código a seguir.
1 # include < iostream >
2 using namespace std ;
3

4 struct Efluente {
5 float pH ; // pH
6 float Condut ; // Condutividade eletrica

226
++
Princípios de programação em C

7 int Turbidez ; // Indice de turbidez


8 float Temper ; // Temperatura
9 float DBO ; // Demanda Bioquimica de Oxigenio
10 float DQO ; // Demanda Quimica de Oxigenio
11 };
12

13 int main ()
14 {
15 Efluente FichaET1 , FichaET2 ;
16

17 FichaET1 . pH = 6.25;
18 FichaET2 . pH = 7.26;
19

20 cout << " pH ET 1.: " << FichaET1 . pH << endl ;


21 cout << " pH ET 2.: " << FichaET2 . pH << endl ;
22

23 return 0;
24 }

Uma estrutura pode conter outras estruturas aninhadas como membros. O exem-
plo apresentado a seguir possui três estruturas. Na primeira (linha 5) estão membros
que guardam informações sobre aspectos da embalagem do alimento, como peso
líquido (em gramas), altura da embalagem (cm), e diâmetro da embalagem (cm).
Os membros da segunda struct (linha 10) servem para armazenar dados de vida
de prateleira, como dia, mês e ano. A terceira struct (linha 15) possui informações
gerais sobre o alimento, mas observe que nesta terceira estrutura, a variável ’Emb’
é do tipo ’Embalagem’, e refere-se ao tipo de dado descrito pela primeira struct.
Na terceira estrutura, a variável ’Valid’ é do tipo ’Validade’, um tipo de dado
definido pela segunda struct.
Outra coisa a observar é que a terceira struct só reconhece os tipos ’Embalagem’
e ’Validade’ porque as estruturas que definem esses tipos foram especificadas no
código antes da terceira estrutura, ou seja, o tipo ’Embalagem’ especificado na linha
17 só é compreendido pelo compilador por que a estrutura que o define foi declarada
na linha 5, antes da linha 17. O mesmo é válido para o tipo ’Validade’. Esse tipo
só é reconhecido pelo compilador por que a estrutura que o define foi declarada na
linha 10, antes da linha 18.
1 # include < iostream >
2 # include < cstring > // strcpy ;
3 using namespace std ;
4

5 struct Embalagem {
6 float PesoLiq ; // Massa do alimento
7 float Altura ; // Altura da lata
8 float Diametro ; // Diametro da lata
9 };

227
++
Princípios de programação em C

10 struct Validade {
11 int Dia ;
12 int Mes ;
13 int Ano ;
14 };
15 struct Alimento {
16 char Descricao [30];
17 Embalagem Emb ;
18 Validade Valid ;
19 };
20

21 int main () {
22 Alimento Embutido ;
23

24 strcpy ( Embutido . Descricao , " Salsicha enlatada tipo Viena " ) ;


25 Embutido . Emb . Altura = 22;
26 Embutido . Emb . Diametro = 6.25;
27 Embutido . Emb . PesoLiq = 180;
28 Embutido . Valid . Dia = 17;
29 Embutido . Valid . Mes = 4;
30 Embutido . Valid . Ano = 2022;
31

32 cout << " Descricao ....: " << Embutido . Descricao << endl ;
33 cout << " Altura lata ..: " << Embutido . Emb . Altura << endl ;
34 cout << " Diametro lata : " << Embutido . Emb . Diametro << endl ;
35 cout << " Peso liquido .: " << Embutido . Emb . PesoLiq << endl ;
36 cout << " Validade .....: " << Embutido . Valid . Dia << " -"
37 << Embutido . Valid . Mes << " -"
38 << Embutido . Valid . Ano << endl ;
39 return 0;
40 }

Os ponteiros podem ser criados não somente para as variáveis dos tipos inteiro,
float, double, etc., mas também podem ser declarados para apontar para estruturas.
No exemplo a seguir, a variável ’R’ é uma instância da estrutura ’Componente’.
Já a variável ’Resistor’ é um ponteiro do tipo ’Componente’, que aponta para a
variável ’R’.
1 # include < iostream >
2 using namespace std ;
3

4 struct Componente // Estrutura que define as proprie


5 { // dades de um componente eletroni
6 float Corrente ; // co : tensao e corrente
7 float Tensao ;
8 };
9

228
++
Princípios de programação em C

10 int main () {
11 Componente * Resistor , R ;
12

13 Resistor = & R ;
14

15 cout << " Informe a corrente : " ;


16 cin >> R . Corrente ;
17

18 cout << " Informe a tensao ..: " ;


19 cin >> R . Tensao ;
20

21 cout << " Corrente : " << (* Resistor ) . Corrente << endl ;
22 cout << " Tensao ..: " << (* Resistor ) . Tensao << endl ;
23

24 return 0;
25 }

O ponteiro para ’R’ pode ter acesso ao conteúdo de qualquer um dos membros
da sua estrutura por meio da notação apresentada nas linhas 22 e 23 do código
acima. Entretanto, uma forma mais simples de escrever os comandos nessas linhas é
o que está apresentado a seguir, que utiliza setas para a direita (’->’) para acessar
os membros da estrutura.
1 cout << " Corrente : " << Resistor - > Corrente << endl ;
2 cout << " Tensao ..: " << Resistor - > Tensao << endl ;

O programador tem também a opção de trabalhar com ’vetores de estruturas’.


Na linha 11 do exemplo a seguir, é declarado um vetor de três posições. Cada
posição irá armazenar um valor do tipo ’Complexo’. Essa é uma forma alternativa
de trabalhar com números complexos, diferente daquela apresentada no Capítulo 7,
p.141. Neste código, as linhas 6 e 7 definem as variáveis para armazenar a parte real
e a parte imaginária do número complexo.
1 # include < iostream >
2 using namespace std ;
3

4 struct Complexo // Estrutura que define um


5 { // numero complexo :
6 float Real ; // Parte real ;
7 float Imag ; // Parte imaginaria ;
8 };
9

10 int main () {
11 Complexo Coord [3]; // Um vetor de 3 posicoes
12

13 Coord [0]. Real = 10; Coord [0]. Imag = 25;


14 Coord [1]. Real = 16; Coord [1]. Imag = 65;
15 Coord [2]. Real = 40; Coord [2]. Imag = 22;

229
++
Princípios de programação em C

16

17 cout << " Ponto 1: " << "(" << Coord [0]. Real
18 << " ," << Coord [0]. Imag
19 << ")" << endl ;
20 cout << " Ponto 2: " << "(" << Coord [1]. Real
21 << " ," << Coord [1]. Imag
22 << ")" << endl ;
23 cout << " Ponto 3: " << "(" << Coord [2]. Real
24 << " ," << Coord [2]. Imag
25 << ")" << endl ;
26 return 0;
27 }

A vantagem de utilizar ’vetores de estruturas’ está no fato de ser possível utilizar


laços de repetição (por exemplo, o for()) para percorrer todos os elementos do vetor,
como mostrado no exemplo a seguir. Neste exemplo são definidas as coordenadas
cartesianas (X, Y ) de 100 pontos. O comando for() na linha 12 é utilizado para
preencher os valores de cada um desses pontos, enquanto que o comando for() na
linha 17 é utilizado para percorrer cada um desses pontos de coordenada e listar seu
valor na tela do computador (com o cout na linha 18).
1 # include < iostream >
2 using namespace std ;
3

4 struct Coord { // Estrutura que define o ponto


5 int X ; // como um ente geometrico , com
6 int Y ; // as coordenadas X e Y
7 };
8

9 int main () {
10 Coord Ponto [100]; // Declara vetor com 100 posicoes
11

12 for ( register int i =0; i <100; i ++) {


13 Ponto [ i ]. X = i ; // Preenche o vetor
14 Ponto [ i ]. Y = (2* i ) ;
15 }
16

17 for ( register int i =0; i <100; i ++) {


18 cout << " ( "
19 << Ponto [ i ]. X
20 << " ,"
21 << Ponto [ i ]. Y << " ) "
22 << endl ;
23 }
24 return 0;
25 }

230
++
Princípios de programação em C

O exemplo a seguir mostra como passar uma struct como argumento de uma
função, conforme discutido no início deste tópico. Neste exemplo, a função ’Calcu-
laDistancia()’ é usada para calcular a distância Euclidiana (Equação 10.1) entre dois
pontos coordenados, dados pelas variáveis ’Origem’ e ’Destino’.

q
dOr ig,Dest = (XOr ig − XDest )2 − (YOr ig − YDest )2 (10.1)

O cálculo da distância Euclidiana entre cidades ou pontos comerciais de distri-


buição de produtos (ver Figura 11.1, p.240) é especialmente útil na resolução de
problemas de logística de transporte de alimentos, embalagens, insumos e matérias-
primas.
No código do exemplo a seguir foi necessária a inclusão da biblioteca cmath (linha
2) para uso da função ’pow()’, utilizada para o calculo da potência de um número
(linhas 30 e 31).
A função ’CalculaDistancia()’, cujo protótipo está escrito na linha 12, só consegue
reconhecer o tipo ’Coord’, passado a ela como parâmetro, por que esse tipo foi
definido antes da linha 12. Assim, o programador deve ficar atento à ordem na qual
alguns tipos de dados são definidos e utilizados dentro do código por meio de structs.
1 # include < iostream >
2 # include < cmath > // Para uso da funcao ’ pow () ’
3

4 using namespace std ;


5

6 struct Coord
7 {
8 int X ; // Coordenada X
9 int Y ; // Coordenada Y
10 };
11

12 float CalculaDistancia ( Coord Origem , Coord Destino ) ;


13

14 int main () {
15 Coord Ponto [100]; // Declara vetor com 100 posicoes
16

17 for ( register int i =0; i <100; i ++) {


18 Ponto [ i ]. X = i ;
19 Ponto [ i ]. Y = (2* i ) ;
20 }
21

22 float D = CalculaDistancia ( Ponto [2] , Ponto [4]) ;


23 cout << " Distancia entre P2 e P4 .: " << D << endl ;
24 return 0;
25 }
26

231
++
Princípios de programação em C

27 float CalculaDistancia ( Coord Origem , Coord Destino )


28 {
29 float Dist ;
30 Dist = pow ( ( Origem . X - Destino . X ) , 2) +
31 pow ( ( Origem . Y - Destino . Y ) , 2) ;
32 Dist = sqrt ( Dist ) ;
33 return ( Dist ) ;
34 }

As structs são amplamente utilizadas para a construção de registros em arquivos


de dados nos quais são armazenadas informações sobre pessoas, processos, matérias-
primas, folhas de pagamento, contabilidade, etc.
Detalhes sobre arquivos de dados serão discutidos no Capítulo 12. A seguir
um exemplo de estrutura na qual os dados do funcionário de uma empresa são
temporariamente armazenados.
1 # include < iostream >
2 # include < string >
3

4 using namespace std ;


5

6 struct Pessoa
7 {
8 string Nome ;
9 string Ident ;
10 int Idade ;
11 char Sexo ;
12 };
13

14 int main ()
15 {
16 Pessoa Funcionario ;
17

18 cout << " Nome ......: "; getline ( cin , Funcionario . Nome ) ;
19 cout << " Identidade : "; getline ( cin , Funcionario . Ident ) ;
20 cout << " Idade .....: "; cin >> Funcionario . Idade ;
21 cout << " Sexo ......: "; cin >> Funcionario . Sexo ;
22

23 // Imprime os dados do funcionario .


24 cout << endl << endl ;
25 cout << " FICHA DO FUNCIONARIO " << endl ;
26 cout << " Nome ......: " << Funcionario . Nome << endl ;
27 cout << " Identidade : " << Funcionario . Ident << endl ;
28 cout << " Idade .....: " << Funcionario . Idade << endl ;
29 cout << " Sexo ......: " << Funcionario . Sexo << endl ;
30 return 0;
31 }

232
++
Princípios de programação em C

10.10 Atividades para fixação da aprendizagem


1. Ponteiros

(a) Quais os valores das variáveis x, y e p no final do código apresentado a


seguir?
1 int x , y , * ptr ;
2 y = 0; ptr = & y ; x = (3 * (* ptr ) ) + (* ptr - 1) ;
3 x ++; x += (* ptr ) ++; --x ; x += (* ptr + 16) ;

(b) Quais valores serão impressos na tela do computador ao final do código


a seguir? (Resolver sem utilizar o computador)
1 int x =200;
2 int * ptr , ** pptr ;
3 ptr = & x ;
4 pptr = & ptr
5 cout << x << * ptr << & ptr
6 << endl
7 << ** ptr << &** pptr
8 << endl ;

(c) Explique a diferença entre os diferentes ’tipos’ de asteriscos utilizados


no programa a seguir. Qual o valor de cada variável após o término do
programa?
1 int z =10;
2 int * ptr , ** pptr , *** ppptr , **** pppptr ;
3 ptr = & z ;
4 pptr = & ptr ;
5 ppptr = & pptr ;
6 cout << z << * ptr << & ptr
7 << endl
8 << ** pptr << & pptr
9 << endl
10 << *** ppptr << & ppptr ;
11 z = (* ptr ) + (3 * (** pptr ) ) - (2 * (*** ppptr ) ) ;
12 z += * ptr * (3*(*** ppptr ) ) ;

(d) Qual a diferença entre os termos: ’passagem de parâmetros por valor’


e ’passagem de parâmetros por ponteiros’ em procedimentos e funções?
Explique e dê um exemplo de cada.
(e) O que é um ponteiro para um vetor ? Explique e dê dois exemplos.
(f) O que é um ponteiro para uma matriz? Explique e dê dois exemplos.
(g) O que faz o seguinte comando? Explique.

233
++
Princípios de programação em C

1 v = ( int *) malloc (100 * sizeof ( int ) ) ;

(h) Escreva um programa que solicita ao usuário a quantidade de embalagens


de alimentos a serem processadas em uma autoclave. O programa deve
alocar dinamicamente um vetor para serem colocados os códigos de lote
de produção dessas embalagens. Depois de ler os valores dos códigos
a partir do teclado, o programa deverá listá-los (imprimir) na tela do
computador. Não deverá haver ’desperdício’ de memória do computador,
ou seja, após a utilização do vetor para listar os dados na tela, esse deverá
ser imediatamente liberado da memória.
(i) O que as linhas abaixo fazem dentro do código de um programa C/C++ ?
Explique.
1 int w =200 , r ; int * k ;
2 k = &w; r = * k + 600;

(j) Crie um procedimento que receba como parâmetros ponteiros para dois
vetores X e Y , ambos do tipo double, e ambos do mesmo tamanho n = 12.
A função deverá retornar um ponteiro para um terceiro vetor R (vetor de
respostas). O vetor R possui cinco posições. As posições de R terão os
seguintes conteúdos:
i. Média aritmética dos valores de X
ii. Média aritmética dos valores de Y
iii. Variância dos valores de X
iv. Variância dos valores de Y
v. Coeficiente de correlação (ρ̂) entre as variáveis X e Y (Equação 10.2)

 ! !
i=n
X i=n
X

i=n
Xi Yi 
X 
i=1 i=1
(xi × yi ) −
 
n
 
 
 i=1 

ρ̂ = v !2   !2  (10.2)
u i=n i=n
u X X
u
u i=n Xi  
i=n
Yi 
uX  X 
i=1 i=1
Xi2 − × Yi 2 −
u   
n n
u 
u i=1   
t   i=1 

(k) Modifique o programa anterior, de modo que ele seja também capaz de
estimar os parâmetros m e b de uma equação linear de primeiro grau, do

234
++
Princípios de programação em C

tipo Ŷ = mX + b, ajustada aos dados de X e Y . Os valores de m e b são


calculados pelas Equações 10.3 e 10.4.

i=n
! " i=n
! i=n
!#
X X X
n X i × Yi − Xi Yi
i=1 i=1 i=1
m= ! !2 (10.3)
i=n
X i=n
X
n Xi2 − Xi
i=1 i=1

i=n
! i=n
!
X X
Yi −m Xi
i=1 i=1
b= (10.4)
n
(l) Crie um vetor W com n valores do tipo float. O vetor somente deverá ser
alocado na memória após o usuário digitar a quantidade n de elementos.
(m) O que há de errado com o código a seguir?
1 int * w ;
2 w = malloc (60 * sizeof ( int ) ) ;
3 w [0] = 200;
4 free ( w +2) ;

2. Structs

(a) Escreva uma struct para armazenar os dados de um alimento enlatado:


i. Código do alimento (inteiro)
ii. Descrição do alimento (string)
iii. Número do lote (string)
iv. Peso total (float)
v. Peso drenado na embalagem (float)
vi. Temperatura de esterilização (float)
vii. Tempo total de processamento térmico (float)
viii. Concentração de nitrito de sódio (float)
ix. Tempo de quarentena, dias (int)
x. Modelo de embalagem (string)
(b) Escreva um programa que implemente a utilização da struct do exercício
anterior.
(c) Escreva um programa que contenha uma struct para armazenar dados de
coordenadas geográficas tridimensionais <x,y,z> do tipo float.

235
++
Princípios de programação em C

(d) Escreva um programa que contenha uma struct para armazenar dados
da rota a ser percorrida pelos caminhões que fazem a distribuição dos
alimentos de uma fábrica. A struct deve possui os seguintes dados:
i. Nome do motorista (char[40])
ii. Nome do cliente (char[40])
iii. Cidade origem (char[30])
iv. Cidade destino (char[30])
v. Tempo de viagem (float)
vi. Distância total (float)
vii. Velocidade máxima registrada no tacógrafo (float)
viii. Qtd. combustível (float)
ix. Produto transportado (string)
x. Qtd. de caixas de produtos (int)
xi. Temperatura do produto durante o transporte (float)
(e) Escreva um programa que contenha uma struct para armazenar dados da
frota de veículos de uma indústria de alimentos. O programa deverá ler os
dados de 10 veículos (digitados pelo usuário) e listá-los na tela. Além da
struct para armazenar os dados do veículo, o programa deverá também
conter uma outra struct, para armazenar informações de datas, conforme
apresentado a seguir.
• Struct ’data’ para armazenar datas
i. Dia (int)
ii. Mês (int)
iii. Ano (int)
• Struct para armazenar dados dos veículos
i. Motorista responsável pelo veículo (string)
ii. Descrição do veículo (string)
iii. Modelo/Marca do veículo (string)
iv. Ano de fabricação (int)
v. Número da placa (string)
vi. Número do chassis (string)
vii. Capacidade máxima de transporte, ton. (float)
viii. Tara do caminhão (peso sem carga), ton. (float)
ix. Consumo médio na cidade, km/litro (string)
x. Consumo médio na rodovia, km/litro (string)
xi. Caminhão refrigerado? (bool)
xii. Data da última manutenção (data)
xiii. Data da próxima manutenção (data)

236
++
Princípios de programação em C

xiv. Quilometragem atual (int)


xv. Data da próxima troca de pneus (data)
xvi. Licenciamento em dia? (bool)
xvii. IPVA em dia? (bool)
xviii. DPVAT em dia? (bool)
xix. Possui multas? (bool)
xx. Possui rastreador GPS? (bool)
xxi. Possui trava eletrônica no compartimento de cargas? (bool)
xxii. Possui rádio de comunicação? (bool)
(f) Escreva um programa que contenha uma struct para armazenar dados de
estocagem de frutas em uma câmara fria. O programa deverá armazenar
até 10 tipos diferentes de frutas, cujos dados deverão ser digitados e
listados na tela.
i. Descrição da Fruta (string)
ii. Quantidade a ser estocada (float)
iii. Identificação do lote (string)
iv. Qtd. máxima de caixas empilhadas (int)
v. Sazonalidade/Época de safra (string)
vi. Temperatura de estocagem (float)
vii. Umidade relativa de estocagem (float)
viii. Tempo máximo/dias de estocagem (int)
ix. Exige convecção forçada? (bool)
x. Taxa de renovação do ar na câmara (float)
(g) Na cadeia produtiva do café, um fator muito importante é a rastreabi-
lidade dos lotes, que deverá disponibilizar informações sobre plantio do
café, colheita, insumos agrícolas, formas de processamento, secagem, in-
tensidade da torra, análise sensorial e outras informações. Na Figura 10.5
está o diagrama esquemático de uma struct que é parte de um sistema
de armazenamento de dados para rastreabilidade do café.
Escreva um programa que utilize a struct da Figura 10.5 para armazenar
informações sobre 12 lotes de café. Os dados devem ser digitados pelo
usuário e listados na tela.
No Capítulo 12 serão apresentadas as formas de como gravar dados de
estruturas desse tipo em arquivos de dados permanentes, para operações
posteriores de consulta, edição, listagem, exclusão, etc.

237
++
Princípios de programação em C

Café

Lote
% arábica

Código do lote % robusta

Amostra Safra de origem

Plantio e colheita Cod. Fazenda

Cod. identif. no campo Seção

Data do plantio Dia Setor

Mês Talhão
Quantidade colhida [ton]
Ano

Data da colheita Dia

Mês
Processamento
Ano
Tipo

Data do processamento Dia

Torra Mês Aroma

Tipo Ano Sabor

Data da torra Dia Corpo

Mês Acidez

Ano Doçura
Anál. sensorial
R L*

Cor da torra Agtron G a*

RGB B b*

CIELab

Figura 10.5: Representação gráfica da estrutura utilizada para armazenamento de


parte dos dados de rastreabilidade do café. (Fonte: autores)

238
Capítulo 11

Geração de números aleatórios

Conteúdo do capítulo
11.1 Os números aleatórios e suas aplicações em simulações
e cálculos de engenharia . . . . . . . . . . . . . . . . . . . 239
11.1.1 As funções rand() e srand() da biblioteca cstdlib . . . . . 240
11.2 Atividades para fixação da aprendizagem . . . . . . . . . 245

11.1 Os números aleatórios e suas aplicações em si-


mulações e cálculos de engenharia
Números aleatórios são valores numéricos gerados aleatoriamente pelo computador.
Esses números possuem muitas aplicações em ciências, engenharia, biomedicina, si-
mulações computacionais, análise estatística, otimização, cálculo numérico e muitas
outras áreas de conhecimento.
Em geral, utiliza-se números aleatórios quando é necessária a não existência de
correlações entre eventos independentes. Métodos de simulação computacional,
como Algoritmos Genéticos, Simulated Annealing, Ant Colony Optimization e o
Método de Monte Carlo se baseiam na geração de números aleatórios para resolver
problemas complexos de otimização combinatória, muito comuns em engenharia.
Criptografia de dados, e análises de partículas em estudos de física quântica, e análise
de alguns tipos de reações químicas também fazem o uso de números aleatórios,
assim como sorteios de loterias, análise de filas, jogos, problemas de competição,
logística, transporte e muitos outros.
O Problema do Caixeiro Viajante (PCV), por exemplo, é um clássico problema
de otimização combinatória, cujas propostas de solução frequentemente empregam
métodos de geração de números aleatórios.
O PCV consiste em encontrar a rota de menor distância a ser percorrida por um
caixeiro viajante, que deverá visitar sequencialmente várias cidades, uma cidade de
cada vez, sem repetir nenhuma, e retornando à cidade de origem.

239
++
Princípios de programação em C

É um típico problema de logística de transporte, em que os vendedores devem


realizar entregas em diversas cidades, mas com a restrição de percorrer a menor
distância (ou tempo) possível, economizando recursos como combustível e outros
possíveis gastos com a viagem. A Figura 11.1 mostra um diagrama esquemático
que destaca parte da rota ótima a ser percorrida por um caixeiro viajante. O PCV
é um problema tipicamente combinatorial, cuja solução pode ser obtida com auxílio
de números aleatórios, gerados para orientar a avaliação sistemática de um grande
número de possíveis rotas a serem percorridas.

6
8
4
5 7
3

Figura 11.1: Caminho destacado evidenciando parte da rota ótima entre diversas
cidades a serem percorridas na solução do Problema do Caixeiro Viajante. (Fonte:
autores)

11.1.1 As funções rand() e srand() da biblioteca cstdlib


A biblioteca padrão cstdlib possui duas funções utilizadas na geração de números
inteiros aleatórios.

• rand(): Esta função é utilizada para gerar números aleatórios. Se o progra-


mador utilizar esta função para gerar, por exemplo, uma sequência de dez
números aleatórios, então exatamente essa mesma sequência será gerada a
cada vez que o programa for executado pelo programador, ou por algum outro
usuário, independente da época (ou quando) o programa for executado.
A função rand() retorna um valor inteiro entre zero e RAND_MAX, que é
uma constante previamente declarada na biblioteca cstdlib, e vale pelo menos

240
++
Princípios de programação em C

32767 entre as diferentes implementações1 do C++ . Este valor pode ser obtido
ao listar na tela o conteúdo da constante RAND_MAX com o objeto cout:
1 # include < iostream >
2 # include < cstdlib >
3 using namespace std ;
4

5 int main ()
6 {
7 cout << " Valor maximo ..: " << RAND_MAX << endl ;
8 return 0;
9 }

• srand(): Esta função também gera números inteiros aleatórios, porém de modo
diferente da função rand(). A função srand() gera os valores aleatórios com
base em um valor de referência, ou ’ponto de partida’, conhecido como ’se-
mente’ (ou seed, em inglês).
Assim, se o programador utilizar, por exemplo, uma seed igual a 10 (dez),
então caso mande gerar uma lista com 5 números aleatórios, a função srand()
irá gerar sempre a mesma sequência de números aleatórios em todas as vezes
que o programa for executado com a seed igual a 10. Mas se o programador
modificar o valor da seed para algum outro valor (12, por exemplo), então
outros números aleatórios serão gerados, mas essa sequência de novos valores
aleatórios será exatamente a mesma a cada vez que o programa for novamente
executado, enquando a seed não for modificada.

• Exemplo de uso da função rand(). Neste exemplo são gerados 10 (dez) núme-
ros aleatórios inteiros. Se o programa for executado várias vezes, a sequência
será sempre a mesma todas as vezes.
1 # include < iostream >
2 # include < cstdlib > // rand () e srand () ;
3 using namespace std ;
4

5 int main () {
6

7 for ( int i =0; i <10; i ++) {


8 cout << rand () << endl ;
9 }
10 return 0;
11 }

1
Na versão do Code::Blocks utilizada ao escrever este livro (versão 20.03, gcc 5.4.0, Linux -
Unicode, 64 bits), o valor de RAND_MAX declarado na biblioteca cstdlib é 2147483647.

241
++
Princípios de programação em C

• Exemplo de uso da função srand() com seed igual a 10. Neste exemplo são
gerados 20 (vinte) números aleatórios inteiros. Se o programa for executado
várias vezes, a sequência será sempre a mesma todas as vezes. Caso o progra-
mador tenha interesse em que o programa gere uma outra sequência, então
ele deverá utilizar um outro valor para seed.
1 # include < iostream >
2 # include < cstdlib >
3 using namespace std ;
4

5 int main () {
6 srand (10) ;
7

8 for ( int i =0; i <20; i ++) {


9 cout << rand () << endl ;
10 }
11 return 0;
12 }

Uma pergunta que pode surgir é a seguinte: ’Como os números gerados são
aleatórios se eles se repetem a cada vez que o programa é executado?’ A resposta
para isso é bem simples. Eles não são verdadeiramente aleatórios.
Os valores gerados pelas funções rand() e srand() são pseudoaleatórios. Para
melhorar a aleatoriedade na geração desses números, o programador pode se valer
de um artifício bastante simples: ao invés de informar um valor fixo para a seed,
basta ele informar um valor que muda a cada instante.
A função time() da biblioteca ctime permite obter o número de segundos de-
corridos2 desde 00:00:00 UTC do dia 1 de janeiro de 1970 até o momento atual,
quando o parâmetro passado a ela é o valor ’NULL’3 .
1 # include < iostream > // O valor aleatorio sera ge
2 # include < cstdlib > // rado com uma seed dada pe
3 # include < ctime > // lo instante de tempo atu
4 using namespace std ; // al ( em quantidade de se
5 // gundos decorridos desde a
6 int main () { // zero hora do dia 01 de ja
7 srand (( unsigned ) time ( NULL ) ) ; // neiro de 1970 ate o ins
8 for ( int i =0; i <10; i ++) { // tante de tempo atual ) . Es
9 cout << rand () << endl ; // se valor de seed muda to
10 } // da vez que o programa for
11 return 0; // executado .
12 }

2
Ver detalhes no Capítulo 4, Seção 4.1.5, p.73.
3
Em C++ ’NULL’ é definido como sendo numericamente igual a zero.

242
++
Princípios de programação em C

Vimos que a função rand() sempre retorna um número inteiro entre zero e
RAND_MAX. Assim, para gerar um número aleatório compreendido entre dois va-
lores, nMin e nMax, a função rand() pode ser utilizada como apresentado a seguir.
1 int Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;

Exemplo:
1 # include < iostream >
2 # include < cstdlib >
3 # include < ctime >
4 using namespace std ;
5 int main () {
6 srand (( unsigned ) time ( NULL ) ) ;
7 int nMin = 5; int nMax = 120;
8 for ( int i =0; i <1000; i ++) {
9 int Aleatorio = rand () %(( nMax - nMin ) + 1) + nMin ;
10 cout << Aleatorio << endl ;
11 }
12 return 0;
13 }

No código a seguir está um programa que mostra como as funções rand() e


srand() podem ser utilizadas para fazer um sorteio do tipo ’cara’ ou ’coroa’.
1 # include < iostream >
2 # include < cstdlib >
3 # include < ctime >
4 using namespace std ;
5 int JogarMoeda ( void ) ;
6

7 int main () {
8 int CaraOuCoroa ;
9 CaraOuCoroa = JogarMoeda () ;
10

11 if ( CaraOuCoroa == 0) {
12 cout << " Deu Cara " << endl ;
13 } else {
14 cout << " Deu Coroa " << endl ;
15 }
16 return 0;
17 }
18 int JogarMoeda ( void ) {
19 srand (( unsigned ) time ( NULL ) ) ;
20 int nFace ;
21 nFace = rand () % 2; // O operador ’% ’ calcula o
22 return ( nFace ) ; // resto da divisao por n =2;
23 }

243
++
Princípios de programação em C

O sorteio de um número entre 1 e 6 pode, por exemplo, ser usado para simular
as jogadas de um dado para escolher a ordem dos tratamentos a serem aplicados a
parcelas de um delineamento experimental.
1 # include < iostream >
2 # include < cstdlib >
3 # include < ctime >
4 using namespace std ;
5 int JogoDeDados ( void ) ; // Prototipo de funcao
6

7 int main () {
8 srand (( unsigned ) time ( NULL ) ) ;
9 for ( int i =1; i <=10; i ++) {
10 cout << " Jogada : " << i << ’\ t ’ <<
11 " Face : " << JogoDeDados () << endl ;
12 }
13 return 0;
14 }
15

16 int JogoDeDados ( void ) {


17 int nDado = rand () %((6 - 1) + 1) + 1;
18 return nDado ;
19 }

Valores numéricos aleatórios com casas decimais também podem ser gerados com
as funções rand() e srand(), em um intervalo pré-definido pelo programador.
1 # include < iostream >
2 # include < cstdlib >
3 # include < ctime >
4 # include < iomanip >
5 using namespace std ;
6 double Aleatorio ( double Min , double Max ) ; // Prototipo
7 int main () {
8 srand (( unsigned ) time ( NULL ) ) ;
9 cout . precision (6) ;
10 cout << setiosflags ( ios :: fixed ) ;
11 for ( int i =1; i <=10; i ++) { // gera valores nume
12 cout << Aleatorio (51 , 82) << endl ; // ricos aleatorios
13 } // entre 51 e 82.
14 return 0;
15 }
16 double Aleatorio ( double Min , double Max ) {
17 double nTemp = ( Max - Min ) ;
18 nTemp = nTemp * ((( double ) RAND_MAX ) - (( double ) rand () ) ) ;
19 nTemp = nTemp / (( double ) RAND_MAX ) ; nTemp = Max - nTemp ;
20 return nTemp ;
21 }

244
++
Princípios de programação em C

Frequentemente é necessário gerar números aleatórios que sigam a algum tipo de


distribuição estatística como, por exemplo, uma distribuição Normal, distribuição de
Bernoulli, Gamma, Poison, etc. Essas situações ocorrem, por exemplo, ao simular
filas ou em outros tipos de simulações computacionais.
Para gerar números aleatórios que sigam a uma distribuição estatística específica
são utilizadas outras bibliotecas para essa finalidade como, por exemplo, a random,
que faz parte das bibliotecas padrões do C++ , mas esse é um assunto que está fora
do escopo deste livro texto e por isso não será abordado aqui.

11.2 Atividades para fixação da aprendizagem


1. Escreva um programa que preencha uma matriz 20x20 com números aleatórios
inteiros entre 0 e 100.

2. Escreva um programa gere 10 números aleatórios inteiros, na faixa que vai de


100 a 900, para serem utilizados na codificação de amostras de uma análise
sensorial vinhos tintos.

3. Escreva um programa que gere p números aleatórios inteiros, na faixa que


vai n1 até n2 . Os valores de p, n1 e n2 devem ser digitados pelo usuário do
programa. O valor p deverá alocar dinamicamente um vetor de p posições na
memória RAM. Os dados deverão ser listados na tela.

4. Modifique o programa do exercício anterior de modo que os números aleatórios


sejam do tipo float, ou seja, que apresentem pelo menos 3 casas decimais.

5. Crie um jogo simples em C++ . Este jogo deverá sortear um número inteiro entre
0 e 100, mas não mostrá-lo ao usuário do programa. O usuário deverá tentar
acertar o número sorteado, digitando sua escolha. Caso o usuário não acerte,
será dada a ele uma nova tentativa, e o jogo deverá informar se essa tentativa
foi maior ou menor do que o valor sorteado. Quando o usuário finalmente
acertar o número sorteado, o programa deverá indicar quantas tentativas foram
necessárias para acertar o número sorteado. (MATOS (2020)).

6. Escreva um programa para gerar números aleatórios inteiros entre 1 e 12. Es-
ses números serão utilizados para definir a ordem de aplicação dos tratamentos
às parcelas de um experimento com embalagens de alimentos. Os números ale-
atórios deverão ser colocados em um vetor de inteiros, alocado dinamicamente
em tempo de execução do programa. No seu código, certifique-se que nenhum
elemento do vetor poderá estar repetido. Liste os dados na tela e libere a
memória ao término do programa.

7. Para um determinado tipo de processo industrial, foi verificado que o seu custo
operacional é uma função de quatro outras variáveis, x, y , z e w . Dada a

245
++
Princípios de programação em C


função: custo(x, y , z, w ) = 4, 25x 3 − 7, 25y z + xz w /100 , com x ∈ [20; 100],
y ∈ [52; 104], z ∈ [16; 49] e w ∈ [67; 206]. Obtenha valores de x, y , z e
w , de modo que o custo fique próximo de R$ 411.832, 21. Para fazer isso,
escreva um programa que gere números aleatórios (double) nas faixas de valores
permitidos para cada uma das variáveis. Faça um laço infinito de repetição com
o comando while() de modo que, em cada ciclo iterativo, os valores aleatórios
que melhorem aproximação do custo desejado sejam armazenados em um vetor
de 4 posições, sendo uma posição para cada variável. Deixe o programa ser
executado por um longo intervalo de tempo como, por exemplo, 2 a 3 minutos,
e avalie os resultados obtidos.

8. A senha para desbloquear um antigo equipamento industrial é composta por


4 números inteiros, de 0 a 9, que deve ser digitada em um pequeno teclado
(Figura 11.2). Por se tratar de um equipamento muito antigo, não há entre
os funcionários da fábrica nenhum que conheça a sequência de dígitos para
desbloquear o equipamento e colocá-lo para funcionar. Sua equipe então teve
a ideia de construir um pequeno robô para digitar aleatoriamente números
nesse teclado, simulando uma tentativa humana de desbloquear o equipamento.
Construa um programa em C++ capaz de gerar sequências inteiras de 4 dígitos
aleatórios a serem digitadas pelo robô. Cada dígito dessa sequência deve estar
compreendido entre 0 e 9, e o robô deverá fazer tentativas por um tempo
indeterminado (loop infinito na geração dos números aleatórios).

0000
1 2 3
4 5 6
7 8 9
X 0 OK

Figura 11.2: Teclado de quatro dígitos utilizado para digitar a senha de desbloqueio
de um antigo equipamento industrial. (Fonte: autores)

246
Capítulo 12

Arquivos de dados em C++

Conteúdo do capítulo
12.1 Conceitos básicos sobre manipulação de arquivos de da-
dos em C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
12.2 Modos de abertura de arquivos de dados . . . . . . . . . 249
12.3 Análise do status de abertura de um arquivo de dados . 251
12.3.1 Fechando o arquivo de dados com close() . . . . . . . . . 251
12.4 Leitura e escrita em arquivos de dados no modo texto . 252
12.5 Leitura de caracteres em um arquivo de dados com a
função get() . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
12.6 Leitura e escrita de dados binários em arquivos de acesso
aleatório . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
12.7 Sistemas de Gestão de Bases de Dados, SGBD . . . . . . 271
12.8 Arquivos para plotagem de funções matemáticas . . . . 272
12.9 Atividades para fixação da aprendizagem . . . . . . . . . 273

Em todas as situações abordadas até aqui, as informações, resultados de cálculos


e dados de processamento eram armazenados unicamente em variáveis de memória.
Embora bastante útil em inúmeras situações, o problema em trabalhar exclusivamente
com variáveis de memória está no fato de elas serem completamente voláteis, e serem
destruídas todas as vezes que o programa é encerrado ou quando o computador é
desligado. Nessa situação todos os valores contidos nas variáveis são definitivamente
perdidos.
O conteúdo abordado neste capítulo mostra como podemos armazenar, de modo
permanente, os valores das variáveis em arquivos físicos no computador, chamados
de arquivos de dados, com a vantagem de podermos recuperar a qualquer momento
as informações armazenadas nesses arquivos e colocá-las novamente nas variáveis, ou
mesmo utilizar esses dados para listar na tela do computador, realizar novos cálculos
ou qualquer outra forma de processamento.

247
++
Princípios de programação em C

Os arquivos de dados são de vital importância para a construção de alguns pro-


gramas como, por exemplo, bancos de dados de materiais em estoque, cadastro de
funcionários, fornecedores, contatos, etc. Este capítulo abordará as operações mais
comuns com arquivos de dados, e a ênfase será dada aos seguintes assuntos:

• Abertura e criação de um arquivo de dados,

• Escrita de informações em arquivos,

• Leitura de informações em arquivos,

• Fechamento de um arquivo.

12.1 Conceitos básicos sobre manipulação de arqui-


vos de dados em C++
• Arquivos de dados são utilizados para armazenar dados permanentemente em
um arquivo físico, externo ao programa executável construído pelo programa-
dor. Como exemplo, os dados de um programa podem ser armazenados em
arquivos como: ’Materiais.dat’, ’Fornecedores.dat’, ’Contatos.dca’.

• A extensão do nome do arquivo pode ser escolhida pelo programador e tem,


em geral, três caracteres alfanuméricos. Para evitar problemas relacionados
a abertura e fechamento, o nome do arquivo deve conter até oito caracte-
res alfanuméricos (recomendação do autor), podendo incluir numerais a partir
do segundo caractere, e não deve possuir acentos ou símbolos estendidos do
teclado como, por exemplo, $, %, #, @, & e outros.

• Em C++ é dado o nome de ’stream’ a um elemento (uma abstração da lin-


guagem C++ ) que representa o dispositivo no qual as operações de leitura e
gravação serão realizadas. Essas ’streams’ são representadas por diferentes
métodos, que incluem ’ifstream’, ’ofstream’ e ’fstream’.

– ifstream: Este tipo de dado representa o arquivo de entrada de dados


(’input’), e é usado para ler informações que estejam armazenadas em
arquivos de dados.
– ofstream: Este tipo de dado representa o arquivo de saída de dados
(’output’), e é usado para criar arquivos de dados, e também para gravar
informações em arquivos de dados.
– fstream: Este tipo de dado representa um arquivo genérico, e possui
as funcionalidades de ’ifstream’ e de ’ofstream’. Em outras palavras,
o ’fstream’ pode ser utilizado para criar arquivos de dados, e para as
operações de gravação e leitura de dados em arquivos.

248
++
Princípios de programação em C

– Para realizar operações com arquivos de dados é necessário incluir duas


bibliotecas ao programa: ’<iostream>’ e ’<fstream>’.
– Chamamos de ’ponteiro do arquivo’ o indicador da atual posição dentro
de um arquivo de dados. Esse indicador de posição pode ser comparado
ao cursor que temos na tela do computador quando trabalhamos com um
processador de textos.
Ao abrir um arquivo, para leitura ou gravação, podemos posicionar esse
cursor logo no início do arquivo, ao seu final ou em qualquer outra po-
sição, permitindo realizar operações como a inserção de dados em uma
posição específica. Também podemos movimentá-lo dentro do arquivo
nas operações de leitura, exclusão ou alteração dos dados contidos no
arquivo.

12.2 Modos de abertura de arquivos de dados


Antes de abrir um arquivo para leitura é necessário que esse arquivo já exista em seu
computador. Se o objetivo do programador for o de abrir um arquivo para leitura,
então os métodos ’fstream’ ou ’ifstream’ podem ser utilizados. Se o objetivo for o
de gravar dados em um arquivo, então os métodos ’fstream’ ou ’ofstream’ podem
ser utilizados.
A função ’open()’ é utilizada para abrir um arquivo. Essa função é membro de
’fstream’, ’ifstream’ e também de ’ofstream’. Sua sintaxe está apresentada a seguir.

void open(<const char *Nome_do_arquivo >, [<ios::modo_de_abertura>])

• <const char *Nome_do_arquivo >: é o nome do arquivo a ser aberto. Deve-


se incluir junto ao nome do arquivo o caminho completo onde ele se encontra.
Exemplo:

– ”c:\dados\Arquivo.dat” (MS Windows)


– ”/home/food/dados/arquivo.dat” (Linux, case sensitive)

• <ios::modo_de_abertura>: Este argumento da função ’open()’ é opcional.


Ele define o modo como o arquivo deverá ser aberto:

– ios::app: Modo ’append’. Informa que o arquivo deverá ser aberto no


modo de adição, ou seja, ao abrir o arquivo, o ponteiro irá para o final
do arquivo, e qualquer dado gravado nesse arquivo, será acrescentado
(adicionado) ao seu final.
– ios::ate: O arquivo será aberto em modo de gravação, e o ponteiro
será posicionado no final do arquivo. Se o arquivo estiver vazio, então o
ponteiro será posicionado no início do arquivo.

249
++
Princípios de programação em C

– ios::in: Abre o arquivo para leitura de dados. Esse é o padrão da ’ifs-


tream’.
– ios::out: Abre o arquivo para gravação de dados. Esse é o padrão da
’ofstream’.
– ios::binary: Abre o arquivo para leitura ou gravação em modo binário,
ao invés do formato ASCII.
– ios::trunc: Se o arquivo existe, esse modo de abertura irá abrir o arquivo
para gravação, porém irá remover (permanentemente!) todos os dados
contidos no arquivo antes que novos dados sejam gravados.

Os modos considerados ’default’ (padrão) para a abertura de arquivos são:

• ifstream: ios::in

• ofstream: ios::out

• fstream: ios::in | ios::out

Ao abrir um arquivo você poderá combinar diferentes modos de abertura utilizando


uma barra vertical (”|”). No exemplo a seguir o arquivo é aberto para gravação
de dados (com a opção ’ios::out’) e com a opção adicional de excluir todo o seu
conteúdo (’ios::trunc’), caso o arquivo já exista.
Se o arquivo não existir, então a função ’open()’ automaticamente criará um
arquivo vazio, com o mesmo nome e endereço daquele que foi informado.
Deve-se observar que a opção ’ios::trunc’ efetivamente exclui todo o conteúdo de
um arquivo, e não há nenhuma possibilidade de esse conteúdo ser recuperado
caso essa operação tenha sido feita por engano, portanto, muito cuidado ao utilizá-la!
1 ofstream ArqDados ;
2 ArqDados . open ( " c :\ temp \ Nomes . dat " , ios :: out | ios :: trunc ) ;

O exemplo a seguir mostra como abrir um arquivo para as operações de leitura e


gravação.
1 fstream ArqDados ;
2 ArqDados . open ( " c :\ temp \ Nomes . dat " , ios :: out | ios :: in ) ;

O próximo exemplo mostra como abrir um arquivo para gravação. Neste caso a
gravação é feita em modo ’append’, e os novos dados serão acrescentados ao final
do arquivo.
1 ofstream ArqDados ;
2 ArqDados . open ( " c :\ temp \ Nomes . dat " , ios :: out | ios :: app ) ;

250
++
Princípios de programação em C

12.3 Análise do status de abertura de um arquivo de


dados
Imediatamente pós o comando para abrir um arquivo para leitura ou gravação, é
necessário verificar se o arquivo foi, ou não, aberto (ou criado) corretamente.
Essa verificação pode ser feita como apresentado a seguir. Observe que o nome
stream é ’Arqdados’ para o exemplo em questão. Obviamente outro nome poderia
ter sido dado pelo programador.
No exemplo abaixo, a função ’open()’ irá abrir o arquivo caso ele já exista, mas
se não existir ela tentará criar um arquivo vazio.
Caso ocorra algum erro e o arquivo não possa ser aberto ou não possa ser criado
(por falta de espaço físico no computador, por exemplo), então a uma mensagem de
erro será impressa na tela do computador (linha 3 do exemplo).
1 if (! ArqDados ) // Falha ao abrir o arquivo
2 {
3 cout << " Falha ao abrir ( ou criar ) o arquivo ! " ;
4 exit ( EXIT_FAILURE ) ;
5 }
6 else // Sucesso ao abrir o arquivo
7 {
8 cout << " Arquivo aberto com sucesso ! " ;
9 ... // Outros comandos para processar os dados
10 ... // do arquivo
11 }

É importante que o programador se habitue a sempre realizar o teste de verificação


de abertura de um arquivo.

12.3.1 Fechando o arquivo de dados com close()


Outro procedimento extremamente importante consiste em fechar o arquivo de dados
tão logo as operações de leitura ou gravação tenham sido realizadas.
A tentativa de encerrar um programa sem que os arquivos de dados tenham
sido devidamente fechados poderá implicar em perdas de informações, ou mesmo a
ocorrência de danos à estrutura do arquivo de dados.
Em situações como desligamento abrupto do computador quando o arquivo de
dados estiver aberto para leitura ou gravação, falta de energia elétrica e problemas
com vírus, por exemplo, a perda de informações poderá ser irreversível.
Uma boa estratégia consiste em sempre verificar que os arquivos de dados tenham
sido fechados corretamente, além de manter o hábito de estar sempre fazendo cópias
de segurança (backups) diários de todos os dados, sempre manter o arquivo aberto
pelo menor intervalo de tempo possível, e evitar exposição do computador a pendrives
ou outras fontes potenciais de contaminações com vírus.

251
++
Princípios de programação em C

Para fechar um arquivo de dados usa-se a função ’close()’.


1 ArqDados . close () ;

12.4 Leitura e escrita em arquivos de dados no modo


texto
Tanto a leitura quanto a gravação de dados em um arquivo de dados são feitos
exatamente da mesma forma que aqueles utilizando os operadores de inserção (<<)
e de extração (>>) de cin e cout. A seguir um exemplo de como gravar dados em
um arquivo externo com o nome ”Alunos.txt” (Figura 12.1).
1 # include < cstdlib > // para uso do exit (0)
2 # include < iostream >
3 # include < fstream >
4 using namespace std ;
5

6 int main () {
7 ofstream ArqDados ; // Cria uma ofstream para um
arquivo
8 ArqDados . open ( " Alunos . txt " , ios :: out ) ;
9

10 if (! ArqDados ) {
11 cout << " Erro ao abrir o arquivo " ;
12 exit ( EXIT_FAILURE ) ; // Fecha o programa ;
13 } else {
14 ArqDados << " Maria Silva " << ’\ t ’ << " SP " << endl ;
15 ArqDados << " Jose Augusto " << ’\ t ’ << " MG " << endl ;
16 ArqDados << " Pedro Paulo " << ’\ t ’ << " BA " << endl ;
17 ArqDados << " Roberta Souza " << ’\ t ’ << " SP " << endl ;
18 ArqDados << " Ana Clara " << ’\ t ’ << " RS " << endl ;
19 }
20 ArqDados . close () ; // Fecha o arquivo de dados ;
21 return 0;
22 }

252
++
Princípios de programação em C

Figura 12.1: Exemplo de saída de dados para um arquivo físico externo. (Fonte:
autores)

A leitura de dados pode ser feita de diferentes maneiras. O exemplo no có-


digo a seguir utiliza a função ’getline()’ para ler o conteúdo das linhas do arquivo
’Alunos.txt’.
1 # include < cstdlib > // para uso do exit ( EXIT_FAILURE )
2 # include < iostream >
3 # include < fstream >
4 using namespace std ;
5

6 int main () {
7

8 char cTexto [41];


9 ifstream ArqDados ;
10 ArqDados . open ( " Alunos . txt " , ios :: in ) ;
11

12 if (! ArqDados ) {
13 cout << " Erro ao abrir o arquivo " ;
14 exit ( EXIT_FAILURE ) ;
15 } else {
16 while (! ArqDados . eof () ) {
17 ArqDados . getline ( cTexto , 40) ;
18 cout << cTexto << endl ;
19 }
20 }
21 ArqDados . close () ;
22 return 0;
23 }

O exemplo a seguir mostra como gravar os resultados de um cálculo com variáveis


em um arquivo de dados externo, com Nome ’Tabela.txt’ e, em seguida como fazer
a leitura desses dados para imprimir na tela.
1 # include < cstdlib > // Para uso do exit (0)
2 # include < iostream > // Biblioteca padrao

253
++
Princípios de programação em C

3 # include < fstream > // Acesso a arquivos


4 # include < cmath > // Funcao matematica ’ pow () ’
5 # include < iomanip > // Precisao de numeros decimais
6 using namespace std ;
7

8 int main () {
9 double x , y , z ;
10

11 fstream ArqDados ;
12 ArqDados . open ( " Tabela . txt " , ios :: out ) ; // Abre p / gravacao
13

14 if (! ArqDados ) {
15 cout << " Erro ao abrir o arquivo " ; exit ( EXIT_FAILURE ) ;
16 } else {
17 ArqDados . precision (12) ;
18 ArqDados << setiosflags ( ios :: fixed ) ;
19

20 for ( register int i =0; i <10; i ++) {


21 x = 2.258 * ( double ) i ; y = pow (x , 1.115) ;
22 z = x + (3.259* y ) ;
23 ArqDados << x << ’\ t ’ << y << ’\ t ’ << z << endl ;
24 }
25 }
26 ArqDados . close () ; // Fecha p / gravacao
27 ArqDados . open ( " Tabela . txt " , ios :: in ) ; // Abre para leitura
28

29 if (! ArqDados ) {
30 cout << " Erro ao abrir o arquivo " ; exit ( EXIT_FAILURE ) ;
31 } else {
32 cout . precision (4) ;
33 cout << setiosflags ( ios :: fixed ) ;
34

35 while (! ArqDados . eof () ) {


36 ArqDados >> x >> y >> z ;
37 cout << x << ’\ t ’ << y << ’\ t ’ << z << endl ;
38 }
39 }
40 ArqDados . close () ;
41 return 0;
42 }

Na linha 11 do exemplo acima é declarada uma stream com o nome de ’Arq-


Dados’. É por meio dessa stream que será estabelecida uma comunicação com o
arquivo de dados externo, que neste caso é o arquivo ’Tabela.txt’.
A função ’open()’ na linha 12 tentará abrir esse arquivo em modo gravação de
dados (ios::out). Na linha 14 é feito um teste lógico para verificar se função open()

254
++
Princípios de programação em C

conseguiu, ou não, abrir esse arquivo corretamente. Caso esse arquivo não exista,
então a função open() irá criar um arquivo vazio com o nome ’Tabela.txt’.
A criação de um arquivo vazio pela função open() é feita somente quando o
arquivo está sendo aberto em modo gravação. Caso a função open() estivesse
tentando abrir o arquivo em modo de leitura (ios::in) e esse arquivo não existisse,
ou por algum motivo não pudesse ser aberto (por exemplo, erro no hard disk),
então um erro seria gerado em tempo de execução do programa, e o mesmo seria
imediatamente abortado.
Nas linhas 17 e 18 do programa são especificados os parâmetros que definem
o número de casas decimais para valores numéricos, que neste caso optou-se por
trabalhar com 12 casas decimais. Entre as linhas 20 e 25 o comando for() é usado
para gerar os valores de x, y e z e gravar esses dados com o operador de inserção
(<<) no arquivo ’Tabela.txt’ (linha 23).
Imediatamente após a gravação dos dados no arquivo, este é fechado com a fun-
ção ’close()’ (linha 26). A segunda parte do programa consiste em abrir novamente
o arquivo de dados (linha 27), porém agora ele será aberto em modo leitura (ios::in).
A abertura do arquivo é feita com a mesma stream ArqDados, e ao ser aberto, o
ponteiro do arquivo é imediatamente deslocado para o seu início. Ao abrir o arquivo
em modo leitura, faz-se um novo teste lógico para verificar se o comando open()
conseguiu abrir o arquivo corretamente (linha 29).
Os comandos nas linhas 32 e 33 determinam que os valores numéricos deverão
estar com 4 (quatro) casas decimais. O comando while() na linha 35 deve ser
interpretado da seguinte maneira: ”faça enquanto não for o final do arquivo (eof:
end of file)”.
A leitura do arquivo será feita desde o início até o seu final, e o operador de
extração (’>>’) será utilizado para ler ar informações contidas no arquivo e colocar
esses valors nas variáveis x,y e z. Imediatamente após a leitura do arquivo de dados,
este é fechado pela função ’close()’ (linha 40).

12.5 Leitura de caracteres em um arquivo de dados


com a função get()
A função ’get()’ serve para ler um caractere por vez, a partir de um arquivo de dados.
Enquanto o ponteiro se desloca dentro do arquivo, o caractere é lido e colocado na
variável que é passada como parâmetro para essa função. É necessário que o arquivo
tenha sido aberto em modo leitura.
O exemplo a seguir mostra como isso pode ser feito.
1 # include < fstream >
2 # include < iostream >
3 using namespace std ;
4 int main () {
5

255
++
Princípios de programação em C

6 ifstream dbProcTerm ;
7 dbProcTerm . open ( " ProcTerm . txt " , ios :: in ) ;
8 char cLetra ;
9 while (! dbProcTerm . eof () ) {
10 dbProcTerm . get ( cLetra ) ;
11 cout << cLetra ;
12 }
13 dbProcTerm . close () ;
14 return 0;
15 }

A função get() é importante nas situações onde é necessário contar o número


de caracteres dentro de um arquivo, ou mesmo quando é necessário copiar dados de
um arquivo para outro arquivo, e também nas situações onde é necessário verificar
a ocorrência de um ou mais caracteres específicos dentro de um arquivo, ou então
para verificar para qual posição o ponteiro do arquivo deverá ser movimentado ao
encontrar um caractere de interesse do programador ou do usuário.
A seguir exemplos que mostram o uso da função get() para contar o número
total de caracteres e de palavras em um arquivo. Observe que o espaço em branco
também conta, visto que ele é um caractere como outro qualquer.
1 # include < fstream >
2 # include < iostream >
3 using namespace std ;
4

5 int main () {
6 ifstream dbProcTerm ;
7 dbProcTerm . open ( " ProcTerm . txt " , ios :: in ) ;
8

9 int vCont = 0; char cLetra ;


10

11 while (! dbProcTerm . eof () ) {


12 dbProcTerm . get ( cLetra ) ;
13 vCont ++;
14 }
15 dbProcTerm . close () ;
16 cout << " Numero total de caracteres ..: " << vCont ;
17 return 0;
18 }

1 # include < fstream >


2 # include < iostream >
3 using namespace std ;
4

5 int main () {
6 ifstream dbProcTerm ;
7 dbProcTerm . open ( " ProcTerm . txt " , ios :: in ) ;

256
++
Princípios de programação em C

9 char cPalavra [35];


10 int nQtd = 0;
11

12 while (! dbProcTerm . eof () ) {


13 dbProcTerm >> cPalavra ;
14 nQtd ++;
15 }
16

17 dbProcTerm . close () ;
18 cout << " Qtd de palavras .: " << nQtd ;
19 return 0;
20 }

O programa a seguir mostra como a função ’getline()’ pode ser usada para contar
o número de linhas em um arquivo, considerando que, neste exemplo, cada linha não
tenha mais do que 250 caracteres.
1 # include < fstream >
2 # include < iostream >
3 using namespace std ;
4

5 int main () {
6 ifstream dbProcTerm ;
7 dbProcTerm . open ( " ProcTerm . txt " , ios :: in ) ;
8

9 char cTextoLinha [251];


10 int nQtd = 0;
11

12 while (! dbProcTerm . eof () ) {


13 dbProcTerm . getline ( cTextoLinha ,251) ;
14 nQtd ++;
15 }
16 dbProcTerm . close () ;
17 cout << " Qtd de linhas ..: " << nQtd ;
18 return 0;
19 }

O exemplo a seguir mostra como podemos abrir simultaneamente dois arquivos


de dados, um para leitura e outro para gravação e, em seguida, copiar os dados de
um arquivo para o outro.
Observe que todos os caracteres do arquivo ProcTerm.txt são copiados para o
outro arquivo, CopiaProcTerm.txt, exceto os caracteres que correspondem à letra
’a’ (ver linha 15). E isso foi feito intencionalmente pelo programador.
Outra observação a ser feita é que nos exemplos apresentados aqui não foi reali-
zado nenhum teste lógico para verificar se os arquivos estão, ou não, sendo abertos
corretamente. Esses testes foram omitidos aqui apenas para reduzir o tamanho dos

257
++
Princípios de programação em C

códigos apresentados, mas o programador deve ter em mente que esses testes sempre
devem ser realizados.
1 # include < iostream >
2 # include < fstream >
3 using namespace std ;
4

5 int main () {
6 ifstream dbArqLeitura ;
7 dbArqLeitura . open ( " ProcTerm . txt " , ios :: in ) ;
8

9 ofstream dbArqGravacao ;
10 dbArqGravacao . open ( " CopiaProcTerm . txt " , ios :: out ) ;
11

12 char cLetra ;
13 while (! dbArqLeitura . eof () ) {
14 dbArqLeitura . get ( cLetra ) ;
15 if ( cLetra != ’a ’) {
16 dbArqGravacao << cLetra ;
17 }
18 }
19

20 dbArqLeitura . close () ;
21 dbArqGravacao . close () ;
22 return 0;
23 }

12.6 Leitura e escrita de dados binários em arquivos


de acesso aleatório
Até aqui foram apresentadas algumas ferramentas para a leitura e gravação de dados
em arquivo ASCII, conhecidos também como arquivos texto. A vantagem em traba-
lhar com arquivo texto é que eles podem ser facilmente abertos em qualquer editor
de texto e seu conteúdo é prontamente identificado, podendo ser lido diretamente
por qualquer pessoa.
Essa, contudo não é a melhor forma de armazenar dados para alguns tipos de
programas. Em algumas situações há a necessidade de trabalhar com informações
armazenadas na forma de blocos, nas quais o acesso deve ser aleatório. Um exemplo
típico é um cadastro de funcionários, no qual o programa deve armazenar os dados
de um funcionário como se fosse um bloco, contendo informações exclusivas de um
determinado funcionário.
Quando é necessário ter acesso aos dados de um funcionário específico, o pro-
grama deve ser capaz de movimentar o ponteiro, localizar esse funcionário dentro do
arquivo de dados e posicionar o ponteiro do arquivo exatamente no início do bloco

258
++
Princípios de programação em C

de informações correspondentes a esse funcionário. Essa forma de acesso na qual o


ponteiro do arquivo pode ir diretamente para um bloco de informações é chamado
de acesso aleatório.
Diferentemente dos arquivos ASCII (arquivos de texto), os arquivos binário não
podem ser abertos e lidos diretamente por uma pessoa. Os arquivos binários são
escritos na forma de uma sequência de bytes, e como não há nenhuma tradução
desses bytes para os caracteres de texto, o que ocorre é que os arquivos binários
são menores, de acesso mais rápido, com maior desempenho e eficiência quando são
utilizados para armazenar dados de acesso aleatório.
Os blocos de dados que compõem um arquivo binário de acesso aleatório são
chamados de registros. Na Tabela 12.1 apresentada a seguir, cada linha é chamada
de ’registro’, enquanto que cada coluna é chamada de ’campo’. Assim, no terceiro
registro desta Tabela, o campo Nome está preenchido com o nome do estudante
Cláudio Oliveira. O campo NotaP2 desse registro está preenchido com o valor 86,8.

Tabela 12.1: Exemplo da estrutura de uma tabela com registros e campos de dados
de estudantes.
Matrícula Nome NotaP1 NotaP2 NotaP3
145 Ana Clara 86.2 68.9 76.4
874 José Carlos 92.7 72.6 69.5
478 Cláudio Oliveira 82.4 86.8 67.6
.. .. .. .. ..
. . . . .
475 Priscila Silva 89.4 98.6 86.6
Fonte: Elaborada pelos autores.

Como mostrado na Tabela 12.1, os blocos de dados em arquivos binários de


acesso aleatório podem ser armazenados na forma de uma estrutura tabular. Nos
códigos em C++ esse formato tabular pode ser implementado com o auxílio de structs,
como apresentado a seguir.
1 struct Ficha
2 {
3 int Matricula ; // Campo matricula : tipo inteiro ;
4 char Nome [31]; // Campo Nome : tipo vetor de caracteres ;
5 float NotaP1 ; // Campo NotaP1 : tipo float ;
6 float NotaP2 ; // Campo NotaP2 : tipo float ;
7 float NotaP3 ; // Campo NotaP3 : tipo float ;
8 };

Para utilizar essa estrutura é necessário declarar uma variável do tipo ’Ficha’,
1 Ficha Estudante ;

Os membros da variável ’Estudante’ poderão ser acessados a partir de um ponto,


como mostrado a seguir. Observe que para o campo ’Nome’ é necessário utilizar a

259
++
Princípios de programação em C

função strcpy da biblioteca cstring, visto que se trata de um campo tipo vetor de
caracteres. Operações com structs já foram apresentadas e discutidas anteriormente
no Capítulo 10, p.224.
1 Estudante . Matricula = 145;
2 strcpy ( Estudante . Nome , " Ana Clara " ) ;
3 Estudante . NotaP1 = 86.2;
4 Estudante . NotaP2 = 68.9;
5 Estudante . NotaP3 = 76.4;

Obviamente, em muitas situações o programador irá construir o programa de


modo que o seu usuário possa entrar com os dados a partir do teclado. Nessa situa-
ção, o preenchimento dos dados de um aluno a partir do teclado é feito normalmente
pelos objetos cin e cout.
1 cout << " Matricula ...: " ;
2 cin >> Estudante . Matricula ; cin . ignore () ;
3 cout << " Nome ........: " ; cin . getline ( Estudante . Nome , 30) ;
4 cout << " Nota Prova 1: " ; cin >> Estudante . NotaP1 ;
5 cin . ignore () ;
6 cout << " Nota Prova 2: " ; cin >> Estudante . NotaP2 ;
7 cin . ignore () ;
8 cout << " Nota Prova 3: " ; cin >> Estudante . NotaP3 ;
9 cin . ignore () ;

Após a entrada dos dados a partir do teclado é necessário criar uma stream, que
será utilizada para estabelecer uma comunicação com o arquivo externo. Para este
exemplo, o arquivo será chamado de ’CadAluno.dat’.
Como o acesso ao arquivo de dados será tanto para leitura quanto para gravação,
então a stream será do tipo fstream.
1 fstream ArqDados ;

Após a criação da stream ’ArqDados’, é necessário informar qual o caminho e o


nome do arquivo que será atribuído a ela, e isso é feito com a função ’open()’.
Observe no exemplo a seguir que os argumentos da função ’open()’ foram dis-
tribuídos em mais de uma linha. Isso foi feito apenas para incluir os comentários
(em vermelho) que indicam os modos de abertura do arquivo ’CadAluno.dat’, porém
todos esses comandos poderiam ter sido colocados em uma única linha. O arquivo
foi aberto em modo binário.
1 ArqDados . open ( " CadAluno . dat " , // Nome do arquivo ;
2 ios :: out | // Abre para gravacao
3 ios :: in | // Abre para leitura
4 ios :: binary | // Abre em modo binario
5 ios :: app ) ; // Abre em modo ’ append ’

260
++
Princípios de programação em C

Como de costume, sempre que a função open() é utilizada para estabelecer uma
comunicação com um arquivo externo, é necessário verificar se essa comunicação foi
estabelecida com sucesso ou não.
1 if (! ArqDados )
2 {
3 cout << " Erro ao abrir cadastro de alunos " ;
4 exit (0) ; // Recurso da biblioteca < cstdlib >
5 } else {
6 // Processamento dos dados aqui ;
7 }

A gravação simultânea de todos os dados contidos na estrutura ’Estudante’ é


feita pela função ’write()’. O primeiro parâmetro desta função se refere à estrutura
que deverá ser inserida no arquivo de dados. O segundo parâmetro refere-se ao
tamanho da estrutura que deverá ser gravada.
1 ArqDados . write ( ( char *) & Estudante , sizeof ( Ficha ) ) ;

Após a gravação o arquivo de dados deverá ser fechado com a função close().
1 ArqDados . close () ;

O código completo do programa para a gravação de dados (na forma de uma


struct) em um arquivo binário de acesso aleatório está apresentado a seguir.
1 # include < iostream > // Biblioteca padrao
2 # include < fstream > // Para acesso a dados
3 # include < cstring > // Para funcao : strcpy ()
4 # include < cstdlib > // Para funcao : exit (0)
5 using namespace std ;
6 struct Ficha {
7 int Matricula ;
8 char Nome [31];
9 float NotaP1 , NotaP2 , NotaP3 ;
10 };
11 int main () {
12 Ficha Estudante ;
13 cout << " Matricula ...: " ; cin >> Estudante . Matricula ;
14 cin . ignore () ;
15 cout << " Nome ........: " ; cin . getline ( Estudante . Nome , 30) ;
16 cout << " Nota Prova 1: " ; cin >> Estudante . NotaP1 ;
17 cin . ignore () ;
18 cout << " Nota Prova 2: " ; cin >> Estudante . NotaP2 ;
19 cin . ignore () ;
20 cout << " Nota Prova 3: " ; cin >> Estudante . NotaP3 ;
21 cin . ignore () ;
22 fstream ArqDados ;
23 ArqDados . open ( " CadAluno . dat " , ios :: out |

261
++
Princípios de programação em C

24 ios :: in | ios :: binary |


25 ios :: app ) ;
26 if (! ArqDados ) {
27 cout << " Erro ao abrir cadastro de alunos " ;
28 exit ( EXIT_FAILURE ) ;
29 } else {
30 ArqDados . write ( ( char *) & Estudante , sizeof ( Ficha ) ) ;
31 if ( ArqDados . fail () ) { // Testa se a gravacao foi OK .
32 cout << " Erro ao fazer a gravacao . " << endl ;
33 ArqDados . clear () ;
34 }
35 }
36 ArqDados . close () ;
37 return 0;
38 }

Para a leitura de dados a partir de um arquivo binário de acesso aleatório primei-


ramente é necessário movimentar o ponteiro do arquivo de dados para o início do
registro a ser lido. Uma boa prática é sempre movimentar o ponteiro para o início do
arquivo imediatamente após a sua abertura. Isso é feito por meio de duas instruções.
1 ArqDados . clear () ;
2 ArqDados . seekg (0 , ios :: beg ) ;

A função clear() serve para limpar o status de erro de uma stream, enquanto
que a função ’seekg()’ serve para movimentar o ponteiro do arquivo para a próxima
posição a ser lida (get) em uma stream. Neste caso, o seu primeiro argumento é
um valor de offset (desvio), relativo ao segundo argumento.
O segundo argumento da função seekg() (ios::beg) refere-se ao início do arquivo.
Em outras palavras, o programador pode utilizar essas duas linhas de código quando
desejar movimentar o ponteiro para o início do arquivo, quando em uma operação
de leitura de dados.
A movimentação do ponteiro para a leitura de um registro específico também é
feita com a função seekg().
Na linha 2 do código a seguir o ponteiro será movimentado para uma posição
que leva em conta o comprimento total de um registro (em bytes), e o número de
registros a ser percorrido, desde o início do arquivo de dados, até chegar no registro
de interesse do programador.
Assim, caso o ele tenha interesse em acessar os dados do terceiro registro, então
ele deverá movimentar o ponteiro do arquivo de dados para a posição ’3 × (tamanho
de um registro de dados)’. Neste exemplo, o tamanho de um registro de dados é
obtido pela função ’sizeof()’.
1 int NumReg = 2;
2 ArqDados . seekg ( ( NumReg ) * sizeof ( Ficha ) ) ;

262
++
Princípios de programação em C

Uma vez encontrado o registro de interesse, podemos ler os seus dados e colocar
nas variáveis da estrutura (struct) ’Estudante’. A leitura de dados de um arquivo
binário aleatório é feita com a função ’read()’.
1 ArqDados . read ( ( char *) & Estudante , sizeof ( Ficha ) ) ;

Uma vez lidos os dados a partir do arquivo, estes são colocados nas variáveis da
estrutura ’Estudante’, essas variáveis podem ser listadas na tela ou utilizadas para
qualquer outra finalidade.
1 cout << Estudante . Nome << endl ;
2 cout << Estudante . Matricula << endl ;
3 cout << Estudante . NotaP1 << endl ;
4 cout << Estudante . NotaP2 << endl ;
5 cout << Estudante . NotaP3 << endl ;

A seguir está apresentada a listagem completa do programa para a leitura de


dados (na forma de registros), por meio da função read(), em um arquivo binário de
acesso aleatório.
1 # include < iostream > // Biblioteca padrao
2 # include < fstream > // Para acesso a dados
3 # include < cstring > // Para funcao : strcpy ()
4 # include < cstdlib > // Para funcao : exit (0)
5 using namespace std ;
6

7 struct Ficha {
8 int Matricula ; // Campo matricula : tipo inteiro ;
9 char Nome [31]; // Campo Nome : tipo vetor de caracteres ;
10 float NotaP1 ; // Campo NotaP1 : tipo float ;
11 float NotaP2 ; // Campo NotaP2 : tipo float ;
12 float NotaP3 ; // Campo NotaP3 : tipo float ;
13 };
14 int main () {
15

16 Ficha Estudante ;
17 fstream ArqDados ;
18 ArqDados . open ( " CadAluno . dat " , ios :: out |
19 ios :: in | ios :: binary |
20 ios :: app ) ;
21 if (! ArqDados ) {
22 cout << " Erro ao abrir cadastro de alunos " ;
23 exit ( EXIT_FAILURE ) ;
24 } else {
25 ArqDados . clear () ; // Limpa o status de erro
26 ArqDados . seekg (0 , ios :: beg ) ; // Inicio do arquivo
27

28 int NumReg ;
29 cout << " Informe numero do registro procurar : " ;

263
++
Princípios de programação em C

30 cin >> NumReg ; cin . ignore () ;


31

32 ArqDados . seekg ( ( NumReg ) * sizeof ( Ficha ) ) ;


33 ArqDados . read ( ( char *) & Estudante , sizeof ( Ficha ) ) ;
34

35 cout << " Nome .....: " << Estudante . Nome << endl ;
36 cout << " Matricula : " << Estudante . Matricula << endl ;
37 cout << " Nota P1 ..: " << Estudante . NotaP1 << endl ;
38 cout << " Nota P2 ..: " << Estudante . NotaP2 << endl ;
39 cout << " Nota P3 ..: " << Estudante . NotaP3 << endl ;
40 }
41 ArqDados . close () ;
42 return 0;
43 }

Caso o programador tenha interesse, ele pode usar um loop do tipo while() e
percorrer todos os registros de um arquivo, a partir do início. O while() será inter-
rompido apenas quando o ponteiro indicar que o final do arquivo foi alcançado.
A função função ’eof()’ (end of file) é utilizada para verificar se o final do arquivo
foi alcançado. Caso isso ocorra ela retorna true. De modo semelhante, há também
a função ’beg()’ (begin of file), que serve para testar se o início do arquivo foi
alcançado, caso o loop esteja percorrendo o arquivo de baixo para cima, em direção
ao primeiro registro.
1 while ( true ) {
2 ArqDados . read ( ( char *) & Estudante , sizeof ( Ficha ) ) ;
3

4 if ( ArqDados . eof () ) {
5 break ; // Sai do while ()
6 }
7

8 cout << " Nome .....: " << Estudante . Nome << endl ;
9 cout << " Matricula : " << Estudante . Matricula << endl ;
10 cout << " Nota P1 ..: " << Estudante . NotaP1 << endl ;
11 cout << " Nota P2 ..: " << Estudante . NotaP2 << endl ;
12 cout << " Nota P3 ..: " << Estudante . NotaP3 << endl ;
13 cout << endl ;
14 }

O processamento condicional de dados é uma opção interessante ao trabalhar


com informações armazenadas na forma de registros. É possível filtrar os dados
de interesse, e selecionar apenas os registros que atendam a determinados critérios
como, por exemplo, no código a seguir, em que apenas serão exibidos os registros
nos quais a nota da prova 3 (’NotaP3’) seja maior que 60.
1 while ( true ) {
2 ArqDados . read ( ( char *) & Estudante , sizeof ( Ficha ) ) ;

264
++
Princípios de programação em C

4 if ( ArqDados . eof () ) {
5 break ;
6 } else {
7 float P3 = Estudante . NotaP3 ;
8 if ( P3 > 60) { // Condicao !
9 cout << " Nome .....: " << Estudante . Nome << endl ;
10 cout << " Matricula : " << Estudante . Matricula << endl ;
11 cout << " Nota P1 ..: " << Estudante . NotaP1 << endl ;
12 cout << " Nota P2 ..: " << Estudante . NotaP2 << endl ;
13 cout << " Nota P3 ..: " << Estudante . NotaP3 << endl ;
14 cout << endl ;
15 }
16 }
17 }

No C++ não há uma função explícita que permita excluir um registro de um


arquivo de dados. Para excluir um registro são necessários os seguintes passos:

1. Abrir o arquivo de dados principal (ex: ’ArqDados.dat’) em modo leitura.

2. Criar um arquivo de dados auxiliar, apenas para uso temporário (ex: ’dbTemp.tmp’).

3. Fazer um loop que percorra todo o arquivo de dados principal. Dentro desse loop,
todos os registros serão copiados para o arquivo temporário, exceto o registro
a ser excluído.

4. Fechar os arquivos de dados (prinicipal e temporário).

5. Renomear o arquivo de dados principal para algum nome que indique que ele não
será mais utilizado como, por exemplo, ’ArqDados.old’. É recomendado não
excluir de imediato o arquivo de dados principal antes de certificar que todo o
procedimento de cópia foi bem sucedido.

6. Renomear o arquivo de dados temporário de modo que ele fique com o nome do
arquivo de dados principal. Exemplo: ’ArqDados.dat’.

7. Utilizar esse ’novo’ ArqDados.dat, que agora não contém o registro excluído.

O código a seguir mostra como excluir um registro seguindo os passos apresen-


tados acima.
1 # include < iostream > // Biblioteca padrao
2 # include < fstream > // Para acesso a dados
3 # include < cstdlib > // Para funcao : exit (0)
4 using namespace std ;
5

6 struct Ficha {

265
++
Princípios de programação em C

7 int Matricula ;
8 char Nome [31];
9 float NotaP1 , NotaP2 , NotaP3 ;
10 };
11 int main () {
12 Ficha Estudante ;
13

14 // - -[ Arquivo temporario aberto para gravacao ] - - - - - - - - - - - - - - -


15 ofstream ArqTemp ;
16 ArqTemp . open ( " dbTemp . tmp " , ios :: out | ios :: binary ) ;
17

18 if (! ArqTemp ) {
19 cout << " Erro ao criar o arquivo temporario " ;
20 exit ( EXIT_FAILURE ) ;
21 }
22

23 // - -[ Arquivo principal , aberto para leitura ] - - - - - - - - - - - - - - - -


24

25 ifstream ArqDados ;
26 ArqDados . open ( " CadAluno . dat " , ios :: in | ios :: binary ) ;
27

28 if (! ArqDados ) {
29 cout << " Erro ao abrir cadastro de alunos " ;
30 exit ( EXIT_FAILURE ) ;
31 } else {
32 int nMat = 0;
33 cout << " Excluir aluno matricula .: " ;
34 cin >> nMat ;
35 cin . ignore () ;
36

37 ArqDados . clear () ;
38 ArqDados . seekg (0 , ios :: beg ) ;
39

40 while ( true ) {
41 ArqDados . read (( char *) & Estudante , sizeof ( Ficha ) ) ;
42

43 if ( ArqDados . eof () ) {
44 break ;
45 }
46

47 int nMatReg = Estudante . Matricula ;


48

49 if ( nMat != nMatReg ) {
50 ArqTemp . write (( char *) & Estudante , sizeof ( Ficha ) ) ;
51 }
52 }
53 }

266
++
Princípios de programação em C

54

55 ArqDados . close () ;
56 ArqTemp . close () ;
57

58 rename ( " CadAluno . dat " ," CadAluno . old " ) ;


59 rename ( " dbTemp . tmp " ," CadAluno . dat " ) ;
60 remove ( " CadAluno . old " ) ; // Usar com cuidado !
61

62 return 0;
63 }

No código acima, a função ’rename()’ foi utilizada para alterar o nome do ar-
quivo físico pre-existente no computador. A função ’remove()’ foi usada para excluir
fisicamente o arquivo.
É necessário ter um certo cuidado ao utilizar a função remove() visto que ao
excluir um arquivo, este será definitivamente excluído, não sendo possível, de modo
algum, recuperar as informações que haviam nesse arquivo.
Na prática, a exclusão real de um registro nem sempre é desejável, e nem sempre é
feita do modo como foi apresentado aqui. Pode ocorrer que um registro importante
seja excluído por engano de um arquivo de dados. Assim, para evitar esse tipo
de problema, a exclusão de um registro não é feita de verdade. O que se faz é
acrescentar ao registro alguma indicação de estatus, como apresentado na Tabela
12.2.
O último campo desta Tabela serve para indicar o estatus de cada registro. Aque-
les assinalados com a letra ’A’ são registros ’ativos’, ou seja, que não estão marcados
como ’excluídos’. Os registros assinalados com a letra ’E’ são aqueles que estão mar-
cados como ’excluídos’.

Tabela 12.2: Exemplo de indicação de estatus de exclusão ou atividade de um regis-


tro.
Matrícula Nome NotaP1 NotaP2 NotaP3 Status
145 Ana Clara 86.2 68.9 76.4 A
874 José Carlos 92.7 72.6 69.5 E
478 Cláudio Oliveira 82.4 86.8 67.6 A
.. .. .. .. ..
. . . . . A
475 Priscila Silva 89.4 98.6 86.6 E
Fonte: Elaborada pelos autores.

Em geral, trabalha-se apenas com os registros que estejam com o estatus ’A’
(ativos), entretanto essa estratégia de trabalhar com registros marcados com algum
estatus de exclusão pode ser difícil de ser utilizada em programas muito grandes,
com muitos arquivos de dados, exigindo bastante atenção por parte do programador.
Em algumas situações é necessário editar (ou modificar, atualizar) os dados que

267
++
Princípios de programação em C

estejam em um registro de um arquivo de dados. Essa é uma situação bastante


comum. No C++ não há uma função explícita que permita fazer a alteração das
informações contidas em um registro. Assim, deve-se seguir um conjunto de passos
para realizar essa tarefa. Esses passos estão apresentados a seguir.

1. Abrir o arquivo de dados em modo leitura e gravação

2. Localizar o registro cujos dados devem ser alterados

3. Posicionar o ponteiro no início do registro (Registro - 1).

4. Sobrescrever os dados que já estejam no registro com os dados atualizados (novos


dados).

5. Fechar o arquivo de dados para que os dados sejam gravados definitivamente no


arquivo.

A seguir um exemplo que mostra como fazer a edição dos dados de um registro
sobrescrevendo os dados que já se encontram nele.
1 # include < iostream > // Biblioteca padrao
2 # include < fstream > // Para acesso a dados
3 # include < cstdlib > // Para funcao : exit (0)
4 using namespace std ;
5

6 struct Ficha
7 {
8 int Matricula ;
9 char Nome [31];
10 float NotaP1 , NotaP2 , NotaP3 ;
11 };
12

13 int main ()
14 {
15

16 Ficha Estudante ;
17

18 fstream ArqDados ; // Abre para leitura e gravacao


19 ArqDados . open ( " CadAluno . dat " , ios :: out |
20 ios :: in | ios :: binary ) ;
21

22 if (! ArqDados )
23 {
24 cout << " Erro ao abrir cadastro de alunos " ;
25 exit ( EXIT_FAILURE ) ;
26 } else {
27 int nMat = 0;
28 cout << " Procurar por matricula .: " ;

268
++
Princípios de programação em C

29 cin >> nMat ;


30 cin . ignore () ;
31

32 ArqDados . clear () ;
33 ArqDados . seekg (0 , ios :: beg ) ;
34 int nReg = 0; // Para identificar o num do registro ;
35

36 while ( true ) {
37 ArqDados . read (( char *) & Estudante , sizeof ( Ficha ) ) ;
38

39 if ( ArqDados . eof () ) {
40 break ;
41 }
42

43 int nMatReg = Estudante . Matricula ;


44 nReg ++;
45

46 if ( nMat == nMatReg ) {
47 break ;
48 }
49 }
50

51 // - -[ Vai para o registro e sobrescreve seus dados ] - - - - - - - - - -


52

53 ArqDados . clear () ;
54 ArqDados . seekg (0 , ios :: beg ) ;
55

56 cout << endl << endl ;


57 cout << " Nome .....: " ; cin . getline ( Estudante . Nome , 30) ;
58 cout << " Matricula : " ; cin >> Estudante . Matricula ;
59 cout << " Nota P1 ..: " ; cin >> Estudante . NotaP1 ;
60 cout << " Nota P2 ..: " ; cin >> Estudante . NotaP2 ;
61 cout << " Nota P3 ..: " ; cin >> Estudante . NotaP3 ;
62 cout << endl ;
63

64 ArqDados . seekg ( ( nReg - 1) * sizeof ( Ficha ) ) ;


65 ArqDados . write ( ( char *) & Estudante , sizeof ( Ficha ) ) ;
66

67 if ( ArqDados . fail () ) { // Testa se a gravacao foi OK .


68 cout << " Erro ao fazer a gravacao . " << endl ;
69 ArqDados . clear () ;
70 } else {
71 cout << " Atualizacao com sucesso . " << endl ;
72 }
73 }
74 ArqDados . close () ;
75 return 0;

269
++
Princípios de programação em C

76 }

Um loop while() pode ser utilizado para listar na tela todos os registros do arquivo
de dados, como mostrado a seguir.
1 # include < iostream > // Biblioteca padrao
2 # include < fstream > // Para acesso a dados
3 # include < cstring > // Para funcao : strcpy ()
4 # include < cstdlib > // Para funcao : exit (0)
5 # include < iomanip > // Para funcao setw ()
6 using namespace std ;
7

8 struct Ficha {
9 int Matricula ;
10 char Nome [31];
11 float NotaP1 , NotaP2 , NotaP3 ;
12 };
13

14 int main ()
15 {
16

17 Ficha Estudante ;
18

19 ifstream ArqDados ;
20 ArqDados . open ( " CadAluno . dat " , ios :: in | ios :: binary ) ;
21

22 if (! ArqDados )
23 {
24 cout << " Erro ao abrir cadastro de alunos " ;
25 exit (0) ;
26 } else {
27 cout << " Nome " << ’\ t ’ << ’\ t ’ << ’\ t ’ << ’\ t ’ <<
28 " Matric " << ’\ t ’ <<
29 " Prova 1 " << ’\ t ’ <<
30 " Prova 2 " << ’\ t ’ <<
31 " Prova 2 " << endl ;
32

33 while ( true ) {
34 ArqDados . read (( char *) & Estudante , sizeof ( Ficha ) ) ;
35

36 if ( ArqDados . eof () ) {
37 break ;
38 }
39

40 cout << std :: setiosflags ( std :: ios :: left ) ; // Alinha


41 cout << setw (30) << setfill ( ’. ’) ; // na tela
42

43 cout << Estudante . Nome << ’\ t ’;

270
++
Princípios de programação em C

44 cout << Estudante . Matricula << ’\ t ’;


45 cout << Estudante . NotaP1 << ’\ t ’;
46 cout << Estudante . NotaP2 << ’\ t ’;
47 cout << Estudante . NotaP3 << endl ;
48 }
49 }
50 ArqDados . close () ;
51 return 0;
52 }

12.7 Sistemas de Gestão de Bases de Dados, SGBD


Os exemplos discutidos neste capítulo apresentam isoladamente alguns recursos de
acesso a dados. Abertura e fechamento de arquivos, localização, seleção, alteração,
listagem e exclusão de registros são, em geral, funcionalidades que constituem e
fazem parte de um mesmo programa e, na prática, não são tratados de modo isolado,
como feito aqui.
Programas para cadastro de fornecedores, clientes e lotes de produtos acaba-
dos, entre outros, operam simultaneamente com muitos arquivos de dados. Com
o aumento da complexidade do fluxo de informações armazenadas nos arquivos de
dados, muitas vezes operando em ambientes multiusuários (conectados em rede), é
necessária a utilização de ferramentas específicas, capazes de auxiliar o programador
na tarefa de gerenciamento, controle e segurança das informações.
Entre essas ferramentas estão os Sistemas de Gestão de Bases de Dados (SGBD),
que são softwares que se encarregam de todo o gerenciamento de acesso mono ou
multiusuário (senhas para acesso), segurança (backup), integridade, tolerância a
falhas, compartilhamento, etc. Entre os mais comuns estão: Oracle, MySQL, Mi-
crosoft SQL Server, MongoDB, PostgreSQL, SQLite, e vários outros.
Atualmente há uma tendência para a utilização de SGDB que permitam a mo-
delagem e construção de bancos de dados em um formato não tabular, diferente
do formato tabular apresentado na Tabela 12.1, p.259, caracterizando um formato
multirrelacional e multidimensional.
O MUMPS, por exemplo, é um sistema completo de gerenciamento de banco de
dados, que pode ser utilizado para armazenar dados de programas C++ e de outras
linguagens de programação. Esse SGBD não armazena informações em formato
tabular, e sim em estruturas multidimensionais denominadas ’Globais’, caracterizadas
por serem estruturas compactas e de altíssima eficiência, desempenho, segurança e
velocidade, para todas as tarefas de inclusão de dados, exclusão, consultas, etc.
O MUMPS foi criado na década de 60, voltado principalmente para aplicações
na área hospitalar, mas é bastante utilizado nos dias atuais por empresas de grande
porte, que necessitam gerenciar diariamente grandes volumes de dados. O Caché,
versão do MUMPS comercializada pela Intersystems (INTERSYSTEMS CORPO-

271
++
Princípios de programação em C

RATION, 2020a), é o SGBD utilizado pelo Departamento de Assuntos de Veteranos


dos Estados Unidos, Agência Espacial Européia, Forças Armadas dos Estados Unidos,
Roche Diagnostics, Johns Hopkins Hospital (EUA), Volvo, Siemens, Kimberly-Clark,
GE Healthcare, Klabin, 3M Health Information System, Tribunal de Justiça do Dis-
trito Federal (Brasil), Petrobrás (Brasil), Rede Globo de Televisão (Brasil), entre
outros (INTERSYSTEMS CORPORATION, 2020b).

12.8 Arquivos para plotagem de funções matemáticas


Em muitas situações é necessário plotar o gráfico de uma função matemática a
partir dos dados gerados por um programa C++ e, para isso, há inúmeras bibliotecas
gratuitas que podem ser facilmente adicionadas ao programa.
O que o exemplo apresentado a seguir faz é apenas gerar um arquivo ASCII
externo, com a extensão .txt, contendo dados coordenados da função y (x) = sen(x),
em radianos, dispostos em duas colunas, x e y , de modo que possam ser plotados
em algum software externo previamente instalado no computador.
Neste exemplo é considerado que o pacote matemático livre Gnuplot 1 esteja
devidamente instalado no computador e o programa C++ irá executá-lo por meio do
commando ’system()’, previamente abordado no Capítulo 8, p.163.
1 # include < iostream >
2 # include < stdlib .h >
3 # include < fstream >
4 # include < cmath >
5 using namespace std ;
6 int main () {
7 fstream out ;
8 out . open ( " Grafico . txt " , ios :: out | ios :: trunc ) ;
9 for ( float i =0; i <=60; i = i +0.001) {
10 out << i << " \ t " << sin ( i ) << endl ;
11 }
12 out . close () ;
13 system ( " gnuplot -p -e \" plot ’ Grafico . txt ’ with lines \" " ) ;
14 return 0;
15 }

1
Disponível para download em: http://www.gnuplot.info/

272
++
Princípios de programação em C

Figura 12.2: Plotagem dos dados de y (x) = sen(x) utilizando o pacote matemático
Gnuplot. (Fonte: autores)

Nas linhas 7 e 8 do exemplo anterior é criado um arquivo externo com o nome


’Grafico.txt’. Dentro do laço for(), entre as linhas 9 e 11, são gerados os valores de
x e y (x) = sen(x), na faixa que vai de 0 a 60, com incrementos de 0,001 unidades.
O comando close() na linha 12 fecha o arquivo de dados após a gravação de todos
os valores numéricos em seu interior, e o comando system() executa o programa
externo, o Gnuplot, passando a ele, como argumento, o nome do arquivo externo
com os dados a serem plotados, obtendo os resultados apresentados na Figura 12.2.

12.9 Atividades para fixação da aprendizagem


1. Escreva um programa para armazenar os dados de contatos dos clientes da
Empresa Junior de Engenharia de Alimentos. O programa deverá permitir a
inclusão, exclusão, alteração e consulta nos arquivos de dados. Inclua informa-
ções importantes como nome, endereço, contato, etc. Cada cliente deverá ser
identificado por um código único de identificação como, por exemplo, o CNPJ
da empresa. Os dados deverão estar organizados em structs, e o programa
deverá ter alguns modos de localização/busca dos clientes cadastrados:

(a) Busca pelo código único de identificação (CPF ou CNPJ) do cliente


(b) Busca pelo nome do cliente

273
++
Princípios de programação em C

(c) Lista todos os clientes atendidos em uma determinada data


(d) Lista todos os clientes atendidos por um determinado membro da Empresa
Júnior

Ao localizar os dados de um cliente, todas as suas informações deverão ser


prontamente exibidas na tela.

2. Modifique o programa acima, de modo que ele possa também armazenar dados
de prestação de serviços. Entre os dados que podem ser armazenados, estão:

(a) Descrição do serviço


(b) Data de início da prestação de serviço
(c) Data de conclusão da prestação de serviço
(d) Nome do membro responsável pela prestação do serviço
(e) Nome do(a) estagiário(a) de apoio à prestação do serviço
(f) Nome do(a) professor(a) orientadora
(g) Número total de parcelas de pagamento
(h) Valor da parcela de pagamento
(i) Custo total do serviço

3. Modifique o programa acima, de modo que ele possa também armazenar dados
de materiais que tenham sido utilizados nas prestações de serviços:

(a) Código do material


(b) Descrição do material utilizado
(c) Quantidade utilizada
(d) Preço por unidade
(e) Preço total
(f) Data da utilização
(g) Nome quem autorizou a utilização do material

Para cada cliente poderá ser utilizado diferentes tipos e quantidades de mate-
riais. O programa deverá ter uma opção para listar na tela todos os materiais
que foram utilizados para um determinado cliente, as quantidades utilizadas,
preços e as datas de utilização.

4. Utilizando o Gnuplot, faça um programa C++ que plote os gráficos das seguin-
tes funções:
w
• p(w ) = 1, 544w 2 × , w ∈ [0, 60]
(5, 666 + w )2

274
++
Princípios de programação em C

• q(w ) = sen(w ), w ∈ [−10, 10]


• r (w ) = atan(w ), w ∈ [−10, 10]
• s(w ) = cos(atan(w )), w ∈ [−10, 10]

5. Segundo a Organização Mundial de Saúde (OMS) a covid-19 é o nome de


uma doença respiratória causada por um tipo de coronavirus. Para estudar
a evolução dos casos de contaminação e o espalhamento dessa doença os
epidemiologistas utilizam modelos matemáticos, sendo que o mais famoso deles
é o modelo S-I-R. Esse modelo está descrito pelas Equações 12.1 a 12.3.

dS I
= −β S (12.1)
dt N

dI I
= β S − γI (12.2)
dt N

dR
= γI (12.3)
dt

No modelo S-I-R:

• S representa o número de indivíduos saudáveis, mas que estão susceptí-


veis à contaminação pelo coronavírus.
• I representa o número de indivíduos efetivamente infectados e que podem
transmitir a doença a outras pessoas da população.
• R representa o número de indivíduos que foram contaminados, mas que
se recuperaram da doença.
• N é o tamanho total da população, em quantidade de indivíduos.
• β é a ’constante de transmissão da doença’, um parâmetro do modelo
(uma constante) que é calculado a partir de informações epidemiológicas
observadas na população.
• γ é a ’constante de recuperação’, uma outra constante do modelo, tam-
bém calculada a partir de informações epidemiológicas observadas na po-
pulação. Em termos numéricos, γ corresponde ao inverso do período
médio de infecção (1/tinfecção ).

As equações do modelo S-I-R podem ser discretizadas no tempo para serem


utilizadas por algum método numérico. Neste exercício a discretização das
Equações 12.1 a 12.3 é feita pelo Método de Euler (RUGGIERO e LOPES
(1996)), e produzem as Equações 12.4 a 12.6 apresentadas a seguir.

275
++
Princípios de programação em C

  
In
Sn+1 = −β Sn × ∆t + Sn (12.4)
N
  
In
In+1 = β Sn − γIn × ∆t + In (12.5)
N

Rn+1 = [(γIn ) × ∆t] + Rn (12.6)

Nas Equações 12.4 a 12.6:

• Sn é o valor de S no instante de tempo atual.


• Sn+1 é o valor de S no próximo instante de tempo (t + ∆t).
• In é o valor de I no instante de tempo atual.
• In+1 é o valor de I no próximo instante de tempo (t + ∆t).
• Rn é o valor de R no instante de tempo atual.
• Rn+1 é o valor de R no próximo instante de tempo (t + ∆t).
• ∆t é o incremento de tempo utilizado na geração dos dados epidemioló-
gicos a partir do modelo S-I-R.

Construa um programa que gere um arquivo externo contendo os dados para


a plotagem das curvas S(t), I(t) e R(t) no Microsoft Excel. O programa
deve ser feito com base nas Equações 12.4 a 12.6. No programa, considere
os seguintes valores fornecidos pelos epidemiologistas: β = 1, 75, γ = 0, 5. O
tamanho da população da cidade é N = 100.000 habitantes, e inicialmente há
apenas dois indivíduos contaminados na população (In = 2, quando t = 0).
Considere também que inicialmente o número de indivíduos susceptíveis é igual
ao tamanho da população (Sn = N, quando t = 0), que em t = 0 o número
de indivíduos recuperados é zero (Rn = 0, quando t = 0). O tempo total de
análise dos dados será de 30 dias, com incrementos ∆t = 0.001 dia.
O arquivo externo gerado pelo programa deverá conter cinco colunas: t, S(t),
I(t), R(t) e CapSUS (uma constante, que define a capacidade máxima de
atendimentos diários que podem ser realizados pelo SUS naquela cidade).
O arquivo externo de dados será importado e analisado no Microsoft Excel.
Plote o gráfico das variáveis nesse arquivo e analise os seguintes cenários:

• Cenário 1: Considere um cenário hipotético em que as pessoas da po-


pulação estejam em casa, efetivamente cumprindo o ’isolamento social’
(quarentena) recomendado pelo Ministério da Saúde. Nessa situação foi
verificado que a ’constante de transmissão da doença’ é relativamente
pequena (altere o valor para β = 1, 08 no programa). Sabendo que a
capacidade de atendimento da população pelo sistema público de saúde é
de no máximo 22.500 pessoas por dia nesta cidade, responda:

276
++
Princípios de programação em C

– O SUS dará conta de atender simultaneamente a todos os infectados?


Em algum momento haverá sobrecarga de atendimentos no sistema
público de saúde? Se sim, a partir de quanto tempo, desde o início
da epidemia, será observado o colapso no sistema público de saúde?
– Qual o número máximo de pessoas infectadas pela doença?
– A partir do início da epidemia, quando irá ocorrer o ’pico’ máximo de
contaminação?
• Cenário 2: Agora considere um outro cenário hipotético, no qual as pes-
soas da população não tenham cumprido o ’isolamento social’ (quaren-
tena). Nessa situação os agentes públicos de saúde constataram que há
maior disseminação da doença entre as pessoas e que a ’constante de
transmissão da doença’ é relativamente maior, β = 3, 25. Mantendo-se
a mesma capacidade de atendimento da população pelo sistema público
de saúde nessa cidade (22.500 atendimentos por dia), responda:
– O SUS dará conta de atender simultaneamente a todos os infectados?
Em algum momento haverá sobrecarga de atendimentos no sistema
público de saúde? Se sim, a partir de quanto tempo, desde o início
da epidemia, será observado o colapso no sistema público de saúde?
– Qual o número máximo de pessoas infectadas pela doença?
– A partir do início da epidemia, quando irá ocorrer o ’pico’ máximo de
contaminação?
– Baseando-se unicamente nas informações geradas pelo modelo ma-
temático, compare os cenários ’com’ e ’sem’ o isolamento social e
responda: O ’isolamento social’ é, ou não, uma boa alternativa para
evitar a sobrecarga do sistema público de saúde e garantir o atendi-
mento a todas as pessoas infectadas? Justifique sua resposta.

6. A Empresa Júnior de Engenharia de Alimentos decidiu montar um cadastro


com informações de empresas cedentes de estágios, com a finalidade de auxi-
liar aos alunos formandos e egressos do curso de Engenharia de Alimentos a
conseguirem um posicionamento no mercado de trabalho.
Na Figura 12.3 está apresentado o diagrama esquemático da estrutura (regis-
tro) que servirá para armazenar as informações de cada empresa no arquivo de
dados.
Escreva o programa que atenda aos interesses da Empresa Junior, lembrando
de acrescentar funcionalidades como inclusão, exclusão, alteração e consulta
dos dados armazenados. O programa ainda deverá possuir um menu de opções
específico para fazer as seguintes consultas personalizadas ao arquivo de dados:

1 - Busca pelo nome da empresa.


2 - Busca pelo CNPJ da empresa.

277
++
Princípios de programação em C

3 - Listar todas as empresas de uma determinada cidade e, logo na frente do


nome da empresa apresentar também o nome do funcionário para contato,
o seu e-mail e o seu número de Whatsapp.
4 - Listar todas as empresas com a vigência do cadastro ’em aberto’, ou
seja, as empresas que neste momento estão oferecendo estágios aos es-
tudantes.
5 - Listar todas as empresas que estarão oferecendo estágios entre os meses
M1 e M2 de um determinado ano, sendo que M1 e M2 correspondem aos
números dos meses, que deverão ser informados pelo usuário do programa
(exemplo: jan = 1, fev = 2, mar = 3, ...)
6 - Listar apenas as empresas em que oferecem transporte, alimentação e
moradia. (obs: ao escrever o programa, uma boa opção é declarar todas
as variáveis referentes aos ’benefícios’ como sendo do tipo booleanas).
7 - Listar na tela os pré-requisitos que uma empresa exige para oferecer
estágio para um estudante. A busca deve ser feita pelo CNPJ da em-
presa. (obs: ao escrever o programa, declare a variável referente ao
’pré-requisito’ como sendo do tipo char[60]).

278
++
Princípios de programação em C

Empresa

CNPJ Nome

Nome da Empresa Setor

Funcionário p/ contato Cargo

Homepage Telefone fixo

Endereço Cidade e-mail Dia

Bairro Whatsapp Mês

Rua Data início Ano

Núm.
Dia
CEP
Mês
Vigência no cadastro Data final
Ano

Cód. convênio Transporte


Dia
Moradia
Inscrição anual Mês
Alimentação
Ano
Pré-requisitos Plano de saúde
Duração
Remuneração
Benefícios
Contratação

Figura 12.3: Representação gráfica da estrutura utilizada para armazenamento de


dados de contato com empresas concedentes de estágio aos estudantes de Engenha-
ria de Alimentos. (Fonte: autores)

279
Capítulo 13

Arquivos de cabeçalho: segmentação


do código em arquivos .h e .cpp

Conteúdo do capítulo
13.1 Subdivisão do código em arquivos .h e .cpp . . . . . . . . 280
13.1.1 Alguns comentários sobre arquivos de cabeçalho . . . . . . 285
13.2 Subdivisão de arquivos de cabeçalho com namespaces . 286
13.2.1 Arquivo de cabeçalho MinhasFuncoes.h . . . . . . . . . 287
13.2.2 Arquivo de implementações MinhasFuncoes.cpp . . . . 287
13.3 Atividades para fixação da aprendizagem . . . . . . . . . 289

13.1 Subdivisão do código em arquivos .h e .cpp


Por meio dos exemplos apresentados nos capítulos anteriores foi possível verificar
que as funcionalidades de um programa podem ser muito ampliadas pela inclusão de
bibliotecas externas, por meio da diretiva ’#include’.
As funções matemáticas descritas no Capítulo 7 são um bom exemplo disso. Elas
foram incluídas no código por meio da biblioteca cmath. Mas afinal, o que tem no
interior dessa biblioteca cmath?
A cmath, como qualquer outra biblioteca para cálculos matemáticos, possui um
conjunto de constantes, macros e funções, que podem ser incluídas e utilizadas
normalmente dentro do código principal de um programa.
Nesse aspecto, duas grandes vantagens podem ser observadas. A primeira delas
consiste em manter todas as funções em um arquivo separado, o que evita sobrecar-
regar o programa principal com linhas e mais linhas de código de programação.
A segunda vantagem está na capacidade de reutilização do código. Assim, por
exemplo, ao criar uma função que calcula o volume de um cilindro reto, em função
do raio de sua base e de sua altura, essa função poderá ser colocada em um arquivo

280
++
Princípios de programação em C

externo, e esse arquivo ser utilizado para a elaboração de diferentes programas, sem
a necessidade de reescrever essa função a cada novo programa.
Dessa forma, o programador poderá construir suas próprias bibliotecas de funções,
procedimentos, constantes e macros e utilizá-las sempre que necessário, diminuindo
sobremaneira a quantidade de trabalho, esforço e tempo ao construir diferentes pro-
gramas.
No Capítulo 4, p.80, foi mostrado como incluir um arquivo externo de macros
ao corpo do programa principal por meio da diretiva ’#include’. O mesmo será
feito aqui neste Capítulo 13, porém, além de constantes e macros, será mostrado
também como declarar e utilizar funções a partir de um arquivo externo.
Para uma abordagem mais prática de como montar uma biblioteca de funções,
as seguintes funções serão utilizadas:

1. Uma função que calcula a soma de dois valores numéricos do tipo float: x e
y:
1 float Soma ( float x , float y ) {
2 float Resp = 0.00;
3 Resp = ( x + y ) ;
4 return ( Resp ) ;
5 }

2. Uma função que calcula a média de dois valores numéricos do tipo float: x e
y.
1 float Media ( float x , float y ) {
2 float Resp = 0.00;
3 Resp = ( ( x + y ) / 2.00 ) ;
4 return ( Resp ) ;
5 }

3. Uma função que retorna o maior entre dois valores numéricos do tipo float:
x e y.
1 float Maior ( float x , float y ) {
2 float Resp = 0.00;
3

4 if ( x > y ) {
5 Resp = x ;
6 } else if ( y > x ) {
7 Resp = y ;
8 } else if ( x = y ) {
9 Resp = 0;
10 }
11 return ( Resp ) ;
12 }

281
++
Princípios de programação em C

A construção de um arquivo externo é subdividida em duas partes. Na realidade


não se trata de criar um único arquivo, mas sim, dois arquivos:

a) Um arquivo com a extensão .h, que contém apenas os protótipos das funções.
Em geral, esse arquivo é denominado arquivo de interface para as funções. A
extensão .h vem de ’cabeçalho’ em inglês (’header’).

b) Um arquivo com a extensão .cpp, que contém as funções implementadas propri-


amente ditas.

• Passo 1: O primeiro passo, portanto, consiste em criar o arquivo ’Minhas-


Funcoes.h’ e colocar nesse arquivo apenas os protótipos das funções, como
mostrado nas linhas 6,7 e 8 da Figura 13.1.

Figura 13.1: Exemplo de arquivo externo de interface (protótipo) de funções. (Fonte:


autores)

Na Figura 13.1, as linhas 1 e 2, bem como a linha 10, devem ser obrigato-
riamente incluídas, e em maiúsculo. Essas linhas são geralmente chamadas
de ’include guard’, ’macro guard’ ou ’header guard’. Elas tem a função de
informar ao compilador que o arquivo de cabeçalho ’MinhasFuncoes.h’ já foi
incluído no programa principal. Caso esse arquivo de cabeçalho seja incluído
novamente no programa, isso irá gerar um erro de compilação.
O problema da dupla inclusão fica mais evidente ao observar a Figura 13.3,
que mostra que a biblioteca ’MinhasFuncoes.h’ foi incluída diretamente no
programa principal (por meio de ’MinhasFuncoes.h’ na linha 2) e também na
Figura 13.2, que mostra que ’MinhasFuncoes.h’ foi incluída indiretamente no
programa principal por meio do arquivo ’MinhasFuncoes.cpp’, o que caracteriza
uma dupla inclusão. Assim, o ’header guard’ tem a função de informar essa
dupla inclusão para o compilador, evitando o erro de compilação.
A primeira inclusão de ’MinhasFuncoes.h’ no programa principal faz com que a
macro MINHASFUNCOES_H_INCLUDED seja definida (Figura 13.1). Em seguida,

282
++
Princípios de programação em C

quando o arquivo ’MinhasFuncoes.cpp’ inclui pela segunda vez ’MinhasFun-


coes.h’, então o teste condicional #ifndef retornará falso, e o pré-processador
do compilador irá saltar todo o bloco de códigos, até a instrução #endif,
evitando, assim, que as funções sejam novamente declaradas no código, e o
programa será compilado corretamente (WIKIPÉDIA, 2017).

• Passo 2: O próximo passo consiste em criar um arquivo de implementação das


funções (Figura 13.2). Esse arquivo tem a extensão .cpp e deve ser colocado na
mesma pasta onde está o programa principal. Na primeira linha desse arquivo
deverá estar a diretiva ’#include’ para interface ’MinhasFuncoes.h’.

Figura 13.2: Exemplo da estrutura típica de um arquivo de implementação de funções


externas. (Fonte: autores)

• Passo 3: Este passo consiste em efetivamente utilizar as funções dentro do


programa principal, como mostrado na Figura 13.3.
Para fazer isso deve-se utilizar a diretiva #include "MinhasFuncoes.h" para
ter acesso às funções presentes na biblioteca. No exemplo da Figura 13.3, a
função ’Media()’ é utilizada na linha 7 para calcular a média de dois valores
numéricos.

283
++
Princípios de programação em C

Figura 13.3: Exemplo da utilização de bibliotecas personalizadas por meio de arquivos


de cabeçalho. (Fonte: autores)

O exemplo apresentado na Figura 13.3 mostra que segmentar o código em arqui-


vos de cabeçalho (arquivos .h) pode ser uma excelente opção para o programador.
Como observado, o programa apresentado nesta Figura se tornou relativamente pe-
queno, visto que as funções que estariam nele foram colocadas em um arquivo ex-
terno.
Assim o código se torna mais bem organizado e pode ser mais facilmente com-
preendido e documentado. O programador também poderá incluir no arquivo .h as
macros e constantes de seu interesse. A Figura 13.4 mostra como isso pode ser
feito.

Figura 13.4: Exemplo de inserção de macros e constantes dentro de um arquivo de


cabeçalho. (Fonte: autores)

A Figura 13.5 mostra como utilizar dentro do programa principal as constantes,


macros e funções definidas em um arquivo de cabeçalho.

284
++
Princípios de programação em C

Figura 13.5: Exemplo de utilização de macros e constantes a partir de um arquivo


de cabeçalho. (Fonte: autores)

13.1.1 Alguns comentários sobre arquivos de cabeçalho


• Em um mesmo programa poderão ser inseridas diferentes bibliotecas externas
de funções como, por exemplo, bibliotecas de funções estatísticas, de cálculos
físico-químicos, etc.

• Um arquivo de cabeçalho poderá fazer referências e incluir funcionalidades con-


tidas em outros arquivos de cabeçalhos.

• No Capítulo 4, p.81, foi apresentado um recurso interno do Code::Blocks para


auxiliar na criação de arquivos de cabeçalho, com inserção automática de ’he-
ader guard’ no código.

• Os nomes das macros nos header guards são definidos pelo programador.

• Além de macros, constantes e funções, os arquivos de cabeçalho também po-


dem conter estruturas (structs), bem como implementar códigos aplicando
outros recursos da linguagem C++ , não abordados aqui neste livro como, por
exemplo, classes, herança, polimorfismo, funções da STL (Standard Template
Library ), etc.

• Funções inline, ponteiros e sobrecarga de funções podem ser utilizados nor-


malmente dentro de arquivos de cabeçalho.

• Eventualmente pode ocorrer de o Code::Blocks não reconhecer, ou não conse-


guir localizar as funções contidas em um arquivo de cabeçalho. Se os arquivos
.h e .cpp foram criados corretamente, então uma forma de resolver o problema
consiste em informar para o Code::Blocks que os arquivos de cabeçalho fazem
parte do projeto atual. Isso é feito adicionando os arquivos .h e .cpp no projeto
atual, como mostrado na Figura 13.6.

285
++
Princípios de programação em C

Figura 13.6: Procedimento para inclusão dos arquivos .h e .cpp em um projeto do


Code::Blocks. (Fonte: autores)

13.2 Subdivisão de arquivos de cabeçalho com na-


mespaces
Os arquivos de cabeçalho podem ser melhor organizados internamente por meio de
seções chamadas de ’namespaces’. Para compreender melhor esse tipo de organiza-
ção, considere um programa que possua um arquivo de cabeçalho com três funções,
sendo que duas delas são funções para cálculos estatísticos, e a outra é uma função
para cálculo do ’valor futuro’ (FV) de um capital aplicado a uma taxa de juros i , por
n períodos de capitalização sendo, portanto, uma função para fins econômicos.
Para uma melhor organização, o arquivo de cabeçalho contendo essas funções
pode ser subdividido em duas seções:

1. A primeira seção: contém apenas as funções para cálculos estatísticos.

2. A segunda seção: contém apenas a função para cálculos de economia.

A reorganização das funções em seções dentro de um arquivo de cabeçalho é


feita com o comando ’namespace’, que tem a sintaxe apresentada a seguir:
namespace Calculos_Estatísticos{
...funções aqui;
}
namespace Calculos_Economia{
...funções aqui;
}

286
++
Princípios de programação em C

As seções definidas pelos namespaces devem ser colocadas tanto no arquivo .h


quanto no arquivo .cpp.
A seguir é apresentado um exemplo no qual o arquivo de cabeçalho (.h) e o
arquivo de implementação das funções (.cpp) estão subdividido em duas seções,
uma contendo apenas as funções estatísticas e outra contendo apenas a função para
cálculo econômico.

13.2.1 Arquivo de cabeçalho MinhasFuncoes.h


1 # ifndef M I N H A S F U N C O E S _ H _ I N C L U D E D
2 # define M I N H A S F U N C O E S _ H _ I N C L U D E D
3

4 namespace CalcEstat // Funcoes para calculos estatisticos ;


5 {
6 float Soma ( float x , float y ) ;
7 float Media ( float x , float y ) ;
8 }
9 namespace CalcEcon // Funcoes para calculos de economia ;
10 {
11 double ValorFuturo ( double PV , double i , int n ) ;
12 }
13

14 # endif // M I N H A S F U N C O E S _ H _ I N C L U D E D

13.2.2 Arquivo de implementações MinhasFuncoes.cpp


1 # include " MinhasFuncoes . h "
2 # include < cmath > // Necessario para uso de pow () ;
3

4 namespace CalcEstat
5 {
6 float Soma ( float x , float y )
7 {
8 float Resp = 0.00;
9 Resp = ( x + y ) ;
10 return ( Resp ) ;
11 }
12

13 float Media ( float x , float y )


14 {
15 float Resp = 0.00;
16 Resp = ( ( x + y ) / 2.00 ) ;
17 return ( Resp ) ;
18 }
19 }

287
++
Princípios de programação em C

20

21 namespace CalcEcon
22 {
23 double ValorFuturo ( double PV , double i , int n )
24 {
25 double FV = 0.00;
26 FV = PV * pow ( ( 1.00 +( i / 100.00) ) , n ) ;
27 return ( FV ) ;
28 }
29 }

A chamada às funções do arquivo de cabeçalho dentro do programa principal


pode ser feita de duas formas.

1. Na forma como apresentado a seguir, é feita uma declaração explícita das


seções (namespaces) contidas no arquivo de cabeçalho (linhas 5 e 6).
1 # include < iostream >
2 # include " MinhasFuncoes . h "
3

4 using namespace std ;


5 using namespace CalcEcon ;
6 using namespace CalcEstat ;
7

8 int main () {
9 cout << Soma (3 , 4) << endl ;
10 cout << ValorFuturo (1000 , 0.5 , 12) << endl ;
11 return 0;
12 }

2. A segunda forma consiste em utilizar o ’operador de resolução de escopo’ (’::’),


mas sem declarar explicitamente as namespaces.
1 # include < iostream >
2 # include " MinhasFuncoes . h "
3

4 using namespace std ;


5

6 int main ()
7 {
8 cout << CalcEstat :: Soma (3 , 4) << endl ;
9 cout << CalcEcon :: ValorFuturo (1000 , 0.5 , 12) << endl ;
10 return 0;
11 }

288
++
Princípios de programação em C

13.3 Atividades para fixação da aprendizagem


1. Escreva uma biblioteca de funções para auxílio nos cálculos de análise de viabi-
lidade econômica de projetos agroindustriais. A biblioteca deve ser composta
pelas 6 (seis) equações (Eq. 8.11) apresentadas na página 170 do Capítulo 8.
Todas as funções retornam valores do tipo double, sendo que algumas estão
sobrecarregadas, visto que possuem o mesmo nome.
Os arquivos .h e .cpp que compõem a biblioteca devem ser colocados na
mesma pasta em que estiver o programa principal e adicionados do projeto
do Code::Blocks;

2. Escreva uma biblioteca que contenha funções para o cálculo das estatísticas
descritivas básicas listadas a seguir. As funções terão como parâmetro de
entrada um ou dois vetores, com elementos do tipo double.

(a) Média dos elementos do vetor.


(b) Variância (Eq. 9.8, p.193) e desvio-padrão (Eq. 9.9, p.193).
(c) Contagem do número total de elementos no vetor
(d) Contagem de número de elementos com valores abaixo da média
(e) Contagem de número de elementos com valores acima da média
(f) Amplitude (maior valor menos o menor valor)
(g) Soma de todos os elementos do vetor: (X)
P

(h) Soma quadrática de todos os elementos do vetor:


P 2
(X )
(i) SomaPdo produto de todos os elementos de dois vetores de mesmo tama-
nho: (XY )
(j) Coeficiente de variação percentual:

desvio-padrão
   
σ̂
CV% = × 100 = × 100
média µ̂

3. Escreva uma biblioteca que contenha funções de conversão de unidades de


pressão. As funções terão como entrada um único valor numérico do tipo
’double’, e retornarão um único valor numérico do tipo ’double’. Algumas das
conversões que podem ser implementadas na biblioteca estão listadas a seguir
(GEANKOPLIS (1993)):

(a) 1 bar = 1 × 105 P a = 1 × 105 N/m2


(b) 1 psi a = 1 lbf /in2
(c) 1 psi a = 2, 0360 in.Hg (na temperatura T = 0 graus Celsius)
(d) 1 psi a = 2, 311 ft H2 O (na temperatura T = 70 graus Fahrenheit)

289
++
Princípios de programação em C

(e) 1 psi a = 51, 715 mm Hg (na temperatura T = 0 graus Celsius)


(f) 1 atm = 14, 969 psi a = 1, 01325 × 105 N/m2 = 1, 01325 bar
(g) 1 atm = 760 mm Hg = 1, 01325 P a (na temperatura T = 0 graus Cel-
sius)
(h) 1 atm = 29, 921 in.Hg (na temperatura T = 0 graus Celsius)
(i) 1 atm = 33, 90 ftH2 O (na temperatura T = 4 graus Celsius)

290
Parte II

PROGRAMAÇÃO APLICADA
Capítulo 14

Módulo 1: Construção de um
programa para cálculo de perda de
carga em válvulas e acessórios de
tubulação

Conteúdo do capítulo
14.1 Referencial teórico da atividade prática . . . . . . . . . . 292
14.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
14.3 Detalhamento e recomendações para a construção do
programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
14.3.1 Passo 1: Cálculo do Número de Reynolds . . . . . . . . . 295
14.3.2 Passo 2: Cálculo da perda de carga total, F . . . . . . 296
P

Esta atividade prática consiste na construção de um programa em C++ para


fazer o cálculo e a contabilidade das perdas de cargas localizadas nos acessórios mais
comuns utilizados em uma tubulação para transporte de fluidos. Na próxima seção
serão apresentadas as principais variáveis necessárias para a construção do programa.

14.1 Referencial teórico da atividade prática


• Número de Reynolds: É um número adimensional que serve para caracterizar
o regime de escoamento no interior de um tubo cilíndrico, fechado e comple-
tamente preenchido. É dado pela Equação 14.1.

ρv D
NRey = (14.1)
µ

292
++
Princípios de programação em C

Na Equação 14.1, ρ é a densidade do fluido, dada em kg/m3 . v é a velocidade


média do escoamento, em m/s. D é o diâmetro interno do tubo, com o
seu valor dado em metro (m). µ é a viscosidade dinâmica do fluido, em
kg/(m × s). A unidade P a × s também é frequentemente utilizada para a
viscosidade dinâmica.
• Perda de carga em expansão abrupta: Se a área da seção de um tubo
aumenta muito suavemente, então a perda de carga nessa região pode ser
desprezada nos cálculos para a maioria das situações práticas. Entretanto, se
um aumento abrupto de área ocorre, então a perda de carga para essa situação
não pode ser desconsiderada. Essa perda de carga é calculada pela Equação
14.2.

2
v12 v12 v12

A1
hex = 1− = (1) = (14.2)
A2 2α 2α 2α

Em que hex é a perda de carga na expansão, em J/kg (ou m2 /s 2 ). v1 é


a velocidade média na seção de menor diâmetro da expansão (na entrada,
ou no interior da expansão), em m/s. α é uma constante que vale 0,5 para
escoamento laminar, e vale 1 (um) para escoamento turbulento. A1 é a área
na entrada da expansão, e A2 é a área na saída da expansão, ambas expressas
em m2 . Em geral, a relação (A1 /A2 ) pode ser considerada igual a zero para a
maioria das aplicações práticas.
• Perda de carga em contração abrupta: Quando a secção transversal de um
tubo é abruptamente reduzida, a perda de carga que ocorre nesse acessório é
calculada pela Equação 14.3.

A2 v22 v2
 
hc = 0, 55 − = (0, 55) 2 (14.3)
A1 2α 2α

Em que hc é a perda de carga na contração, em J/kg (ou m2 /s 2 ). A área


na entrada da contração (A1 ) é, geralmente, muito maior do que a área na
saída da contração (A2 ) e, por isso, a relação (A2 /A1 ) pode ser considerada
igual à zero para a maioria das aplicações práticas. Os valores de A1 e A2 são
expressos em m2 . v2 é a velocidade média na seção de menor diâmetro da
contração (na saída da contração), dada em m/s. α é uma constante que vale
0,5 para escoamento laminar, e vale 1 (um) para escoamento turbulento.
• Perda de carga em válvulas e acessórios: É calculada pela Equação 14.4.

v12
hf = (kf ) (14.4)
2

293
++
Princípios de programação em C

hf é a perda de carga na válvula ou acessório, expressa em J/kg (ou m2 /s 2 ).


kf é um fator adimensional de perda de carga para a válvula ou acessório. Os
valores de kf para escoamento turbulento são dados na Tabela 14.1. Na Tabela
14.2 são dados os valores de kf para o regime de escoamento laminar. v1 é a
velocidade média do fluido no tubo que chega até à válvula ou acessório, em
m/s.

Tabela 14.1: Fator adimensional de perda de carga (kf ) no regime de escoamento


turbulento para válvulas e acessórios de tubulação.
Válvula ou acessório kf
Joelho 45 graus 0,35
Joelho 90 graus 0,75
Tê 1,00
Curva de retorno (180 graus) 1,50
Acoplamento ou união 0,04
Válvula de gaveta (totalmente aberta) 0,17
Válvula de gaveta (meio aberta) 4,50
Válvula globo (totalmente aberta) 6,00
Válvula globo (meio aberta) 9,50
Válvula angular (totalmente aberta) 2,00
Válvula de retenção (bola) 70,00
Válvula de retenção (portinhola) 2,00
Hidrômetro (disco) 7,00
Adaptado de GEANKOPLIS (1993), p.93.

Tabela 14.2: Fator adimensional de perda de carga (kf ) no regime de escoamento


laminar para válvulas e acessórios de tubulação.
Tipo de Número de Reynolds
acessório 50 100 200 400 1000 Turb
Joelho de 90 graus 17,00 7,00 2,50 1,20 0,85 0,75
Tê 9,00 7,80 3,00 2,00 1,40 1,00
Válvula globo 28,00 22,00 17,00 14,00 10,00 6,00
Válvula de retenção (portinhola) 55,00 17,00 9,00 5,80 3,20 2,00
Adaptado de GEANKOPLIS (1993), p.94.

A justificativa para o fato de a perda de carga apresentar duas unidades de medida,


é que essas unidades são equivalentes entre si. Isso pode ser demonstrado a partir
da Equação 14.5, que mostra que a força atuante sobre um corpo é numericamente
igual ao produto da massa pela aceleração ao qual esse corpo está submetido. Mais

294
++
Princípios de programação em C

à direita da Equação, estão expressas as unidades de medida para as grandezas


apresentadas.

m
F~ = m × a~ → N = kg × 2 (14.5)
s
Ao dividir ambos os lados da Equação 14.5 por kg, obtém-se a relação apresen-
tada na Equação 14.6.

N m
= 2 (14.6)
kg s
Multiplicando-se ambos os lados da Equação 14.6 por m, obtém-se a relação
apresentada na Equação 14.7

N ×m m2
= 2 (14.7)
kg s
Na Equação 14.7, o numerador da fração à esquerda do sinal de igual tem unidade
de energia, ’Joules’ (J = N × m), e esta equação pode ser reescrita como mostrado
na Equação 14.8.

J m2
= 2, (equivalência das unidades de medida para a perda de carga.) (14.8)
kg s

14.2 Objetivos
• O programa deverá solicitar ao usuário que informe todos os acessórios pre-
sentes na tubulação, suas respectivas quantidades e tipos.

• Em seguida o programa deverá contabilizar a perda de carga total dos aces-


sórios e fornecer na tela o valor F , em J/kg
P

14.3 Detalhamento e recomendações para a constru-


ção do programa
14.3.1 Passo 1: Cálculo do Número de Reynolds
Inicialmente os valores de ρ, v , D e µ deverão ser solicitados ao usuário do pro-
grama. Após digitados, esses valores serão usados para calcular o Número de Rey-
nolds (NRey ). A partir de NRey a constante α poderá ser calculada, e seu valor será
α = 0, 5, para regime de escoamento laminar, e α = 1, para regime de escoamento
turbulento.

295
++
Princípios de programação em C
P
14.3.2 Passo 2: Cálculo da perda de carga total, F
O programa deverá solicitar ao usuário que informe todos os acessórios presentes
na tubulação, bem como as quantidades de cada um. Após entrar com todas essas
informações, o programa deverá apresentar na tela um relatório semelhante ao que
está apresentado a seguir. O programa deverá também gerar e exportar esse relatório
para um arquivo externo, com o nome PerdaLoc.txt.

===================================================================
CALCULO DA PERDA DE CARGA LOCALIZADA - UFLA - GCA187 - 2020
===================================================================
[Emitido em: 04/11/2019 - 09:22:23]
DADOS DO PROBLEMA:
------------------
>> Densidade......: 998.20 [kg/m^3]
>> Vel. media.....: 1.2 [m/s]
>> Viscosidade....: 1.005e-3 [Pa.s]
>> Numero Reynolds: 90821.30 [Regime: turbulento (alfa = 1.0)]

===================================================================
CONTABILIDADE DA PERDA DE CARGA EM VALVULAS E ACESSORIOS
===================================================================
ID Descricao Qtd F unitario [J/kg] F parcial [J/kg]
-------------------------------------------------------------------
01 Contracao 1 0.396 0.396
02 Expansao 1 0.720 0.720
03 Joelho 6 0.540 3.240
04 Valvula globo 8 4.320 34.560
05 Valvula retencao 4 1.440 5.760
-------------------------------------------------------------------
PERDA DE CARGA TOTAL [J/kg].................: 44.676
===================================================================

296
Capítulo 15

Módulo 2: Construção de um
programa para cálculo da perda de
carga em tubos retos

Conteúdo do capítulo
15.1 Referencial teórico da atividade prática . . . . . . . . . . 297
15.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
15.3 Detalhamento e recomendações para a construção do
programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
15.3.1 Passo 1: Cálculo do número de Reynolds . . . . . . . . . . 298
15.3.2 Passo 2: Cálculo da rugosidade relativa . . . . . . . . . . 298
15.3.3 Passo 3: Cálculo do valor de f , fator de fricção de Fanning 299
15.3.3.1 Como utilizar a Equação 15.7 . . . . . . . . . . . 300

Esta atividade prática consiste na construção de um programa em C++ para fazer


o cálculo das perdas de cargas em tubos retos, utilizados para o transporte de fluidos.
Considera-se que os tubos sejam cilíndricos, fechados e que operem completamente
preenchidos. Na próxima seção serão apresentadas as principais variáveis e equações
necessárias para a construção do programa.

15.1 Referencial teórico da atividade prática


• Número de Reynolds: É um número adimensional que serve para caracterizar
o regime de escoamento no interior de um tubo cilíndrico, fechado e comple-
tamente preenchido. É dado pela Equação 15.1.

ρv D
NRey = (15.1)
µ

297
++
Princípios de programação em C

Na Equação 15.1, ρ é a densidade do fluido, dada em kg/m3 . v é a velocidade


média do escoamento, em m/s. D é o diâmetro interno do tubo, com o seu
valor dado em metro (m). µ é a viscosidade dinâmica do fluido, em kg/(m×s).
A unidade P a × s é frequentemente utilizada para a viscosidade dinâmica.

• : É a rugosidade média dos tubos retos, dada em metros (m). Esse valor
depende, sobretudo, do tipo de material de constituição dos tubos, condições
de utilização, idade, se é um tubo novo ou usado, etc. Valores de rugosi-
dade () podem ser encontrados em livros de operações unitárias, tubulações
industriais, hidráulica e em materiais disponibilizados pelos fabricantes e forne-
cedores de tubos.  também pode ser medido experimentalmente por meio de
um instrumento denominado ’rugosímetro’.

• fD : é um valor adimensional que se chama fator de fricção de Darcy-Weisbach.

• f : é um valor adimensional que se chama fator de fricção de Fanning.

• L: é o comprimento longitudinal do tubo, em m.

15.2 Objetivos
• O programa deverá solicitar ao usuário que informe a quantidade de tubos retos
(em metros lineares de cano), rugosidade (), diâmetro interno e o número de
Reynolds para o escoamento.

• Em seguida o programa deverá calcular a perda de carga total nesses canos


e fornecer na tela o valor F , em J/kg
P

15.3 Detalhamento e recomendações para a constru-


ção do programa
15.3.1 Passo 1: Cálculo do número de Reynolds
O programa deverá inicialmente calcular o número de Reynolds para o escoamento,
conforme a Equação 15.1. Esse valor será utilizado nos próximos cálculos desta
seção.

15.3.2 Passo 2: Cálculo da rugosidade relativa


O próximo passo a ser feito pelo programa consiste em calcular o valor da rugosidade
relativa, dado pela Equação 15.2.


r = (15.2)
D

298
++
Princípios de programação em C

15.3.3 Passo 3: Cálculo do valor de f , fator de fricção de Fanning


O fator de fricção de Fanning (f ) é um valor adimensional que será utilizado no
cálculo da perda de carga (Ff ) nos tubos, Equação 15.3 (GEANKOPLIS (1993)).
Essa perda de carga Ff é expressa em J/kg.

L v2
Ff = 4f (15.3)
D 2
Assim, antes de efetivamente utilizar a equação 15.3, é necessário calcular o
valor de f , que pode ser obtido a partir de ábacos ou, mais precisamente, a partir da
equação de Colebrook, Equação 15.4, (IBARZ e BARBOSA-CÁNOVAS (2003)). O
inconveniente da equação de Colebrook está no fato de ao utilizá-la, não ser possível
isolar a variável de interesse (fD ).

   
1 2, 51  fD
p = −2 log  D + p , f = (15.4)
fD 3, 71 NRey fD 4

Deve-se observar primeiramente que é necessário calcular a variável fD (fator de


fricção de Darcy-Weisbach) para, em seguida, calcular o valor de f (fator de fricção
de Fanning), para que finalmente este possa ser inserido na Equação 15.3.
Em termos computacionais, para calcular o valor fD a partir da Equação 15.4 é
necessário aplicar algum método numérico como, por exemplo, o método de Newton-
Rapson, que permitirá obter o valor de fD a partir de um ciclo iterativo de operações.
O método de Newton-Raphson é baseado em um processo iterativo no qual o
resultado a ser obtido no passo (N + 1) depende do valor obtido no passo anterior,
N.


f (xn )
xn+1 = xn − , n ∈ N, xn = x0 (15.5)

f 0 (xn )
n=0

Na Equação 15.5, x0 é uma aproximação inicial para o ciclo iterativo, dada pelo
programador ou usuário do programa. n é a n-ésima iteração. f 0 (xn ) é a derivada da
função no ponto xn .
Devemos agora aplicar o método de Newton-Raphson (Equação 15.5) à equação
de Colebrook (Equação 15.4), mas antes vamos reescrevê-la, de modo a tornar essa
tarefa um pouco mais fácil, como apresentado na Equação 15.6.

" #   
 
1 K D 2, 51
p + 2 log K1 + p 2 = 0, K1 =   , e K2 = (15.6)
fD fD 3, 71 NRey

299
++
Princípios de programação em C

Ao aplicar o método de Newton-Raphson à Equação 15.6, obtém-se a Equação


15.7.

 
1 K
q + 2 log K1 + q 2 
fDN fDN
fDN+1 = fDN −   (15.7)
 
 
 K2 1 
− −
  
3/2

N


K2  2 f D

N 3/2
  
 fD ln (10) K1 + q
 
fDN

Na Equação 15.7, os valores de K1 e K2 são os mesmos dados na Equação 15.6.


fDN+1 é o valor do fator de fricção de Darcy-Weisbach na próxima iteração. fDN é o
valor do fator de fricção de Darcy-Weisbach na iteração atual.

15.3.3.1 Como utilizar a Equação 15.7


Para utilizar a equação 15.7 será necessário construir um programa no qual o usuário
deverá entrar com os seguintes dados:

• Rugosidade,  (em metro, m)

• Número de Reynolds, NRey (adimensional)

• Diâmetro interno do tubo, D (em metro, m)

• Um chute inicial,fDN = 0, 01 (adimensional)

Em seguida, o programa deverá fazer fazer um ciclo iterativo com 50 ou mais


iterações (sugestão: 100 iterações para uma boa precisão), como esquematizado a
seguir.

300
++
Princípios de programação em C

Algoritmo 1: Cálculo iterativo do fator de fricção de Fanning


Input: , NRey , D
Input: fDN = 0, 01 (Chute inicial)
1 Inicialização;

2 Entrar com , NRey , D e fD na Equação 15.7;


N

3 if NRey >= 3500 then


4 for i ← 0 to 100 do
5 Calcular: fDN+1 (Equação 15.7);
6 fDN ← fDN+1 ;
7 end
8 end
9 if NRey <= 2100 then
64
10 fDN+1 ← ;
NRey
11 end
12 if (NRey > 2100) e (NRey < 3500) then
13 f = 0;
14 Exibe mensagem de erro: ’região de transição’;
15 Aborta o cálculo;
16 end

f N+1
Output: f ← D
4

Após calcular o valor de f (fator de fricção de Fanning), este deverá ser inserido
na Equação 15.3, juntamente com os valores de comprimento total de tubo (L, em
metros), diâmetro interno do tubo (D, em metros), e velocidade (m/s). O algoritmo
apresentado a seguir mostra como isso pode ser feito.

Algoritmo 2: Cálculo da perda de carga em tubos retos


Input: f , L, D, v
1 Inicialização;
2 Entrar com f , L, D e v na Equação 15.3;
3 Calcular: Ff (Equação 15.3);
Output: Ff

O valor Ff corresponde à perda de carga total, em J/kg, para os tubos retos. A


janela principal de entrada de dados do programa e a apresentação dos cálculos deverá
ser feita, em função do comprimento total L, como apresentado a seguir. Veja que o
programa abortará o cálculo e exibirá uma mensagem de erro, caso seja de transição
o regime de escoamento informado pelo número de Reynolds, NRey ∈ ]2100, 3500[.
O programa deverá também gerar e exportar esse relatório para um arquivo externo,
com o nome PerdaTubos.txt.

301
++
Princípios de programação em C

===================================================================
CALCULO DA PERDA DE CARGA EM TUBOS RETOS - UFLA - GCA187 - 2020
===================================================================
[Emitido em: 04/11/2019 - 20:19:44]
DADOS DO PROBLEMA:
-----------------
>> Rugosidade........: xxxx [m]
>> Densidade.........: xxxx [kg/m^3]
>> Velocidade media..: xxxx [m/s]
>> Diametro..........: xxxx [m]
>> Viscosidade.......: xxxx [Pa.s]
>> Chute inicial.....: 0.01 [adimensional]
>> Comprimento total.: xxxx [m]

===================================================================
VALORES CALCULADOS PELO PROGRAMA
===================================================================
>> Numero de Reynolds.................: xxxxx [turbulento]
>> Rugosidade relativa................: xxxxx [adimensional]
>> f_D (Fator fric. Darcy-Weisbach)...: xxxxx [adimensional]
>> f (Fator fric. Fanning)............: xxxxx [adimensional]
-------------------------------------------------------------------
>> Ff (PERDA DE CARGA EM TUBOS RETOS).: xxxxx [J/kg]
===================================================================

302
Capítulo 16

Módulo 3: Construção de um
programa para dimensionamento de
uma bomba hidráulica

Conteúdo do capítulo
16.1 Referencial teórico da atividade prática . . . . . . . . . . 303
16.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
16.3 Detalhamento e recomendações para a construção do
programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306

As bombas hidráulicas são equipamentos importantes para a indústria de alimen-


tos porque promovem o transporte dos fluidos de processos desde o local onde estão
armazenados até o local da fábrica onde serão efetivamente utilizados. Este traba-
lho consiste na construção de um programa para o dimensionamento de uma bomba
hidráulica. O programa deverá operar em conjunto com aqueles outros programas,
construídos nas práticas anteriores (Trabalhos 1 e 2), os quais serão utilizados para
fornecer os valores de perda de carga total, referente às válvulas e acessórios pre-
sentes na tubulação, e também o valor de perda de carga total correspondente aos
tubos retos (canos).

16.1 Referencial teórico da atividade prática


Nos tópicos apresentados a seguir estão descritos os principais parâmetros e variáveis
que compõem os cálculos de dimensionamento de uma bomba centrífuga.

• ∆P : Para o dimensionamento da bomba será necessário informar o valor de


diferença de pressão (em kP a) desde o ponto 1 (entrada) até o ponto 2 (saída)
identificados na Figura 16.1 pelos números 1 e 2. O valor da diferença de
pressão (∆P , em kP a) será calculado pela Equação 16.1.

303
++
Princípios de programação em C

Figura 16.1: Diagrama esquemático de um sistema de transporte de fluidos por meio


de uma bomba hidráulica. (Fonte: autores)

∆P = P2 − P1 (16.1)

Na Equação 16.1, P1 é a pressão no ponto 1 (ver Figura 16.1). P2 é a pressão


no ponto 2. Ambos valores de pressão são dados em kP a. ∆P é o valor da
diferença de pressão (em kP a) entre os pontos 2 e 1.

• ∆Y : É a diferença de altura (cota) entre os pontos 2 e 1. Em geral essa dife-


rença de altura é estabelecida com base em um plano arbitrário de referência.
O valor de ∆Y é calculado pela Equação 16.2, com o resultado expresso em
metros. Y1 é a altura (m) desde o ponto 1 até um plano arbitrário de referência.
Y2 é a altura (m) desde o ponto 2 até o mesmo plano arbitrário de referência.

∆Y = Y2 − Y1 (16.2)

• Φ é a vazão, em m3 /s na tubulação entre os pontos 1 e 2. Esse valor depende,


sobretudo, de quanto tempo será necessário (ou desejado) para transportar
1 m3 do fluido desde o ponto 1 até o ponto 2. Se, por exemplo, há uma
intensão de transportar 10.000 litros de água desde o ponto 1 até o ponto 2
em um intervalo de 30 minutos, então, o valor de Φ pode ser calculado como
na Equação 16.3.

1m3
       
10.000l 1mi n 10.000 1
Φ= = = ≈ 0, 0056m3 /s
30mi n 1.000l 60s 30 × 1.000 × 60 180
(16.3)

304
++
Princípios de programação em C

• F : Corresponde à soma algébrica do total das perdas de carga em válvulas


P

e acessórios (perda de carga secundária), com o total da perda de carga nos


tubos retos (perda de carga primária). Os valores de perda de carga secundária
podem ser calculados com auxílio do programa do Capítulo 14, e os valores
de perda de carga primária podem ser calculados com auxílio do programa do
Capítulo 15.

• α: é uma constante que deverá ser informada no modelo matemático do ba-


lanço de energia mecânica. Esse modelo é dado pela Equação 16.4, e será
o modelo utilizado para o dimensionamento da bomba hidráulica. α vale 1
(um) para o regime de escoamento turbulento, e vale 0,5 para o regime de
escoamento laminar.

1 ∆P X
v22med − v12med + g (∆Y ) + (16.4)

+ F = −Ws
2α ρ

• v1med : é a velocidade média do escoamento no ponto 1 (ver Figura 16.1).

• v2med : é a velocidade média do escoamento no ponto 2 (ver Figura 16.1).

• g: é a constante gravitacional, ≈ 9, 80665 m/s 2 .

• ρ: é a densidade do fluido, em kg/m3 .

• Ws :é o trabalho de eixo, em J/kg, exercido pela bomba para deslocar o fluido


desde o ponto 1 até o ponto 2 identificados na Figura 16.1.

• η: fator de rendimento da bomba. É um valor adimensional entre 0 e 1.

16.2 Objetivos
• O programa deverá solicitar ao usuário que informe a diferença de pressão
(∆P ) entre os pontos 1 e 2, a cota (∆Y ) entre os pontos 1 e 2, o valor de α, a
velocidade média do escoamento nos pontos 1 e 2, a densidade (ρ) do fluido,
e a perda de carga total de todo o sistema, ou seja a perda de carga primária
total (com auxílio do programa do Capítulo 15) e a perda de carga secundária
total (com auxílio do programa do Capítulo 14).

• O programa deverá fornecer a potência da bomba hidráulica, em Watts (W )


e também em HP , considerando algum fator de rendimento para a bomba (η)
que será informado pelo usuário do programa.

• O programa deverá exportar um relatório contendo os valores das variáveis


utilizadas nos cálculos, assim como o valor da potência da bomba, para um
arquivo externo com o nome PotBomba.txt.

305
++
Princípios de programação em C

16.3 Detalhamento e recomendações para a constru-


ção do programa
Os valores das variáveis serão informados pelo usuário do programa e serão utilizados
juntamente com a Equação 16.4, conforme o algoritmo apresentado a seguir.

Algoritmo 3: Cálculo da potência de uma bomba hidráulica


Input: NRey
Input: v1med , v2med
Input: Y1 , Y2
Input: P1 , P2
Input: ρ P
Input: F
1 Inicialização;
2 Calcular α (usar NRey para calcular α) ;
3 Calcular ∆Y (Equação 16.2);
4 Calcular ∆P (Equação 16.1);
5 Calcular F (Programas Cap. 26 e 27);
P

6 Aplicar os valores calculados na Equação 16.4;


Output: −Ws

Após obter o valor da potência da bomba (−Ws ) por meio da Equação 16.4, será
necessário converter esse valor de J/kg para Watts. Isso pode ser feito multiplicando-
se o valor em J/kg pela densidade (ρ) fluido, e também pela vazão (Φ), como
apresentado no exemplo a seguir.

Ws = −153, 93 J/kg (16.5)

0, 005 m3
     
−153, 93 J 998, 20 kg
Ws = × × = −768, 26 J/s = −768, 26 W
kg m3 s
(16.6)

O sinal negativo que aparece no resultado acima é apenas uma convenção, e


serve para indicar que a bomba realiza trabalho sobre sua vizinhança. Nos próximos
cálculos esse sinal negativo será desconsiderado.
Uma bomba hidráulica não tem um rendimento (η) de 100%. Na prática o seu
rendimento é algo entre 60% e 90% para a maioria dos modelos. Informações sobre
o rendimento de uma bomba podem ser obtidas junto ao seu fornecedor/vendedor.
Supondo que o usuário do programa informe o valor de 65% para o rendimento da
bomba, então o cálculo da potência deve ser corrigido (Wcor r ) de modo a considerar
essa informação (η = 0, 65).

306
++
Princípios de programação em C

768, 26 W 768, 26 W
Wcor r = = = 1181, 93 W (16.7)
η 0, 65
Considerando que 1 HP = 745, 7 W , então podemos obter o valor da potência
da bomba em HP .

 
1 HP
HP = (1181, 93 W ) × = 1, 585 HP ≈ 1, 6 HP (16.8)
745, 7 W

O valor final (em HP ou Watts) da potência da bomba poderá ser arredondado


para cima com a função ceil da biblioteca cmath. Mais informações sobre essa
função podem ser encontradas no Capítulo 7, Seção 7.1.5, p.139.

===================================================================
CALCULO DE POTENCIA DE BOMBA HIDRAULICA - UFLA - GCA187 - 2020
===================================================================
[Emitido em: 04/11/2019 - 09:22:23]
DADOS DO PROBLEMA:
------------------
>> Numero Reynolds...: 61810 [Regime: turbulento (alfa = 1.0)]
>> V1_Media..........: 0.683 [m/s]
>> V2_Media..........: 0.683 [m/s]
>> Delta Y....[cotas]: 15.00 [m]
>> Delta P..[pressao]: 24.472 [kPa]
>> Densidade.........: 998.20 [kg/m^3]
>> Vazao.............: 0.005 [m^3/s]
>> Perda carga total.: 6.837 [J/kg]
===================================================================
POTENCIA DA BOMBA
===================================================================
>> Fator de rendimento.......................: 0.65
>> Trabalho de eixo (Ws).....................: -153.96 [J/kg]
>> Potencia nao corrigida com fator de rendim: 768.42 [Watts]
>> Potencia real (corrigida).................: 1182.18 [Watts]
>> Potencia real (corrigida).................: 1.585 [HP]
-------------------------------------------------------------------
POTENCIA REAL RECOMENDADA PARA AQUISICAO..: 2.000 [HP]
===================================================================

Uma boa alternativa é agrupar os códigos das atividades propostas nos Capítulos
14, 15 e 16 em um único programa, de modo a oferecer ao usuário alguma facili-
dade e flexibilidade para o dimensionamento de bombas hidráulicas. Os programas

307
++
Princípios de programação em C

propostos nesses três capítulos são apenas para fins didáticos e podem ser acres-
centados de muitas outras funcionalidades como, por exemplo, a inserção de uma
quantidade maior de acessórios de tubulação, valores tabelados de rugosidade, tipos
de materiais de constituição de tubos (aço carbono, aços inoxidáveis, cobre, PVC,
etc). Também podem ser acrescentadas funções para cálculo de NPSH e curva ca-
racterística de bombas, bem como informações sobre fornecedores e preços atuais
desses equipamentos.

308
Parte III

ANEXOS
Capítulo 17

Anexos

310
++
Princípios de programação em C

17.1 Principais palavras reservadas da linguagem C++

Tabela 17.1: Principais palavras reservadas da linguagem C++


alignas alignof and and_eq asm
atomic_cancel atomic_commit atomic_noexcept auto bitand
bitor bool break case catch
char char8_t char16_t char32_t cin
class compl concept const consteval
constexpr constinit const_cast continue cout
co_await co_return co_yield decltype default
define defined delete do double
dynamic_cast elif else endif endl
enum error exit explicit export
extern false final float for
friend goto if ifdef ifndef
include inline int INT_MAX INT_MIN
iomanip iostream line long main
MAX_RAND module mutable namespace new
noexcept not not_eq npos NULL
nullptr operator or or_eq override
pragma private protected public reflexpr
register reinterpret_cast requires return short
signed sizeof static static_cast std
struct synchronized switch template this
thread_local throw true try typedef
typeid typename undef union unsigned
using virtual void volatile xor
xor_eq wchar_t while
Fonte: Elaborada pelos autores. Adaptada de PRATA (2012).

311
++
Princípios de programação em C

17.2 Tabelas de caracteres ASCII

Tabela 17.2: Tabela de caracteres ASCII. Valores de 0 a 63


Cód. decimal Cód. Hex Caract. Nome Cód. decimal Cód. Hex Caract.
000d 00h ␀ (nul) 032d 20h ␣
001d 01h ␁ (soh) 033d 21h !
002d 02h ␂ (stx) 034d 22h "
003d 03h ␃ (etx) 035d 23h #
004d 04h ␄ (eot) 036d 24h $
005d 05h ␅ (enq) 037d 25h %
006d 06h ␆ (ack) 038d 26h &
007d 07h ␇ (bel) 039d 27h '
008d 08h ␈ (bs) 040d 28h (
009d 09h (tab) 041d 29h )
010d 0Ah ␊ (lf) 042d 2Ah *
011d 0Bh ␋ (vt) 043d 2Bh +
012d 0Ch (np) 044d 2Ch ’
013d 0Dh ␍ (cr) 045d 2Dh -
014d 0Eh ␎ (so) 046d 2Eh .
015d 0Fh (si) 047d 2Fh /
016d 10h ␐ (dle) 048d 30h 0
017d 11h ␑ (dc1) 049d 31h 1
018d 12h ␒ (dc2) 050d 32h 2
019d 13h ␓ (dc3) 051d 33h 3
020d 14h ␔ (dc4) 052d 34h 4
021d 15h ␕ (nak) 053d 35h 5
022d 16h ␖ (syn) 054d 36h 6
023d 17h ␗ (etb) 055d 37h 7
024d 18h ␘ (can) 056d 38h 8
025d 19h ␙ (em) 057d 39h 9
026d 1Ah (eof) 058d 3Ah :
027d 1Bh ␛ (esc) 059d 3Bh ;
028d 1Ch ␜ (fs) 060d 3Ch <
029d 1Dh ␝ (gs) 061d 3Dh =
030d 1Eh ␞ (rs) 062d 3Eh >
031d 1Fh ␟ (us) 063d 3Fh ?
Fonte: Elaborada pelos autores. Adaptada de PRATA (2012).

312
++
Princípios de programação em C

Tabela 17.3: Tabela de caracteres ASCII. Valores de 64 a 127


Cód. decimal Cód. Hex Caract. Cód. decimal Cód. Hex Caract.
064d 40h @ 096d 60h ‘
065d 41h A 097d 61h a
066d 42h B 098d 62h b
067d 43h C 099d 63h c
068d 44h D 100d 64h d
069d 45h E 101d 65h e
070d 46h F 102d 66h f
071d 47h G 103d 67h g
072d 48h H 104d 68h h
073d 49h I 105d 69h i
074d 4Ah J 106d 6Ah j
075d 4Bh K 107d 6Bh k
076d 4Ch L 108d 6Ch l
077d 4Dh M 109d 6Dh m
078d 4Eh N 110d 6Eh n
079d 4Fh O 111d 6Fh o
080d 50h P 112d 70h p
081d 51h Q 113d 71h q
082d 52h R 114d 72h r
083d 53h S 115d 73h s
084d 54h T 116d 74h t
085d 55h U 117d 75h u
086d 56h V 118d 76h v
087d 57h W 119d 77h w
088d 58h X 120d 78h x
089d 59h Y 121d 79h y
090d 5Ah Z 122d 7Ah z
091d 5Bh [ 123d 7Bh {
092d 5Ch \ 124d 7Ch |
093d 5Dh ] 125d 7Dh }
094d 5Eh ˆ 126d 7Eh ˜
095d 5Fh _ 127d 7Fh ␡
Fonte: Elaborada pelos autores. Adaptada de PRATA (2012).

313
++
Princípios de programação em C

Tabela 17.4: Tabela de caracteres ASCII extendidos. Valores de 128 a 191


Cód. decimal Cód. Hex Caract. Cód. decimal Cód. Hex Caract.
128d 80h e 160d A0h  
129d 81h 161d A1h ¡
130d 82h ‚ 162d A2h ¢
131d 83h f 163d A3h £
132d 84h „ 164d A4h ¤
133d 85h ... 165d A5h ¥
134d 86h † 166d A6h ¦
135d 87h ‡ 167d A7h §
136d 88h ^ 168d A8h ¨
137d 89h ‰ 169d A9h ©
138d 8Ah Š 170d AAh ª
139d 8Bh ‹ 171d ABh «
140d 8Ch Œ 172d ACh ¬
141d 8Dh 173d ADh
142d 8Eh Ž 174d AEh ®
143d 8Fh 175d AFh ¯
144d 90h 176d B0h °
145d 91h ‘ 177d B1h ±
146d 92h ’ 178d B2h ²
147d 93h “ 179d B3h ³
148d 94h ” 180d B4h ´
149d 95h • 181d B5h µ
150d 96h – 182d B6h ¶
151d 97h — 183d B7h ·
152d 98h ~ 184d B8h ¸
153d 99h ™ 185d B9h ¹
154d 9Ah š 186d BAh º
155d 9Bh › 187d BBh »
156d 9Ch œ 188d BCh ¼
157d 9Dh 189d BDh ½
158d 9Eh ž 190d BEh ¾
159d 9Fh Ÿ 191d BFh ¿
Fonte: Elaborada pelos autores. Adaptada de PRATA (2012).

314
++
Princípios de programação em C

Tabela 17.5: Tabela de caracteres ASCII extendidos. Valores de 192 a 255


Cód. decimal Cód. Hex Caract. Cód. decimal Cód. Hex Caract.
192d C0h À 224d E0h à
193d C1h Á 225d E1h á
194d C2h  226d E2h â
195d C3h à 227d E3h ã
196d C4h Ä 228d E4h ä
197d C5h Å 229d E5h å
198d C6h Æ 230d E6h æ
199d C7h Ç 231d E7h ç
200d C8h È 232d E8h è
201d C9h É 233d E9h é
202d CAh Ê 234d EAh ê
203d CBh Ë 235d EBh ë
204d CCh Ì 236d ECh ì
205d CDh Í 237d EDh í
206d CEh Î 238d EEh î
207d CFh Ï 239d EFh ï
208d D0h Ð 240d F0h ð
209d D1h Ñ 241d F1h ñ
210d D2h Ò 242d F2h ò
211d D3h Ó 243d F3h ó
212d D4h Ô 244d F4h ô
213d D5h Õ 245d F5h õ
214d D6h Ö 246d F6h ö
215d D7h × 247d F7h ÷
216d D8h Ø 248d F8h ø
217d D9h Ù 249d F9h ù
218d DAh Ú 250d FAh ú
219d DBh Û 251d FBh û
220d DCh Ü 252d FCh ü
221d DDh Ý 253d FDh ý
222d DEh Þ 254d FEh þ
223d DFh ß 255d FFh ÿ
Fonte: Elaborada pelos autores. Adaptada de PRATA (2012).

17.3 Fatores de conversão de unidades de medida


17.3.1 Conversão de unidades de calor, energia e trabalho
Dados de conversão de unidades de calor, energia e trabalho adaptados de GEAN-
KOPLIS (1993).

315
++
Princípios de programação em C

1 J = 1 N · m = 1 kg · m2 /s2
1 kg · m2 /s2 = 1 J (Joule) = 107 g · cm2 /s2 (erg)
1 btu = 1.055, 06 J = 1, 05506 kJ
1 btu = 252, 16 cal (termoquímica)
1 kcal (termoquímica) = 1.000 cal = 4, 1840 kJ
1 cal (termoquímica) = 4, 1840 J
1 cal (IT) = 4, 1868 J
1 btu = 251, 996 cal (IT)
1 btu = 778, 17 ft · lbf
1 hp · h = 0, 7457 kW · h
1 hp · h = 2.544, 5 btu
1 ft · lbf = 1, 35582 J
1 ft · lbf /lbm = 2, 9890 J/kg

17.4 Exemplos de formatação com o uso do printf()


da linguagem C
17.4.1 Formatação simples, com um único argumento
1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 printf ( " abcd " ) ;
6 return (0) ;
7 }

17.4.2 Formatação simples, com argumentos de tipos variáveis


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 int x = 5;
6 float y = 6.25;
7 double z = 3.14159;
8 char r = ’M ’;
9 char s [] = " Estudante " ;
10

11 printf ( " % d % f % lf % c % s " , x , y , z , r , s ) ;


12 return (0) ;
13 }

316
++
Princípios de programação em C

17.4.3 Impressão de aspas duplas


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 printf ( " Texto com \" aspas duplas \" delimitando palavras " ) ;
6 return (0) ;
7 }

17.4.4 Impressão de aspas simples


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 printf ( " Texto com \ ’ aspas simpes \ ’ delimitando palavras " ) ;
6 return (0) ;
7 }

17.4.5 Impressão de uma barra simples


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 printf ( " Impressao de uma barra simples : \\ " ) ;
6 return (0) ;
7 }

17.4.6 Impressão do símbolo de porcentagem


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 printf ( " Cerca de 80 %% das pessoas estavam ausentes " ) ;
6 return (0) ;
7 }

317
++
Princípios de programação em C

17.4.7 Salto para o início da próxima linha com ’\n’


1 printf ( " Linha1 \ nLinha2 \ nLinha3 \ nLinha4 " ) ;

17.4.8 Salto de linha com o caractere ’\f’


1 printf ( " Texto1 \ fTexto2 \ fTexto3 \ fTexto4 " ) ;

17.4.9 Retorno para o início da linha com o caractere ’\r’


1 printf ( " Primeiro \ rSegundo " ) ;

17.4.10 Tabulação horizontal com o caractere ’\t’


1 printf ( " Valor1 \ tValor2 \ tValor3 " ) ;

17.4.11 Tabulação vertical com o caractere ’\v’


1 printf ( " Valor1 \ vValor2 \ vValor3 " ) ;

17.4.12 Sinal sonoro audível (apenas no MS Windows)


1 printf ( " \ a " ) ;

17.4.13 Backspace com o caractere ’\b’


1 printf ( " Texto1 \ b \ b \ bTexto2 " ) ;

17.4.14 Mudança de base: octal e hexadecimal


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 int nValor = 56;
6 printf ( " Valor octal ......: % o \ n " , nValor ) ;
7 printf ( " Valor hexadecimal : % x \ n " , nValor ) ;
8 return (0) ;
9 }

318
++
Princípios de programação em C

17.4.15 Impressão de número de ponto flutuante em notação


científica, expresso na base 10
1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 float nValor = 56.74;
6 printf ( " Valor : % e " , nValor ) ;
7 return (0) ;
8 }

17.4.16 Especificação da largura mínima de impressão de núme-


ros inteiros
1 printf ( " %6 d " , 5) ;

Produz1 : ␣␣␣␣␣5
1 printf ( " %6 d " , -5) ;

Produz: ␣␣␣␣-5
1 printf ( " %6 d " , 1013254488) ;

Produz: 1013254488
1 printf ( " %6 d " , -1013254488) ;

Produz: -1013254488

17.4.17 Especificação da largura mínima de impressão de um


número inteiro com passagem de parâmetro referente à
quantidade total de caracteres
1 printf ( " %* d " , 10 , 86) ; // * = 10

Produz: ␣␣␣␣␣␣␣␣86

17.4.18 Especificação da largura mínima de impressão de uma


string com passagem de parâmetro referente à quanti-
dade total de caracteres
1 printf ( " %.* s " , 3 , " abcdefghijk " ) ; // .* = 3

Produz: abc
1
O símbolo ␣ refere-se a um caractere de espaço simples no texto de saída da função printf().

319
++
Princípios de programação em C

17.4.19 Justificando o número à esquerda antes de imprimir


1 printf ( " % -8 d " , 6) ;

Produz: 6␣␣␣␣␣␣␣
1 printf ( " % -8 d " , -17) ;

Produz: -17␣␣␣␣␣

17.4.20 Preenchendo espaços em branco com zeros


1 printf ( " %07 d " , 8) ;

Produz: 0000008
1 printf ( " %07 d " , -192) ;

Produz: -000192

17.4.21 Inserção do sinal de ’+’ antes de números


1 printf ( " %+8 d " , 125) ;

Produz: ␣␣␣␣+125
1 printf ( " %+08 d " , 125) ;

Produz: +0000125
1 printf ( " %+08 d " , -125) ;

Produz: -0000125
1 printf ( " %+ -8 d " , 5) ;

Produz: +5␣␣␣␣␣␣
1 printf ( " %+ -8 d " , -4) ;

Produz: -4␣␣␣␣␣␣
1 printf ( " % -8 d " , 4) ; // Com espaco apos o %

Produz: ␣4␣␣␣␣␣␣
1 printf ( " %+08 d " , 0) ;

Produz: +0000000

320
++
Princípios de programação em C

17.4.22 Impressão de strings


1 printf ( " %6 s " , " " ) ;

Produz: ␣␣␣␣␣␣
1 printf ( " %6 s " , " a " ) ;

Produz: ␣␣␣␣␣a
1 printf ( " %6 s " , " abc " ) ;

Produz: ␣␣␣abc
1 printf ( " %6 s " , " abcdefghijk " ) ;

Produz: abcdefghijk
1 printf ( " % -6 s " , " " ) ;

Produz: ␣␣␣␣␣␣
1 printf ( " % -6 s " , " r " ) ;

Produz: r␣␣␣␣␣
1 printf ( " % -6 s " , " kwr " ) ;

Produz: kwr␣␣␣
1 printf ( " % -6 s " , " abcdefghijk " ) ;

Produz: abcdefghijk

17.4.23 Impressão de números de ponto flutuante


1 # include < stdio .h >
2 # include < stdlib .h >
3 int main ()
4 {
5 float Pi = 3.14159265359;
6 printf ( " %.0 f \ n " , Pi ) ; // Saida : 3
7 printf ( " %.0 f . \ n " , Pi ) ; // Saida : 3.
8 printf ( " %.1 f \ n " , Pi ) ; // Saida : 3.1
9 printf ( " %.2 f \ n " , Pi ) ; // Saida : 3.14
10 printf ( " %.6 f \ n " , Pi ) ; // Saida : 3.141593
11 return (0) ;
12 }

1 printf ( " %6.0 f \ n " , Pi ) ;

Produz: ␣␣␣␣␣3

321
++
Princípios de programação em C

1 printf ( " %6.1 f \ n " , Pi ) ;

Produz: ␣␣␣3.1
1 printf ( " %6.2 f \ n " , Pi ) ;

Produz: ␣␣3.14
1 printf ( " %6.3 f \ n " , Pi ) ;

Produz: ␣3.142
1 printf ( " %6.10 f \ n " , Pi ) ;

Produz: 3.1415927410

322
Bibliografia

ALEXANDRESCU, A. The D Programming Language. Boston: Addison-Wesley,


2010.

ARMSTRONG, J. C++ for Financial Mathematics. New York: Chapman & Hall,
2017.

BARTON, J. J.; NACKMAN, L. R. Scientific and Engineering C++ : An introduc-


tion with advanced techniques and examples. Boston: Addison-Wesley, 1999.

BECKER, P. Working Draft, Standard for Program-


ming Language C .
++
Disponível em: http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf. Acesso em: 7 set.
2019.

BERK, Z. Food Process Engineering and Technology. New York: Elsevier, 2009.

BJÖRNANDER, S. C++ Windows Programming. Develop Real-World Applica-


tions in Windows. Birmingham: Packt, 2016.

BOLDRINI, J. L.; COSTA, S. I. R.; FIGUEIREDO, V. L.; WETZLER, H. G. Álgebra


Linear. 3. ed. ver. ampl. Campinas: Universidade Estadual de Campinas; São
Paulo: Harbra, 1986.

BRONSON, G. J. C for Engineers and Scientists: an introduction to programming


with ANSI C. Minnesota: West, 1993. 643p.

BRONSON, G. J. C++ for Engineers and Scientists. 4th. ed. Boston: Cengage
Learning, 2013.

COOK, J. D. Five Tips for Floating Point Programming. Disponível


em: https://www.codeproject.com/Articles/29637/Five-Tips-for-Floating-Point-
Programming. Acesso em: 21 dez. 2019.

DAMAS, L. Linguagem C. 10. ed. Rio de Janeiro: Livros Técnicos e Científicos,


2007.

DAS, V. V. Principles of Data Structures Using C and C++ . New Delhi: New Age
International, 2006.

323
DAVIS, D. S. Nomography and Empirical Equations. New York: Reinhold Pu-
blishing Corporation, 1955.

DAVIS, S. R. C++ for Dummies. 7th. ed. New Jersey: John Wiley & Sons, 2014.

DEITEL, P.; DEITEL, H. C++ : How to Program. 8th. ed. Nova Jersey: Prentice
Hall, 2011.

DUFFY, D. J. Introduction to C++ for Financial Engineers: an object-oriented


approach. New York: John Wiley & Sons, 2006.

ERNERFELDT, E. Float or double?. I Like Big Bits (June 1, 2017). Disponível


em: http://www.ilikebigbits.com/2017_06_01_float_or_double.html. Acesso
em: 21 dez. 2019.

EUBANK, R. L.; KUPRESANIN, A. Statistical Computing in C++ and R. Boca


Raton: CRC, 2011. The R Series.

GADDIS, T.; WALTERS, J.; MUGANDA, G. Starting Out With C++ Early Ob-
jects. 8th. ed. Boston: Addison-Wesley, 2014.

GEANKOPLIS, C. J. Transport Processes and Unit Operations. 3rd. ed. New


Jersey: Prentice-Hall International, 1993.

GIBBS, M. How to use Structs in C++ Programming. Chapter 8/Lesson


1. Disponível em: https://study.com/academy/lesson/how-to-use-structs-in-c-
programming.html. Acesso em: 29 dez. 2019.

GOODRICH, M. T.; TAMASSIA, R.; MOUNT, D. Data Structures & Algorithms


in C++ . 2nd. ed. New York: John Wiley & Sons, 2009.

GREGOIRE, M. Professional C++ . 3rd. ed. Indianapolis: John Wiley & Sons, 2014.

HAYES, G.D. Manual de Datos para Ingeniería de los Alimentos. Zaragoza:


Editorial Acribia, 1992.

HEWLETT-PACKARD DEVELOPMENT COMPANY, L.P. HP 12C Plati-


num Owner’s Handbook and Problem-Solving Guide. Disponível em:
http://h10032.www1.hp.com/ctg/Manual/bpia5309.pdf. Acesso em: 02 jan.
2020.

IBARZ, A.; BARBOSA-CÁNOVAS, G.V. Unit Operations in Food Engineering.


New York: CRC, 2003. 873p.

INTERSYSTEMS CORPORATION. Banco de dados para aplicações. Disponí-


vel em: https://www.intersystems.com/br/produtos/cache/. Acesso em: 02 jan.
2020a.

324
INTERSYSTEMS CORPORATION. Our Clients and Partners. Disponí-
vel em: https://www.intersystems.com/who-we-are/our-clients-and-partners/.
Acesso em: 02 jan. 2020b.

KATUPITIYA, J.; BENTLEY, K. Interfacing With C++ . Programming Real-


World Applications. Berlin, Heidelberg: Springer-Verlag, 2006.

KERNIGHAN, B. W.; RITCHIE, D. M. C: A linguagem de Programação. Porto


Alegre: Campus, 1986.

KERNIGHAN, B. W.; RITCHIE, D. M. C: Programming Language. 2nd. ed. New


Jersey: Prentice-Hall; Englewood Cliffs, 1988.

KILCAST, D.; SUBRAMANIAM, P. (ed.) The stability and shelf-life of food.


Cambridge: Woodhead, 2000. 340p.

KOFFMAN, E. B.; WOLFGANG, P. A. T. Objects, Abstraction, Data Structures


and Design Using C++ . New York: John Wiley & Sons, 2006.

LIANG, Y. D. Introduction to Programming with C++ . 3rd. ed. London: Pearson


Education, 2014.

MALIK, D. S. C++ Programming. Program Design Including Data Structures.


6th. ed. Boston: Cengage Learning, 2013.

MALIK, D. S. C++ Programming. Program Design Including Data Structures.


8th. ed. Boston: Cengage Learning, 2018.

MATOS, F. J. M. C Progressivo: um curso completo de linguagem


C. Gerando números aleatórios em C: rand, srand e seed. Disponí-
vel em: https://www.cprogressivo.net/2013/03/Como-gerar-numeros-aleatorios-
em-C-com-a-rand-srand-e-seed.html. Accesso em: 02 jan. 2020.

NYHOFF, L. Programming in C++ for Engineering and Science. Boca Raton:


CRC, 2012.

PAREWA LABS PVT. Ltd. C++ malloc(). Disponível em:


https://www.programiz.com/cpp-programming/library-function/cstdlib/malloc.
Acesso em: 29 dez. 2019.

PARKER, M. Learning D. Open Source Community Experience Distilled. Bir-


mingham: Packt, 2015.

PRATA, S. C++ Primer Plus. Developer’s Library. 6th. ed. Boston: Addison-
Wesley, 2012.

RAO, S. Sams Teach Yourself C++ in One Hour a Day. 7th. ed. London: Pearson
Education, 2012.

325
REESE, R. Understanding and Using C Pointers. Sebastopol: O’Reilly Media,
2013.

RUDEK, M.; CARNEIRO, G. L.; PEREIRA, A. Z. Técnicas de Programação. Cu-


ritiba: Pontifícia Universidade Católica do Paraná, 2002. (Apostila). Disponível
em: http://www.escolaelectra.com.br/alumni/biblioteca/Teleprocessamento_-
basica.pdf. Acesso em: 26 dez. 2019.

RUGGIERO, M. A. G.; LOPES, V. L. R. Cálculo Numérico: aspectos teóricos e


computacionais. 2. ed. São Paulo: Pearson Makron Books, 1996. 406p.

RUPPE, A. D. D Cookbook: open source community experience distilled. Bir-


mingham: Packt, 2014.

SAHIN, S.; SUMNU, S.G. Physical properties of foods. New York: Springer Science
+ Business Media, 2006. 257p. Food Science Text Series.

SAHNI, S. Data Structures, Algorithms and Applications in C++ . 2nd. ed. Hyde-
rabad:. Universities, 2005.

SALLEH, S.; ZOMAYA, A. Y.; BAKAR, S. A. Computing for Numerical Methods


Using Visual C++ . New Jersey: Wiley-Interscience; John Wiley & Sons, 2008.

SANTOS, J. C. Matemática Financeira: calculadora HP-12c. Mais de 200 pro-


blemas solucionados. São Paulo: Villipress, 2001. v.1. Série Análise de Negócios.
Coleção Sapientia. Arte e Ciência.

SCHEINERMAN, E. C++ for Mathematicians: An introduction for students and


professionals. Boca Raton: CRC, 2006.

SIERRA, F. J. C. C/C++ Curso de Programación. 3. ed. Madrid: RA-MA Editorial,


2007.

SINGH, R. P. Computer Applications in Food Technology. use of spreadsheets in


graphical, statistical, and process analyses. Cambridge: Academic, 1996.

STROUSTROUP, B. An Overview of the C++ Programming Language. Boca


Raton: CRC, 1999.

STROUSTROUP, B. A Tour of C++ . C++ In-Depth Series. London: Pearson


Education, 2013a.

STROUSTROUP, B. Interview. Bjarne Stroustroup. About C++ and...


few more things. (Software Developer’s Journal. 01/2011). Disponível em:
http://www.stroustrup.com/polish-interview.pdf. Acesso em: 03 set. 2019.

STROUSTROUP, B. The C++ Programming Language. 4th. ed. Londom: Pearson


Education, 2013b.

326
SUN, D.W. (ed.) Thermal Food Processing: new technologies and quality issues.
Boca Raton: CRC, 2006. 640p.

SWOKOWSKI, E.W. Cálculo com geometria analítica. São Paulo: Makron Books,
1983.

VARZAKAS, T.; TZIA, C. (ed.) Food Engineering Handbook. Food Engineering


Fundamentals. Boca Raton: CRC, 2005.

WEISS, M. A. Data Structures and Algorithm Analysis in C++ . 4th. ed. London:
Pearson Education, 2014.

WIKIPÉDIA. Include guard. Disponível em: https://pt.wikipedia.org/wiki/Include_-


guard. Acesso em: 03 jan. 2019.

ZAK, D. An Introduction to Programming With C++ . 8th. ed. Boston: Cengage


Learning, 2016.

ZEITZ, P. The Art and Craft of Problem Solving. 2nd. ed. New York: John Wiley
& Sons, 2007.

327
328

Você também pode gostar