Você está na página 1de 295

MAKRON Books

,
SUMARIO

Prefácio ............................................................... .XVII

Uma Visão Geral ....................................................... . XIX


Classes e objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XIX
Encapsular e esconder . .. .. . .. . .. .. . .. .. . . .. . .. . .. .. .. . .. . .. . .. . .. . .. . .. . XX
Herança ................................................................ XX
Polimorfismo e sobrecarga . .. .. .. .. . .. .. . .. . .. .. . .. .. . .. .. . . .. . .. .. .. . .. XXII
C é um subconjunto de C++ . . .. . .. . ... . .. . .. . .. . .. . .. .. .. . .. . .. . .. . ... . XXITI

Capítulo 1 Conceitos Básicos ................... ... .................. .. ... 1


A estmtura básica de um programa em C++ . . .. .. . . . ... . .. . .. . .. . .. . .. .. .. . . 1
Forma geral das fnnções C++ ............................................ 1
O primeiro programa .. . .. . .. . .. .. . .. .. . .. . .. . .. .. . .. .. . .. . .. . .. . ... . .. . . 2
Nome das funções . . . .. .. . .. .. . .. . . .. .. . .. . .. . .. .. . .. .. . .. . .. . . .. .. . .. . .. 2
O tipo void . .. .. . .. .. . .. . .. . .. .. . .. .. . .. .. . .. . .. . ...... . . .. .. . .. . .. .. . . . 2
Chaves . . .. .. . .. . .. .. . .. . .. .. . .. . .. .. . .. . .. .. . .. . .. . .. . .. . .. . .. . ... . .. . . 3
Espaços em branco ............. . ............... .. .............. . ........ 3
Instruções de programa .................................................. 4
Imprimindo usando cout ............ . ........ .. ..... .. ........ . ..... . ... 4
O pré-processador C++ .................................................... 5
A diretiva #include ..................................................... 5

IX
X Treinamento em Linguagem C++

Arquivos de inclusão .................................................... 6


O arquivo iostream.h . ........ .. .. . .. . ..... . ... . .. . .. .. .... . .. .. .. . ... . .. 6
Executando o primeiro programa ........................................... 6
Códigos especiais .......................................................... 7
Imprimindo numa nova linha ............................................ 8
Constantes numéricas .... . ..... . .. . ...... . ..... . .. . ...... . ................. 8
Cadeia de caracteres constante . .. .. . .. .. .. . .. .... .. . .. .. .. . . .. . .. .. .. . .. .. . . 9
Aspas simples ou aspas duplas ........................................... 9
Imprimindo outros tipos de dados ........................................ 9
Variáveis .... . ............ . ............ . .................. . ............ . . 10
Declarações de variáveis ......... . .. . ............ . ............... . ...... 11
Tipos de variáveis ............... . ............... . ...................... 12
Inicializando variáveis . ..... . ......... . ..... . ......... . ..... . .. . ... . .. . . 14
Variáveis ponto flutuante (float) ......................................... 14
O modificador unsigned: inteiros com e sem sinal ... . .. . .. . .. . .. .. .. . .. . . 16
N omes de variáveis ............. . ............... . ............... . ...... 17
Palavras-chave de C++ .......... . .. . ............ . .. . ............ . .. . .. . ... 18
Manipuladores de tamanho de campos na impressão .. . .. ... . . .. . .. .. . .. .. . . 19
Tamanho de campos com números inteiros ............................... 19
Tamanho de campos com pontos flutuantes .............................. 21
Tamanho de campos com cadeias de caracteres ........... . .. . .. . .. . ...... 22
Manipuladores de bases numéricas . . ............... . ............ . .. . ...... 23
Imprimindo caracteres gráficos . .. .. . .. .. . .. . .. .. . .. . ... . .. . . .. .. . .. . .. . .. . 23
Re\risão . .. . .. . .. . o •• • •• • ••••• • •• •• •• • •• • •• • •• •26 •• • ••• • •• • • •••• • •• •• • •• •• • •

Exercícios .......................... o ••••••••••••••••••••••••••••••••••••• 28

Capítulo 2 Operadores . ... ... ... .. .. ... ... .... .. ... .. ... .. .... . ........ . 34
Operador de atribuição: = . ..... . .. . .. . ........ . ...... . .. . ............ . .. . . 34
Operadores aritméticos: + - * I % . .. . .. .. .. . . .. .. . .. . ... . .. . . .. .. . .. . .. .. .. 35
Precedência .. . .. . .. . .. .. . .. .. . .. . .. . .. .. . .. .. . .. . ... . .. . . .. .. . .. . ...... 36
O operador menos unário: - ............................................... 37
Lendo com cin e o operador de extração >> . . .. .. . .. . .. .. .. . . .. .. . .. . .. . ... 37
Múltiplas entradas com cin . .. .. .. . .. .. .... . . .. .. . .. .. .. . .. . . .. .. . .. .. .. 38
O programa que adivinha a soma de cinco números ............... . . . .... 39
Sumário XT

Manipuladores de bases numéricas: dec hex oct .. . .. . .. .. . . ........ .. .. . .. . .40


O qualificador const .. .. . .. . .. . .. ..... .. . .. . .. . .. .. .. . .. . ..... . .. ..... .. . . 40
Conversões de tipos e o operador de molde . ........... . .. . ................. 41
As funções getche() e getch() ............... . ............... . .............. 42
Comentários .. . .. . ............ . .. . ............ . ..... .. .............. ... .. 43
Sintaxe ................................................................ 44
Operadores de incremento (++) e de decremento (--) . . ... . .. . .. . .. . ...... . .. 44
Precedência ..................... . ............... .. ..................... 46
Cout enganando você ..................................................... 47
Operadores aritméticos de atribuição: += -= *= I= %= ..... .. .............. 49
Operadores relacionais: > >= < <= == != ................................ 51
Precedência .. . .. . ............... . .. .. ........... . .. .. .. . ..... .. . . ...... 52
Operadores lógicos: && I I ! . .. .. .. . .. . .. . .... .. .. .. . .. .. . .. . .. . .. . .. ... . 53
O operador condicional temário: ?: ................. . ............... . ...... 54
Tabela de precedência dos operadores . . .. . .. . .. .. . .. .. . .. . .. .. . .. . .. . . .. .. . 55
Operadores: avaliação lógica ou numérica ...... .... ............... . ...... 56
Revisão ........ . .. .. . . ........ .. .. . .. .. .. . ..... . .. .. . .. .. . ..... . .. .. . .. .. 56
Exercícios ................................................................ 57

Capítulo 3 Laços .. ... ... .. .... .. ... ... . .... .. ........ ... .. .......... .. .. 63
O laço for . . ............ . ........ ... .... . .. . .. . .. .. . o o •• • ••••• • •• •• • o • •• •• 63
Sintaxe do laço for ... . . ........... . . o • •••• o ••• •• o • o ••••••••••••••••••• o 64
Variáveis declaradas na instrução for .................................... 66
Flexibilidade do laço for . .. . . .. .. . .. .. .. . . .. ..... .. . .. .. . . .. ..... . .. .. .. 67
O operador vírgula ....... o ••••• o •••••••••• 67 o •••• • •• o ••••••••••••••••••••

Usando caracteres ...................................................... 67


Usando chamadas a funções ...... .... ............ . .............. . ...... 68
Omitindo expressões do laço for . .. . .. ........ . .. .. . .. .. . ..... . .. .. . .. .. 68
Um laço infirlito . o •• • o o •• o •• •• o •• o •• •• o • • o ••••••••••• o •• • • • o •• o •• o ••• o o • 69
Omitindo o corpo do laço for . .. . ... . .. . . . .. . .. . ... . .. . .. .. . . .. .. .. . .. . . 69
Múltiplas instruções no corpo de um laço for ............................. 69
Visibilidade de variáveis de bloco .. . .. . .. . .. . .. . ... . .. . .. . .. . .. .. .. . . .. . 71
Laços for aninhados .. ....... .. .. .. . .. . .. .... .. .. .. .. . ..... . . .. . ... . .. .. 72
O programa que imprime um cartão de natal . . . ..................... .. . . . 73
Xll T1'einnmento em Linguagem C++

O laço while .. . .. . ... . .. . ..... . .. .. . ... . . ..... . .. .. .. . .. . ..... ..... .. ... . 76


Sintaxe do laço while .. . .. . . .. .. .... .. .. . .. . . .. .. .. . .. . .. .... .. .. .. . .. . . 77
Laços while aninhados . ........ . ...... . .... . ..... .. .. . ..... ...... . ..... 78
O laço do-while .. . . ...................................................... 79
Sintaxe do laço do-while ......... . ............... . ............ .. . . ...... 80
Re,risão ........ . .. .. . .. ....... .. .. ..... .. . ..... . .. .. .. . .. . ..... . .. . .. .. .. 81
Exercícios ................................................................ 82

Capítulo 4 Comandos de Decisão .. ... .. ... ... ... .. ... .. ... ... ... .. .... .. 87
O comando if . .. .. . ..... .. . .. .. . ......... . . .. ..... . ... . .. . . .. ..... . ... . .. 87
Sintaxe do comando if ........ .. . . .. . ......... . .. ..... .. . ..... . .. . ... . .. 88
O programa que conta zeros .. . .. . .. ... ....... . .. . ............ . .. . .. ... . 88
Implementando um algoritmo . .. .. . .... .. .. . . .. .. . ...... .... . .. .. . .. .. .. 89
O comando if-else ................................................. . ...... 90
Sintaxe do comando if-else ............................................. 91
O programa que conta zeros modificados ...... . .. . ............ . .. . ...... 92
Um tabuleiro de xadrez .. . .. . .. .. . .. .. . .. . .. . ...... . .. .. .... .. .. . . . .. .. . 92
O jogo de cara ou coroa ................................................. 94
Desenhando linhas ................ ... ............. . .............. .. .... 96
Comandos if aninhados ...... . .................. .. ..................... 97
Usando operadores lógicos ............................................. 101
Os comandos break e continue .. . .. . ..... . ..... . ..... .. .. . .. .. . . .. . .. . .. . 102
O comando continue .. .. .... . .. . ...... . ..... .... ..... . ........ .. .. . .. . 104
O comando goto . . .. .. .. . .. . .. . .. . ... . .. . .. . ........ . .. . .. .. . .. . .. .. . .. . 105
O comando switch ............... . ............ " ......................... 106
Sintaxe do comando switch ............ . . ... . ................. . .. .. .. . . 106
O programa DIASEMAN.CPP .... ...... . .............. . ............ . .. . 107
O programa CALC.CPP modificado .. .. . .. . .. .. . .. . .. .. . .. . . .. . .. . .. .. . 109
Casos sem break em comandos switch .. . .. . .. . .. .. . .. . . .. . .. . ...... . .. . 110
Revisão . .. . .. .. . .. . .. . .. .. . .. .. . .. . .. . ... . .. . .. . .. . ... . .. . .. . .. . .. . .. . . . 111
Exercícios . . ...... o • o •• o • ••••••••• o • o o ••••••• o • o o • o • o •••••••• o • o •• o • o o o o • 112

Capítulo 5 Funções .................................................... 117


Chamando uma função .. .. ....... . . . . .. . . ... . . .... . . . ..... ........ . . .... 118
Funções simples o • • •• •• •• • •• • •• • •• • ••• • •• • •• • •• • •• • ••• • •• • • • •• • •••••• • ••• 119
Sumário Xlll

O protótipo de funções .................................................. 120


Protótipo externo e local ............................................... 121
Eliminando o protótipo de funções ..................................... 122
Tipos de funções ........................................................ 123
O comando return . . .............. . .................................. .... 123
Limitações do comando return . .. ..... . . ..... . .. .. ..... . ........... .. . . 124
Definição da fw1ção ...... . ........ . .. . ..... .... .. . ... . .. . .. . ........ . .. . 124
Parâmetros da função .................................................... 125
Passagem por valor ...................................................... 126
Funções que não retornam nada: tipo void .. . .............. .. ............. 127
Funções que não recebem nada e não retornam nada .... . ..... . ..... . .. . ... 128
Passando vários argumentos ....... . .. . ........ . .. .. ................. . ... 129
Escrevendo várias funções num mesmo programa . .. .. .. . .. .......... ...... 130
Chamadas a funções usadas como argumento de outras funções ............. 132
O operador unário de referência: & ....................................... 133
Passagem por referência ........ . ...................................... 134
Ordenando uma lista de números ...................................... 136
Referências constantes .. . .. . .. . .. . ...... . . . ......... . .. . .. . ..... . .. . .. . 137
Considerações sobre referências ........................................ 138
Valores default para os argumentos de uma função ........................ 139
Sobrecarga de funções . .... . .. . ............... .. ............. . .. . .. ...... 140
O programa LINHAl.CPP modificado .. . ..... . ..... . .. . ......... . .. . .. . 142
Funções inline . .. . .. .. .. . .. . .. . .. . ... . .. . .. . .. . ........ . .. . .. . ...... . .. . 143
Quando usar inline .. . ..... . . ..... .. ... ... .. . ... . . .. .. .... . . .. .. . . . ... 144
Funções recursivas ...................................................... 145
Como trabalha uma função recursiva? . . .. . .. .. . .. .. . . .. . .. . .. . .. .. .. . . . 146
Jogo da torre de hanoi ........... . ................................. . ... 148
Classes de armazenamento ............................................... 150
A classe auto . .. . .. . .. . .. . .. . .. . ... . .. . .. . .. . .. . ..... . .. .. . . .. .. .. . .. . 151
A classe extern . . .. .. .. . . .. .. . .. . ... . .. . .. . .. . .. . .. . .. . .. . .. . .. .. .. . .. . 152
O operador de escopo: :: . ..... . .. . ..... . .. . .. . .. .. .. . . .. .. . .... .. .. . .. . 153
A palavra-chave extern . .. . .. . .. .. .. . .. . .. . .. . .. .. .. . .. . . . .. . .. .. .. . .. . 154
Retornando de uma função por referência ............................... 154
A classe statk ......................................................... 155
XIV Treinamento em Linguagem C++

Uma função que gera números aleatórios ............................... 156


A classe static extem .. . .. . . .. .. .. . .. .. .. . . .. .. . .. . .. . . .. ..... . .. .. . ... 158
Classe de armazenamento de fw1ções ................................... 160
A classe register ...................................................... 160
Observações técnicas ........ . .. . ...... . ..... . ......... . ........... .... 162
O pré-proce.ssador . . .. .. ........ . .. .. . .. .. . . . .. . .. .. . .. .. . ..... . .. .. . .. .. 162
A diretiva #define ...... . .. ... ...... . ..... .... .. . ... . .. . . . ..... .. .. . .. . 163
Macros ......................... . ............... .. .................... 165
O uso de parênteses em macros .............. . ......................... 167
Definindo macros usando outras macros .. . ............... . . .. .......... 168
Macros em várias linhas ............................................... 169
Macros versus funções inline ..... . .. . .. . ..... . .. .. .. . .. .. .... . .. . .. . .. . 169
A diretiva #undef ..................................................... 172
A diretiva #include ................................................... 172
Arquivos de inclusão . . .. . .. . .. .. . .. .. . .. . .. .. . .. . ... . . .. . .. . .. .. .. . .. . 173
Compilação condicional ...... . .. . ........... . ............... . ..... .. . . 174
As diretivas #if, #ifdef, #ifndef, #elif, #else e #endif ..................... 175
O operador defined .. .. . .. . .... . ... . .. . .. . ..... . ... . .. . .... . .. .. .. . .. . 177
A diretiva #error .......... . .. . ........................................ 177
Re,,isão ................................................................. 177
Exercícios . . .. . ...... . ..... . .. . ............ . .. . .. ... . . .. . .. . .. . .......... 180

Capítulo 6 Matrizes ................................................... 188


Declaração da matriz .. .. . .. . .. . .. . .. .. .. . .. . ......... . ..... . .... .. .. . .. . 190
Referendando os elementos da matriz ..................................... 191
Matrizes de outros tipos de elementos ..................................... 191
Um número desconhecido de elementos ......................... . .. . .. . .. . 193
Checando limites . . .. .. .. . ..... . .. .. . .. .. . .. . .. .. . .. . .. .. . .. . .. . .. .. . .. .. 194
Inicializando matrizes .. .... .. .. . . . ... . .. . .. . .. . ..... .. .. . .. . . . ...... . .. . 195
Ma trizes de mais de uma dimensão . . .. . ... . . .. .. . . . ... . .. . .. . .... .. .. . .. . 197
Inicializando matrizes de duas dimensões ................ . ................ 202
Inicializando matrizes de três dimensões .. . .. . .. . .. .. .. . .. . .. . .... .. .. . .. . 205
Ma trizes como argumentos de funções .. .. . .. .... .. .. . ..... . .. .... .. . .. .. . 206
As matrizes são passadas para funções por referência .... . ........ . ... .. . 208
Sumário XV

Ordenando os valores de uma matriz . ... . . ..... . . ...... ....... . .. .. .. . .. . 208


A ordenação bolha .. .. . .. . . .. .. .. . .. .. .. . . .... .. . .. .. . .. .... .. .. .. . ... 210
Matrizes de duas dimensões como argumento de fw1ções .... . .... . ........ . 211
Strings ........... . ...................................... . ............... 214
Strings constantes .............. . ...... . ..... . ......... .. ..... ......... 215
Strings variáveis ........................ . . .. . .. .. . .. . . ..... . .. .. . ... . . 216
A função getsO ........ . . . .. . ...... . ..... .... .. . ... . .... . ..... .. .. . .. . 217
Inicializando strings ................................................... 218
Aritmética com endereços .................... . ......................... 219
Outras funções de manipulação de strings . . ............... . . ... . . ....... 220
A função strlen() .. .. .. . ..... . .. .. . .. .. . .. . .. . .. .. . . .. . ..... . .. .. .. . .. . 221
A função strcat() ...... . ..... .. . . .. .. .. . ..... . .. .. . .. . . ............ . .. . 222
A função strcmp() ........................ .. . . .. . ... . .. . . .. . .. . .. ...... 223
A função strcpy() ........... . .. . ............... . .. .. ....... . ......... . 226
As funções strncat(), strncmp(), strncpy() . . .. .... .. . .. .. . .. . .. . .. . .. . .. . 227
Uma matriz de strings ........ . . . ............ . ......... . ........... .. . . 227
Revisão ........ . .. .. . . ........ .. .. . .. .. .. . ..... . .. .. . .. .. . ..... . .. .... . . 229
Exercícios ............................................................... 230

Capítulo 7 Estruturas . .. ......... .. .... ... ... .... .. . .... ... .. ... ... .. .. . 237
Criando novos tipos de dados com struct . .................. . .. . .. . ...... . . 238
Definindo a estru tura ... . . ..... . .. . ... . . .. ..... . ... . . .. .. . .. .. . . .. .. .. . .. 239
Declarando uma variável do tipo definido ... . .. . . .. . . ..... . .... ........... 240
Acessando os membros da estrutura .. .. .. . .. . ..... . .. . .. . .. .. .... .. .. . .. . 241
Combinando declarações ........ ......... ............. ................... 241
Inicializando estruturas .................. ....... . ........ . ...... . ...... . . 242
Atribuições entre estruturas ....... . ...... . ........ . .. .... ............ . .. . 243
Operações entre estruturas . ..... . .. . . .. .. . .. . .. .. . .. . .. .. . .. . .... .. . .. .. . 243
Estruturas aninhadas .... . .. . .. . .. . ... . .. . .. . ........ . .. . .. . .. . ...... . .. . 244
Inicializando estruturas aninhadas . . ... . .. . .. . .. . .. . ... . .. . .... . .. .. .. . .. . 245
Passando estruturas para funções ............ ..... ....... .... ........ . .... 246
Passando estruturas para funções por referência .... .. .. . .. . .. . .. . ..... . .. . 248
Funções que retornam uma estrutura . . .. .. . .. .... . .. .. . .. .. . .. .... .. . .. .. . 249
Ma trizes de estruturas 9 t I • t I t t I ' t I I t ' • ' I • t I t • I t t I I t t I I t r ' t ' t t I I ' I t I I I I I I t 251
XVI Treinamento em Linguagem C++

Declarando a matriz de estruturas ........ .... . .. .. .. . .............. . .. . 255


Acessando membros da matriz de estruturas ... .. . .. .. .. . . .. . . .. .. . .. .. . 256
As funções atoi() e atof() ................. . ......... . ..... . ............... 256
A função exit() .......................................................... 257
Estruturas e classes ............ . .. . ............ . ......... . ............ .. . 257
Tipos de dados enumerados: enum . .. . .. . . .. . .. . .. .. .. . .. . . .............. 258
Uniões .. . .. . ..... . ...... . .. . .. . ...... . ..... .... .. . ... . .. . .. . ......... . . . 259
O operador sizeof ..................................................... 262
U11iões anôrlimas ....... .. . .. ............... . .......................... 263
O operador de endereços: & ... . . . ....... . . . ............. . . ... ......... 265
Uniões de estruturas .. . ..... . .. .. . .. .. . .. . .. . .. .. . . .. . ......... . .. . ... 267
A ROM BIOS .. . .. . ............... . .. .. . . ..... . .. .. .. . .. .. . . ..... .. ..... 268
Conhecendo a biblioteca da ROM BIOS . .... . .. .. .. . .. .. ...... ..... . .... 269
Acessando a ROM BIOS ...... ......................................... 269
Os principais registradores do 8086 . . .. . . .. . .. . .. .. . .. .. . .. . .. . . .. . ... . . 270
Número de interrupções ...... . .. . ................................. .. .. 271
A função C++ int86() e o arquivo dos.h ....... . . ......... .. ............. 272
Descobrindo o tamanho da memória principal .. . .. .... .. . . .. .. . .. . .. . .. . 273
Limpando a tela ............. . ................ . . . ..................... 274
Montando o tamanho do cursor ........................................ 276
Fazendo o cursor desaparecer ..... . ..... . .. . ............... . ..... .... .. 279
Revisão ........ . .. .. . . ...... . .. . .. . ... . ........ .. .. . .. .. ........ . ... .. . . 281
Exercícios . . .. ..... . ..... .. . .. .. . .. . ... . . .. .. . .. . .. . ... . .. . .. . .. . .. . .. . . . 283

Apêndice - Tabela ASCII ... .. ........ . ...... ... ........ ... ..... . . . ..... 292
,
PREFACIO

O curso completo está dividido em dois volumes. O Módulo 1 abrange os


Capítulos 1 a 7 e o Módulo 2, os Capítulos 8 a 13. Este livro foi planejado para
um curso completo de programação em linguagem C++. O estudante deve ter
conhecimentos básicos de sistema operacional nos equipamentos da família
IBM-PC, XT, ATou PS/2.
O objetivo principal é o de apresentar a linguagem C++ de maneira
simples e clara e mostrar como C++ pode ser usada para a criação de programas
sérios. Os exemplos expostos não estão relacionados a nenhum assunto especí-
fico e podem ser facilmente adaptados a qualquer área de aplicação.
O livro apresenta uma organização didática dos temas abordados e
pode ser adotado em cursos de computação de escolas técnicas ou universida-
des. Ao aluno interessado é dada a oportunidade de criar novos programas e
desenvolver novas idéias a partir das apresentadas.
É certamente possível aprender C++ sem conhecer a linguagem C. Esse
livro foi planejado para o ensino da linguagem C++ como linguagem indepen-
dente. Você pode aprender C++ mesmo como primeira linguagem de progra-
mação. Entretanto seus conceitos e sua sintaxe não são tão fáceis como os de
uma linguagem como BASIC ou PASCAL, e os programadores iniciantes podem
sentir alguma dificuldade.
Os exemplos deste livro foram processados utilizando o compilador
TURBO C++ da Borland ou o compilador C++ 7.0 da Microsoft para computa-
dores IBM-PC e sistema operacional MS-DOS versão 6.0.

XVII
Página em branco
,.,
UMA VISAO GERAL

CLASSES E OBJETOS

A idéia fundamental de linguagens orientadas ao objeto é a possibilidade de


combinar num único registro campos que conterão dados e campos que são
funções para operar os campos de dados do registro. Uma unidade assim
definida é chamada classe.
Uma classe é considerada um tipo de dado como os tipos que existem
predefinidos em compiladores de diversas linguagens de programação.
Como exemplo, considere o tipo int que é predefinido em C e C++.
Podemos declarar quantas variáveis do tipo int forem necessárias ao programa.
De modo similar, podemos declarar quantas variáveis quisermos de uma classe
já definida.
Uma variável de uma classe é chamada objeto e conterá campos de
dados e funções.
Definir uma classe não cria nenhum objeto, do mesmo modo que a
existência do tipo int não cria nenhuma variável.

XIX
XX Treinamento em Linguagem C++

As funções de um objeto são chamadas funções-membro ou métodos


e, de modo geral, são o único meio de acesso aos campos de dados também
chamados variáveis de instância.

ENCAPSULAR E ESCONDER

Se o programa necessita atribuir um valor a alguma variável de instância, deve


chamar uma função-membro que recebe o valor como argumento e faz a
alteração. Não podemos acessar variáveis de instância diretamente.
Desta forma, os campos de dados estarão escondidos para nós, o que
previne alterações acidentais. Dizemos então que os campos de dados e suas
funções estão encapsulados (de cápsula) numa única entidade.
As palavras encapsular e esconder são termos técnicos da definição de
linguagens orientadas ao objeto.
Se alguma modificação ocorrer em variáveis de instância de um certo
objeto, sabemos exatamente quais funções interagiram com elas: são as funções-
membro do objeto. Nenhuma outra função pode acessar esses dados. Isso
simplifica a escrita, manutenção e alteração de programas.
Um programa em C++ consiste em um conjunto de objetos que se
comunicam por meio de chamadas às funções-membro.
A frase "chamar uma função-membro de um objeto" pode ser dita como
"enviar uma mensagem a um objeto".

HERANÇA

A programação orientada ao objeto oferece uma maneira de relacionar classes


umas com as outras por meio de hierarquias.
No nosso dia-a-dia, esse processo está presente quando dividimos
classes em subclasses, mantendo-se o princípio de que cada subclasse herda as
Umn visão geral XXT

características da classe da qual foi derivada. Por exemplo: a classe de animais


é dividida nas subclasses mamíferos, aves, peixes etc. Uma das características da
classe animais é a reprodução. Todas as suas subclasses têm essa característica.
Além das caracterís ticas herdadas, cad a subclasse tem suas caracterís-
ticas particulares.

CLASSE BASE
~
características
A B

características características características


A A B A B c
B E F
c D F G

CLASSES DERIVADAS

Em programação orientada ao objeto, o conceito de subclasse ou


processo de classes derivadas é chamado HERANÇA.
Em C++, a classe de origem é chamada classe-base e as classes que
compartilham as características de uma classe-base e têm outras características
adicionais são chamadas classes derivadas.
Uma classe-base representa os elementos comuns a um grupo de
classes derivadas.
Você poderia pensar em herança como algo semelhante ao uso de
funções para simplificar tarefas tradicionais. Você escreve uma função quando
identifica que várias secções diferentes de um programa, em parte, executam a

mesma coisa.
Em C++, você define uma classe-base quando identifica características
comuns em um grupo de classes derivadas.
XXJJ Treinamento em Linguagem C++

Da mesma forma que você pode criar uma biblioteca de funções úteis
a diversos programas, pode formar uma biblioteca de classes que poderão vir
a ser o núcleo de muitos programas.
O uso de uma biblioteca de classes oferece uma grande vantagem sobre
o uso de uma biblioteca de funções: o programador pode criar classes derivadas
de classes-base de biblioteca. Isto significa que, sem alterar a classe-base, é
possível adicionar a ela características diferentes que a tornarão capaz de
executar exatamente o que desejarmos.
Uma classe que é derivada de uma classe-base pode, por sua vez, ser
a classe-base de outra classe.
O uso de classes derivadas aumenta a eficiência da programação pela
não-necessidade da criação de códigos repetitivos. A uma função de biblioteca
não podemos adicionar outras implementações a não ser que ela seja reescrita
ou que tenhamos seu código-fonte para alterá-la e recompilá-la.
A facilidade com que classes existentes podem ser reutilizadas sem
serem alteradas é um dos maiores benefícios oferecidos por linguagens orien-
tadas ao objeto.

POLIMORFISMO ESOBRECARGA

O sentido da palavra polimorfismo é o do uso de um único nome para definir


várias formas distintas.
Em C++, chamamos de polimorfismo a criação de uma família de
funções que compartilham do mesmo nome, mas cada uma tem código inde-
pendente.
O resultado da ação de cada uma das funções da família é o mesmo. A
maneira de atingir esse resultado é distinta. Como exemplo, suponhamos que
desejemos calcular o salário líquido de todos os funcionários de uma empresa.
Nessa empresa há horistas, mensalistas, os que ganham por comissão etc.
Criamos um conjunto de funções em que cada uma tem um método
diferente de calcular o salário. Quando a função é chamada, C++ saberá
identificar qual é a função com o código adequado ao contexto.
Uma visão geral XXlll

A sobrecarga é um tipo particular de polimorfismo. Como exemplo,


tomemos o operador aritmético+. Em C++, usamos esse operador para somar
números inteiros ou para somar números reais:
5 + 2
3.4 + 5.8

O computador executa operações completamente diferentes para somar


números inteiros e números reais. A utilização de um mesmo símbolo para a
execução de operações distintas é chamada sobrecarga. Em C++, além das
sobrecargas embutidas na linguagem, podemos definir outras com capacidades
novas.
Por exemplo, podemos definir a seguinte operação nova para o símbolo +:
"ABC" + "DEF " "ABCDEF "

O polimorfismo e a sobrecarga são habilidades únicas em linguagens


orientadas ao objeto.

,
CE UM SUBCONJUNTO DE C+ +

C++ é uma linguagem derivada da linguagem C. O conjunto de instruções que


fazem parte da linguagem C também é parte de C++.
Os elementos principais que foram adicionados à linguagem C para dar
origem a C++ consistem nas classes, nos objetos e na idéia de programação
orientada ao objeto.
Se você já sabe programar em C, conhece a maior parte da sintaxe de
C++ e tem pouco a aprender.
C++ é rica em recursos que atendem às limitações impostas pelas
linguagens procedurais.
Página em branco
Capítulo 1
,
CONCEITOS BASICOS

,
A ESTRUTURA BASICA DE UM PROGRAMA EM C+ +

A unidade fundamental de programas C++ são as funções. Um programa C++


consiste em uma ou várias funções.

FORMA GERAL DAS FUNÇOES C+ +

Os elementos básicos de toda função C++ são os seguintes:


tipo nome ()

{
i nstrução_ l i

i nstrução_2 i

instrução_n i

1
2 Treinamento em Li11guagem C++ Cap. 1

O PRIMEIRO PROGRAMA

Vamos começar com um programa muito simples:


#include <i ostream . h>

void ma in ()
(
cout << 11
Prime ir o Programa 11
;

Você pode digitar este programa e gravá-lo em disco com o nome


PrimP.CPP. O sufixo .CPP indica programa-fonte em C plus plus.

NOME DAS FUNÇOES

Este programa compõe-se de uma única função chamada main. O nome de uma
função pode ser qualquer um, com exceção de main, reservado para a função
que inicia a execução do programa.
Em todo programa C++, deve existir uma única função chamada main.
A função main marca o ponto de partida do programa. Se um programa for
constituído de uma única função, esta será main. O programa termina quando
for encerrada a execução da função main.

O TIPO void

A função main particular de nosso programa é do tipo void. O tipo void indica
que a função não tem valor de retorno, ou seja, não retoma nada. Os tipos de
funções serão abordados em detalhes no capítulo de funções.
Cap. 1 Conceitos básicos 3

CHAVES

Toda função C++ deve começar com uma chave de abertura de bloco I e deve
terminar com uma chave de fechamento de bloco }. As chaves delimitam o corpo
da função.

ESPAÇOS EM BRANCO

Você pode inserir espaços em branco e tabulações e pular linhas à vontade em


seus programas. O compilador ignora esses caracteres. Você pode escrever
várias instruções em uma única linha, separadas por qualquer número de
espaços ou tabulações, ou pode escrever uma instrução em várias linhas. Não
existe um estilo obrigatório para a escrita de programas C++.
O nosso primeiro programa poderia ser escrito da seguinte forma:
#include <iostream.h>

v o i d main() {
cout <<
"Primeiro Programa "

'
}

A sintaxe anterior não é recomendada, pois esse estilo causa sérios


problemas de legibilidade.
Algumas exceções no uso de espaços, tabulações e linhas em branco
devem ser consideradas: cadeias de caracteres constantes como "Primeiro
Programa" não podem ser separadas em diversas linhas; nomes de funções,
operadores e comandos da linguagem não podem ser separados. Diretivas do
pré-processador como #include não podem ser escritas em diversas linhas.
4 Treinamento em Li11guagem C++ Cap. 1

INSTRUÇOES DE PROGRAMA

O nosso primeiro programa contém uma única instrução:


cout << '' Primeiro Programa'' ;

Essa instrução imprime a frase entre aspas duplas na tela.


Toda instrução C++ termina em um ponto-e-vírgula(;). O ponto-e-vír-
gula é parte crucial da sintaxe da linguagem e facilmente pode ser esquecido
por programadores distraídos, o que acarretaria a apresentação de um erro de
compilação.
Uma função pode ter qualquer número de instruções. As instruções
devem ser escritas entre as chaves que delimitam o corpo da função e são
executadas na ordem em que as escrevemos.

IMPRIMINDO USANDO cout

cout (pronuncia-se "C out") é um objeto de uma classe de I/0 (leitura e


impressão) predefinida em C++. A descrição completa do uso de cout requer
um entendimento maior sobre classes, objetos e sobrecarga de operadores. Esses
assuntos serão discutidos detalhadamente mais adiante.
Neste ponto, daremos apenas uma idéia breve do seu funcionamento.
C++ fornece uma biblioteca de funções e classes conhecida como
"streams". Elas contêm os elementos necessários para a execução de operações
de leitura e impressão (I/0). O objeto cout está associado à saída padrão
(geralmente o vídeo).
O operador<<, chamado "operador de inserção", conecta a mensagem
a ser impressa à cout.
As definições e declarações necessárias para o uso de "streams" estão
contidas no arquivo "iostream.h" instalado no diretório INCLUDE pelo seu
compilador.
Cap. 1 Conceitos básicos 5

,
O PRE-PROCESSADOR C+ +

A primeira linha de nosso programa


#include <i os tream. h>

não é uma instrução C++ e sim uma diretiva do pré-processador C++.


O pré-processador C++ é um programa que examina o programa-fonte
em C++ e executa nele certas modificações com base em instruções chamadas
diretivas. Toda diretiva é iniciada pelo símbolo # e seu texto deve ser escrito
em uma única linha. Se o texto for muito grande, pode-se terminar a linha com
a barra invertida "\" e continuar em outra linha.
Diretivas do pré-processador não fazem parte da linguagem C++; elas
servem para auxiliar no desenvolvimento do programa-fonte.

A DIRETIVA #include

A diretiva #indude provoca a inclusão de outro arquivo em nosso programa-


fonte. Na verdade, o compilador substitui a diretiva #include de nosso progra-
ma pelo conteúdo do arquivo indicado antes de o programa ser compilado.
Usar a diretiva #indude é similar a usar o comando de um processador
de textos que inclui um texto gravado em disco no texto que estamos editando.
A primeira linha do nosso programa
#include <i ostream . h>

solicita que o compilador inclua o arquivo iostream.h em nosso programa antes


de compilá-lo.
Além do u so dos sinais de< e>, a diretiva #include aceita uma segunda
sintaxe:
#inc lude "iostream . h ''

Quando usamos os sinais de< e>, o arquivo é procurado somente no


diretório INCLUDE. Quando usamos aspas duplas, o arquivo é procurado primei-
ramente no diretório atual e depois, se não for encontrado, no diretório INCLUDE.
6 Treinamento em Li11guagem C++ Cap. 1

,.,
ARQUIVOS DE INCLUSAO

Os arquivos de inclusão (também chamados arquivos de cabeçalho) são textos


escritos em caracteres ASCII normais. Em geral, eles contêm definições e
declarações necessárias para que o compilador reconheça vários identificadores
da linguagem C++.
Você pode verificar o conteúdo desses arquivos utilizando o comando
type do DOS.
Geralmente, os arquivos de inclusão têm um nome terminado com o
sufixo ".H" (de header ou cabeçalho) e estão gravados no diretório INCLUDE.

O ARQUIVO iostream.h

O arquivo iostream.h é um exemplo de arquivo de inclusão. Ele contém


declarações necessárias ao uso do objeto cout e do operador de inserção <<.
Sem essas declarações/ o compilador não reconhece cout e <<.
O arquivo iostream.h inclui ainda um objeto para recuperar dados
digitados no teclado e também outras definições básicas de I/0 (impressão e
leitura) necessárias a todos os programas que fizerem uso da saída padrão
(vídeo) e da entrada padrão (teclado).

EXECUTANDO O PRIMEIRO PROGRAMA

O nosso primeiro programa, quando executado, irá imprimir na tela:


Prime i ro Programa

Se você executar o nosso primeiro programa três vezes seguidas, obterá


a seguinte saída:
Primeiro ProgramaPrimeiro ProgramaPrimeiro Programa
Cap. 1 Conceitos básicos 7

Note que o objeto cout não imprime numa nova linha automaticamente.
A impressão é colocada na posição atual do cursor. Se desejar, você deve inserir
um caractere de nova linha explicitamente.
O caractere de nova linha não pode ser inserido diretamente pelo teclado.
Por que não usar a tecla [ENTER]?
Porque, se você pressionar a tecla [ENTER] em alguma posição na frase
que deve ser impressa, o processador de textos que edita o seu programa-fonte
abandonará a linha atual e passará para uma nova linha, deixando a linha
anterior inacabada, e o objeto cout não o tomará como parte da impressão.

,
CODIGOS ESPECIAIS

Além da tecla [ENTER], vários outros caracteres não podem ser digitados do
teclado para dentro do nosso programa. Esses caracteres que não podem ser
obtidos diretamente do teclado são codificados em C++ por meio da combinação
do sinal \ (barra invertida) com outros caracteres.
A tabela a seguir mostra esses códigos.

CÓDIGOS ESPECIAIS SIGNIFICADO


\n Nova linha (CR+LF)
\t Tab
\b Retrocesso
\f Salta página de formulário
\a Beep- Toca o alto-falante
\r CR - Cursor para o início da linha
\\ \ - Barra invertida
\0 Null-Zero
\' ' - Aspa simples
\" " - Aspa dupla
\xdd Representação hexadecimal
8 Treinamento em Li11guagem C++ Cap. 1

IMPRIMINDO NUMA NOVA LINHA

Vamos alterar o nosso exemplo para que a frase seja impressa numa nova linha
toda vez que o programa for executado. Para isso, é necessário inserir um código
de nova linha no início da frase a ser impressa. Códigos especiais podem ser
colocados em qualquer lugar dentro de uma cadeia de caracteres.
#include <ios tream . h>
ma in (}
{

c out << " \ nPrime i r o p r ograma";


}

,
CONSTANTES NUMERICAS

Uma constante tem valor fixo e inalterável. Números constantes em C++ podem
ser escritos nas seguintes bases numéricas:

DECIMAL Escrevemos um número em decimal de forma pura e


simples, como a que estamos acostumados.
Exemplos: 2345, 501 88.
Observe que números em decimal não podem estar entre
aspas.

HEXADECIMAL Os números escritos na base 16 devem ser precedidos de Ox.


Exemplo: Ox41, Oxlafb Ox54c2. 1

OCTAL Os números escritos na base 8 devem ser precedidos de um


zero na frente.
Exemplo: 041, 0101 0754.
Cap. 1 Conceitos básicos 9

CARACTERE A numeração caractere só está definida para números entre


O e 255. Isto significa que a forma caractere é definida para
números que caibam em um único byte. Caracteres
constantes são escritos entre aspas simples.
Exemplo: O número decimal 65 pode ser escrito como'A'.
Outros exemplos: '5', 'a', 'w', '\n', '\t'.

Observação: Note que um zero na frente de um número é avaliado como


representação octal. Ou seja, escrever 10 não é a mesma coisa
que escrever 010. O número 010 é o número 8 em decimal.

CADEIA DE CARACTERES CONSTANTE

A expressão "Primeiro programa" é um exemplo de cadeia de caracteres


constante. A linguagem C++ reconhece uma cadeia de caracteres constante
quando delimitada por aspas duplas, como mostrado na expressão anterior.

ASPAS SIMPLES OU ASPAS DUPLAS

Algumas linguagens de programação permitem o uso de aspas simples ou


duplas indistintamente. Em C++, as aspas simples servem para representar um
único caractere ASCII com um valor numérico entre Oe 255 e as aspas duplas,
para representar cadeias de caracteres.

IMPRIMINDO OUTROS TIPOS DE DADOS

O próximo exemplo mostra como imprimir diferentes tipos de dados utilizando


cout.
10 Treinamento em Linguagem C++ Cap. 1

#include <ios t ream.h>


void ma in ()
{
cout << '' Venu s esta a '' << 67 << "milhoes de milhas''
<< \n << '' do sol'';
1 1

Note que utilizamos o operador << repetidamente na instrução. Este


uso é perfeitamente correto. O programa envia primeiramente a cadeia "Venus
esta a " para cout, então envia o número 67, e em seguida a cadeia "milhoes
de milhas", o caractere de nova linha '\n' e finalmente a cadeia "do sol".
Vamos agora escrever um programa com mais de uma instrução:
#include <iostream.h>
void ma in ()
{

c out << '' A letra '' << j 1 1


;

cout << '' pronuncia-se '' << '' jota" << I


. I ,
'
}

Observe que 'j' é delimitado por aspas simples, enquanto "jota" é


delimitado por aspas duplas. Isto indica ao compilador como diferenciar um
caractere de uma cadeia de caracteres.
Note também que a saída é escrita em duas linhas de programa, o que
não constitui duas linhas impressas de texto. Se você desejar imprimir um
caractere de nova linha, deve inseri-lo explicitamente.

,
VARlAVEIS

As variáveis são o aspecto fundamental de qualquer linguagem de computador.


Uma variável em C++ é um espaço de memória reservado para arma-
zenar um certo tipo de dado e tendo um nome para referenciar o seu conteúdo.
Cap. 1 Conceitos básicos 11

O espaço de memória ocupado por uma variável pode ser compartilhado


por diferentes valores segundo certas circunstâncias. Em outras palavras, uma
variável é um espaço de memória que pode conter, a cada tempo, valores diferentes.
Para explicar o uso de variáveis, vamos escrever um programa que cria
duas variáveis:
#inc l ude <ios tream.h>
vo id ma in ()
{

int numl;

num1=44;
c o ut << '' \nO prime iro nóme ro é '' << numl ;

in t num2;

num2 =88;
cout << " \nO segundo nómero é " << num2 ;

Se você executar este programa, obterá a seguinte saída:


O pr i meiro número é 44
O segundo núme r o é 88

Este programa cria primeiramente a variável numl, imprime o valor


atribuído a ela como parte de uma frase, para depois criar a variável num2,
atribuir 88 a ela e imprimir seu conteúdo.

DECLARAÇÕES DE VARIÁVEIS

As instruções
int numl;
int num2;
12 Treinamento em Linguagem C++ Cap. 1

são exemplos de declaração de variáveis, isto é, apresentam um tipo int e um


nome para acessar seu conteúdo.
Uma declaração de variável é uma instrução para reservar uma quan-
tidade de memória apropriada a fim de armazenar o tipo especificado, nesse
caso int, e indicar que seu conteúdo será referenciado pelo nome dado a ela.

Uma declaração de variável consiste no nome de um tipo, seguido


do nome da variável, seguido de ponto-e-vírgula.

Em C++, todas as variáveis devem ser declaradas. As variáveis devem


ser declaradas antes de serem usadas no programa. Uma variável pode ser
declarada em qualquer lugar do programa.

C++ não funciona se você não declarar suas variáveis. As variáveis podem ser
declaradas em qualquer lugar do programa.

Se você tiver mais de uma variável do mesmo tipo, poderá declará-las


de uma única vez, separando seus nomes por vírgulas.
int aviao , foguete , he licoptero;

,
TIPOS DE VARIAVEIS

O tipo de uma variável informa a quantidade de memória, em bytes, que a


variável ocupará e a forma como um valor deverá ser armazenado e interpretado.

Tipo de variável diz respeito ao tamanho de memória e à forma de armazenamento.

Em C++, existem cinco tipos básicos de variáveis. Nos computadores


de ambiente MS-DOS, a tabela seguinte é válida:
Cap. 1 Conceítos básicos 13

TIPO BIT BYTES ESCALA


char 8 1 -128 a 127
int 16 2 -32768 a 32767
float 32 4 3.4E-38 a 3.4E+38
double 64 8 1.7E-308 a 1.7E+308
void o o nenhum valor

Com exceção de void, os tipos de dados básicos podem ser acompa-


nhados por modificadores na declaração de variáveis. Os modificadores de tipo
oferecidos por C++ são:
l ong
short
uns i gned

Um modificador de tipo pode ser utilizado sem que seja especificado


o tipo da variável. Quando isso é feito, o compilador assume, por default, que
o tipo é int.
Os modificadores podem ser utilizados com os tipos e as escalas
descritos pela tabela a seguir:

TIPO BIT BYTES ESCALA


unsigned char 8 1 O a 255
unsigned 16 2 O a 65535
short 16 2 -32768 a 32767
long 32 4 -2147483648 a 2147483647
unsigned long 32 4 O a 4294967295
long double 80 10 3.4E-4932 a 1.1E+4932

O tipo int tem sempre o tamanho da palavra da máquina, isto é, em


computadores de 16 bits ele terá 16 bits de tamanho.
O tipo short tem tamanho diferente do tipo int em outros computado-
res, geralmente a metade do tamanho de um int. Em MS-DOS, o tipo short é
idêntico ao tipo int e, por esse motivo, é pouco usado.
14 Treinamento em Linguagem C++ Cap. 1

,
INICIALIZANDO VARIAVEIS

E' possível combinar uma declaração de variável com o operador de atribuição


para que a variável tenha um valor inicial ao mesmo tempo de sua declaração;
é o que chamaremos de inicialização de variável. Como exemplo, escreveremos
um programa que cria três variáveis e as inicializa.
#include <ios tream.h>
ma in (}
{

int evento - 5;
char corrida - 'C';
f l oat tempo - 27. 25 ;

cout << " \nO tempo vitorioso na eliminatoria "


<< corrida << " \nda competição " << evento
<< " fo i " << tempo << I

I •
1

A saída será:
O tempo vitorioso na eliminatoria C
da competição 5 foi 27 . 25 .

Este programa utiliza os três tipos de variáveis mais comuns: int, char
e float.

Inicializar uma variável significa atribuir um valor a ela na mesma


instrução de sua declaração.

VARIÁVEIS PONTO FLUTUANTE (lloat)

Números em ponto flutuante correspondem ao que os matemáticos chamam de


"números reais".
Cap. 1 Conceitos básicos 15

Existem várias maneiras de escrever números em ponto flutuante. A


notação "3.16E7" é um meio de indicar que 3.16 será multiplicado por 10 elevado
à potência 7, isto é, 31600000. Esta indicação chama-se notação científica e é
usada para armazenar números em ponto flutuante na memória do computador.
Assim, valores armazenados em variáveis float são guardados na
memória em duas partes. Estas duas partes são chamadas de mantissa e
expoente. A mantissa é o valor do número e o expoente é a potência que irá
aumentá-lo.
Por exemplo, 12345 é representado por 0.12345E5, onde o número que
segue o (E) é o expoente, e 0.12345 é o valor do número.
Variáveis do tipo float são guardadas em 4 bytes: um para o expoente
e 3 para a mantissa.

3 bytes 1 byte

+ 0.12345 5

sinal fração expoente

Observe que uma variável do tipo long int ocupa o mesmo espaço que
uma variável do tipo float, mas são tipos diferentes, já que a forma de
armazenamento é distinta. Lembre-se: um tipo de variável define um tamanho
e uma forma de armazenamento.
16 Treinamento em Linguagem C++ Cap. 1

O MODIFICADOR unsigned: INTEIROS COM ESEM SINAL

O computador interpreta o bit mais significativo de uma variável como bit de


sinal. O modificador unsigned indica que o tipo associado deve ter seu bit
superior interpretado como outro bit qualquer e não como bit de sinal.
O modificador unsigned é utilizado quando a quantidade representada
é sempre positiva, como, por exemplo, quando indicamos uma quantidade de
alguma coisa (copos, lápis, laranjas etc.).
Observe o programa a seguir:
#inc l ude <ios t ream . h>
ma i n {}
{

unsigned j=65000 i

cout << " \ nVar unsigned - n <<


.
]i

.
int i = ] i

cout << " \nVar i nt - 11 <<


.
~i

A saída será:
Var unsigned - 65 000
Var int - - 536

A razão disto está na maneira pela qual o computador interpreta o bit


15 de uma variável int. Na forma binária, o bit 15 de uma variável do tipo int
positiva é sempre O, e o de uma negativa é sempre 1.
O computador ignora o bit de sinal de uma variável unsigned, tratan-
do-o como um bit a mais para números positivos.
Os números negativos são conhecidos como complementos de dois dos
números positivos, pois a conversão de um número positivo para o seu negativo
Cap. 1 Conceitos básicos 17

é feita por um processo de duas etapas. No momento, você não precisa entender
como é feita essa conversão. No segundo volume deste livro, voltaremos a este
assunto.
Essa explicação vale também para o bit de ordem superior de outros
tipos de variáveis. Por exemplo, o tipo unsigned char tem um tamanho de um
byte e pode armazenar números entre O e 255, enquanto o tipo char armazena
números entre -128 a 127.

,
NOMES DE VARIAVEIS

A escolha de nomes significativos para suas variáveis pode ajudá-lo a entender


o que o programa faz e a prevenir erros.
Você pode usar quantos caracteres quiser para um nome de variável,
com o primeiro sendo obrigatoriamente uma letra ou o caractere de sublinhado.
O nome de uma variável pode conter letras maiúsculas ou minúsculas, dígitos
de O a 9 e o caractere de sublinhado.

Em C++, letras maiúsculas e minúsculas são diferentes.

Os seguintes nomes são distintos:


PESO
Peso
peso
peSo

Em C++, somente os 32 primeiros caracteres são significativos, isto é:


Orcamento_de_ Contabil idade_ de _ 199 2
Orcamento_de _ Conta bil idade _ de_ 1993

são considerados o mesmo nome.


Uma variável não pode ter o mesmo nome de uma palavra-chave de
C++. A tabela a seguir mostra as palavras-chave.
18 Treinamento em Linguagem C++ Cap. 1

PALAVRAS-CHAVE DE C++

asm - far public


auto far register
break float return
case for _saveregs
catch friend _seg

- cdecl goto short


cdecl huge signed
char if sizeof
class inline _ss
const int static
continue interrupt struct

- cs - loadds switch
default long template
do - near this
double near typedef
.
_ds new umon
else operator unsigned
enum _pascal virtual

- es pascal void
_export private volatile
extern protected while
Cap. 1 Conceitos básicos 19

..
MANIPULADORES DE TAMANHO DE CAMPOS NA IMPRESSAO

O objeto cout permite estabelecer o tamanho de um campo para a impressão.


Isto significa que podemos definir o número de colunas que serão ocupadas
por um valor ou texto a ser impresso. Geralmente, a definição de tamanho de
campos é usada para alinhamento e estética de um relatório.
Os manipuladores de tamanho de campos estão definidos no arquivo
"iomanip.h " e são os seguintes:

setw Seleciona o tamanho do próximo campo a ser impresso.

setprecision Define o número de casas decimais a serem impressas para


números em ponto flutuante (float).

setfill Seleciona o caractere que deverá preencher as colunas em


branco de um campo.

,
TAMANHO DE CAMPOS COM NUMEROS INTEIROS

A seguir, mostraremos um programa que não utiliza tamanho de campos e o


mesmo programa com definições de tamanho de campos. Compare a apresen-
tação da saída dos dois programas.
#include <iostream . h>
voi d ma in ()
{

i n t l ap=45 , bor=234 5 ,can=42 0,cad= 8, fit=1 3050;


cout << " \ n \ n\ n";
cout << ' \n ' << "La pi s "<< lap ;
cout << ' \ n << "Borracha "<< bor ;
I

cout << \ n << "Cane tas "<< can ;


I I

cout << 1\ n l << "Cadernos "<< cad;


c out << \n ' << "F i tas
I "<< f it;
}
20 Treinamento em Linguagem C++ Cap. 1

Eis a saída:
Lap is 45
Borracha 2345
Canetas 420
Ca d e r nos 8
Fi t as 13 050

#include <iostream . h>


#include <i omani p . h>
v oid ma in ( )
{

in t l ap = 4 5 1 bor =234 5 1 ca n = 4 20~c a d= 8 ~ f i t = 1 3050 ;


cout << " \n\n \ n ";
cou t << 1\ n l << "Lap i s " << setw (12 ) << lap ;
cout << 1\n l << "Borracha "<< s e t w(1 2 ) << bor;
cout << \n << "Canetas "<< s e t w (1 2 ) << c a n ;
I I

cout << 1\n l << "Ca dernos H<< setw (12) << cad ;
c out << \n << "Fitas
I I 11 << s e tw(12) << fit ;
}

Eis a saída:
Lap i s 45
Bo rracha 2345
Canetas 420
Cadernos 8
Fitas 1 305 0

O próximo exemplo preenche as colunas em branco com o caractere'.'.


#include <i ostream . h >
#includ e <iomani p . h>
void ma i n ()
{
int l ap =45 , bor = 234 5 , can=42 0 ~ c a d= 8 ~ fit=1 30 5 0 ;

cout << '' \n\ n\ n'' ;


Cap. 1 Conceitos básicos 21

cout << set f i ll ( 1 . 1 ) ;


c out << \n << "Lapis
I I ti<< s e tw(12) << lap;
cout << 1\n l << "Borracha 11 << setw(12) << bor ;
cout << \n << "Canetas "<<
I I setw(12) << can ;
cout << \n << "Cade r nos "<<
I I s e tw (12) << cad;
cout << \n << "Fitas
I I <<1t setw(12) << fit;
)

Eis a saída:
Lap i s ... .. ..... 45
Borracha ........ 234 5
Canetas ......... 4 20
Ca dernos ........... 8
Fitas ....... 13050

TAMANHO DE CAMPOS COM PONTOS FLUTUANTES

Além do tamanho em colunas a ser ocupado por um número ponto flutuante,


pode-se definir o número de casas decimais a serem impressas para obter
precisão e arredondamento. Veja um exemplo:
#inc l ude <i os t ream.h>
#inc l ude <iomanip . h >
void ma in ()
{

float lap=4 . 875 ~ bor=234 . 5 4 2 1 can=42 . 036 ~ cad=8 .01 fit= 1 3 .0 5 ;

c out << " \n\n \n";


cout << s e tprecision( 2 ) ;
c out << \n << "La pis
I I "<< s e tw (12) << l ap;
c out << \n << "Borracha 11 << s e tw( 12 ) << b o r;
I I

cout << \n << "Canetas "<< setw (12) << can ;


I I

cout << \n << "Cadernos << setw (12) << cad;


I I 11

cout << \n << "Fit a s


I I << setw (12) << fi t;
lt

}
22 Treinamento em Linguagem C++ Cap. 1

Eis a saída:
Lapis 4 . 88
Borracha 234 . 54
Canetas 42 . 04
Cadernos 8 . 00
Fitas 13 . 05

TAMANHO DE CAMPOS COM CADEIAS DE CARACTERES

O manipulador setw justifica campos numéricos e cadeias de caracteres à direita


no campo de impressão definido.
#include <iostream . h>
#include <iomanip . h>
void ma in ()
{
c o ut << '' \n\n\n '';
cout << "OBJETO '' << setw{ 12) << "CODIGO'' << \n
1 1
;

cout << \n << "Lapis


I I
"<< setw(12) << " WQR " ;
cout << \n << "Borracha "<< setw(12) << "ASO" ;
I I

cout << \n << "Canetas "<< se t w{12) << "KPX";


I I

cout << \n << "Cadernos "<< setw(12) << "FJ I";


I I

cout << \n << "Fitas


I I
"<< setw{12) << "TYE" ;
}

Eis a saída:
OBJETO CO DIGO
Lapis WQR
Borracha ASO
Canetas KPX
Cadernos FJI
Fitas TYE

Observação: Se o tamanho do campo especificado em setw for menor que o


tamanho mínimo necessário para impriinir o valor associado, a impressão
utilizará o número necessário de colunas, ignorando o tamanho do campo.
Cap. 1 Conceitos básicos 23

,
MANIPULADORES DE BASES NUMERICAS

O objeto cout permite-nos estabelecer a base numérica na qual desejamos ver


.
1mpresso '
um numero.
Os manipuladores de bases numéricas estão definidos no arquivo
"iostream.h" e são os seguintes:

dec A impressão do próximo campo é apresentada em decimal (modo default).


hex A impressão do próximo campo é apresentada em hexadecimal.
oct A impressão do próximo campo é apresentada em octal.

#include <iostream . h>


void ma in ()
{

int n =65 ;
cout << ' \n ' << ''Hexadecimal '' << hex << n ;
cout << , \n , << "Oc tal " << oct << n ;
cout << ' \n ' << "Decimal " << dec << n ;
}

Eis a saída:
Hexadecima l 4 1
Oc tal 101
Decimal 65

,
IMPRIMINDO CARACTERES GRAFICOS

Como você provavelmente sabe, todo caractere (letra, dígito, caractere de pontua-
ção etc.) é representado no computador por um número. O código ASCII dispõe
de números de Oa 127 (decimal) abrangendo letras, dígitos de O a 9, caracteres de
pontuação e caracteres de controle como salto de linha, tabulação etc.
24 Treinamento em Linguagem C++ Cap. 1

Os computadores IBM-PC usam 128 caracteres adicionais, com códigos


de 128 a 255, que consistem em símbolos de línguas estrangeiras e caracteres
gráficos.
Já mostramos como imprimir caracteres ASCII usando o objeto cout.
Os caracteres gráficos e outros não-padrões requerem outra maneira de escrita
para serem impressos. A forma de representar um caractere de código acima
de 127 é:
\ xdd

onde dd representa o código do caractere na base hexadecimal. Observe que


\xdd é um caractere e pode ser contido por uma cadeia de caracteres entre aspas
duplas.
Neste livro, usaremos esse formato para impressão de qualquer carac-
tere gráfico.
O programa a seguir imprime um carro e uma caminhonete. Observe
a listagem:
#include <i ostream.h>
ma in {}
{

cout << " \n\n ";


cout << " \n \ xDC\ x DC\xDB\xDB\xDB\xDB\xDC\x DC" ;
cout << " \n \xDFO \ xDF\xDF\xDF \ xDFO\xDF '';

cout << • \n \n " ;


cout << '' \n \xDC \ xDC\xDB \xDB\xDB\xDB\xDB\xDB\xDB '';
cout << '' \n \xDFO\xDF\xDF\xDF\xDF\xDFOO\ xDF '';

c out << " \n\n n;

)
Cap. 1 Conceitos básicos 25

A saída será:
Carro

Cami nhão

O próximo exemplo desenha uma moldura na tela:


#include <i ostr e am.h>
rnain (}
{

cout << H\n\n ";

c out << '' \n\ xC9\ xCD\xBB'';


cout << " \n\ x BA \ xBA '';
cout << '' \n\xCB\xCD\ x BC '' ;

cout << H \n\n H;

A saída será:
26 Treinamento em Linguagem C++ Cap. 1

Os códigos dos caracteres são os seguintes:

C9 CD BB

fF

--

C8 CD BC

""
REVISA O

1. Todo programa em C++ deve ter uma função chamada main(), que é a
primeira função a ser executada. O programa termina sua execução quando
é encontrada a chave que fecha o corpo da função main().
2. O pré-processador é uma linguagem para o compilador C++. Suas instru-
ções são chamadas diretivas.
3. A diretiva #include causa a inclusão de outro arquivo em nosso programa-
fonte.
4. Arquivos de inclusão são textos escritos em caracteres ASCII normais.
S. O arquivo iostream.h contém as definições básicas de impressão em vídeo
e leitura de teclado.
Cap. 1 Conceitos básicos 27

6. O identificador cout é um objeto predefinido em C++ e corresponde à saída


padrão (vídeo).
7. O operador<< conecta a frase que queremos imprimir à cout.
8. Os caracteres que não podem ser obtidos diretamente do teclado para
dentro do programa são codificados em C++ por meio da combinação do
sinal \ (barra invertida) com outros caracteres, conforme a tabela de códigos
..
especiaiS.
9. Números em C++ podem ser escritos em C++ em decimal, hexadecimal,
octal ou formato caractere.
10. Uma declaração de variável consiste no nome de um tipo, seguido do nome
da variável seguido de ponto-e-vírgula.
11. Todas as variáveis devem ser declaradas antes de ser usadas. C++ não
funciona se você não declarar suas variáveis.
12. As variáveis podem ser declaradas em qualquer lugar do programa.

13. O tipo de uma variável define seu tamanho de memória em bytes e a forma
como um valor deve ser armazenado e recuperado.
14. Os cinco tipos básicos de variáveis em C++ são: char, int, float, double e
void.
15. Os modificadores de tipo são utilizados para alterar o tamanho de um tipo
de variável ou para alterar a interpretação do seu bit mais significativo.
16. Os três modificadores de tipo em C++ são: long, short e unsigned.

17. Nomes de variáveis devem começar com uma letra ou o caractere de


sublinhado. O nome de uma variável pode conter letras maiúsculas ou
minúsculas, dígitos de O a 9 e o caractere de sublinhado.
18. Em C++, somente os 32 primeiros caracteres de um nome de variável são
significativos.
19. Em C++, letras maiúsculas e minúsculas são diferentes.
28 Treinamento em Linguagem C++ Cap. 1

,
EXERCICIOS

1. Um dos alunos preparou o seguinte programa e apresentou-o para ser


avaliado. Ajude-o.
#in c l ude < iostre a m.h>
void lYia i n ()
{

cout << Existem 56 semanas no ano ;


}

2. Qual será a impressão obtida por cada uma das seguintes instruções?
Assuma que elas fazem parte de um programa completo.
a) cout << "\n\tBom Dia ! Shirley.";

b) cout << "Você já tomou café ?\n";

c) cout << "\n\nA solução não existe ! \nNão i nsista";

d) cout << "Duas\tl i nhas\tde\tsaída\nou\tuma?";

e) cout << "um" << 1


\n 1
<< "dois" << 1
\n 1
<< "tres";

3. Qual é a saída do seguinte programa?


#in c l ude < ios t r e a m.h>
void ma in ()
{

cout << '' \n\t\ '' Primeiro programa \ '' '';


}

4. Qual é a saída do programa a seguir?


# include <iostream.h>
voi d ma in ()
{

cout << ' \n ' << ' \t ' << '\''' <<
" Prime i r o progr ama";
cou t << ' \ " ' ;
}
Cap. 1 Conceitos básicos 29

5. Identifique o tipo das seguintes constantes:


a) '\r'

b) 2130

c) -123

d) 33.28

e) Ox42

f) 0101

g) 2.0e30

h) '\xdc'

i) '\"'

j) '\ \'
k) 'F'

1) o
m) '\0'

n) "F"
o) -4567.89

6. O que é uma variável em C++?


7. Um tipo de variável em C++ define:
a) uma variável armazenada em hexadecimal;
b) o tamanho de memória que a variável ocupará;

c) uma variável em binário;


d) a base a ser usada para armazenar uma variável;

e) a forma de armazenamento de um valor na variável.


30 Treinamento em Linguagem C++ Cap. 1

8. Em que partes do programa é possível declarar variáveis em C++?


9. Quais dos seguintes nomes são válidos para variáveis em C++?
a) 3ab
b) _sim
c) n -a-o
d) OOFIM

e) int
f) A123

g) x**x
h)- -A
i) y-2

j) OOFIM
k) \meu
1) *y2
10. Quais das seguintes instruções são corretas?
a) int a;
b) float b;
c) double float c;
d) unsigned char d;
e) unsigned e;
f) long float f;

g) long g;
11. O tipo float ocupa o mesmo espaço que ___ variáveis do tipo char.
Cap. 1 Conceitos básicos 31

12. Verdadeiro ou Falso: tipos de variáveis long podem conceber números não
maiores que o dobro da maior variável do tipo int.
13. Qual o trecho de programa que inicializa a variável x?
a) int Xi x=5i

b) int x=5 i

c) int x,y=5i

d) X=Y i

14. Arquivos de inclusão são:


a) bibliotecas;
b) compiladores;
c) arquivos em ASCII;
d) linkeditores.
15. Arquivos de inclusão servem para:
a) auxiliar o compilador a compilar;
b) auxiliar o programador a elaborar o fonte;
c) executar instruções;
d) incluir programas.
16. A diretiva #include é:
a) uma instrução C++;
b) uma instrução de linguagens orientadas ao objeto;
c) uma instrução do pré-processador;
d) um objeto.
17. Diretivas do pré-processador são executadas pelo:
a) compilador;
b) microprocessador;
32 Treinamento em Linguagem C++ Cap. 1

c) linkeditor;
d) programa.

18. Códigos especiais servem para:


a) codificar senhas;
b) nomear arquivos escondidos;
c) substituir caracteres que não podem ser digitados no teclado;
d) desenvolver programas codificados.

19. Qual é a diferença no uso de aspas simples e aspas duplas em C++?

20. Quais instruções são corretas?

a) cout

<< "Primeiro Programa " i


b) cout <

< " Prime iro Programa" i

c) cout << " Primeiro

Programa " i

d) cout

<<

" Primeiro Programa"



I

21. Reescreva o programa que desenha uma moldura na tela para que ele
desenhe uma moldura similar, mas com quatro caracteres de largura e
quatro caracteres de altura. Use o caractere 11, de código BA hexa, para
complementar a moldura.
Cap. 1 Conceitos básicos 33

22. Escreva um programa que contenha uma única instrução e imprima na tela:
um
dois
tres

23. Escreva um programa que imprima na tela:


Programação orientada ao objeto .
Linguagem C plus plus .

a) com uma única instrução;


b) com três instruções;
c) dentro de uma moldura.
Capítulo 2

OPERADORES

C++ é uma linguagem rica em operadores, em torno de 50. Alguns são mais
usados que outros, como é o caso do operador de atribuição e dos operadores
aritméticos que executam operações aritméticas .

...
OPERADOR DE ATRIBUIÇAO: =

Em C++, o sinal de igual não tem a interpretação dada em matemática.


Representa a atribuição da expressão à sua direita à variável à sua esquerda.
Por exemplo:
X = 2QJ 00;

atribui o valor 2000 à variável de nome x. A ação é executada da direita para a


esquerda.
Toda expressão C++ tem um valor. É simples entender que
5 + 2

tem o valor 7.
Talvez não seja tão simples você compreender que
X = 3

34
Cap. 2 Operadores 35

tem o valor 3. Uma expressão de atribuição tem o valor atribuído. Por esse
motivo, podemos escrever

e, lembrando que atribuições são executadas da direita para a esquerda, a


expressão anterior pode ser escrita
y = ( x = 3)

e y terá valor 3.
Em C++, expressões desse tipo são chamadas de atribuições múltiplas.

,
OPERADORES ARITMETICOS: + - *I %

C++ oferece cinco operadores aritméticos binários (que operam sobre dois
operandos) e um operador aritmético unário (que opera sobre um operando).
São eles:
Binários
+ Soma
Subtração
* Multiplicação
I Divisão
% Módulo

Unário
Menos unário
Estes operadores representam as operações aritméticas básicas de soma,
subtração, divisão, multiplicação e módulo.
O operador módulo opera somente com operandos inteiros e dá como
resultado o resto da divisão do inteiro à sua esquerda pelo inteiro à sua direita.
36 Treinamento em Linguagem C++ Cap. 2

Por exemplo,
17%5

tem o valor 2, pois, quando dividimos 17 por 5, restam 2.

"
PRECEDENCIA

Operadores têm uma regra de precedência e de associatividade que determina


exatamente como a expressão é avaliada. Se
int x = 5, y = 3, z = 1, n;

na expressão
n = z + y * x;

o valor 16 será atribuído à variável n.


O operador* tem precedência maior que a do operador+; isto faz com
que a operação de multiplicação seja executada antes da soma.
Por outro lado, podemos usar parênteses para mudar a ordem de
avaliação. As expressões entre parênteses são avaliadas primeiro. Considere a
-
expressao:
n = (z + y) * x ;

agora n conterá o valor 20.


Verifique a expressão
X - y + 5

Os operadores+ e- têm a mesma precedência e a regra de associativi-


dade é da "esquerda para a direita", o que indica que a operação é executada
da esquerda para a direita. Na expressão anterior, y será subtraído de x antes
da execução da operação de soma.
Os operadores*, I e % têm a mesma precedência e associatividade da
"esquerda para a direita".
Cap. 2 Operadores 37

A multiplicação, a divisão e o módulo têm precedência sobre a soma e a subtração.

,
O OPERADOR MENOS UNARIO: -

O operador menos unário é usado somente para indicar a troca do sinal


algébrico do valor. Pode também ser pensado como o operador que multiplica
seu operando por -1. Por exemplo:
X - -8;
x - -x;

Depois destas duas instruções, o conteúdo de x será 8.


Não existe em C++ o operador+ unário, portanto escrever "x = +8" está
errado.

,..,
LENDO COM cin E O OPERADOR DE EXTRAÇAO > >

O objeto cin (pronuncia-se "C in") manipula toda entrada do teclado por meio
do operador de extração >> que conecta a entrada de dados à variável que a
conterá. As definições necessárias ao uso de cin e >> estão no arquivo "ios-
tream.h". Veja um exemplo:
#include <iostream . h>
void ma in ()
{
cout << '' \nDigite a sua idade em anos : " ;
int anos;

cin >> anos ;

cout << '' \nA sua idade em dias é: " << (anos * 365);
}
38 Treinamento em Linguagem C++ Cap. 2

A execução do programa é a seguinte:


C: \>IDADE
Digite a sua idade em anos : 4
A sua idade em d ias é : 1460

O objeto cin faz com que o programa aguarde que você digite a sua
idade e pressione a tecla [ENTER] para finalizar a entrada.
O operador >> toma o valor do objeto "streams" à sua esquerda e o
coloca na variável à sua direita.

,
MULTIPLAS ENTRADAS COM cin

#include <iostream . h>


vo i d ma in ()
{
cout << '' \nDigite as notas das 4 provas : '' ;
fl oat pl,p2,p3,p4;

cin >> pl >> p2 >> p3 >> p 4;

float media = (pl+p2+p3+p4)/4 .0;


, .
cout << '' \nMEDIA: " << med 1a;
)

Eis a saída:
C: \>MEDIA
Dig it e as notas das 4 provas : 5.5 7 . 5 3 .0 6.0
MÉDIA : 5 . 5

O operador>> pode apresentar-se diversas vezes numa instrução com


a finalidade de permitir a introdução de d iversos valores ao mesmo tempo.
Quando utilizamos múltiplos valores de entrada, a primeira variável mencio-
nada conterá o primeiro valor digitado, e as outras serão sempre preenchidas
na ordem em que aparecerem.
Cap. 2 Operadores 39

Múltiplas entradas são digitadas separadas por um espaço em branco.


O objeto cin entende um espaço em branco como término de uma entrada e o
[ENTER] como finalizador geral.

,
O PROGRAMA QUE ADIVINHA A SOMA DE CINCO NUMERO$

O programa a seguir usa um algoritmo interessante para adivinhar a soma de


cinco números. Você digita um número qualquer e o computador informa o
resultado da soma dos cinco números dos quais o primeiro você já forneceu.
Você digitao segundo número e o computador mostra o terceiro, você digitao
quarto e o computador mostra o quinto.
Veja a listagem:
#include <iostream. h>
voi d ma in ()
{
cout << " \ nDig it e um núme r o de at é 4 algari smos : " ;
int x,r;
c~n >> x ;
'

r = 19998 + x ;
cout << " \ nO resul tado da soma é : " << r ;
cout < < " \nDigit e o segundo núme r o : ";
c l' n >> x;
cout << '' \nO me u número é : '' << 9999 - x ;
cout << '' \nDigite o quarto número : '';
.
c ~ n >> x ;

cout << '' \nO meu número é : '' < < 9999 - x ;
}

Eis um exemplo de sua execução:


Digite um número de até 4 algarismos : 198
O resultado da soma é : 20196
Digite o segundo número : 1234
O meu núme r o é: 876 5
Dig ite o quarto número : 22 33
40 Treinamento em Linguagem C++ Cap. 2

O meu n úmero é : 77 66

Observe que 198 + 1234 + 8765 + 2233 + 7766 = 20196.

,
MANIPULADORES DE BASES NUMERICAS: dec hex oct

O objeto cin permite estabelecer a base numérica na qual desejamos a entrada


de um número.
Os manipuladores de bases numéricas são os mesmos que utilizamos
com o objeto cout.
Eis um exemplo:
#include <iostream . h>
void ma i n ()
{
int n ;
c out << " \nDi gi te um número em Hexadecima l " ;
cin >> hex >> n ;
cout << " \nO número em Decimal é " << dec << n ;
}

O QUALIFICADOR const

A p alavra-ch ave const assegu ra que a variável associad a não será alter ada em
todo o programa. Esse q ualifícador é indicado para declarar valores constantes.
Veja um exemplo de seu uso:
#include <iostream. h>
void ma in ()
{

c o nst char b i p = ' \a ' ;


con s t double p i = 3 . 141592 ;
Cap. 2 Operadores 41


double ralo ;

cout << " \nDigite o raio da esfera : " ;


. .
c1n >> ralo ;

d ouble area= 4 .0 * pi * ra l o * raio;


.

cout << bip << bip;


cout << 11
\nArea da esfera = 11
<< area ;
)

Observe que as variáveis associadas ao qualificador const devem ser


inicializadas .

...
CONVERSOES DE TIPOS E OOPERADOR DE MOLDE

Algumas vezes, precisamos forçar o compilador a avaliar um valor ou uma


expressão com um tipo particular. Por exemplo, suponhamos que desejemos
imprimir o valor numérico de um caractere da tabela ASCII. Para isso, usaremos
um novo operador chamado operador de molde, que consiste em escrever o
nome do tipo desejado e em seguida o valor ou a expressão a ser avaliada entre
parênteses.
char ch -
-
I A' .
I

cout << int (ch); 11 Impri me 6 5

A expressão int(ch) resulta ch convertido para o tipo int antes de ser


utilizado. Observe que o molde produz o valor de ch no tipo apropriado sem
contudo modificar o tipo da variável ch. Isto significa que ch continua sendo
do tipo char.
Você pode utilizar outra sintaxe para o molde:
(int) ch em vez de i nt(ch)

A sintaxe (int)ch é a única aceita pela linguagem C.


42 Treinamento em Linguagem C++ Cap. 2

AS FUNÇÕES getche() Egetch()

Em algumas situações, o objeto cin não se adapta perfeitamente, pois você


precisa pressionar a tecla [ENTER] toda vez que desejar terminar a leitura.
A biblioteca de funções C++ oferece duas funções que lêem um
caractere no instante em que é digitado, sem esperar [ENTER].
#include <iostream . h>
#include <conio . h>
voi d ma in ()
{
char ch ;
cout << '' \ nPres sio ne uma tecla '';

ch = getche() ;

cout << " \ nA t e cla sucessora ASC II é "<< char(ch+l) ;


}

Eis a saída:
Press i one uma tec l a X
A tecla sucessora ASCII é Y

A função getche() retoma o caractere lido do teclado. O valor retornado


de uma função pode ser chamado de valor da função ou resultado da função.
A expressão
ch = getch e();

atribui o valor da função getche à variável ch.


A função getch() é similar a getche(), exceto pelo fato de que o caractere
digitado não é impresso no vídeo. Dizemos que a função getch() não ecoa no
vídeo.
As duas necessitam do arquivo "conio.h" .
Cap. 2 Operadores 43

Experimente executar o exemplo anterior utilizando a função getch()


no lugar de getche().

,
COMENTAR/OS

Comentários podem ser colocados em qualquer lugar do programa e são


tratados pelo compilador como espaços em branco.
Comentários são utilizados para documentar o seu código-fonte.
A seguir, mostraremos um exemplo que contém as duas formas de
comentários permitidas em C++.
!* Este programa mostra o uso da função getche (),
do operador de molde e o uso das duas formas
de escrever comentários em C++ .
*I

#inc l ude <i ostream . h > /1 dire tiva do pré-processador


#include <conio . h> 11 necessário para getche()

11 Iníc io do pr ograma
void ma in ()
{
char ch ; !* declaração de variável * /
cout << " \nPressione uma t e cla ";

ch - getche ( ); 11 solicita uma tecla

cout << " \nA t e cla sucessora ASCII é " << char(ch+l) ;
)
44 Treinamento em Linguagem C++ Cap. 2

SINTAXE

Comentários são delimitados por I* e *I, podem ser escritos em várias linhas,
numa única linha ou na mesma linha de uma instrução C++. Asteriscos dentro
de comentários podem ser colocados livremente. Por exemplo:
!* ** * *********** ** ******** * ** * ********* ************ * *
* Este p rograma mostra o u so da fu nção ge t che( ) , *
* do operador de molde e o uso das duas formas *
* de escrever comentários em C+ +. *
**************************** * *********************** /

Não são permitidos os símbolos de comentários no interior de um


comentário.
I * Estou escrevendo um I * comentário * / il ega l * I

I* Estou escr evendo outro / * come ntário ilegal *I

Os símbolos /* e *I são a única forma de escrever comentários em C.


C++ permite uma segunda sintaxe que é conhecida como "comentários
de linha". Este estilo de comentário começa com duas barras (!I) e termina com
o final da linha. Tudo o que estiver escrito após as duas barras será ignorado
pelo compilador.

OPERADORES DE INCREMENTO ( + +) E DE DECREMENTO (- -)

O operador de incremento (++) é um operador unário que adiciona 1 à variável


operando.
O operador de incremento pode ser usado de duas formas: prefixado
quando aparece antes do nome da variável e pós-fixado quando aparece em
seguida ao nome da variável.
A instrução
x = x + 1; 11 adici ona 1 a x
Cnp. 2 Operadores 45

é equivalente a
++x ; 1/ adici ona 1 a x

que é equivalente a
X++ ; 11 adiciona 1 a x

A diferença entre as operações executadas pelo operador prefixado e


o pós-fixado aparece em instruções que fazem mais do que somente incrementar
a variável operando. Por exemplo:
n - 5;
x - ++n;

cout << ''\ nN= '' << n << '' X= " << x;

A saída será
N=6 X=6

O operador de incremento prefixado incrementa a variável operando


antes de executar a instrução em que ele aparece. Desta forma, n terá seu valor
incrementado de 1 antes de ser atribuído a x.
Observe agora o próximo exemplo:
n = 5;
x = n++ ;
cout << ''\nN= '' << n << " X= " << X;

A saída será
N=6 X=S

O operador de incremento pós-fixado incrementa a variável operando


logo após a execução da instrução em que ele aparece. Desta forma, n é atribuído
a x e depois seu valor é incrementado de 1.
Quando o operador de incremento aparece sozinho numa instrução,
como em
X++ i

não faz diferença o uso prefixado ou pós-fixado.


46 Treinamento em Linguagem C++ Cap. 2

A sintaxe e modo de uso do operador de decremento (--) prefixado e


pós-fixado é idêntica à do operador de incremento, exceto porque a variável é
decrementada de 1.
X = X - 1;

é equivalente a
-- x ;

que é equivalente a
x-- ;

PRECEDÊNCIA

Em C++, os operadores unários têm precedência sobre os operadores binários.


Isto significa que operadores de incremento e decremento têm precedência sobre
os operadores aritméticos. Por exemplo:
x = a * b+ + ;

é equivalente a
x = a * (b++) ;

Não confunda precedência com o modo de operação do operador de


incremento. Na instrução anterior, o resultado da operação de multiplicação de
a por b será atribuído a x e depois b será incrementada.
A precedência informa que a operação pós-fixada ++ será executada
antes da multiplicação. O modo de operar do operador pós-fixado é o de
incrementar a variável operando após a execução da instrução.
Na expressão
x = a * ++b ;

a variável b é incrementada e depois é multiplicada por a e finalmente o


resultado é atribuído a x.
Cap. 2 Operadores 47

cout ENGANANDO VOCE"

Expressões que envolvam quaisquer operadores C++ podem ser utilizadas,


entre parênteses, com cout. Por exemplo, a instrução
cout << (+ +X ) << ' \ n' << (5 *y+4) ;

é completamente correta.
Você pode ser iludido ao tentar imprimir urna mesma variável diversas
vezes usando o operador de incremento ou decremento. Por exemplo:
n = 5;
cout << n << ' \ t '
<< ( n+l } << ' \t '
<< (n++} ;

Isto parece razoável, e você pode pensar que a impressão será:


5 6 7

De fato, em vários sistemas estas linhas funcionarão de acordo, mas


não em todos.
O problema é quando cout toma os valores a serem impressos. Ele pode
avaliar o último valor primeiro, e isto provocaria a seguinte impressão:
6 7 5

o que pareceria loucura.


A mesma situação é encontrada em expressões de atribuição com a mesma
variável aparecendo mais de urna vez. A maneira de avaliar é imprevisível.
Testes elaborados com o compilador Borland C++ versão 3.1 confirmam
que a avaliação é feita da direita para a esquerda. Nos exemplos a seguir,
obtivemos os seguintes resultados:
#include <iostream . h>
void ma in ()
{
int i=3, n;
48 Treinamento em Linguagem C++ Cap. 2

n - i* (i+l) +( ++i ) ;

cout << '' \nn - '' << n ;

n = 24

Agora, executando o mesmo programa com a expressão de atribuição


colocada na instrução cout, obtivemos um resultado diferente:
#include <iostream . h>
void ma in ()
{

int i= 3 , n;

cout << " \nn - " << (n - i * (i +l) + (++i));

n = 16

Alterando o programa para que utilize o operador pós-fixado em vez


do prefixado, obtivemos:
#include <iostream . h >
void ma in ()
{
i nt i= 3 , n ;

n - i* (i+l) +( i ++);

cout << '' \nn - '' << n ;

n - 15
Cap. 2 Operadores 49

#include <i ostream.h>


void ma in ()
{
int i=3 ~ n ;

cout << '' \nn - '' << (n- 1 * (i +l ) + (i+ +)};

n = 15

Expressões de atribuição também dão problemas:


#include <iostream . h>
void ma in ()
(

int i=3~ n;

cout << (i = i+ l } << I\t I


<< (i=i+l} << I\ t I
<< (i=i+ l};

6 5 4

, ,.
OPERADORES ARITMETICOS DE ATRIBUIÇAO: += --- * = I= %=

Estes operadores são binários e combinam as operações aritméticas com atri-


buição. O operando da esquerda é sempre o nome de uma variável e o da direita,
uma expressão qualquer. A operação consiste em atribuir um novo valor à
variável que dependerá do operador e da expressão à direita.
50 Treinamento em Linguagem C++ Cap. 2

Como regra geral, se x é uma variável, exp uma expressão e op um


operador aritmético, então
X op= exp equivale a X - X op (exp )

Exemplos:
• • •
l += 2 i equivale a l -- l + 2;
X *-- y+l ; equivale a X - X * (y+ 1 ) i
t I= 2 . 5 i equivale a t - t I 2.5;
p %= 5 ; equivale a p - p % 5;
d - - 3; equivale a d -- d - 3;

As expressões com estes operadores são mais compactas e normalmente


muito usadas em C++.
Veja um exemplo:
11 medi as . cpp
11 c a lcula a médi a aritmética de 4 notas
#include <iostream.h>
void ma in ()
{

float nota , media = 0 . 0 ;


cout << '' \nDigite a primeira nota : '' ;
cin >> nota;
media += nota;

cout << '' \nDigite a segunda nota : '' ;


cin >> nota ;
media += nota ;

cout << " \nDigite a terceira nota: " ;


c in >> nota ;
media += nota ;

cout << " \nDigite a quarta nota: " ;


c in >> nota ;
media += nota ;
Cap. 2 Operadores 51

media I = 4 .0;
'
cou t << " \nMEDI A: " << me d i a ;
}

OPERADORES RELACIONAIS: > >= < <=


,_
-- .-
Os operadores relacionais fazem comparações. São eles:

> maJ.or

>=maior ou igual

< menor

<= menor ou igual

== igual

! = diferente
Nos próximos capítulos, falaremos sobre laços e comandos de decisão.
Estas construções requerem que o programa pergunte sobre relações entre
variáveis ou expressões. Operadores relacionais são o vocabulário que o pro-
grama usa para fazer essas perguntas.
Em C++, não existe um tipo de variável chamado "booleana", isto é,
que assuma um valor verdadeiro ou falso. O valor zero (O) é falso; qualquer
valor diferente de zero é verdadeiro e é representado pelo inteiro um (1). Assim,
em C++ toda expressão ou variável têm um valor verdadeiro ou falso.
#inc l ude <i os t r e a m.h>
v oid ma in ()
{
int verdadei r o ,fa lso ;

ver dade iro = (1 5 < 2 0) ;


f a l so - (1 5 20) ;
52 Treinamento em Linguagem C++ Cap. 2

cout << '' \ nVerdadeiro " << verdadeiro ;


cout << " \nFa lso " << f also ;
)

A saída será
Verdadeiro 1
Falso IJJ

Note que o operador relaciona! de igualdade é representado por dois


sinais de igual. Um erro comum é o de usar um único sinal de igual como
operador relaciona!. O compilador não avisará que isto é um erro, pois toda
expressão tem um valor que, dependendo do contexto, pode ser avaliado como
verdadeiro ou falso. Este não é um erro de programa e sim um erro de lógica
do programador.
Operadores relacionais avaliam seus operandos como números e o
resultado da operação é um valor lógico 1 para verdadeiro e o valor lógico O
para falso.

J\

PRECEDENCIA

Os operadores relacionais têm precedência menor que a dos operadores arit-


méticos. Isto significa que os operadores aritméticos são avaliados antes dos
relacionais.
#include <ios tream . h>
void ma in ()
{

cout << " \ n" << (4 +1<3 ) ;


cout << " \ n " << ( 2<1 +3) ;
)

A saída será
(jJ

1
Cap. 2 Operadores 53

,
OPERADORES LOGICOS: && II I

Operadores lógicos também fazem comparações. A diferença entre comparações


lógicas e relacionais está na forma como os operadores avaliam seus operandos.
Operandos de operadores lógicos são avaliados como lógicos (O ou 1), e não
, .
como numencos.
C++ oferece três operadores lógicos. São eles:
&& lógico E
li lógico OU
I lógico NÃO

Destes operadores, ! é unário e os outros dois são binários. Os opera-


dores lógicos são geralmente aplicados a expressões relacionais.
Se el e e2 são duas expressões, então:

el && e2 Resulta 1 (verdadeiro) somente se e1 e e2 forem verdadeiras. Em


qualquer outra situação, resulta O (falso).

el I I e2 Resulta O (falso) somente se el e e2 forem falsas. Em qualquer


outra situação, resulta 1 (verdadeiro).

!el Resulta 1 (verdadeiro) somente se el for falsa.

Alguns exemplos:
(di a==7 && mes==6 } // verdadeiro se dia for 7 e mes for 6
(op== 'S' I I op== 's') //verdadeiro se op f or Sou s
( !masculino ) / /verdadeiro s e masculino for 0

Outros exemplos:
! 5 // Lê-se '' não verdadeiro '' ou 0 .
1 II 2
X && y
a < b I I a ==c
a >= 5 && x <= 6*y
54 Treinamento em Linguagem C++ Cap. 2

!x
I , . I
. J
! (a +3 )

,
O OPERADOR CONDICIONAL TERNARIO: '·••
O operador condicional possui uma construção um pouco estranha. E' o único
operador C++ que opera sobre três expressões. Sua sintaxe geral possui a
seguinte construção:
e xp l .
? e xp2 .. e xp3

A expl é avaliada primeiro. Se seu valor for diferente de zero (verda-


deira), a exp2 é avaliada e seu resultado será o valor da expressão condicional
como um todo. Se expl for zero, a exp3 é avaliada e será o valor da expressão
condicional como um todo.
Na expressão
max = (a > b) ? a : b ;

a variável que contém o maior valor numérico entre a e b será atribuída a max.
Outro exemplo:
abs = (x > 0 ) ? x : - x ; // abs é o v a l or abso l uto d e x

A instrução
cout << ( (x%2)? "Impar" : " Par ");

imprime "Impar " se x for um número ímpar, caso contrário imprimirá "Par".
Cap. 2 Operadores 55

I\

TABELA DE PRECEDENCIA DOS OPERADORES

A tabela seguinte apresenta a tabela de precedência dos operadores já discuti-


dos. Os operadores que estão no mesmo bloco têm a mesma precedência e são
executados antes do que vier antes na expressão.

OPERADOR TIPOS

- Menos unário
+ Incremento prefixado ou pós-fixado
-- Decremento prefixado ou pó-fixado
I
• Lógico NÃO
* Multiplicação arihnética
I Divisão aritmética
% Módulo aritmético
+ Mais aritmético
- Menos aritmético
< Menor relaciona}
<= Menor ou igual relaciona!
> Maior relacional
>= Maior ou igual relaciona!
--
-- Igual relaciona}
,_
.- Diferente relaciona!
&& E lógico
II OU lógico
..
?· Condicional
-- Atribuição
*-- Aritmético de atribuição (vezes)
I= Aritmético de atribuição (divide)
0
/o= Aritmético de atribuição (módulo)
+= Aritmético de atribuição (soma)
-- Aritmético de atribuição (menos)
56 Treinamento em Linguagem C++ Cap. 2

~ , ,
OPERADORES: AVALIAÇAO LOGICA OU NUMERICA

Todo operador opera sobre um ou mais operandos e a operação por ele


executada produz um resultado.
Os operandos são avaliados ou como numéricos ou como lógicos,
dependendo do operador. Da mesma forma, o resultado de uma operação pode
ser ou um valor numérico ou um valor lógico.
O modo de avaliação dos operandos e o resultado produzido pelos
operadores aritméticos, relacionais e lógicos estão resumidos na tabela a seguir:

OPERADORES OPERANDOS RESULTADO


Aritméticos Numéricos Numérico
Relacionais Numéricos Lógico
Lógicos Lógicos Lógico

,.,
REVISA O

1. O operador de atribuição tem uma interpretação diferente da matemática.


Representa a atribuição da expressão à sua direita à variável à sua esquerda.
2. Os operadores aritméticos executam operações de soma, subtração, multi-
plicação, divisão e módulo.
3. O identificador cin é um objeto predefinido em C++ e corresponde à entrada
padrão (teclado).
4. O operador >> conecta os valores digitados no teclado (cin) às variáveis
que os conterão.
5. O qualificador const é utilizado para declarar valores constantes.
6. O operador de molde modifica o tipo de uma expressão para um tipo
desejado.
7. As funções getche() e getch() retornam um caractere pressionado no teclado
e necessitam do arquivo conio.h.
Cap. 2 Operadores 57

8. Há duas formas de escrever comentários em C++: entre os sinais de I* e* I


ou numa única linha, precedidos de I I.
9. Os operadores de incremento (++) e de decremento (--) incrementam ou
decrementam a variável operando de 1.
10. Os operadores aritméticos de atribuição(+=,-=,*=, I= e%=) executam uma
operação aritmética e uma atribuição simultaneamente.
11. Os operadores relacionais comparam dois valores indicando se são iguais,
se um é maior que o outro etc. O resultado é um valor lógico verdadeiro
ou falso. Falso é indicado por O e verdadeiro, por 1.
12. Os operadores lógicos E e OU combinam duas expressões lógicas e resultam
um valor lógico. O operador lógico NÃO muda um valor lógico de
verdadeiro para falso e de falso para verdadeiro.
13. O operador condicional opera sobre três expressões. A primeira é avaliada
e, se verdadeira, a expressão toda assume o valor da segunda expressão;
caso contrário, assume o valor da terceira expressão.

,
EXERCICIOS

1. Quais dos seguintes operadores são aritméticos?


a) +;
b) &&;

c) %;
d) <;

e) <<.
2. Uma expressão:
a) geralmente avalia um valor numérico;
b) sempre ocorre fora de qualquer função;
c) deve ser parte de uma instrução;
58 Treinamento em Linguagem C++ Cap. 2

d) indica o estado de emoção do programa;


e) sempre mistura símbolos com números inteiros.
3. Assuma que todas as variáveis são do tipo int e encontre o valor de cada
uma delas:
a) x -- (2+ 1) * 6;

b) y -- (5+ 1) / 2*3;

c) 1 - j = (2+3)/4 ;

d) a -- 3+2 *(b=7 /2 );

e) c -- S+l fll%4/2;

4. Reescreva a seguinte instrução usando operador de incremento.


numero = numero + 1 ;

5. Como será interpretada a expressão " x+++y "?


a) X++ + y

b) X + ++y

Escreva um pequeno programa e verifique a interpretação dada em seu


compilador.
6. Quais são os valores de cada variável nas seguintes expressões?
int a =l , b=2 , c =3, d =4 ;

a) a += b+c;

b) b *= c - d + 2;

c) d !\--
o- a + a + a;

d) d -= c -= b - = a;

e) a += b+ = c+ = 7;
Cap. 2 Operadores 59

7. Os operadores relacionais são usados para:


a) combinar valores;
b) comparar valores;
c) distinguir diferentes tipos de variáveis;
d) trocar variáveis por valores lógicos.
8. Quais das seguintes expressões são corretas?
a) a --
-- I A'

b) a > b

c) a =< b

d) a > = b

e) -a - b

f) -a -- -- b

g) - a --
-- b

h) a -_,. b
i) - 8 5 . 2 > = (X * 45 . 3 + 32 . 34 )

j) a + b + c -x * -y

k) I a I + I b I ! = 16 + I w I

9. Qual é o valor das seguintes expressões?


a) 1 > 2

b) ! ( 1 > 2)

c) 3 --
-- 2

d) ! ( -5 )

e) I '
J
I
,_
.- I '
J
I

f) I '
J
I
., -_ I '
J
I
+ 2

g) I '
J
I
., -_ I '
J
I
--
-- I '
J
I
60 Treinamento em Linguagem C++ Cap. 2

10. Qual é o valor de k?


int k , j= 3 ;
k = j == 3 ;

11. Qual é o valor de y?


f l oat y; int x;

X - 22345 ;
y - float (x) ;

c o ut << y ;

12. Indique o valor de cada uma d as seguintes expressões (consulte a tabela de


precedência dos operadores).
int i =l , j=2 , k =3 , n=2 ;
float x=3 . 3 , y=4.4;
• •
a) l < J + 3
.
b) 2 * l - 7 <= J• - 8
c) -X + y >= 2 .0 * y

d) X y

e) X .1 -- y
• •
f) l + J + k -2 * -k
g) ! (n-j )

h) ! n - j

i) ! x*! x

j) i&&j &&k
k) illj-3&& 0

I) i <j &&2 >=k

m) i<j I l 2>= k
Cap. 2 Operadores 61

n) l• --2
--
I
I
I )•
I
--4
--
I
I
I
I
k--5
--

o) i =2 1 I j ==4 11 k==5

p) X< =S . QJ&&x ! =1. (/)I I i>j

13. Escreva expressões equivalentes sem usar o operador de negação (!).

a) ! (i==j)

b) !(i+ 1 < j - 2)

c) .
I ( ~
• < j && n < m)

d) .I ( ~
• < 1 11 j < 2 && n < 3)

14. Qual é o valor das seguintes expressões?

int a =l , b=2 , c=3 ;


++a/a&& ! b&&c ll b--l l -a+4 * c> ! ! b

15. A expressão seguinte é obscura. Coloque parênteses para tomá-la clara.


a = X < y ? X < Z ? X : Z : y < Z ? y : Zj

16. Escreva uma expressão lógica que resulte 1 se o ano for bissexto e O se o
ano não for bissexto.
Um ano é bissexto se for divisível por 4, mas não por 100. Um ano também
é bissexto se for divisível por 400.
17. Faça um programa que solicite ao usuário o ano e imprima "Ano Bissexto"
ou "Ano Não-Bissexto" conforme o valor da expressão do exercício 15.
Utilize o operador condicional.
18. Escreva um programa que solicite ao usuário a altura e o raio de um cilindro
circular e imprima o volume do cilindro. O volume de um cilindro circular
é calculado por meio da seguinte fórmula:
Vol = 3 . 14159 2 * r aio * raio * altura

19. Num cercado, há vários patos e coelhos. Escreva um programa que solicite
ao usuário o total de cabeças e o total de pés e determine quantos patos e
quantos coelhos encontram-se nesse cercado.
62 Treinamento em Linguagem C++ Cap. 2

20. Dois amigos jogam na loteria toda semana. Escreva um programa que
solicite com quanto cada um entrou em dinheiro e o valor do prêmio que
deve ser rateado em partes diretamente proporcionais às quantias com que
cada um entrou. O programa deve imprimir quanto receberá cada um se
eles ganharem.
21. A importância de 780.000,00 será dividida entre os três primeiros colocados
de um concurso, em partes diretamente proporcionais aos pontos consegui-
dos por eles. Construa um programa que solicite o número de pontos dos
três primeiros colocados e imprima a importância que caberá a cada um.
22. Sabendo que o latão é obtido fundindo-se sete partes de cobre com três
partes de zinco, faça um programa que solicite quantos quilos de latão ele
quer produzir e imprima quantos quilos de cobre e de zinco são necessários.
23. Uma firma contrata um encanador a 20.000,00 por dia. Crie um programa
que solicite o número de dias trabalhados pelo encanador e imprima a
quantia líquida que deverá ser paga, sabendo-se que são descontados 8%
para imposto de renda.
24. (Difícil) Faça um programa que solicite um caractere do teclado por meio
da função getch(); se for uma letra minúscula imprima-a em maiúsculo,
caso contrário imprima o próprio caractere. Use uma expressão condicional.
Capítulo 3

LAÇOS

Laços são comandos da linguagem C++ úteis sempre que uma ou mais instru-
ções devam ser repetidas enquanto uma certa condição estiver sendo satisfeita.
Em C++ existem três estruturas de laços:
for
while
do - while

O LAÇO for

O laço for é geralmente usado quando queremos repetir algo um número fixo
de vezes. Isto significa que utilizamos um laço for quando sabemos de antemão
o número de vezes a repetir.
O exemplo seguinte imprime uma linha de 20 '*' utilizando um laço for
na sua forma mais simples.
// f ordemo.cpp
#include <iostream . h>
void ma in()
{

63
64 Treinamento em Linguagem C++ Cap. 3

int i;
f o r ( i =0 ; i < 2 0 ; i++)
cout << ' * ';
}

SINTAXE DO LAÇO for

A instrução for consiste na palavra-chave for seguida de parênteses que contêm


três expressões separadas por pontos-e-vírgulas. Chamaremos a primeira destas
expressões de inicialização, a segunda de teste e a terceira de incremento.
Qualquer uma das três expressões pode conter qualquer instrução
válida em C++.
Em sua forma mais simples, a inicialização é uma instrução de atribui-
ção (i= O) e é sempre executada uma única vez antes de o laço ser iniciado.
O teste é uma condição avaliada como verdadeira ou falsa e controla
o laço (i < 20). Esta expressão é avaliada toda vez que o laço é iniciado ou
reiniciado. Se verdadeira (dife rente de zero), a instrução do corpo do laço é
executada (cour << '*'). Quando o teste torna-se falso (igual a zero), o laço é
encerrado e o controle passa para a instrução seguinte ao laço.
O incremento geralmente define a maneira pela qual a variável de
controle será alterada cada vez que o laço for repetido (i++). Essa expressão é
executada sempre, imediatamente após a execução do corpo do laço.

Ponto-e-vírgula

Inicialização Teste Incremento

for ( 1 = (/) . 1 <+2(/) . i++ ) +--


cout << , * ' .'
' '
I
Sem
Corpo do laço ponto-e-vírgula

No nosso exemplo, o laço for é executado 20 vezes. N a primeira vez,


a inicialização assegura que i vale zero. Na última vez, i vale 19; a informação
é dada no teste (i<20). Em seguida, i passa a valer 20 e o laço termina. O corpo
do laço não é executado quando i vale 20.
Cnp. 3 Laços 65

Veja outro exemplo:


11 Tabuada6 .cpp
11 Imprime a tabuada do 6
#include <i ostream .h>
#include <iomani p.h>

void ma in ()
{
int i;

.
for(i=1 • J. <= 1Q) • Í++)
' '

cout << '\n' << setw{3 ) << l << setw{5) << (i*6) ;
}

Eis a saída:
1 6
2 12
3 18
4 24
5 30
6 36
7 42
8 48
9 54
1lll 60

Vamos modificar o programa tabuada6.cpp para que imprima a tabua-


da invertida.
11 Tabuada 6.cpp
11 Imp rime a tabuada do 6 invertida
#include <i ostream . h>
#include <iomanip . h>

void ma i n ()
{
66 Treinamento em Linguagem C++ Cap. 3

int i;

for(i =10 . I

l >= 1 . i -- )
I

cout << I \n << setw(3 ) << l. << setw(5 ) << (i *6) ;


I

Eis a saída:
10 6(/J
9 54
8 48
7 42
6 36
5 3(/)
4 24
3 18
2 12
1 6

O próximo exemplo imprime os múltiplos de 3 entre 3 e 100.


11 Hult i pl 3 . cpp
11 Imprime os múltiplos de 3 entre 3 e 1(/JQJ
#include <iostream . h>
vo id ma in ()
{
for( int i =3 ; i <= 1 00 ; i += 3)
cout << \ t << i ; 1 1

VARIÁVEIS DECLARADAS NA INSTRUÇÃO for

Observe a variável i declarada no interior da expressão de inicialização do laço


for do programa anterior.
for( int i =3 ; i <= 100 ; i += 3)

Em C++, geralmente declaramos as variáveis tão próximo quanto


possível do ponto onde elas serão usadas.
Cap. 3 Laços 67

FLEXIBILIDADE DO LAÇO for

Nos exemplos anteriores, utilizamos o laço for na sua forma mais simples. Isto
é, a primeira expressão para inicializar a variável, a segunda para expressar um
limite e a terceira para incrementar ou decrementar a variável.
Entretanto, elas não estão restritas apenas a estas formas. Exemplos de
outras possibilidades são mostrados a seguir.

,
O OPERADOR VIRGULA

Qualquer uma das expressões de um laço for pode conter várias instruções
separadas por vírgulas. A vírgula, neste caso, é um operador C++ que significa
"faça isto e depois isto". Um par de expressões separadas por vírgula é avaliado
da esquerd a para a direita.
11 Mostra o u s o do ope rador v í rgula no l aço for
11 Imprime os n úmeros de 0 a 98 de 2 e m 2
#inc l ude <iostream . h >
void ma in ()
{
.
f or (int i=0 , in t j =0 ; (i+j ) < 100 ; 1++ , j ++ )
c o u t << (i + j ) < < " " ;
}

USANDO CARACTERES

A variável do laço pode ser do tipo char. Veja um exemplo:


#inc l ude <i o s t ream . h>
void ma in ( )
{
for( char c h =' a' ; ch <= ' z '; ch++)
cou t << ''\nO valo r ASCII de '' << c h << '' é ''
<< i nt (ch);
}
68 Treinamento em Linguagem C++ Cap. 3

USANDO CHAMADAS A FUNÇOES

E' possível chamar funções a partir de expressões do laço for.


11 Codif ica a entrada
#inc l ude <i ostr earn. h>
#inc l ude <c onio .h>
void ma in()
{
for(char ch=getch ( } ; ch != 'X' ; ch - get ch( ))
c ou t << char (ch+l ) ;
}

Este exemplo lê caractere a caractere do teclado e imprime o seguinte


da tabela ASCII.

OMITINDO EXPRESSÕES DO LAÇO for

Qualquer uma das três expressões de um laço for pode ser omitida, embora os
pontos-e-vírgulas devam permanecer. Se a expressão de inicialização ou a de
incremento forem omitidas, serão simplesmente desconsideradas. Se a condição
de teste não estiver presente, será considerada permanentemente verdadeira.
11 Codifica a e ntrada
#include <iostream . h>
#include <conio . h>
vo i d ma i n()
{
char c h;

for( ; (ch=getch () ) ! = ' X' ; )


cout << char(ch+l) ;
}

Note que colocamos parênteses extras envolvendo a expressão de


atribuição (ch = getch()). Estes parênteses são realmente necessários, pois a
Cap. 3 Laços 69

precedência de != é maior que a de =; isto significa que, na falta de parênteses,


o teste relacional != seria feito antes da atribuição e a expressão seria equivalente a:
c h = ( ge te h ( ) ! = ' X' }

e ch teria um valor de O ou 1.

UM LAÇO INFINITO

Um laço infinito é aquele que é executado sempre, sem parar. Um laço infinito
sempre tem a expressão de teste verdadeira; um modo de parar sua execução
é desligando o computador.
f or ( ; ; } cout << '' Laço Infini t o '';

OMITINDO O CORPO DO LAÇO for

O corpo do laço pode ser vazio, entretanto o ponto-e-vírgula deve permanecer.


for ( ; (ch=getch()) ! = ' X '; cout << c har(ch+l))

I

Outro exemplo:
f o r( int i= 0 ; i < = 100(/J •
I i - i+l )
.
I

, M

MULTIPLAS INSTRUÇOES NO CORPO DE UM LAÇO for

Se um laço for deve executar várias instruções a cada iteração, elas devem estar
entre chaves.
Sintaxe:
70 Treinamento em Linguagem C++ Cap. 3

------~-'sem ponto-e-vírgula aqui


for(
. - 0 • < 10 • i++) •
~ ~
' '
{
instrução .
'
i nstrução .
'
i nstrução •
'
}

[ sem ponto-e-vírgula aqui

Em C++, um bloco de código é uma série de instruções entre chaves e


é tratado como um grupo de instruções numa unidade executável. Isto significa
que um bloco de código é tratado como sendo ele mesmo uma única instrução.
Veja um exemplo:
// MEDIA. CPP
// Imp rime a média aritmética de 10 notas
#include <iostream . h>
# i nc l ude <iomanip . h>
void ma in ()
{

fl oat soma = 0 . 0;
const int max = 10 ;

cout << setprecis i on(2);

for(int i=0 ; i < max ; i++)


{

cout << "\nNota • << ( i+ 1} << '' - '' ;


float nota ;
cin >> nota ;
soma += nota ;
}

cout << " \nMédia - • << (soma / max ) ;


}
Cap. 3 Laços 71

Em todo lugar onde é possível colocar uma instrução C++, é também


possível inserir um bloco de código. Por exemplo:
li BLOCO . CPP
#include <iostream . h>
vo id ma in ()
{

int i= S ;

{ I I Inicio do bloco

int i =15(/J ;
cout << i ; 11 Imprime 15(/J

} I I Fim do bloco

cout << i; I/ Imp rime 5


}

,
VISIBILIDADE DE VARIAVEIS DE BLOCO

Um aspecto importante dos blocos de código é o de que uma variável declarada


dentro de um bloco não é visível fora dele.
No programa MEDIA. CPP, declaramos a variável nota dentro do bloco.
Esta variável só pode ser acessada pelas instruções do mesmo bloco escritas
após sua declaração.
Se você inserir a instrução
nota = 54.5;

após o corpo do laço for, o compilador emitirá um erro, informando que a


variável nota não existe.
Observ e a variável i do bloco interno no programa BLOCO.CPP. Esta
é uma nova variável com o mesmo nome da variável criada no bloco da função
main (). Ela é criada quando o bloco inicia sua execução e é destruída quando
72 Treinamento em Linguagem C++ Cap. 3

o bloco termina. Assim, a instrução após o fim do bloco utiliza a variável i do


bloco de main O pois a outra não mais existe.

LAÇOS lor ANINHADOS

Quando um laço for faz parte do corpo de outro laço for, dizemos que o laço
interno está aninhado.
Para mostrar esta estrutura, preparamos um programa que imprime a
tabuada do 2 ao 9.
11 Tabuada . cpp
11 I mprime a tabuada do 2 ao 9
# i nc l ude <ios t ream. h>
#include <i omani p . h>
v o i d ma in ()
{
for ( in t k= (lJ ; k< =l ,. k++ )
{

c out << ' \ n , ;


f or( int i= l ,• ~• <= 4 ,• i ++ )
c out << "TABUADA DO " << se t w (3)
<< ( i+4* k +l) << " " .,
cout << ' \ n ' ;
. .
f o r ( ~ - 1 ; ~ <= 9 ,• i ++ }
{
f o r ( in t j= 2 +4* k ; J
. <=5+4 *k ; j++)
.
cout << s etw( 3) << J << x"
"
<< s e tw (3 ) << ~• << " -- "
<< setw( 3) << J. * ~. << " " ,.
cout << ' \n ' ;
)
}
}

A saída do programa tabuada.cpp cabe numa única tela e é a seguinte:


Cap. 3 Laços 73

TABUADA DO 2 TABUADA DO 3 TABUADA DO 4 TABUADA DO 5


2 X 1 - 2 3 X 1 - 3 4 X 1 - 4 5 X 1 - 5
2 X 2 - 4 3 X 2 - 6 4 X 2 - 8 5 X 2 - 10
2 X 3 - 6 3 X 3 - 9 4 X 3 - 12 5 X 3 - 15
2 X 4 -- 8 3 X 4 -- 12 4 X 4 -- 1 6 5 X 4 -- 20
2 X 5 - 10 3 X 5 -- 15 4 X 5 - 20 5 X 5 -- 25
2 X 6 - 12 3 X 6 - 18 4 X 6 - 24 5 X 6 - 30
2 X 7 -- 14 3 X 7 -- 21 4 X 7 -- 28 5 X 7 -- 35
2 X 8 - 16 3 X 8 - 24 4 X 8 - 32 5 X 8 - 40
2 X 9 -- 18 3 X 9 -- 27 4 X 9 -- 36 5 X 9 -- 45
TABUADA DO 6 TABUADA DO 7 TABUADA DO 8 TABUADA DO 9
6 X 1 -- 6 7 X 1 -- 7 8 X 1 -- 8 9 X 1 -- 9
6 X 2 -- 12 7 X 2 -- 14 8 X 2 -- 16 9 X 2 -- 1 8
6 X 3 - 18 7 X 3 - 21 8 X 3 - 24 9 X 3 - 27
6 X 4 - 24 7 X 4 - 28 8 X 4 - 32 9 X 4 -- 36
6 X 5 -- 30 7 X 5 -- 35 8 X 5 -- 40 9 X 5 -- 45
6 X 6 -- 36 7 X 6 -- 42 8 X 6 -- 48 9 X 6 -- 54
6 X 7 - 42 7 X 7 - 49 8 X 7 - 56 9 X 7 - 63
6 X 8 - 48 7 X 8 - 56 8 X 8 - 64 9 X 8 - 72
6 X 9 - 54 7 X 9 - 63 8 X 9 - 72 9 X 9 - 81

O laço for mais externo (da variável k) é executado duas vezes: a


primeira para imprimir o primeiro bloco de tabuadas (de 2 a 5) e a segunda
para imprimir o segundo bloco (de 6 a 9). O segundo laço for imprime os títulos.
Os dois laços mais internos imprimem a tabuada propriamente dita.

O PROGRAMA QUE IMPRIME UM CARTAO DE NATAL

Agora que já aprendemos a trabalhar com o laço for, vamos escrever um


programa mais elaborado que imprimirá um cartão de natal. O programa usa
todos os conceitos vistos até este ponto e vale a pena você tentar entendê-lo.
//Na ta l.cpp
// I mprime uma árvore de natal
#inc l ude <iostream . h >
#incl ude <conio . h>
74 Treinamento em Linguagem C++ Cap. 3

void ma in ()
{

cout << '' \nSinal interno direito : '';


char sd = getch e ();
cout << " \nSinal interno esquerdo : " .
'
char se = g etche();
cout << " \n\n ";
for ( int i=0 ; i < 4 ; i++)
{
for(int k=l ; k < 5 ; k+ +)
{
f or( i nt j=l;j<=40 - {2*i+k) ; j++) cout << ' ' .
'
cout << I i I I

f or ( j= l • J• < (2 *i+k ) . j ++) cout << se;


' . '
for( j=l . J < (2 *i+k ) . j ++) cout << sd ;
' '
cout << "\\ \n ";
}
}

for(i=0 ; i < 2 ; i++)


{

f or(int j=0;j < 38 ; ]+ +) cout << ' ' .


'
c ou t < < " I I \ n " ;
}

cout << ' \n ';


for(int j=0 ; j < 35 ; j++) cout << ' ' .
'
cout << '' FELIZ NATAL\n '';
f or(j=0 ; j < 3 1 ; j ++ ) cout << ' ' .
'
cout << " E Ulv:! PROSPERO 1994! \n";

getch() ;
}
Cnp. 3 Laços 75

Eis a saída:
C : \>NATAL

Sina l i nterno d i re ito : >


S i na l interno esquerdo: <

1\
/ <> \
/<<>>\
/<<<>>> \
/<<>>\
!<<<>>>\
!<<<<>>>>\
! <<<<< >>>>>\
!<<<<>>>> \
! <<<<<>>>>>\
/ <<<<<<>>>>>> \
/ <<<<<<<>>>>>>> \
!<<<<<<>>>>>>\
! <<<<<<<>>>>>>>\
! <<<<<<<<>>>>>>>>\
/<< <<<<<<<>>>>>>>>>\

FELIZ NATAL
E UM PROS PERO 199 4!

Observe que a variável j não existe fora do bloco onde ela foi declarada.
Assim, é necessário declará-la novamente em outros blocos que desejam utilizá-la.
76 Treinamento em Linguagem C++ Cap. 3

O LAÇO while

A segunda estrutura de laço em C++ é o laço while. À primeira vista, o laço


while parece simples se comparado ao laço for; utiliza os mesmos elementos,
mas eles são distribuídos de maneira diferente no programa.
Um laço while é apropriado em situações em que o laço pode ser
terminado inesperadamente, por condições desenvolvidas dentro do laço.
Veja o exemplo:
11 Contachar . cpp
11 Conta caracteres de uma frase

#include <iostream . h>


#include <conio . h >
void ma i n ()
{

int cont=0;

vvhile(getche() != ' \r ' )


cont++ ;

cout << '' \nO nómero d e caracteres é '' << cont;

O programa solicita a digitação de uma frase, cada caractere digitado


é contado e acumulado na variável cont até que a tecla [ENTER) seja pressio-
nada. O programa imprime o total de caracteres da frase.
O laço while termina quando a tecla [ENTER) é pressionada. Neste
caso, não conhecemos de antemão o número de iterações que serão feitas. Em
situações semelhantes, o laço while é mais apropriado.
Cap. 3 Laços 77

SINTAXE DO LAÇO while

A instrução while consiste na palavra-chave while seguida de uma expressão


de teste entre parênteses. Se a expressão de teste for verdadeira, o laço while é
executado uma vez e a expressão de teste é avaliada novamente. Este ciclo de
teste e execução é repetido até que a expressão de teste se torne falsa (igual a zero),
então o laço termina e o controle do programa passa para a linha seguinte ao laço.
O corpo de um while pode ter uma única instrução terminada por
ponto-e-vírgula, várias instruções entre chaves ou ainda nenhuma instrução
mantendo o ponto-e-vírgula.
Em geral, um laço while pode substituir um laço for da seguinte forma
dentro de um programa:
Expressão de Inicializa ção ;

while ( Expressão de Teste )


{

Expressão de Incremento;

Como exemplo, tomemos o programa fordemo.cpp para reescrevê-lo


usando um laço while em vez do laço for original.
// fordemo.cpp
#include <iostream . h>
vo id ma in ()
{
int i= 0; I !Iniciali zação

while ( i < 20 ) I /Teste


{
cout << I * f •

. '
l ++; // I ncremento
}
}
78 Treinamento em Linguagem C++ Cap. 3

Em situações em que o número de iterações é conhecido, como no


programa fordemo.cpp, o laço for é a escolha mais natural.

LAÇOS while ANINHADOS

Uma das instruções de um bloco de código que compõe o corpo de um laço


while pode ser outro laço while. Considere o seguinte programa que testa a
sua capacidade de adivinhação.
11 Adivinha.cpp
I/ Testa a sua capacidade de ad ivinhar uma l et ra
#include <iostream . h>
#include <stdlib .h> I/ para rand {)
#include <conio . h> I/ para getch {)
void ma in {)
{
char c h =' s' ;
while {ch== ' s')
{
char adiv = rand {) % 26 + ' a ';
int tentativas = 1;
cout << " \n\ nDigite uma letra entre 'a' e 'z' : \n ";
char resp;
while {{ resp=getch{)) ! =adiv)
{
cout << resp ;
cout << '' é i ncorreto . Tent e novament e\n'';
tentativas++ ;
}
cout << '\n' << resp << '' E' CORRETO !!'' ;
cout << "\nVoce acertou em " << tentativas
<< '' tentativas '';
cout << ''\nQuer joga r novamente? (s/n) : '';
ch=getche( );
}
)
Cap. 3 Laços 79

Eis uma execução:


C :\ >ADIVINHA

Digit e uma le tra e ntre 'a' e 'z':


o é i nco rre to . Te nt e novamente
v é incorre to . Te nt e novame nt e
t é i ncorreto . Tente novamen te
e é incorreto . Tente novamente
a é i ncorreto . Te nte novament e
j é i ncorre to . Te nt e novamente

i É CORRETO ! !
Voce acertou em 7 tentativas
Quer jogar no v a mente? (s/n) : n

Na instrução
char a d iv = rand( ) % 2 6 + ' a';

utilizamos uma nova função de biblioteca C++, a função rand (), que necessita
da inclusão do arquivo stdlib.h. Esta função retoma um inteiro aleatório entre
O e 32767.
A expressão "rand()% 26" resulta o resto da divisão do valor de rand()
por 26, que é um número entre O e 25. A este número é somado o caractere 'a'
para gerar uma letra minúscula aleatória.

OLAÇO do-while

A terceira e última estrutura de laço em C++ é o laço do-while. Este laço é


bastante similar ao laço while e é utilizado em situações em que é necessário
executar o corpo do laço uma primeira vez e depois avaliar a expressão de teste
e criar um ciclo repetido.
80 Treinamento em Linguagem C++ Cap. 3

SINTAXE DO LAÇO do-while

do
{

i nstrução;
i ns t rução;

) while (teste ) ; ponto-e-vírgula aqui

A instrução do-while consiste na palavra-chave do seguida de um bloco


de uma ou mais instruções entre chaves e terminada pela palavra-chave while
seguida de uma expressão de teste entre parênteses terminada por ponto-e-vírgula.
Primeiramente, o bloco de código é executado, em seguida a expressão
de teste entre parênteses é avaliada; se verdadeira, o corpo do laço é mais uma
vez executado e a expressão de teste é avaliada novamente. Este ciclo de
execução do bloco e teste é repetido até que a expressão de teste se torne falsa
(igual a zero), então o laço termina e o controle do programa passa para a linha
seguinte ao laço.
Um bom exemplo do uso de um laço do-while é o programa ADIVI-
NHA.CPP escrito anteriormente. Nesse programa, queremos que o usuário
jogue uma primeira vez para depois perguntarmos se ele deseja jogar novamen-
te. Assim, queremos que o corpo do laço seja executado para depois testar a
resposta do usuário. Observe a modificação.
11 Adivinha . cpp
11 Testa a sua capacidade de adivinhar uma letra
#include <iostream . h>
#include <Stdl i b .h> // para r a nd( )
#include <conio .h> // para getch( )
void ma in ()
{

do
{

c har adiv = rand() % 26 + 'a ' ;


i nt tentat i va s = 1 ;
Cap. 3 Laços 81

cout << " \n\ nDigite uma letra entre 'a' e 'z' : \n ";
char r esp;
whil e((resp=getch()) ! =adiv)
{
cout << r esp;
cout << '' é incorre t o. Te nte novamente\n'';
tentativas++ ;
}
,
cout << '\ n ' << resp << '' E CORRETO !!'';
cout << " \nVoce acertou e m " << tentativas
<< '' t e ntativas '';
cout << '' \ nQuer jogar novamente? ( s/n ) : '';

} while( getche( ) == ' s ' ) ;

Nesta versão1 não há necessidade da variável ch.

'"'
REVISA O

1. A possibilidade de repetir ações é uma das razões pelas quais usamos o


computador. Os laços for, while e do-while são as estruturas oferecidas
por C++ para cumprir esta tarefa.
2. Um laço for é utilizado quando conhecemos de antemão o número de
iterações a serem executadas.
3. O operador vírgula permite que qualquer uma das expressões de um laço
for possa conter várias instruções. Um par de instruções separadas por
vírgula é avaliado da esquerda para a direita.
4. O corpo de um laço pode ser formado a partir de uma única instrução ou
de um bloco de múltiplas instruções entre chaves.
82 Treinamento em Linguagem C++ Cap. 3

5. Uma construção agrupada por chaves é chamada de bloco de código e é


tratada como uma única instrução. Em todo lugar onde é possível colocar
uma instrução C++, é também possível inserir um bloco de código.
6. Uma variável declarada dentro de um bloco de código não é visível fora dele.
7. Laços while e do-while são apropriados para situações em que o laço pode
ser terminado inesperadamente por condições desenvolvidas dentro do laço.
8. O corpo de um laço while pode nunca ser executado. Entretanto, o corpo
de um laço do-while é sempre executado pelo menos uma vez.
9. A expressão de teste de um laço while é avaliada antes de o corpo do laço ser
executado, e a de um laço do-while, depois de o corpo do laço ser executado.
10. A função rand() necessita da inclusão do arquivo stdlib.h e retoma um
número inteiro aleatório.
11. Comandos de laços podem fazer parte do corpo de outro laço. Neste caso,
dizemos que laços internos estão aninhados.

,
EXERCICIOS

1. Um laço for de uma única instrução termina com:


a) vírgula;
b) chave de abertura;
c) chave de fechamento;
d) ponto-e-vírgula.
2. Um laço while de uma única instrução termina com:
a) vírgula;
b) chave de abertura;
c) chave de fechamento;
d) ponto-e-vírgula.
Cap. 3 Laços 83

3. Um laço do-while de uma única instrução termina com:


a) vírgula;
b) chave de aberhua;
c) chave de fechamento;
d) ponto-e-vírgula.

4. Um laço for de múltiplas instruções termina com:


a) vírgula;
b) chave de abertura;
c) chave de fechamento;
d) ponto-e-vírgula.

5. Um laço while de múltiplas instruções termina com:


a) vírgula;
b) chave de abertura;
c) chave de fechamento;
d) ponto-e-vírgula.

6. Um laço do-while de múltiplas instruções termina com:


a) vírgula;
b) chave de abertura;

c) chave de fechamento;
d) ponto-e-vírgula.

7. As três expressões que compõem a expressão do laço for são separadas por
-------------------- ·
8. Múltiplas expressões de incremento na expressão do laço for são separadas
por _________________
84 Treinamento em Linguagem C++ Cap. 3

9. Um laço do-while é útil quando seu corpo:


a) nunca é executado;
b) pode nunca ser executado;
c) deve ser executado pelo menos uma vez;
d) termina após a primeira execução.
10. A expressão de inicialização de um laço for:
a) nunca é executada;
b) é executada uma única vez a cada iteração;
c) é executada enquanto o laço não termina;
d) é executada uma vez antes de o laço ser iniciado.
11. Verdadeiro ou Falso: Os dois fragmentos seguintes produzem o mesmo
resultado.
a) f o r ( i=({) ; i< 1 ({) ; i+ +)
f or( j =0 ; j< 10 ; j ++)
cout << i +j ;
b) for ( i=0 , j= 0 ; i<10 ; i++)
for( ; j<10 ; j+ +)
cout << i + j;
12. Qual é o erro deste programa?
11 Soma dos quadrados
#include <iostream.h>
void ma in()
{

for (i nt i =l; i<1 0 ; i++)


{
int soma= Ql;
soma += i *i ;
}

cout << soma;


}
Cap. 3 Laços 85

13. Qual é a saída do programa seguinte?


#include <i ostream . h>
void ma in()
{
fo r (int a =36 ; a>0 ; a / =2)
cout <<a<< ' \t' ;
}

14. Este programa imprime uma letra I bem grande na tela:


# inc l ude <ios t ream .h>
void main()
{
int i = ClJ;
cout << '' \n\niiiiiii\n '';

while ( i < 17)


{
cout << '' III \n '';

~ ++ ;

)
cout << '' I IIIIII\n'';
}

a) modifique o programa para que utilize um laço for no lugar de um laço


while;
b) construa um programa similar que imprima a letra E;
c) responda: neste exemplo, qual dos laços se adapta melhor? Por quê?.
15. Escreva um programa que imprima os caracteres da tabela ASCII de códigos
32 a 255. O programa deve imprimir cada caractere, seu código decimal e
seu código hexadecirnal.
16. Escreva um programa, utilizando um laço while, que leia caracteres do
teclado. Enquanto o usuário não pressionar a tecla ESC de código 27, os
caracteres lidos não são ecoados no vídeo. Se o caractere lido for urna letra
minúscula, o programa a imprime em maiúsculo e, se for qualquer outro
caractere, ele mesmo é impresso. Utilize o operador condicional ternário.
86 Treinamento em Linguagem C++ Cap. 3

17. Elabore um programa que solicite um número inteiro ao usuário e crie um


novo número inteiro com os dígitos em ordem inversa. Por exemplo, uma
execução do programa é:
Digite um número inte i ro : 5382
Seu n úme r o i nver t i d o é : 2 835

18. Escreva um programa que solicite um número entre 3 e 18 e calcule a


probabilidade que esse número tem de sair, jogando-se três dados ao
mesmo tempo. A probabilidade é calculada por meio da seguinte fórmula:
P = ( nl I n2} * 1 (/) QJ • (/)
onde nl é o número de casos em que a soma dos dados é igual ao número
entrado pelo usuário e n2 é o número total de casos possíveis. Por exemplo,
se o número inserido for 6, o programa imprime:
A probabil idade de sa i r 6 é 4 . 63% .

19. O número de combinações de n objetos diferentes, onde r objetos são


escolhidos de cada vez, é dado pela seguinte fórmula:
fatorial de n
· 1 d e r * f ator~a
nCr = f ator~a · 1 de (n-r)

Escreva um programa que calcule o número de combinações de n objetos


tomados r de cada vez. Os valores n e r devem ser solicitados ao usuário.
Capítulo 4
,..
COMANDOS DE DECISAO

Uma das tarefas fundamentais de qualquer programa é decidir o que deve ser
executado a seguir. Os comandos de decisão permitem determinar qual é a ação
a ser tomada com base no resultado de uma expressão condicional. Isto significa
que podemos selecionar entre ações alternativas dependendo de critérios de-
senvolvidos no decorrer da execução do programa.
C++ oferece três comandos de decisão:
i f
if - else
switch

O COMANDO if

O comando if instrui o computador a tomar uma decisão simples.


I I Ifdemo. c pp
#inc l ude <io s t ream.h>
voi d ma in()
{
cout << " \ n Quantos a nos você tem? ";
int anos;

87
88 Treinamento em Linguagem C++ Cap. 4


c1n >> a nos ;

if( anos< 30 )
cout << " \nVocê é muito jovem !";

Se você digitar um número menor que 30, o programa imprimirá "Você


é muito jovem!". Se você digitar um número maior ou igual a 30, o programa
não fará absolutamente nada.

SINTAXE DO COMANDO il

A instrução if consiste na palavra-chave if seguida de uma expressão de teste


entre parênteses. Se a expressão de teste for verdadeira, a instrução é executada;
do contrário, nada é feito.
O corpo de um if pode ter uma única instrução terminada por ponto-
e-vírgula ou várias instruções entre chaves.
if( Expressão de Teste )
{
instrução;
instrução;
}

O PROGRAMA QUE CONTA ZEROS

!/ CONTAZ.cpp
#inc l ude <i ostream.h>
#include <conio . h>
void ma in ()
{
char ch;
int cont= 0 ;
Cap. 4 Comandos de decisão 89

c o ut << " \nDigite uma frase ";

while ( (ch=getche ( )) ! = ' \r ')


i f ( ch:: I ([) I )
{

cout << '' \nZERO d e t ectado '';


cont++ ;
}

cout << " \nVocê d i gitou " << con t << " zeros ";

A parte principal deste programa é o laço while que lê caracteres do


teclado enquanto não for pressionada a tecla [ENTER]. O corpo do laço é
composto por uma única instrução if que verifica se o caractere é zero; se for,
imprime "ZERO detectado" e incrementa o contador de zeros. Finalmente, o
programa imprime o número de zeros digitados.
Como nas outras estruturas já vistas, caso várias instruções SeJam
necessárias no corpo de um if, elas devem estar entre chaves.

IMPLEMENTANDO UM ALGORITMO

Deparei, um dia, com um estranho método de encontrar o quadrado de um


número positivo. O algoritmo é o seguinte:

O quadrado de um número positivo n é igual à soma dos


. . , ,
n pnmeuos numeros 1mpares.

Por exemplo:
32 = 1 + 3 + 5
62 = 1 + 3 + 5 + 7 + 9 + 11
82 = 1 + 3 + 5 + 7 + 9 + 11 + 13 + 15
90 Treinamento em Linguagem C++ Cap. 4

Este algoritmo pode ser traduzido na seguinte fórmula matemática que


facilmente é demonstrada por indução finita .
n-1
n2 = L(2i+l)
i=O

O programa a seguir implementa esse algoritmo.


11 QUADRADO . CPP
#include <iostream . h>
vo i d ma in ()
{
int n, soma=0 ;

cout << '' \nDigite um nómero \n'';


cin << n;
cout << "O quadrado de " << n << " é ";

if ( n < 0 ) n - -n; 11 Muda si nal

for(int i =l ; n > 0; n -- )
{
.
soma += 1 ;
i += 2 ·
'
}

cout << soma;


}

O COMANDO il-else

O comando if-else é uma expansão de um simples comando if. O comando if


permite que executemos algo somente se a sua expressão de teste for verdadeira,
caso contrário nada é executado.
Cap. 4 Comandos de decisão 91

Suponhamos que você queira executar alguma coisa se a expressão de


teste for verdadeira e outra coisa se a expressão de teste for falsa. Neste caso,
você deve usar o comando if-else.

SINTAXE DO COMANDO il-else

A instrução if-else consiste num if seguido de uma instrução ou de um bloco


de instruções, seguido da palavra-chave else, seguido de uma instrução ou um
bloco de instruções.
Uma única instrução não necessita de chaves:
if ( Expressão d e tes te)
instrução;
else
instrução ;

Várias instruções necessitam estar entre chaves:


if( Expressão de Tes te )
{
instrução ;
instrução;
}
e lse
{

instrução ;
instrução ;
}

O corpo de um else pode ter uma única instrução terminada por


ponto-e-vírgula ou várias instruções entre chaves.
92 Treinamento em Linguagem C++ Cap. 4

O PROGRAMA QUE CONTA ZEROS MODIFICADOS

I! CONTAZ . CPP
#include <i ostream . h>
#incl ude <conio .h>
void ma in ()
(
char ch ;
int cont=0 ;

cout << '' \nDigit e uma fras e";

while( (ch=ge tche( )) != ' \ r' )


i f (c h== ' (/) ' )
(
cout << "\nZERO detec tado";
cont+ +;
}

if(cont > (/))


cout << " \nVocê digitou '' << cont << '' zeros '';
e l se
cout << " \nVocê não digitou nenhum zero ";

Nesta versão, o programa CONTAZ.CPP imprime "Você não digitou


nenhum zero" se zero nenhum for digitado.

UM TABULEIRO DE XADREZ

O programa a seguir imprime um tabuleiro de xadrez utilizando caracteres


gráficos do IBM-PC. A estrutura de controle é feita por dois laços for, sendo
um para o controle das linhas e o outro para o controle das colunas. O corpo
do laço interno é composto por um comando if-else que reconhece quando
imprimir um quadrado cheio e quando imprimir um quadrado branco.
Cap. 4 Comandos de decisão 93

Veja a listagem:
!! XADREZ . CPP
#incl ude <iostream . h>
voi d ma i n ()
{

for(int lin= l ; lin<=8; lin++)


{

f or(int col=l;co1<=8;col++)
if( (lin+col)%2==0) // é número par ?
cout << '' \xDB \ xDB '';
else
cout << " ,
li •

cout << ' \n ' ;


}
}

C: \>XADREZ
94 Treinamento em Linguagem C++ Cap. 4

O laço for externo (da variávellin) move o cursor uma linha para baixo
a cada iteração até que lin seja 9. O laço interno (da variável col) move o cursor
na horizontal uma coluna por vez (cada coluna tem a largura de 2 caracteres)
até que seja 9. O comando if-else imprime ora quadrado cheio, ora quadrado
branco.

OJOGO DE CARA OU COROA

O programa a seguir implementa um jogo de cara ou coroa. Neste exemplo, um


jogador escolhe cara e o outro, coroa. É introduzida uma das escolhas, o
computador joga a moeda e produz a resposta. O jogo pode ser repetido várias
vezes, e o número de vezes é escolhido por um jogador. O programa utiliza a
função rand() para simular a moeda.
11 CARCOROA.CPP
11 Jogo de cara ou coroa
#include <iostream.h>
#include <std lib .h> I I para rand()
void ma in()
{

int n , perda=0 , ganho=0 ;

cout << " \nQuantas vezes você quer jogar? ";



cln >> n;

for ( int i =0; i < n ; i++ )


{
int resp;
cout << "Escolha: 0=Cara e l=Coroa:'';

Cln >> resp;
while ( resp != 0 && resp != 1)
{
cout << "ERRO : entre 0 cara e 1 coroa\n ";
.
cln >> resp;
}

if( (rand()%2}==resp)
Cap. 4 Comandos de decisão 95

ganho++ ;
if (resp == 0)
cout << "Cara, você ganhou. \n" ;
else
cout < < "Coroa , v oce ganhou . \n ";
~

}
else
{
perda++;
if(resp==l)
cout << "Cara , você p e r deu . \ n n ;
else
cout << "Coroa , você perdeu . \n ";
)
}

cout << " \n\nRelatório Final : " ;


cout << " \nNo . de j ogos que você ganhou : " << ganho ;
cout << " \nNo . de jogos que você perdeu : " << perda ;
}

Eis uma execução:


C: \>CARCOROA

Quantas vezes você quer jogar? 8


Escolha : 0=Cara e l=Coroa : (/)
Cara, você ganhou .
Escolha : (/)=Cara e l=Coroa : l
Car a, voce perdeu .
~

Escolha : 0=Cara e l=Coroa : QJ


Cara , você ganhou .
Escolha : 0=Cara e l =Coroa : (/)
Car a, voce ganhou .
~

Escolha : 0=Cara e l=Coroa : l


Cara, você perdeu .
96 Treinamento em Linguagem C++ Cap. 4

Escolha: 0 =Cara e l =Coroa: l


Coroa , v ocê ganhou.
Escol ha : 0 =Cara e l =Coroa : 0
Coroa , você perdeu .
Escolha: 0 =Cara e l =Coroa : l
Coroa, você ganhou .

Relatório Final :
Número de jogos que você ganhou : 5
Número de JOgos que você perdeu : 3

DESENHANDO LINHAS

O próximo exemplo utiliza caracteres gráficos para desenhar uma linha na tela.
A estrutura deste programa é semelhante à do programa XADREZ.CPP.
11 DI AGONAL . CPP
#include <iostream . h>
vo id ma in ()
{
f or( i nt lin= l; l in < 25 ; lin+ +)
fo r (int co l= l; col < 25; col ++)
i f(lin ==col)
cout << ' \xDB ';
else
cout << ' \ xB0';
cout << ' \n ' ;
}
}
Cap. 4 Comandos de decisão 97

Eis a saída:

COMANDOS il ANINHADOS

Quando você tem um certo número de if(s) e else(s), como o computador


decide qual else é de qual if? Por exemplo, considere o fragmento de programa
seguinte:
98 Treinamento em Linguagem C++ Cap. 4

if ( X > y )
if ( y! =0 )
a = x/y ;

e ls e
a=y;

Quando será executada a instrução a=y;? Em outras palavras, o else


está associado ao primeiro ou ao segundo if?
O else está sempre associado ao mais recente if sem else. Então, se x
não for maior que y, nada será executado. Ou seja:
if ( x >y)
if( y! =Ol )
a = x/y ;

e l se
a =y ;

Caso não seja isto o desejado, devemos usar chaves:


if( X > y )
{ if( y!=0 )
a = x/y;
}

e lse
a =y ;

Vamos modificar o programa DIAGONAL.CPP a fim de usar a cons-


trução if-else aninhada para desenhar duas linhas cruzadas na tela.
11 DI AGONAL . CPP
#inc l ude <i ostream.h>
vo id ma in ()
{
for(int lin=l ; lin < 25 ; lin++ )
{

fo r (int col=l; col < 25; co l ++)


if( l in==COl)
Cap. 4 Comandos de decisão 99

cout << 1
\ x DB 1
;

e l se
if ( col == 25 - lin )
cout < < 1
\ xDB 1
;

el s e
cout << I \ xB0 1 ;

cout << ' \n 1


;

}
}

Eis a saída:
100 Treinamento em Linguagem C++ Cap. 4

Quando escrevemos construções if-else aninhadas, o programa-fonte


pode tornar-se difícil de entender e interpretar. Verifique o exemplo a seguir
que simula uma calculadora de quatro operações:
// CALC . CPP
#incl ude <i ostrea m. h>
void ma in ()
{
const int TRUE=l ;

while (TRUE) / / Sempre verda de iro


{
float nl , n2;
c har op ;

cout << " \nDigite número operador número : ";


c1n >> nl >> op >> n2 ;

i f ( op == '+' )
cou t << nl + n2 ;
else
if( op == '- ' )
cout << nl - n2 ;
e lse
if ( op == * 1 1
)

cout << nl * n2;


else
i f ( op == I I I )

c out << n l I n2;


}
}

Construções if-else aninhadas podem ser escritas de forma a tornar o


programa mais legível. Reformatando o programa, obtivemos a seguinte listagem:
/1 CALC .C PP
#include <iostream . h >
Cap. 4 Comandos de decisão 101

vo id ma in ()
{

const int TRUE=l ;

while(TRUE) //Sempre verda de i ro


{
float nl ,n2;
char op ;

cout << " \nDigite número operador número : " ;


c1n >> nl >> op >> n2 ;

if( op --
-- ' + ' ) cout << nl + n2;
else if ( op ' -' ) cout << nl - n2 ;
else if ( op ' *' ) cout << nl * n2 ;
else if( op 'I ' ) cout << nl I n2 ;
}

USANDO OPERADORES LÓGICOS

Operadores lógicos são comuns em expressões de teste de comandos if(s).


I! BOMDIA . CPP
#include <iostream . h>
vo id ma in ()
{

int dia,mes;

cout << '' Digite : dia mes\n '';


cin >> dia >> mes;

if (mes==12 && dia == 25)


cout << "FELIZ NATAL! ";
else
102 Treinamento em Linguagem C++ Cap. 4

caut << " BOM DI A!";


}

Podemos simplificar o programa DIAGONAL.CPP com o emprego de


operadores lógicos:
11 DI AGONAL . CPP
#include <iastream.h>
vaid main ()
{
far(int lin= l ; lin < 25 ; lin ++)
{
far(int cal =l ; cal < 25 ; cal ++)
i f( l in==col I I col == 25 - lin)
caut << \xDB
1 1
;

else
caut << ' \ x B0 I;
caut << \n ' ;
I

}
}

OS COMANDOS break E continue

Os comandos break e continue são instruções que devem pertencer ao corpo


de um laço for, while ou do-while. Esses comandos não podem ser utilizados
em outras partes de um programa. O comando break tem um segundo uso que
será discutido, ainda neste capítulo, junto ao comando switch.
O comando break causa a saída imediata do laço; o controle passa para
a próxima instrução após o laço. Se a instrução break pertencer a urna estrutura
de laços aninhados, afetará somente o laço ao qual pertence e os laços internos
a ele.
Tomemos o programa CALC.CPP. Este programa tem urna falha: não
acaba nunca. Vamos modificá-lo para que termine quando o usuário digitar um
valor zero para nl.
Cap. 4 Comandos de decisão 103

11 CALC.CPP
#include <iostream.h>
void ma in ()
{

const int TRUE=l ;

whil e( TRUE) //Sempr e ve r dade iro


{

float nl ,n2;
char op ;

cout << " \n insira ZERO para terminar ou ";


cout << " \nDig ite númer o operador número: ";
cin >> nl >> op >> n2 ;

i f (n1==0.QJ) break ;

if ( op -- I +I )
cout << nl + n2 ;
e ls e if ( op I - I )
cout << nl - n2 ;
else if ( op -- I * I ) cout << nl * n2 ;
else if ( op I I I )
cout << nl I n2 ;
}
}

O próximo exemplo simula um jogo de adivinhação. Neste jogo, o


usuário pensa em um número entre 1 e 99 e o programa adivinhará qual é.
I I NUMADIV . CPP
11 Adivinha o número que o usuário pensou
#inc lud e <ios t ream.h>
#incl ude <conio . h>
vo id ma in ()
{

cout << '' Pense em um número ent r e 1 e 99 , e responda \ n ''


<< " - , >ou < para i gual, maior ou menor \ n ";

float incr=50.QJ, adiv=50.0;


104 Treinamento em Linguagem C++ Cap. 4

vvhile ( incr > l)


{

char ch ;

incr 1 =2 ;
cout << '' \n= , >ou< a " << adiv << " ? '';

if ( (ch=getche () ) == ' = ') break;

else if( ch == '>' ) adiv += lncr ;


else adi v -= i ncr;

}
cout << " \nO número é " << adiv ;
cout << " \ nCOMO SOU ESPERTO ! ! ! ! ";
}

O COMANDO continue

O comando continue força a próxima iteração do laço e pula o código que estiver
abaixo. Nos laços while e do-while, um comando continue faz com que o
controle do programa avalie imediatamente a expressão de teste e depois
continue o processo do laço. No laço for, é executada a expressão de incremento
e, em seguida, o teste.
O exemplo seguinte imprime os caracteres digitados no teclado que são
diferentes de dígitos.
//El i mina i mpressão de dígito s
#include <iostream . h>
#include <conio .h>
vo id ma in ()
{

char ch ;
while ((ch=getch()} ! ='X ' )
Cap. 4 Comandos de decisão 105

if (ch> = ' 0 ' &&ch< = ' 9 ' )


continue ;
c out << c h ;
}

O COMANDO goto

O comando goto está disponível em C++ para fornecer alguma compatibilidade


com outras linguagens de programação. A utilização deste comando é desacon-
selhada.
A instrução goto causa o desvio do controle do programa para a
instrução seguinte ao rótulo com o nome indicado. Um rótulo é um nome
seguido de dois-pontos(:). Veja um exemplo:
if ( == 0) X

goto erro ;
else
r = n/x;

• • • • •

. . . .. .

e rro :
c out << ''\ nERRO : d i v i são por zero '';

O comando goto e o rótulo correspondente devem estar no corpo da


mesma função.
A princípio, você nunca precisará usar goto em seus programas. Mas,
se você tiver um programa em outra linguagem que deva ser traduzido para
C++ rapidamente, o comando goto poderá ajudá-lo.
106 Treinamento em Linguagem C++ Cap. 4

O COMANDO switch

O comando switch permite selecionar uma entre várias ações alternativas.


Embora construções if-else possam executar testes para escolha de uma entre
várias alternativas, muitas vezes são deselegantes. O comando switch tem um
formato limpo e claro.

SINTAXE DO COMANDO switch

A instrução switch consiste na palavra-chave switch seguida do nome de uma


variável ou de um número constante entre parênteses. O corpo do comando
switch é composto de vários casos rotulados por uma constante e opcionalmente
um caso default. A expressão entre parênteses após a palavra-chave switch
determina para qual caso será desviado o controle do programa.
O corpo de cada caso é composto por qualquer número de instruções.
Geralmente, a última instrução é break. O comando break causa a saída
imediata de todo o corpo do switch. Na falta do comando break, todas as
instruções após o caso escolhido serão executadas, mesmo as que pertencem
aos casos seguintes.
O comando break tem somente dois usos em C++: em laços ou no
comando switch.
swi tch ( variá v e l o u constant e) --1sem ponto-e-vírgula I
{
- -------1dois-pontos I

-------- 1dois-pontos 1
Cap. 4 Comandos de decisão 107

i nstrução;
instrução ; Icorpo do terceiro caso
break ;
default : Idois-pontos
i nstrução;
ins t rução ; Icorpo do caso default

) Isem ponto-e-vírgula
Você não poderá usar uma variável nem uma expressão lógica como
rótulo de um caso. Pode haver nenhuma, uma ou mais instruções seguindo cada
caso. Estas instruções não necessitam estar entre chaves.
O corpo de um switch deve estar entre chaves.
Se o rótulo de um caso for igual ao valor da expressão do switch, a
execução começa nele. Se nenhum caso for satisfeito e existir um caso default,
a execução começará nele. Um caso default é opcional.
Não pode haver casos com rótulos iguais.

O PROGRAMA DIASEMAN.CPP

O nosso primeiro exemplo imprime o dia da semana a partir de uma data. O


ano deve ser maior ou igual a 1600, pois nesta data houve uma redefinição do
calendário e o algoritmo utilizado não funcionará.
11 DIASEMAN.CPP
11 Imprime o dia da semana a partir de uma data
#incl ude <iostream . h>
#include <conio . h>
vo id ma i n ()
{
i nt dia , me s , ano ;
const char ESC = 27;
108 Treinamento em Linguagem C++ Cap. 4

do
{

cout << " \nDigite a data na f orma dd mm aaaa : ";


cin >> dia >> mes >> ano ;

i n t f - ano + dia + 3 * (mes - 1) - 1 ;

if(mes < 3) ano--;


else f -= int( 0.4*mes+2 . 3) ;

f+= int( ano/4) - int( (a no/1 00 + 1) *0 .7 5);

f !!< -
o -
7 '·

switch(f)
{
case (/):
cout << ''\ nDomingo'';
break;
case 1 :
cout << ''\nSegunda-feira ";
break;
case 2:
cout << " \nTerça - fe i ra'' ;
break;
case 3 :
cout << " \nQuarta-feira " ;
break;
case 4 :
cout << "\nQuinta -f eira " ;
break;
case 5 :
cout << ''\ nSexta - feira '';
break;
Cap. 4 Comandos de decisão 109

case 6 :
cout << '' \nSábado '';
}
} whi le ( getch (} != ESC) ;
}

Observ e a execução do programa.


Digi t e a data na fo rma dd mm a a aa : 7 11 197 4
Quinta-feira
[ENTER)
Di g it e a data n a f orma dd mm a aaa : 12 1 1976
Segunda - feira
[ENTER)
Digite a data na forma dd mm aaaa : 30 7 1978
Domingo
[ESC ]

O PROGRAMA CALC.CPP MODIFICADO

Reescreveremos o programa CALC.CPP para que use um switch em vez de


ninhos de if-else. Repare na clareza da escrita.
!! CALC .CPP
11 Usa switch em ve z de if - e l se
#include <iostream . h>
void ma in()
{

const int TRUE=l ;

while (TRUE) / / Sempre verdade i ro


{
float nl ,n2 ;

c o u t << " \nDig ite número operador número : ";


cin >> n1 >> op >> n2 ;
110 Treinamento em Linguagem C++ Cap. 4

switch(op)
{
case + I I :
cout << nl + n2; break ;
case I

- I •
cout << nl - n2; break ;
case * •I I •
cout << nl * n2; break;
case I I I :
cout << nl I n2 · break;
I

default .• cout << "Operador desc onhecido" ;


}
}
)

CASOS SEM break EM COMANDOS switch

Quando vários casos devem executar as mesmas instruções, construímos casos


sem break.
Suponhamos que desejemos permitir ao usuário do programa
CALC.CPP utilizar o sinal (*) ou (x) para indicar multiplicação e o sinal (!) ou
(\) para indicar divisão. Observe a modificação do programa:
I! CALC . CPP
11 Mostra cas os sem break
#include <iostream . h>
void ma in()
{

const int TRUE=l ;

while (TRUE) //Sempre verdadeiro


{
float nl ~ n2 ;

cout << " \nDigite número operador número : ";


cin >> nl >> op >> n2 ;
Cap. 4 Comandos de decisão 111

switch(op)
{
case ' + ' •
• cout << nl + n2 ; break ;
case ' - ' cout << nl n2 ; break ;
case 'X' •

case ' * ' .


• cout << nl * n2 '· break;
cas e ' \ \ ' :
case ' I ' .• cout << nl I n 2 ; break;
default .• cout << "Operador desconhecido ";
)
)
}

...
REVISA O

1. Os comandos de decisão permitem selecionar quais instruções o programa


deve ou não executar. São eles: if, if-else e switch.
2. O comando if fornece um meio de decidir entre executar ou não uma seção
de código particular.
3. O comando if-else executa uma seção de código se a expressão de teste for
verdadeira e outra seção de código se o teste for falso.
4. Uma instrução if-else simples pode ser substituída pelo operador condicio-
nal ternário quando o corpo do if e o do else forem expressões.
5. O comando else, em construções aninhadas, é sempre associado ao mais
recente if sem else. O uso de chaves permite modificar esta associação.
6. O comando switch permite escolher uma entre várias seções de códigos
alternativas. Cada seção é identificada por uma constante seguida de
dois-pontos.
7. O nome rótulo é dado a um nome ou constante seguidos de dois-pontos.
112 Treinamento em Linguagem C++ Cnp. 4

8. Num comando switch, o controle do programa é desviado para o caso


rotulado pela constante igual à da expressão do switch ou, se não houver
nenhum caso com rótulo igual, para o caso default se este existir.
9. O comando break provoca uma saída imediata do laço ou switch a que ele
pertence.
10. O comando continue força a próxima iteração do laço que o contém.
11. O comando goto desvia o programa para a instrução seguinte ao rótulo
indicado.

,
EXERCICIOS

1. Numa construção if sem else, o que acontece se a condição de teste for


falsa?
a) o controle procura pelo último else do programa;
b) nada;
c) o controle passa para a instrução seguinte ao if;
d) o corpo do comando if é executado.
2. A principal diferença no modo de operação de um comando i f e de um laço
while é:
a) a expressão de teste é avaliada diferentemente;
b) o corpo de um laço while é executado sempre, e o do comando if
somente se a condição de teste for verdadeira;
c) o corpo de um laço while pode ser executado diversas vezes, enquanto
o corpo de um if é executado urna única vez;
d) a expressão de teste é avaliada antes da execução do corpo de um while
e depois da execução do corpo de um if.
Cap. 4 Comandos de decisão 113

3. O else de uma construção if-else é executado quando:


a) a expressão de teste do if for falsa;
b) a expressão de teste do if for verdadeira;
c) a expressão de teste do else for falsa;
d) a expressão de teste do else for verdadeira.
4. Num programa, o comando else fará par com qual if?
a) o último if com mesmos requisitos do else;
b) o último if sem else;
c) o último if de corpo não envolto por chaves;
d) o último if de corpo não envolto por chaves e sem else.
5. A vantagem de uma construção switch sobre um if-else é:
a) a condição default pode ser utilizada em switch;
b) switch fornece clareza e facilidade de leitura;
c) os casos de um switch são avaliados de forma a permitir diversas
escolhas;
d) várias instruções podem ser executadas em cada caso de um switch.
6. Verdadeiro ou Falso: Toda construção switch pode ser transformada em
ninhos de if-else.
7. Verdadeiro ou Falso: Todo ninho de if-else pode ser transformado numa
construção switch.
8. Um comando break:
a) termina um programa;
b) deve ser utilizado seguindo as instruções de cada caso num switch;
c) causa a saída imediata de um if;
d) causa a saída imediata de um laço for, while ou do-while;
e) causa a saída imediata de um switch.
114 Treinamento em Linguagem C++ Cap. 4

9. Um comando continue:
a) continua o programa após uma pausa;
b) desvia para o próximo caso de um switch;
c) permite a repetição contínua de um laço;
d) provoca a próxima iteração de um laço.
10. Verdadeiro ou Falso: A instrução goto é o método mais primitivo de
interromper o fluxo de um programa e é desaconselhada em programação
moderna.
11. Converta o fragmento seguinte para que utilize um laço for.
int i = 0;
l oop : cout << {i + +);
goto l oop ;

12. A substituição do código:


if{ch > = '0' && ch < = '9'}
continue;
else
cout << ch ;

por
{ch > = ' 0' && ch <=' 9 ') ? continu e: cout << c h ;

está errada. Explique.


13. Substitua o uso do if-else pelo operador condicional.
i f { X > y}
m = x;
els e
m - y;
Cap. 4 Comandos de decisão 115

14. A sintaxe de um laço while é semelhante à de um if. Se i é uma variável


inteira, responda: Os dois códigos seguintes provocam o mesmo efeito?
a) whil e( i = 8)
{

cout << l << (i+2) << (i+3 ) ;
i = 1/J;
}

b) i f ( i = 8)
cout << i << (i+2 ) << ( i+3) ;

15. A seguinte estrutura switch é correta?


switch ( temp )
{

case temp < 1 1/J:


cout << ''Está verdadeiramente frio !'';
break ;

case t e mp < 25:


cout << "Que t empo agradável! ";
break;

default :
cout << "Certamente está quente!";
break;
}

16. Modifique o programa XADREZ.CPP para imprimir um tabuleiro maior,


que preencha a tela.
17. Modifique o programa DIAGONAL.CPP para que imprima quatro linhas:
as duas que já estão no programa; a terceira, que é uma linha vertical que
passa pelo centro do retângulo; e a quarta, que é uma linha horizontal
passando pelo mesmo centro. As quatro linhas se cruzam no mesmo ponto.
116 Treinamento em Linguagem C++ Cap. 4

18. Escreva um programa que encontre o menor inteiro positivo n que satisfaça
as seguintes condições:
n I 3 = x inteiros e resto 2
n I 5 - y inte i ros e resto 3
n I 7 - z inteiros e resto 4

19. Escreva um programa que solicite ao usuário três números inteiros a, b e c


onde a é maior que 1. Seu programa deve somar todos os inteiros entre b
e c que sejam divisíveis por a.
20. A seqüência de números de Fiboncci é a seguinte:
1, 1, 2, 3, 5, 8, 13, 21, ...
os dois primeiros termos são iguais a 1. Cada termo seguinte é igual à soma
dos dois anteriores;
escreva um programa que solicite ao usuário o número do termo e calcule
o valor do termo;
por exemplo: se o número fornecido pelo usuário for igual a 7, o programa
deverá imprimir 13.
21. Escreva um programa que crie um número aleatório x por meio da função
rand(). O programa deve solicitar um número n ao usuário e compará-lo
com x.
se n for menor que x, o programa deve imprimir "MUITO PEQUENO" e
solicitar novamente um número para o usuário;
se n for maior que x, o programa deve imprimir "MUITO GRANDE" e
solicitar novamente um número para o usuário;
o programa termina quando o usuário adivinhar o número x tomado aleato-
riamente e deve imprimir "CERTO" e o número de tentativas até o acerto.
Capítulo 5
,..
FUNÇOES

Uma função é um conjunto de instruções desenhadas para cumprir uma tarefa


particular e agrupadas numa unidade com um nome para referendá-la.
A principal razão para usar funções é a de dividir a tarefa original em
pequenas tarefas que simplificam e organizam o programa como um todo.
Uma outra razão para escrever funções é a de reduzir o tamanho do
programa. Qualquer seqüência de instruções que apareça no programa mais de
uma vez é candidata a ser uma função.
O código de uma função é agregado ao programa uma única vez e pode
ser executado muitas vezes no decorrer do programa.
O grande princípio de linguagens estruturadas é o de dividir um
programa em funções. Linguagens orientadas ao objeto oferecem, além de
funções, outros caminhos poderosos para a organização de programas que
analisaremos, passo a passo, ao longo deste livro.
Funções em C++ e em C têm o mesmo propósito de dividir o programa
em subprogramas.

117
118 Treinamento em Linguagem C++ Cap. 5

..
CHAMANDO UMA FUNÇAO

Um programa pode conter uma ou mais funções, das quais uma delas deve ser
main(). A execução do programa sempre começa emmain() e, quando o controle
do programa encontra uma instrução que inclui o nome de uma função, a função
é chamada.
Chamar uma função é o meio pelo qual solicitamos que o programa
desvie o controle e passe para à função, execute suas instruções e depois volte
à instrução seguinte à da chamada a função.
Você já escreveu programas que chamam funções. Como exemplo,
considere o seguinte programa:
#include <ios tream . h>
#include <conio . h>
vo id ma in ()
{

cout << '' Pressione uma t ec l a '';

getche(); 11 Estamos chamando a função getche

cout << " \ nFIM " ;


}

Várias funções, como getche(), são fornecidas pelo sistema e agregadas


ao nosso programa na linkedição. Outras podem ser escritas pelo programador.
A sintaxe da instrução de chamada a uma função é a mesma tanto para funções
escritas pelo programador como para as do sistema.
Nosso objetivo, neste capítulo, é expor detalhadamente como escrever
nossas próprias funções.
Cap. 5 Funções 119

,..
FUNÇOES SIMPLES

Vamos começar mostrando uma função que converte a temperatura de graus


Fahrenheit em graus Celsius.
#include <iostream.h>

int c e l s ius(int fah r } ; l i Prot ótip o

void ma in ()
{
int c, f ;

cout << " \nDigite a temperatura em graus Fahrenheit : ";


cin >> f ;

c = ce lsius( f); l i Chamada à função

cout << " \nCelsius = " << c;


}

I I c e l siu s ()
11 Definição da função

int celsius( int fahr}


{

i nt c;
c = (fahr - 32) * 5 /9 ;

ret urn c ;
)

Como você pode ver, a estrutura de uma função C++ é semelhante à


da função main(). A diferença é que main() possui um nome especial.
120 Treinamento em Linguagem C++ Cnp. 5

Os componentes necessários para adicionar uma função a um programa


são: o protótipo da função, a chamada à função e à sua definição.

, ~

O PROTOT/PO DE FUNÇOES

Da mesma forma que com relação a uma variável, não podemos também usar
uma função sem antes declará-la.
A declaração de uma função é chamada protótipo e é uma instrução,
geralmente colocada no início do programa, que estabelece o tipo da função e
os argumentos que ela recebe.

O protótipo de uma função deve preceder a sua definição e a sua chamada.

O protótipo de uma função tem a mesma forma da definição da função


anterior a seu corpo, exceto por terminar com ponto-e-vírgula após o fechamen-
to do parêntese.
O propósito principal de escrever protótipos de funções em C+ + é o de
fornecer ao compilador as informações necessárias sobre o tipo da função e o
número e o tipo dos argumentos.
Sem o protótipo da função, o compilador não teria como verificar e
checar se há erros no uso da função.
O nosso exemplo declara a função na instrução:
int celsius ( i nt fahr) ; //Protótipo

Esta declaração informa que a função de nome celsius() é do tipo int


e recebe como argumento um valor int que será armazenado na variável fahr.
A informação do nome da variável que recebe o argumento é faculta-
tiva, mas o tipo é obrigatório. Poderíamos escrever o mesmo protótipo da
seguinte forma:
i nt c e lsi us( i nt) ; // Pro t ót i po
Cap. 5 Funções 121

,
PROTOTIPO EXTERNO ELOCAL

H á duas formas d e declarar funções em C++. A mais usada é chamada protótipo


externo e é escrita antes de qualquer função, corno no exemplo que já apresen-
tamos. Esta declaração é feita urna única vez e é visível para todas as funções
que a chamam.
A outra forma é chamada protótipo local e é escrita no corpo de todas
as funções que a chamam antes de sua chamada. Verifique:
#include <iostream . h>
void ma in ()
{

i nt celsius( i nt f a h r); /I Prot ótipo Local


int c , f ;

cout << '' \nDi gite a temperatura em graus Fahrenheit : '';


c in >> f ;

c - ce lsius (f) ; /I Chamada à função

cout << '' \nCe lsius - '' << c;


}

/I cels ius ()
11 Def i nição da função

int celsius( int fahr)


{

int c;
c = (fahr - 32) * 5/9;

return c;
}
122 Treinamento em Linguagem C++ Cap. 5

T N

ELIMINANDO O PROTOTIPO DE FUNÇOES

Se a definição da função for feita antes da instrução de sua chamada, o seu


protótipo não é obrigatório. O nosso exemplo poderia ser escrito da seguinte
forma:
#inc lude <iostream. h >

11 celsius()
11 Def i nição da função
i nt c el sius( int fa hr )
{

int c ;
c = ( fahr - 32) * 5/9 ;

r e turn c ;
}

void ma i n ( )
{

i nt c, f ;

cout << " \nDigite a temperatura em g raus Fahrenheit : ";


cin >> f ;

c = celsius(f ); l i Chamada à função

cout << 11
\nCelsius = 11
<< c;
}

Funções definidas antes de serem chamadas não necessitam de protótipo.

Bons programadores escrevem os protótipos de todas as suas funções,


mesmo os das funções definidas antes de sua chamada.
Cap. 5 Funções 123

..
TIPOS DE FUNÇOES

O tipo de uma função é definido pelo tipo de valor que ela retoma por meio
do comando return.
Uma função é dita do tipo int quando retoma um valor do tipo int.
Os tipos de funções C++ são os mesmos tipos de variáveis, exceto
quando a função não retoma nada. Neste caso, ela é do tipo void.

O tipo de uma função é determinado pelo valor que ela retoma via comando return
e não pelo tipo de argumentos que ela recebe.

O COMANDO return

O comando return termina a execução da função e retorna o controle para a


instrução seguinte do código de chamada.
Se após a palavra return houver uma expressão, o valor da expressão
é retornado à função que chama. Este valor é convertido para o tipo da função,
especificado no seu protótipo.
A sintaxe de uma instrução return tem uma das três formas seguintes:
r e turn ;
return expressão ;
return (expressão) ;

Podemos eliminar a variável desnecessária declarada no corpo da


função celsius() e colocar a expressão de cálculo diretamente junto ao comando
return. Veja a mudança:
int ce l s iu s( int fa h r )
{

re turn (fahr - 32) * 5/9 ;

)
124 Treinamento em Linguagem C++ Cap. 5

Um return desacompanhado de expressão somente termina a função e


indica uma função do tipo void.
A instrução return não é obrigatória. Uma função sem comando return
termina quando encontra a chave (}), que indica o fim da função. Tais funções
são do tipo void.
O valor de retorno de uma função é acessado, na instrução de chamada,
por meio do nome dela seguido de parênteses contendo ou não argumentos.
No nosso exemplo, tomamos o valor da função celsius() na instrução:
c = c el si us( f); l i Chama d a à função

Este valor pode, então, ser atribuído a uma variável, como no nosso
exemplo, ou fazer parte de alguma expressão.
Várias instruções return podem fazer parte de uma função, mas somen-
te uma será executada.

-
LIMITAÇOES DO COMANDO return

Enquanto vários valores podem ser passados para uma função, não é permitido
o retorno de mais de um valor por meio do comando return.

O comando retum pode retomar somente um único valor para a função que chama.

- -
DEF/NIÇAO DA FUNÇAO

O código C++ que descreve o que a função faz é chamado definição da função.
Sua forma geral é a seguinte:
t i p o nome (declaração dos parâmetros)
{
i n s t ruçõe s;
}
Cap. 5 Funções 125

A parte anterior à chave de aberhtra ({) compreende o cabeçalho da


definição da função, e tudo o que estiver entre as chaves compreende o corpo
da definição da função.
A definição de qualquer função C++ começa com o nome do tipo da
função, o mesmo de seu protótipo.

A ~

PARAMETROS DA FUNÇAO

As informações transmitidas para uma função são chamadas parâmetros.


A função deve declarar essas informações entre os parênteses, no
cabeçalho de sua definição.
Os parâmetros podem ser utilizados livremente no corpo da função.
i nt c e l sius( int fahr }
{

int C i
c = ( fahr - 32 } * 5/9 i

re t urn C i

Variáveis que não fazem parte dos parâmetros de uma função não
podem ser declaradas em seu cabeçalho.
A função celsius() necessita de uma variável auxiliar c que foi declarada
após a abertura da chave. Esta variável é criada toda vez que a função inicia
sua execução e destruída quando a função termina, sendo visível somente para
as instruções do corpo da função.
A variável c de main() é outra variável e não tem nada a ver com a
variável c de celsius().
126 Treinamento em Linguagem C++ Cnp. 5

PASSAGEM POR VALOR

No nosso exemplo, a função cria uma nova variável para receber o valor
passado. Sua declaração indica que o valor enviado será armazenado na variável
fahr criada quando a função inicia a sua execução e destruída quando a função
termina.
Receber parâmetros desta forma, em que a função cria novas cópias dos
parâmetros transmitidos, chama-se Passagem por Valor.
O próximo exemplo mostra uma função que recebe um número inteiro
como argumento e retoma o seu valor absoluto. O valor absoluto de um número
é o próprio número quando o sinal é ignorado. Por exemplo, o valor absoluto
de 5 é 5 e de -5 é também 5.
#include <iostream. h>

i nt a b s ( i n t n) ; l i Protótipo

v oid ma in ()
{

cout << abs(0 ) << ' \t ' << abs ( -3) << ' \ t ' << abs(10) ;
}

I I a b s ()
11 Calcula o valor a bsoluto de um número

int abs( i nt n)
{
ret urn ( n > 0 } ? n : -n;
}

A função main() pode tanto enviar uma constante para abs() como uma
variável. O mesmo ocorre com a função celsius().
Cap. 5 Funções 127

FUNÇÕES QUE NÃO RETORNAM NADA: TIPO void

Uma função que não retoma nada é batizada como de tipo void. Como exemplo,
escreveremos uma função que desenha uma linha com um certo número de
asteriscos.
11 LINHA. CPP
#include <iostream . h>

voi d l i nha(int n) ;

void ma in ()
{

cout << " \n\n ";


linha (21) ;
cout << " \n * FELI Z ANIVERSARIO *\n ";
linha ( 21) ;

II linha()
11 Desenh a uma l i nha na tela
void linha (int n)
{
f or( i nt i=!ll ; i <n ; i ++) cout << I *I •

'
}

Eis a saída:
** ** ** ***** ** * ** ** ** *
* FELIZ ANI VERSARIO *
** ** *** ******* ** ** ** *
128 Treinamento em Linguagem C++ Cap. 5

.. .. ..
FUNÇOES QUE NAO RECEBEM NADA ENAO RETORNAM NADA

O fato de uma função não receber nenhum argumento é indicado, no protótipo,


como void. A função seguinte usa o caractere '\x07', chamado BELL, para tocar
o alto-falante. Observe que ela não recebe nada e não retoma nada.
11 DOISBEEP.CPP
#i nc l ude <iostream . h>
#include <conio .h>

void doisbeep(void) ; I/ Protótipo

void ma in ()
{
cout << '' \nDigite um dígito entre 0 e 9 '';

char dig = ge tche() ;

if (! (dig>= ' 0 ' && dig <= '9'))


{
cout << \nERRO! !
11 11
;

do i sbeep() ;
}
}

/I doisbeep ()
11 toca o alto-falante duas vezes
void doisbeep(void)
{
cout << ' \x07 ';

for(int i=0 ; i<5000 ; i++) ;

cout << '\x07 ';


}
Cap. 5 Funções 129

,
PASSANDO VARIOS ARGUMENTOS

Se mais de um argumento é necessário, eles podem ser passados na lista de


argumentos separados por vírgulas. Podemos passar quantos argumentos
desejarmos para uma função. A seguir, vemos um exemplo de um programa
que passa dois argumentos para a função retangulo(), cujo propósito é desenhar
retângulos de vários tamanhos na tela. Os dois argumentos são a largura e a
altura do retângulo; cada retângulo representa um cômodo de uma casa.
//RETANG. CPP
//Desenha cômodos de uma casa

#include <i ostr e am.h>

void retangulo( int largura , int altura) ;

void main (void)


{

cout << " \ nSala \ n ";


retangulo(22 , 12) ;
cout << " \nCozi nha\n ";
r e tangulo(l6 ,1 6) ;
cout < < '' \ nBanheiro \n '';
r e tang ulo(6 , 8) ;
c o u t << '' \ nQuarto\ n";
retangulo(l2 , 12) ;
)

I I r e tangul o ( )
11 Desenh a um retângu lo na te l a
vo i d re t angulo( int lar gura , int a l tura)
{

largura /=2 ;
altura /=4 ;
for (int j =l ; j<= al tura ; ]++)
{
130 Treinamento em Linguagem C++ Cap. 5

cout << " \ t \t ";


f o r( int k =l ; k <= l argura ; k+ +) cout << 1
\XDB 1
;

cout << I \n I ;

}
}

Se você executar este programa, obterá a seguinte imagem na tela:


S ala

Cozinha

Banhei ro

Qua r t o

, ~

ESCREVENDO VARIAS FUNÇOES NUM MESMO PROGRAMA

Você pode escrever quantas funções quiser num programa, e qualquer função
pode chamar qualquer outra.
Em C++, não é permitido definir uma função dentro de outra função.
As funções são módulos independentes.
Cap. 5 Funções 131

Como exemplo, vamos modificar o programa LINHA.CPP para que


imprima o texto e a moldura centralizados. Para isto, criaremos a função
espacos(), que imprime um número de espaços em branco.
//CENTRA. CPP
//Centraliz a um texto com mol dura

#include <iostream. h >

void linha(int n) ;
vo i d espacos(int n);

void ma in ()
{

cout << " \n\n ";


espaces (30) ;
linha(2 1) ;
cout<<' \n ';
espaces (30) ;
cout << '' * FELIZ ANIVERSARIO *\ n'';
espaces (30) ;
linha (21) ;

I I linha ()
11 Desenha uma linha na tela
void l i nha ( int n )
{
for(int i=0 ; l<n ; i++) cout << I * f •

'
}

11 espacos()
1/ Imprime espacos em branco
vo id espacos( int n)
{
132 Treinamento em Linguagem C++ Cnp. 5

f o r ( i n t i =Cli ; i <n ; i+ +) cou t << ' ';


}

Eis a saída:
********** * **********
* FEL I Z ANIVERSARIO *
******** * *** ** ** *****

....
CHAMADAS
....
A FUNÇOES USADAS COMO ARGUMENTO DE OUTRAS
FUNÇOES

Você já sabe que a chamada a uma função pode ser utilizada numa expressão
da mesma forma que utilizamos valores numéricos. Podemos também utilizar
a chamada a uma função como argumento para outra função.
O próximo exemplo calcula a soma dos quadrados de dois números
fornecidos pelo usuário. Eis a listagem:
//MULTFUNC . CPP

#include <i ostream. h >

f loa t s omasqr( float m, f loat n);


floa t s qr( f loat z ) ;
float soma(float m, float n) ;

void ma in ()
{

fl oat a , b ;
cout << '' \nDigite do i s nómeros '';
cin >> a >> b ;
cout << " \nA soma dos quadrados é " << somasqr(a , b) ;
}
Cap. 5 Funções 133

f loa t somasqr(f loat m, fl oat n )


(
return soma( sqr (m) , sqr(n ) ) ;
)

float s q r(float z)
(
r eturn z*z ;
)

f loat soma(float m, float n)


{

r eturn m+n ;
)

O OPERADOR UNÁR/0 DE REFERÊNCIA: &

O operador de referência cria outro nome para uma variável já criada. As


instruções
int n ;
i nt& nl =n;
informam que nl é outro nome para n. Toda operação em qualquer dos nomes
tem o mesmo resultado.
Uma referência não é uma cópia da variável a quem se refere. É a mesma
variável sob nomes diferentes. As instruções
i nt n ;
i nt& nl - n ;

n = 5;

cou t << nl i
134 Treinamento em Linguagem C++ Cnp. 5

nl - 8;

cout << n ;

imprimem 5 e 8.
O operador unário &, quando usado na criação de referências, faz parte
do tipo:
int& é um tipo de dado

Toda referência deve obrigatoriamente ser inicializada.


int n·
'

int& nl ; // ERRADO
int& nl = n ; // CERTO

PASSAGEM POR REFERÊNCIA

O uso mais importante para referências é ao passar argumentos para funções.


Os exemplos de argumentos de funções vistos até o momento são passados por
valor.
Quando argumentos são passados por valor, a função chamada cria
novas variáveis do mesmo tipo dos argumentos e copia nelas o valor dos
argumentos passados. Desta forma, a função não tem acesso às variáveis
originais da função que chamou, portanto não as pode modificar.
A principal vantagem da passagem por referência é a de que a função
pode acessar as variáveis da função que chamou. Além desse benefício, este
mecanismo possibilita que uma função retorne mais de um valor para a função
que chama. Os valores a serem retornados são colocados em referências de
variáveis da função chamadora.
O próximo exemplo mostra o uso simples de referência como argumen-
to de uma função.
//REFER .C PP
//Most ra passagem d e argument os por referênci a
Cap. 5 Fu nções 135

#include <i ostr e am. h>

void reajusta20 ( float& p , float& r) i

void ma in ()
{
fl oat p r eco , val_ r e a j ;

do
{
c o ut << '' \n\ n insira o p reco atua l : '' i

Cln >> pre coi
r e aj ust a 2 0(prec o , val_reaj ) i
cout << " Preço novo - " << preco
<< " \ nAumento - " << va l_reaj i
} while( preco ! = 0 . 0) i
}

//re ajusta20()
// Reajusta o preco em 20%
void reajusta20(float& p , floa t& r )
{
r -- p * 0.2 i
p -- p * 1. 2 i
}

O programa solicita que o u suário insira o preço atual de uma merca-


doria, modifica o preço para um valor reajustado em 20% e calcula o valor do
aumento.
A função reajusta20() poderia encontrar o novo preço e o valor do
reajuste sem utilizar referências, mas como estas informações seriam passadas
para main()? Por meio do comando return, é possível retornar um dos valores,
mas não os dois.
Funções que recebem argumentos por referência utilizam o operador
& somente na definição do tipo do argumento.
136 Treinamento em Linguagem C++ Cnp. 5

Observe que a chamada a uma função que recebe uma referência é


idêntica à chamada às funções em que os argumentos são passados por valor.
A declaração
float& p , fl oat& r

indica que p e r são outros nomes para as variáveis passadas como argumento
pela função que chama. Em outras palavras, quando usamos p e r, estamos
realmente usando preco e val_reaj de main().
Referências não existem em linguagem C e não há um meio de criar
outro nome para uma mesma variável.

,
ORDENANDO UMA LISTA DE NUMERO$

O próximo exemplo cria uma função que troca o conteúdo de duas variáveis.
Utilizaremos a função troca() para ordenar uma lista de três números.
//ORDENA.CPP
//Ordena u ma l i st a d e t rês núme r o s
#include <iostream . h>

void troca( float & n, fl oat& m);

void ma in ()
{
float nl , n2,n3 ;

cout << '' \ n\nDi gi te três números: '';


cin >> nl > > n2 > > n3 ;

if(nl > n2) troca (nl , n2) ;


if(nl > n3) troca (nl , n3) ;
if ( n2 > n3) troca(n2, n3) ;

cou t << " \nn l =" << nl ;


Cap. 5 Fu nções 13i

c o ut << '' \ nn2 - '' < < n2 ;


cout << '' \nn 3 - '' << n3 ;

I /troca ( )
//Pe rmuta o valor d e duas variáve is
void t r oca(floa t & n , f l oat& m)
{

f l oat temp=n ;
n - m;
m = t emp;
}

Eis a saída:
Di g i t e três números : 50 13 28

nl - 13
n2 - 28
n3 - 50

A função main() verifica a ordem dos números digitados e, se encontrar


um par de números que não estejam na ordem crescente, fa z a troca.

J\

REFERENCIAS CONSTANTES

Você pode combinar a palavra-chave const com a declaração de uma referência


para uma variável:
i nt n= 4 56 ;
const int& nl =n ;

Estas declarações fazem de nl um nome "read-only" para n. Você não


poderá fazer nenhuma modificação em nl, somente em n.
Utilizamos referências constantes quando a função não necessita alte-
rar as variáveis enviadas como argumentos. Imagine uma função que recebe
138 Treinamento em Linguagem C++ Cnp. 5

muitos dados como argumentos. Se forem passados por valor, a função criará
uma cópia das variáveis da função que chama; por serem mu itos dados, o
programa pode não rodar. Veja o exemplo:
//REFCONST . CPP
//Mo stra o uso de r efer ência constant e
#include <i ostream.h>

void imprime (const double& n , const double& m) i

vo i d ma i n ()
{
dou ble nl , n2 i

cout << '' \n\nDigite dois nómeros : ''i


c in >> nl >> n2 i
i mpr ime (nl , n2) ;
}

I I imprime ()
//Imprime o quadrado dos argumentos
vo i d imprime(const doubl e& n , const double& m}
{

cout << " \ nO quadrado de 11


<< n << 11
e' 11
<< n *ni
cout << " \nO quadrado d e 11
<< m << 11
e' 11
<< m*m i
}

O uso de referências constantes é um meio de economia de memória.

CONSIDERAÇÕES SOBRE REFERÊNCIAS

O uso de referências poderá ser bastante confuso para alguém que leia o
programa. Sem que seja lido o protótipo da função, é impossível saber se a
função recebe uma referência da variável ou um simp les valor. Assim, não
sabemos se a variável passad a como argumento é alterada ou não. As referências
devem ser utilizadas com cuidado.
Cap. 5 Funções 139

...
VALORES DEFAULT PARA OS ARGUMENTOS DE UMA FUNÇAO

O protótipo de uma função pode incluir valores para um, alguns ou todos os
parâmetros. Se forem omitidos os argumentos correspondentes na chamada à
função, os valores default serão automaticamente usados. Se os argumentos
correspondentes forem enviados, estes serão respeitados.
Como exemplo, vamos alterar a função linha() para que ela receba dois
argumentos: o caractere para o desenho da linha e o número de caracteres a
desenhar. A função imprime uma linha de 20 asteriscos por default.
//LI NHAl.CPP
//Mos tra o uso de valores de f aul t pa ra argumentos
#include <i ost ream . h>

void l i nha (int n = 20 , char ch- ' *' ) ;

void ma i n ()
{

linha() ; cout << ' \ n ' ;


linha ( 34) ; cout << ' \n ' ;
1 inha ( 4 5 , ' = ' ) ; cout << ' \n ' ;
}

I I linha()
11 De senha uma l i nha na tela
void linh a ( int n , char ch)
{
for(i nt i=0 ; i<n ; i++) cout << ch;
}

Eis a saída:
*********** ** *******
******** ******************** ******
---------------------------------------------
140 Treinamento em Linguagem C++ Cap. 5

Neste programa, a função linha() é chamada três vezes. Na primeira


vez, os argumentos omitidos assumirão os valores 20 e'*' respectivamente. Na
segunda, os argumentos são 34 e '*'. E, na terceira, serão respeitados os
argumentos enviados.
Se o primeiro argumento for omitido, todos os subseqüentes deverão
ser omitidos. Se o segundo argumento for omitido, todos os subseqüentes
deverão ser omitidos e assim por diante. Por exemplo, a seguinte instrução é
ilegal:
linha( , '+' ) ; / /ERRO

Se um argumento for omitido, todos os subseqüentes deverão ser omitidos.

Podemos escrever funções que tenham parâmetros inicializados com


um valor default e parâmetros não-inicializados, mas após a primeira iniciali-
zação todos os parâmetros seguintes devem ser inicializados.
linha ( int n = 20 , char ch); // ERRO

linha( int n , c har ch = '*'); //CORRETO

,..
SOBRECARGA DE FUNÇOES

Sobrecarregar funções significa criar uma família de funções com o mesmo


nome, mas com a lista de parâmetros diferentes. Funções sobrecarregadas
devem ter a lista de p arâmetros diferentes ou em número ou em tipo.
Quando a função é chamada, é a lista de parâmetros passada para ela
que permite ao sistema identificar qual é o código adequado.
Por exemplo, suponhamos que você queira criar uma função que calcule
o cubo de seu argumento e que o argumento possa ser um número inteiro, um
float ou um double. Para resolver este problema, você pode criar uma família
de funções cubo() com parâmetros diferentes.
Cap. 5 Funções 141

//CUBO.CPP
//Mostra o uso de sobreca rga de f unções
#include <iostream . h>

int cubo ( i nt n) i

f l oat cubo (float n) i

doubl e cubo(doubl e n) i

void ma in ()
{
cout << cubo(876 ) << ' \n ' i

cout << cubo( 12 .34) << ' \ n ' i


cout << cubo(doub l e(4567 . 3 5 )) << ' \ n ' i

int cubo( i nt n)
{

return n*n*n i
)

float cubo (float n)


{
re tur n n*n*ni
}

double cubo (double n )


{

re t urn n*n*n i
}

Observe que o sistema considera somente a lista de parâmetros para


escolher a função apropriada a cada chamada, e não o valor de retorno.
int minha f (int ) i / /ERRADO
float minha f (int) i //Parâmetro igual
142 Treinamento em Linguagem C++ Cap. 5

O PROGRAMA LINHA J.CPP MODIFICADO

O programa LINHAl.CPP não permite definir o caractere do desenho sem


também definir o número de caracteres a desenhar. Suponhamos que você
queira que a função possa ser chamada com qualquer dos dois argumentos, com
os dois em qualquer ordem, ou sem nenhum. Podemos definir uma família de
funções como mostra o programa seguinte:
//LINHA2.CPP
//Hostra o uso de sobrecarga de f unções
#incl ude <iostream.h>

void l i nha(int n) i
void l i nha(char ch) i
void l inha(vo i d) i
void l i nha (int n, char ch) i

void l i nha (char ch, int n} i

v o i d ma in ()
{

linha() i cout << ' \n' i


linha( 34 } i cout << ' \n ' i
linha(4 5 , ' = ')i cout << ' \n' i
linha ( ' + ' } i
}

void l i nha(int n)
{
for(int i=0i i <n i i+ +) cout << I * I •

'
}

void linha(char c h)
{
for (i nt i=0 ; i <20 ; i++) cout << ch ;
}
Cap. 5 Funções 143

void linha ()
(
for ( int i =0 i i<2 0 i i+ + ) cout << I * ,
I •

vo id l i nh a(int n, char ch )
{
f or( i nt i =0 i i <n i i ++) cout << ch;
)

void l i n ha(char c h,int n)


{

for( i nt i=0; i<n i i+ +) cout << ch;


)

FUNÇÕES inline

A palavra-chave inline, quando colocada como primeiro elemento do cabeçalho


da definição de uma função, causa a inserção de uma nova cópia da função em
todo lugar onde ela é chamada.
Como exemplo, vamos escrever um programa que lê caracteres do
teclado e chama uma função que analisa cada caractere: se for uma letra
maiúscula, converte-a para minúscula; se não, retoma o próprio caractere.
#include <i ostream.h>
#include <conio .h>

inline char minusculo(char c h)


{
return((Ch> = 'A' && ch< = ' Z ' )? (ch- ' A' + ' a ') : ch ) i
)

vo id ma in ()
{
144 Treinamento em Linguagem C++ Cnp. 5

c o nst char ctr l z=26;


char ch ;

while( (ch=minusculo(getch(} )) ! = ctr lz)


cout << ch;
}

Como você pode observar, escrevemos funções inline exatamente da


mesma maneira como escrevemos funções comuns, exceto pela inclusão do
qualificador inline no início da definição da função.
A definição de uma função inline deve preceder a primeira chamada
a ela. Ou seja, se a função for chamada em main(), seu código deve ser escrito
antes de main(). Isto é necessário, pois o compilador deve conhecer de antemão
o código da função para poder inseri-lo dentro do programa.
Como a função minusculo() foi definida antes de ser chamada, não é
necessário escrever seu protótipo.

QUANDO USAR inline

Mencionamos anteriormente que uma função é um código presente uma única


vez no programa que pode ser executado muitas vezes. Assim, um dos motivos
para escrever funções é o de poupar memória.
A chamada a uma função provoca o desvio do controle do programa
para o código da função e, ao término da execução deste código, um novo desvio
para a instrução seguinte à da chamada.
Por um lado o uso de funções poupa espaço de memória, por outro
requer mais tempo de execução.
Quando escrevemos funções pequenas, podemos poupar tempo de
execução colocando o código da função diretamente no programa.
Se a função é muito pequena (uma ou duas instruções), as instruções
necessárias à sua chamada podem ocupar mais espaço de memória que as
instruções do seu próprio código.
Em casos semelhantes, é aconselhável criar funções inline.
Cap. 5 Funções 145

...
FUNÇOES RECURSIVAS

Uma função é dita recursiva se é definida em termos dela mesma. Isto é, uma
função é recursiva quando dentro dela está presente uma instrução de chamada
a ela própria.
Como exemplo, vamos escrever uma função que calcula o fatorial de
um numero.
'

//FATORIAL . CPP
//Mostra o uso de funções r ecursivas
#incl ude <i ostream . h>

long fatorial(int n);

void ma i n ()
{

i nt n ;

while(l)
{
cout << '' \nDi g ite um nómero : ";
c1n >> n;
if( n < 0 ) br e ak ; //Te rmina se No . negativo
cout << '' \nFatoria l = '' << f atorial(n);
}
}

// fat orial ()
//Cal cula o fatori al de um nómero. Recursiva
long fatorial ( int n }
{
return( (n== 0) ? long( l ) : l ong(n) * f atorial (n - 1)) ;
}
146 Treinamento em Linguagem C++ Cnp. 5

O código gerado por uma função recursiva exige a utilização de mais


memória, o que torna a execução mais lenta. Não é difícil criar funções
recursivas, o difícil é reconhecer as situações nas quais a recursão é apropriada.
Três pontos devem ser lembrados ao escrever funções recursivas:
A primeira tarefa, ao pensar em criar uma função recursiva, é escrever
o problema em termos de recursão. O fatorial de um número n qualquer pode
ser definido por meio da seguinte expressão:
n! = n * (n -1 ) !

Toda função recursiva deve ter uma condição de término chamada


condição básica. A função fatorial(), quando chamada, verifica se n é zero. Se
esta condição for satisfeita, interrompe a recursão.
Cada vez que a função é chamada recursivamente, deve estar mais
próxima de satisfazer a condição básica. Isto garante que o programa não girará
em uma seqüência infindável de chamadas. Em nossa função, a cada chamada
o valor de n estará mais próximo de zero.

COMO TRABALHA UMA FUNÇAO RECURSIVA?

A' primeira vista, não é fácil entender o funcionamento de uma função recursiva.
Para facilitar o entendimento, vamos imaginar que uma chamada
recursiva é a chamada a outra função que tenha o mesmo código da função
original.
Por exemplo, a seqüência de chamadas à função fatorial(), se o seu
argumento inicial for 3, poderia ser a seguinte:
long fatoria l( i nt n)
{
return( (n==0)? l ong(l) : 3 * f1 ( 2)) ; //chama outra função
}

l ong f1 ( int n)
{

re tur n( (n== 0)? long(l) : 2 * f2( 1 )) ; //chama outra função


Cap. 5 Funções 147

l ong f2 (int n)
{
r e turn( (n==0) ? l ong( l) : 1 * f3(Ql)) ; // chama outra função
}

long f3 ( int n)
{
re tur n( 1) ;
}

O que ocorre na memória é quase a mesma coisa, exceto pelo fato de


que não há repetição do código da função.
Observe que várias chamadas estão ativas ao mesmo tempo. Enquanto
a última chamada não terminar, a penúltima não termina e assim por diante.
Isto faz com que as variáveis de cada chamada sejam todas mantidas na
" . . , .
memona, o que requer mais memona.
O próximo exemplo ilustra esse fato. O programa aguarda que o
usuário digite uma frase e termina quando a tecla [ENTER] é pressionada. A
frase é reimpressa ao contrário.
I !INVERTE. CPP
//Imprime uma frase inve rtida . Usa recursão

#include <iostream . h>


#include <conio . h >

v oid inverte(void) ;

void ma in ()
{
148 Treinamento em Ling uagem C++ Cnp. 5

cout<<' \ n ';
inve rte() ;
)

// i n v e rte()
// Inverte uma frase usando recursão
v oid invert e( )
{

char ch ;
if ((ch=getche () ) != ' \r ' ) i nverte() ;
cout << ch ;
}

Se você digitar "BOM DIA!" o programa imprimirá


!AID MOB

JOGO DA TORRE DE HANOI

Neste jogo temos três hastes, que chamaremos de haste Origem, haste Destino
e haste Temporária, e um número qualquer de discos de tamanhos diferentes
posicionados inicialmente na haste Origem. Os discos são dispostos em ordem
de tamanho, de forma que o maior disco fica embaixo, em seguida o segundo
maior e assim por diante.
O objetivo do jogo é movimentar um a um os discos da haste Origem
para a haste Destino utilizando a haste Temporária como auxiliar. Nenhum
disco pode ser colocado sobre um disco menor.
Cap. 5 Funções 149

Origem Temporária Destino

A função que vamos escrever recebe o número de discos e o nome das


hastes como argumento e imprime a solução. Para isto, vamos considerar os
seguintes passos como uma solução do problema:
1. Mover n-1 discos da haste Origem para a haste Temporária.
2. Mover o disco n da haste Origem para a haste Destino.
3. Mover n-1 discos da haste Temporária para a haste Destino.
A função recursiva mover() foi escrita seguindo os três passos acima.
Veja a listagem:
//HANOI . CPP
#include <iostream . h>
vo id mover(int n , char Orig , cha r Temp , c har Des t ) ;
vo id ma in ()
{

move r( 3 , ' 0 ', 'T', 'D' ) ;


}

void mover(int n , char Orig , c har Temp , char De st)


{
150 Treinamento em Linguagem C++ Cnp. 5

if (n==1 }
cout << " \nMova o disco 1 da haste " << Orig
<< '' para a haste " << Dest ;
else
{
mover(n-1,0rig ,Dest,Temp) ;
cout << " \nMova o disco " << n << " da haste "
<< Orig << '' para a haste '' << Dest ;
mover(n-l,Temp , Orig,Dest) ;
}
}

Eis a saída:
Mova o disco 1 da haste O para a haste D
Mova o disco 2 da haste O para a haste T
Mova o disco 1 da hast e D para a haste T
Mova o disco 3 da haste O para a haste D
Mova o disco 1 da haste T para a haste O
Mova o disco 2 da haste T p ara a haste D
Mova o disco 1 da ha ste O para a haste D

CLASSES DE ARMAZENAMENTO

Todas as variáveis e funções C++ têm um tipo e uma classe de armazenamento.


Você já sabe que o tipo de uma variável diz respeito ao tamanho que ela ocupará
na memória e à forma como será armazenada.
A classe de armazenamento de uma variável determina em que pontos
do programa ela pode ser acessada, quando ela será criada e quando será
destruída, em que lugar ela será armazenada e qual será seu valor inicial.
São quatro as classes de armazenamento em C++:
auto (automáticas)
extern (externas)
Cap. 5 Funções 151

static (estáticas)
register (em registradores)

A CLASSE auto

As variáveis que temos usado em todos os nossos exemplos estão confinadas


nas funções que as usam; isto é, são "visíveis" ou "acessíveis" somente às
funções em que estão declaradas. Tais variáveis são da classe auto.
A palavra-chave auto pode ser usada para especificar uma variável
automática, mas não é necessária, visto que a classe auto é "default".
O código
void ma in ()
{

int n ;
• •

é equivalente a
void ma in ()
{

auto int n ;
. . .
}

Estas variáveis são criadas em tempo de execução, especificamente


quando o programa encontra a instrução de sua declaração, e são destruídas ao
término da execução do bloco ao qual pertencem.
Variáveis automáticas podem ser acessadas somente pelas instruções
do mesmo bloco e escritas após a sua declaração. Por meio de referências a elas,
algumas funções poderão também acessá-las.
Quando uma variável automática é criada, o programa não a inicializa
com nenhum valor específico. Variáveis automáticas conterão um valor inicial
aleatório, chamado "lixo".
152 Treinamento em Linguagem C++ Cap. 5

A CLASSE extern

Ao contrário de variáveis automáticas, declaradas dentro das funções, as


variáveis externas são declaradas fora de qualquer função. A instrução de
declaração de uma variável externa é idêntica à de uma variável automática. O
acesso a elas é permitido a todas as funções definidas após a sua declaração, e
elas existirão enquanto o programa estiver sendo executado.
As variáveis da classe extern são criadas em tempo de compilação,
especificamente quando o programa estiver sendo compilado, e são inicializa-
das com zero por falta de inicialização explícita.
//Host r a o uso de variáve is e x ter nas

#include <i ostr e am. h>

int 1 ; // Ini cializada c om ze ro


i nt ]=234; / / I ni cializada com 23 4

void f unc(void ) ;

vo id ma in ()
{

cout <<i<< '\ t ' << j << '\n ';


func ();
cout <<i<< '\ t ' << j << '\n ';

void f u nc ()
{
i= 25 ; ] =48 ;
}
Cap. 5 Funções 153

Eis a saída:
(/) 234
25 48

O OPERADOR DE ESCOPO: ::

Observe o seguinte programa:


//Most ra o uso de variáveis e xt ernas

#include <ios tream.h>

int i ; //Inicializada com zero


int j =23 4; // Inicializada com 234

void ma i n ()
{

int i=5 , j=l0 ; //Var i áve i s automáticas


cout << i<< '\n ' << j ;
}

O que o programa imprime? Quais variáveis serão usadas em main()?


Em C++, variáveis automáticas têm precedência sobre variáveis exter-
nas. Assim, o exemplo anterior imprimirá 5 e 10.
Você pode solicitar ao compilador que utilize a variável externa em vez
de a automática colocando o operador :: antes do nome da variável. Por
exemplo:
//Mo s t ra o uso do operador de escopo

#include <iostream . h>

int i ; // Ini c i alizada com zero


int j=234; // Inic i alizada com 234
154 Treinamento em Linguagem C++ Cnp. 5

vo id ma in ()
(
int i =5 I j =l !ll ; //Variáveis automá ti cas
Co u t << :: l.• << I\ t I << ; ; j <<
I \nI //ext ernas
;

cout << i << \t <<


1 1
j <<
1
\n1
// aut omáticas
;

Agora o programa imprimirá:


Ql 234
5 10

A PALAVRA-CHAVE extern

A p alavra extern não é usada para criar variáveis da classe extern e sim para
informar ao compilador que a variável em questão foi criada em outro programa
compilado separadamente e que será linkeditado junto a este para formar o
programa fina l.
void ma in ()
{

extern i nt x ; //Não cria a variáve l


. . . .. .
}

Se uma variável externa criada em outro programa for usada em seu


fonte, o compilador apresentará uma mensagem de erro e não compilará o seu
programa.

RETORNANDO DE UMA FUNÇÃO POR REFERÊNCIA

Além de passar parâmetros por referência para uma função, uma referência a
uma variável externa pode ser usada como valor retornado de uma função.
//Mostra retorno por referência
# include <i os t ream . h>
Cap. 5 Funções 155

i nt x; //Variáv e l externa
int& initx(void ) ;// Protó tipo da funç ão

vo i d ma i n ( )
{

initx( ) - 56 7; //At r i bui um valor a x

c o ut << x;
)

i nt& i n i t x ()
{

return x;
)

Neste exemplo, o valor retornado pela função initx() é uma referência


à variável x. Como resultado, a expressão initx() é outro nome para a variável
x e a chamada à função pode aparecer do lado esquerdo do sinal de atribuição:
ini t x() = 5 67 ;

Para entender a utilidade desta técnica, você deve aprender mais sobre
C++. Mais adiante, serão mostrados exemplos práticos.

A CLASSE static

As variáveis da classe static de um lado se assemelham às automáticas, pois


são conhecidas somente das funções que as declaram, e de outro lado se
assemelham às externas, pois mantêm seus valores mesmo quando a função
termina.
As variáveis da classe static são criadas em tempo de compilação,
especificamente quando o programa está sendo compilado, e são inicializadas
com zero por falta de inicialização explícita.
//Mostra o uso de variáveis s t atic
#inc l ude <io s t ream.h>
156 Treinamento em Linguagem C++ Cnp. 5

void soma (v oid) i / / Pro t ó t ipo

void ma i n ()
{

s o ma() i
soma () i
soma( ) i
}

void s o ma ()
{
static i nt ki
c o ut << " \ nk = " << ( k+ +) i
}

A saída será:
k - 0
k - 1
k - 2

UMA FUNÇÃO QUE GERA NÚMEROS ALEATÓRIOS

Nós já usamos a função de biblioteca C++ rand() que gera números aleatórios.
Agora desenvolveremos a nossa própria função, visto que ela não é implemen-
tada em todos os sistemas.
O esquema começa com um número chamado "semente" usado para
produzir um novo número que se tornará a nova semente. A nova semente é
usada para produzir uma nova semente e assim por diante. Desta forma, a
função deve lembrar-se da semente usada na última chamada e para isto
variáveis static se adaptam p erfeitamente. O método é baseado em congruência
linear, que não explicaremos aqui.
Cap. 5 Funções 157

//TESTRAND . CPP
//Mostra o uso de variáveis static

#include <i ostream . h>


uns i gne d rand(void) ;

v oid ma in ()
{

for(int i=0 ; i < 5 ; i++)


cout << ' \n ' << rand() ;
}

I / rand()
//Gera números al eatórios
unsigned rand ()
{

sta tic unsigned semente = 1 ;


s emente =(seme nt e* 25173 + 13 849}%65 536 ; //Fórmula mágica
return semente ;
}

A variável semente começa com o valor 1 e este é alterado pela fórmula


a cada chamada a esta função. Ao executar este programa, obteremos a seguinte
saída:
39022
61087
20196
45005
388 2

Se o programa for executado novamente, a saída será:


39022
61087
201 96
45005
3882
158 Treinamento em Linguagem C++ Cap. 5

Observe que a saída é exatamente a mesma nas duas execuções. O


problema é que, a cada execução, a variável semente começa com o valor 1.
Para resolvê-lo, devemos inicializar a semente com um valor novo a cada
execução. Como fazer isto? Podemos solicitar a entrada da semente pelo usuário
e criar uma função que a inicializa.
Como desejamos que a variável semente possa ser acessada tanto pela
função rand() como pela função que a inicializa, poderíamos pensar em criá-la
como externa. Mas variáveis externas podem ser acessadas por qualquer ftmção
do programa e não queremos que nenhuma outra função, exceto estas duas, tenha
acesso a esta variável. A solução está no uso de variáveis estáticas externas.

A CLASSE static extern

Outro uso da classe static é associado a declarações externas criando um


mecanismo de "privacidade". Para declarar uma variável estática externa,
acrescentamos a palavra static à declaração externa.
Uma variável estática externa tem as mesmas propriedades de uma
variável externa, exceto pelo fato de que variáveis externas podem ser usadas
em qualquer parte do programa, enquanto variáveis estáticas externas somente
podem ser acessadas pelas ftmções do mesmo programa-fonte e definidas
abaixo de suas declarações.
//Mo stra o uso de variáve is e státicas e x ter nas
#inc l ude <i os t ream.h>

uns i g ned rand(voi d);


void inits(int n) ;

vo id ma in ()
{
int s;
cout << '' \nDi gite a sua semente : '';
.
c~n >> s ;
inits (s) ;
for (int i=@ ; i < 5 ; i+ + )
cou t << ' \n ' << rand() ;
)
Cap. 5 Funções 159

static int semente ; //Variável estática externa

//rand ()
//Gera números aleatórios
uns i g n e d rand ()
{
semente = (se me nt e*2 5173 + 13 849}%65536 ; //Fórmula mágica
return semente;
}

// inits(}
// I ni cializa a semente
void in its (int n)
{
semente=n ;
}

Eis duas execuções desta versão:


Digite a sua semente: 1

39022
61087
2019 6
4500 5
3882

Digit e a sua s e ment e : 3

23832
20241
63678
35119
49332
160 Treinamento em Linguagem C++ Cap. 5

CLASSE DE ARMAZENAMENTO DE FUNÇOES

Toda função C++ é da classe extern, ou seja, toda função C++ é visível a todas
as outras.
Uma função, além de externa, pode ser também estática. Especificar
uma função usando static permite que a função seja acessível somente às
funções do mesmo programa-fonte definidas abaixo dela, ao contrário das
outras que podem ser acessadas por outros arquivos compilados em módulos
separados.

A CLASSE register

A classe de armazenamento register indica que a variável associada deve ser


guardada fisicamente numa memória de acesso muito mais rápido chamada
registrador. Um registrador da máquina é um espaço de 16 bits (no IBM-PC)
onde podemos armazenar um int ou um char. Em outras palavras, as variáveis
da classe register são semelhantes às automáticas, mas se aplicam apenas às
variáveis do tipo int e char.
Cada máquina oferece um certo número de registradores que podem
ser manuseados pelos usuários. Por exemplo, o computador IBM-PC oferece
somente dois registradores para este uso, portanto só podemos ter duas
variáveis em registradores em cada tempo. Mas isto não nos impede de declarar
quantas variáveis register quisermos. Se os registradores estiverem ocupados,
o computador simplesmente ignora a palavra register das nossas declarações.
Basicamente, variáveis register são usadas para aumentar a velocidade
de processamento. Assim, o programador deve escolher as variáveis que são
mais freqüentemente acessadas e declará-las como da classe register. Fortes
candidatas a este tratamento são as variáveis de laços e os argumentos de
funções.
Cap. 5 Funções 161

Veja um exemplo que mostra a diferença de velocidade entre variáveis


de memória e em registradores.
//REGISTER . CPP
//Mostra o uso de variáveis reg i ster

#inc l ude <iostream.h>


#inc l ude <t ime . h >//pro tót ipo de time ()

void ma i n ()
{
int if j i
r eg is te r int mf n i
long t i

t=time (0) i
f or ( j=0 i j<50 00i ] ++ )
f or (i=0 i i <500 0 ii ++)
.
f

cout<< " \nTempo dos laços nao register : "<<(time(0) -t ) i

t=time(0) i
for(m= 0 i m< 5000im++ )
f o r(n =0 ; n<5 000; n ++ )

f

cout << " \nTemp o do s laços regist er : " << (time(0) - t ) i


}

Este programa usa a função time(), presente na biblioteca do compila-


dor Borland C++.
O tempo apresentado por este programa será por volta da metade com
o uso de variáveis register.
162 Treinamento em Linguagem C++ Cnp. 5

~ ,
OBSERVAÇOES TECNICAS

As variáveis automáticas podem ser inicializadas por meio da chamada a uma


função:
void ma i n ()
{
int x = abs (- 5 ) i
. . .
}

enquanto variáveis static ou extern não podem. O motivo é que elas são criadas
em tempo de compilação e não há como executar uma função nesse momento.
v o id ma in ()
{

static in t x - abs(-5) i / / ERRADO

,
O PRE-PROCESSADOR

O pré-processador C++ é um programa que examina o programa-fonte em C++


e executa certas modificações nele antes da compilação, com base em instruções
chamadas diretivas.
O pré-processador faz parte do compilador e é executado automatica-
mente antes da compilação. Diretivas seriam as instruções que o pré-processa-
dor executa.
Diretivas do pré-processador devem fazer parte do texto-fonte que
criamos, mas não farão parte do programa que compilamos: elas são retiradas
do texto pelo pré-processador antes da compilação.
As diretivas são geralmente usadas para tornar o programa-fonte mais
claro e fácil de manter.
Você já usou a diretiva #include para incluir textos em seus programas.
Cap. 5 Funções 163

O conjunto das diretivas mais comuns reconhecidas pelo pré-processa-


dor é o seguinte:
#define
#undef
#include
#if
#ifdef
#ifndef
#else
#elif
#endif
#erro r
As diretivas podem ser colocadas em qualquer lugar do programa;
geralmente são escritas no início do programa, antes de main() ou antes do
começo de uma função particular. Elas se aplicam somente do ponto onde são
escritas ao final do programa-fonte.

A DIRETIVA #define

A diretiva #define, na sua forma mais simples, é usada para definir constantes
simbólicas com nomes apropriados. Veja o exemplo:
#include <i ostream. h >
#defi ne PI 3 . 14

float area(float raio} ;

void ma in ()
{
fl oat r aio ;
164 Treinamento em Linguagem C++ Cnp. 5

cout << " \nDigi te o ra io de uma esfera : ";


.
c~n >>
.
ra~o ;

cout << '' \nA área da esfera é de '' << area(raio);


)

f l oat area(float raio )


{
re turn 4 . 0 * PI * PI;
)

Quando o compilador encontra a diretiva #define, procura em cada


linha abaixo dela a ocorrência da palavra PIe a substitui por 3.14.
O nome que segue a palavra #define é chamado identificador. A frase
escrita após o identificador é chamada texto . Um ou mais espaços separam o
identificador do texto.
Na linha
#de fine PI 3 .14

a palavra PI é o identificador e 3.14 é o texto.


Por convenção, o identificador é sempre escrito em letras maiúsculas.
Observe que não há ponto-e-vírgula após nenhuma diretiva do pré-pro-
cessador.
Cada diretiva deve ser escrita em uma linha nova. Em outras palavras,
não podemos escrever mais de uma diretiva numa mesma linha.
A diretiva #define executa uma mera substituição textual seletiva. No
exemplo:
#define P I 3.14
• • •

cout << " PI ANO" i

x = PI * PI ; //Quadrado de PI
• • •
Cap. 5 Funções 165

a cadeia de caracteres "PIANO" não será alterada. Não há substituição dentro


de cadeias de caracteres. Não há substituição dentro de comentários. Após o
pré-processamento o trecho anterior será transformado em:

cout << "PIANO" i

. . .
X = 3 . 14 * 3. 14 ; //Quadrado d e PI
• • •

Por meio da diretiva #define, podemos definir textos ou instruções


completas com um nome indicativo, como mostra o trecho a seguir:
#de fine ERRO cout << '' \a \aERRO! !''

i f ( zebra}
ERRO;

O qualificador const pode ser usado para substituir definições de


constantes com #define. A principal vantagem que o qualificador const tem
sobre a diretiva #define é que uma constante declarada com const é uma
localização de memória semelhante a uma variável e reconhecida pelo compi-
lador. Em outras palavras, uma constante tem um tipo definido e se for usada
ou declarada de modo errado o compilador acusará, enquanto a diretiva #define
não é reconhecida p elo compilador.

MACROS

Até o momento, consideramos somente a diretiva #define na sua forma mais


simples. Agora mostraremos como escrever diretivas #define que aceitam
argumentos, chamadas macros.
//PRNMACRO . CPP
//Mostra o uso de macros
166 Treinamento em Linguagem C++ Cap. 5

#inc l ude <ios t ream.h>

#define PRN(n) cout << n << ' \n '

void ma in ()
{
int nl , n2 ;
n 1=14 16 ;
n2=nl/2 ;

PRN(nl ) ; //Chamada à macro


PRN(n2 ) ;
}

O programa imprime:
1416
708
As chamadas às macros são substituídas, em nossos programas, por
suas definições. Assim, toda ocorrência de PRN(n) do exemplo será trocada por
cout << n << '\n' de tal forma que no lugar de n é usado o argumento da
chamada à macro. Após o pré-processamento, o nosso programa será o seguinte:
// PRNMACRO . CPP
//Mo stra o uso de macros

#incl ude <i ostream.h>

void ma in ()
{
int n l,n2;
n1=1416;
n 2=nl /2 ;

cout << nl << '\n '


cout << n2 << '\n '
}
Cap. 5 Funções 167

Na definição de uma macro, nunca deve haver espaço em branco no


identificador. Por exemplo:
#define PRN (n} cout << n << '\ n '

não funcionará, porque o espaço entre PRN e (n) é interpretado como fim do
identificador.

"
O USO DE PARENTESES EM MACROS

A falta de parênteses em macros pode provocar erros consideráveis. Suponha


que seu programa contenha as seguintes linhas:
#de f i ne SOMA(x,y) X + y

. .. . .

z = 10 * SOMA(3 ,4);

Qual é o valor atribuído a z? Você deve estar pensando que 3 será


adicionado a 4, produzindo 7, e este resultado, quando multiplicado por 10,
produzirá 70. ERRADO!!
O pré-processador executa uma substituição literal e em nada inteli-
gente. A instrução final será:
z = 10 * 3 + 4;

e o valor 34 será atribuído a z.


A solução é colocar o texto entre parênteses:
#def i ne SOMA( x, y ) (X + y)

A instrução pré-processada será:


z = 10 * (3 + 4 };

Entretanto, parênteses envolvendo o texto não solucionam todos os


problemas. Considere o seguinte trecho:
168 Treinamento em Linguagem C++ Cap. 5

#define PROD(x,y) (x * y}

• • • •

• • • •

z = PROD(2 + 3, 4 ) ;

A instrução pré-processada é
z = (2 + 3 * 4);

e o resultado não é o esperado.


A solução é envolver cada argumento por parênteses:
#def i ne PROD(x,y) ( (X) * ( y) }

DEFININDO MACROS USANDO OUTRAS MACROS

Uma macro pode ser definida usando outra macro. Verifique o exemplo:
//Mostra o uso de macros que chamam outras macros

#include <iostream . h>

#define PI 3.1416
#define SQ(x) ( (x} * (x)}
#defi ne AREA(x} ( (4 } * (PI} * SQ (x}}

void ma in (}
{

float ra1 o ;
.

cout << '' \nDigite o ra i o de uma es f era :");

• .
c 1n >> ra1o ;
Cap. 5 Funções 169

cout << " \nA área da esfera é " << AREA ( raio);
)

,
MACROS EM VARIAS LINHAS

Diretivas com um texto grande podem ser escritas em mais de uma linha se a
barra invertida (\) for colocada no final da linha, antes de prosseguir para a
próxima linha. Veja o exemplo:
#d e fin e MAI USC(ch} ( (ch} >= 'a' && (ch) < = 'z' ) ? \
( (ch) - 'a' + 'A' ) : (ch)

MACROS VERSUS FUNÇÕES inline

As macros definidas com #define são similares a funções inline, entretanto as


funções inline são reconhecidas pelo compilador, enquanto as macros são
implementadas no programa por meio de uma simples substituição de texto.
O tipo de argumentos em macros não é avaliado pelo compilador, o
que em alguns contextos é uma vantagem.
Por exemplo, a macro SOMA() pode ser usada com qualquer tipo de
valores:
a = SOMA(3 . 4 8, 4 . 5) ; / / valores float
b - SOMA( 2 , 3 ); // va l ores int

Se uma função for escrita para calcular a soma de dois números, será
necessário respeitar o tipo de seus argumentos ou escrever uma farm1ia de
funções sobrepostas.
Por outro lado, a falta de avaliação dos argumentos pode provocar
resultados inesperados. Verifique os dois exemplos seguintes: o primeiro im-
plementa uma macro e o segundo, uma função inline.
//Mostra probl e mas com macro s
170 Treinamento em Linguagem C++ Cap. 5

#include <i ostream. h>


#incl ude <conio .h>

#define MAIUSC(ch } ( (c h l>= ' a ' && (ch} <= ' z ' } ? \
( (c h} - ' a ' + ' A ' ) .• ( c h)

void ma in ()
{

char cp ;

cp= MAIUSC(ge tch() } ; //Prob l e mas

c o u t << cp ;
}

Execute este programa e observe o efeito da chamada a uma função


como argumento da macro. Agora verifique a implementação com urna função
inline.
//Macros versus funçõ e s inline

#include <iostream . h>


#include <conio .h>

i nline char maiusc(char ch)


{

return (ch>= ' a ' && ch <= ' z ' }? (ch- ' a ' + ' A' } : ch ;
}

void ma in ()
{
char cp ;

cp= maiusc(getch() ) ; 1/ Sem Problemas

cout << cp ;
)
Cap. 5 Funções 171

Mais dois exemplos:


I /NACRO
#include <iostream . h>

#de fine MIN(x,y) (x < y) ? (x) .• (y)

void ma in ()
{

int nl - 1 , n2 - 2 , n;

n=MIN(n1++ , n2++) ;

cout << 11
\nnl= 11
<< nl << 11
n2 =" <<n2 <<" n="<<n;
}

//FUNCAO inline
#inc lude <iostream . h>

inline int min(int x , int y)


{
return (x < y) ? x : y ;
}

void ma in ()
{
int nl - 1 , n2 - 2,n;

n=min(nl++,n2++) ;

cout << 11
\nnl= 11
<< nl << 11
n2= "<<n2 << " n="<<n ;
}
172 Treinamento em Linguagem C++ Cnp. 5

A DIRETIVA #undef

A diretiva #undef remove a mais recente definição criada com #define.


#de f i ne GRANDE 3
#de f i ne ENORME 8
#define SOMA(x ,y ) (x) +( y )
....
• • • •

#undef GRANDE //Cancela a de fini ção de GRANDE


#de f i ne ENORME lfl) //ENORME agora vale 1(/)
....
....
#undef ENORME //ENORME volta a valer 8
• • • •

....
#undef ENORME //Cancela a definição de ENORME
. . . ..
....
#undef SOMA //Cancela a macro SOMA

Observe que, para remover uma macro, somente o nome da macro deve
constar na diretiva #undef. Não deve ser incluída a lista de argumentos.

A DIRETIVA #include

A diretiva #include causa a inclusão de outro arquivo em nosso programa-fonte.


Na verdade, o compilador substitui a d iretiva #include de nosso programa pelo
conteúdo do arquivo indicado, antes de o programa ser compilado.
A linha
#include <iostream . h>

solicita ao compilador incluir o arquivo iostream.h em nosso programa antes


de comp ilá-lo.
Cap. 5 Funções 173

Além do uso dos sinais de< e>, a diretiva #include aceita uma segunda
sintaxe:
#include '' iostream . h ''

Quando usamos os sinais de < e >, o arquivo é procurado somente no


diretório INCLUDE. Quando usamos aspas duplas1 o arquivo é procurado
primeiramente no diretório atual e depois, se não for encontrado, no diretório
INCLUDE.

ARQUIVOS DE INCLUSAO

Os arquivos de inclusão (também chamados arquivos de cabeçalho) são textos


escritos em caracteres ASCII normais, criados geralmente para incorporar
definições de constantes, macros, protótipos de funções/ definições de tipos de
dados complexos, funções inline e declarações de variáveis externas.
Você pode verificar o conteúdo desses arquivos utilizando o comando
type do DOS.
Geralmente, os arqu ivos de inclusão têm um nome terminado com o
sufixo ".H" (de header ou cabeçalho) e estão gravados no diretório INCLUDE.
Por exemplo, o arquivo conio.h contém o protótipo das funções getch()
e getche() e é por esse motivo incluído nos programas que fazem uso destas
funções.
Vários arquivos de inclusão são fornecidos junto ao seu compilador;
eles contêm o protótipo das funções de biblioteca e as definições de classes e
objetos do próprio sistema.
Você pode criar outros arquivos de inclusão. Você pode organizar
definições de constantes e macros num arquivo separado e, toda vez que um
programa necessitar utilizá-las, só deverá incluí-lo por meio da diretiva #include.
Suponha que você tenha escrito várias fórmulas matemáticas para calcular as
áreas de diversas figuras:
#de f i n e PI 3. 14159
#de f ine A_CIRC( ra i o) (PI*(raio) * ( r aio))
#de f i ne A_ RET(base,altura ) ( (base ) * (a ltu ra ) )
174 Treinamento em Linguagem C++ Cnp. 5

#define A_TRI (base,altura) ((base)*(a ltura ) / 2)


#define A_ ELIP(raiol , r aio2) (PI *( raio l )*( raio2))
#define A_TRAP(a lt , ladl,lad2) ( (a 1 t ) * ( ( l adl) + ( lad2 ) ) I 2)

O texto acima pode ser gravado com o nome areas.h e todo programa
que fizer uso destas macros deve simplesmente conter a diretiva:
#include ''areas . h ''

As possibilidades do uso de #defin e e #include podem ser bastante


criativas. Analise o programa a seguir:
#include ''pascal.h''

prog ram
b eg in
write( " Isto é linguagem C++?? " ) ;
end

Humm... isto parece familiar, um pequeno programa em Pascal. O


segredo está no arquivo pascal.h a seguir.
#include <i ostream.h>
#de fine program void ma in ()
#de fine begin {
#define write(x) cout << X
#de f i ne e nd }

COMPILAÇAO CONDICIONAL

O pré-processador oferece diretivas que permitem a compilação condicional de


um programa. Elas facilitam o desenvolvimento do programa e a escrita de
códigos com maior portabilidade de uma máquina para outra ou de um
ambiente a outro. São elas:
Cap. 5 Funções 175

AS DIRETIVAS #if, #ifdef, #ifndef, #elif, #e/se e #endif

Cada diretiva #if deve terminar pela diretiva #endif. Entre #if e #endif pode
ser colocado qualquer número de #elif, mas só se permite uma única diretiva
#else. A diretiva #else é opcional e, se estiver presente, deve ser a última anterior
a #endif. Observe o exemplo:
#de fin e DEBUG 1

• • • •

....

#if DEBUG == 1
cout << '' \nERRO - '' << e rro 1 ;
#elif DEBUG == 2
cou t << " \nERRO - " << err o2 ;
#el s e
cout << " \nERRO não doc umentado";
#end i f

Outro exemplo:
#i f CORES > 5
#d ef ine SOMBRA 1
# i f COR_ FUNDO == 1
# i nclude ''corfundo .h''
#e l se
#include '' sernfundo .h''
#e ndif
#else
#define SOMBRA 0
#if CGA == 1
#include "cga . h "
#else
#includ e ''mono . h ''
#endif
#endif
176 Treinamento em Linguagem C++ Cnp. 5

Para testar constantes definidas com #define que não tenham valor
nenhum, podemos utilizar #ifdef e #ifndef. Por exemplo:
#define VERSAO_DEMO

. ...
. .. . .

#ifdef VERSAO_DEMO
#define NUM_REC 20
#else
#de fi ne NUM_REC MAXINT
#e nd if

O último exemplo mostra como um único programa-fonte pode gerar


dois executáveis diferentes: se a diretiva que define VERSAO_DEMO for
inserida, o executável poderá manipular somente 20 registros e estará criada a
versão demo de seu programa. Caso esta diretiva não esteja presente, o
programa poderá manipular o número máximo de registros.
Veja outro exemplo:
#ifdef REDE
#define PASSWORD
#include "redes .h"
#else
#include "monouso. h ''
#endif

A diretiva #ifndef verifica a não-definição da constante. Por exemplo:


#i fndef WINDOWS
#define VERSAO "\nVersão DOS"
#e lse
#define VERSAO ''\nVersão Windows ''
#endif
Cap. 5 Funções 177

O OPERADOR delined

Uma alternativa ao uso de #ifdef e #ifndef é o operador defined.


#i f defined( UNIX) && !define d(INTEL_48 6}
. ...
....
#endif

A DIRETIVA #error

A diretiva #error provoca uma mensagem de erro do compilador em tempo de


compilação.
#i f TAMANHO > TAMANHOl
#error "Tamanho incompatível "
#endif

..
REVISA O

1. As funções são escritas para decompor um problema em problemas meno-


res, simplificando e organizando o programa como um todo.
2. As linguagens orientadas ao objeto oferecem outros meios de organização
de programas.
3. A instrução que solicita ao programa a execução de uma função é conhecida
como "chamada à função".
4. Toda função C++ deve ser declarada. A declaração de uma função é
chamada PROTÓTIPO DA FUNÇÃO.
5. O protótipo de uma função informa o tipo da função e o número e tipo de
seus argumentos.
178 Treinamento em Linguagem C++ Cap. 5

6. O tipo de uma função é definido pelo valor retornado por meio do comando
return.
7. O comando return encerra a execução da função e pode retornar somente
um único valor para a função que chama.
8. O mecanismo por meio do qual uma função recebe argumentos em variáveis
criadas em seu cabeçalho para armazenar uma cópia dos valores passados
é chamado "Passagem por Valor".
9. O operador de referência{&) é usado junto ao nome de um tipo para criar
uma referência a uma variável. Uma referência não é uma cópia da variável
a quem se refere. É a mesma variável sob diferentes nomes.
10. "Passagem por referência" é o nome dado à passagem de argumentos para
funções que os declaram como referência às variáveis originais. Esta forma
de passar argumentos permite às funções alterar as variáveis enviadas pela
função que chama.
11. Argumentos recebidos em referências constantes são utilizados para eco-
. ' .
normzar memona.
12. O protótipo de funções pode incluir valores "default'' para argumentos de
funções. Estes valores são usados quando os argumentos correspondentes,
na instrução de chamada, são omitidos.
13. Uma família de funções com o mesmo nome e lista de argumentos diferentes
em número e/ ou tipo é chamada "SOBRECARGA DE FUNÇÕES".
14. O código de uma função inline é inserido em todo lugar onde ela é
chamada.
15. Uma função inline deve ser escrita antes de qualquer função que a chama.
16. Funções inline poupam tempo de execução, mas não memória.
17. Uma função é dita recursiva se, em seu corpo, estiver presente uma
instrução de chamada a ela própria.
18. A classe de armazenamento de uma variável informa visibilidade, tempo
de vida, lugar da memória onde será alocada e seu valor inicial.
19. Em C++, há quatro classes de armazenamento: auto, extern, static e register.
A classe auto é a default".
'I
Cap. 5 Funções 179

20. O operador de escopo(::) é usado junto ao nome de uma variável externa


que desejamos acessar quando há uma variável automática de mesmo
nome, visto que a classe auto tem precedência sobre a classe extern.
21. A palavra extern não é usada para criar variáveis externas e sim para
informar ao compilador que a variável em questão foi criada em outro
módulo.
22. Uma função pode retornar uma referência a uma variável externa. Como
resultado, a expressão " func() = 20; " é válida.
23. A classe static, usada com variáveis externas ou funções, tem o sentido de
privacidade. Variáveis e funções estáticas externas são acessadas somente
pelas funções escritas abaixo delas e no mesmo programa-fonte.
24. As variáveis das classes auto ou register são criadas em tempo de execução,
enquanto as das classes static ou extern, em tempo de compilação.
25. O pré-processador C++ é um programa contido no compilador que altera
o programa-fonte antes da compilação.
26. Diretivas são as instruções que o pré-processador executa.
27. A diretiva #define é usada para definir constantes ou macros. Em C++, é
preferível substituir o uso de #define por constou inline.
28. A diretiva #undef cancela a mais recente definição criada com #define.
29. A diretiva #include causa a inclusão de um outro arquivo em nosso
programa-fonte.
30. As diretivas #if, #ifdef, #ifndef, #elif, #else e #endif permitem compilação
condicional.
31. O operador defined é uma alternativa ao uso de #ifdef e #ifndef.
32. A diretiva #error permite a apresentação de uma mensagem de erro do
compilador em tempo de compilação.
180 Treinamento em Linguagem C++ Cnp. 5

,
EXERCICIOS

1. Quais das seguintes razões são válidas para escrever funções?


a) economizar memória;
b) rodar mais rápido;
c) dar um nome a um bloco de código;
d) dividir uma tarefa em pequenas unidades;

e) ajudar a organizar o programa;


f) reduzir o tamanho do programa.
2. Quais das seguintes instruções é uma chamada à função sorte?
a) sorte = 5;

b) int sorte () { return r and () ; }

c) x = sorte () ;

d) int y = sorte() % l flJ;

3. Qual é a diferença entre definir e declarar uma função?


4. O que são parâmetros de uma função?
a) a parametrização das variáveis recebidas;
b) as variáveis da função que recebem os valores da função que chama;
c) os valores retornados da função;
d) as variáveis visíveis somente pela função que chama.

5. O protótipo de uma função:


a) pode ser escrito em qualquer lugar do programa;
b) deve preceder a definição da função e toda chamada a ela;
c) pode ser suprimido se a função for definida antes de ser chamada;
Cap. 5 Funções 181

d) é uma instrução que pertence ao corpo da função.


6. O tipo de uma função:
a) é definido pelos argumentos que ela recebe;
b) é definido pelo valor retornado pelo comando return;
c) é sempre void;
d) pode ser qualquer um, exceto void.
7. O comando return:
a) é de uso obrigatório em todas as funções;
b) termina a execução da função;
c) retoma para o início da função;
d) pode retornar um único valor à função que chama.
8. Argumentos de funções podem ser:
a) constantes;
b) variáveis;
c) chamadas a funções;
d) expressões;
e) protótipos de funções.
9. Quando argumentos são passados por valor:
a) a função cria novas variáveis para recebê-los;
b) a função acessa as próprias variáveis da função que chama;
c) a função pode alterar as variáveis da função que chama;
d) a função não pode alterar as variáveis da função que chama.
10. Uma função que não recebe argumentos é do tipo:
a) int;
b) void;
182 Treinamento em Linguagem C++ Cnp. 5

c) float;
d) Não é possível identificar o tipo da função somente com estas informações.

11. Uma função que não retorna nenhum valor é do tipo:


a) int;
b) void;
c) float;
d) Não é possível identificar o tipo da função somente com estas informações.

12. A instrução
int& x = y;

a) cria a variável x com o valor de y;


b) cria uma cópia da variável y;
c) x é a mesma variável que y;
d) y é uma referência à variável x.

13. Quando argumentos são passados por referência:


a) a função cria novas variáveis para recebê-los;
b) a função acessa as próprias variáveis da função que chama;
c) a função pode alterar as variáveis da função que chama;
d) a função não pode alterar as variáveis da função que chama.

14. O que são referências constantes e para que servem?


15. Funções sobrecarregadas:
a) são um grupo de funções, todas de mesmo nome;
b) simplificam a vida do programador;
c) todas têm o mesmo tipo e número de argumentos;
d) sobrecarregam o programador.
Cap. 5 Funções 183

16. Uma função inline:

a) deve ser escrita numa única linha;


b) pode ser escrita em qualquer parte do programa;
c) deve ser escrita antes da primeira chamada a ela;
d) haverá tantas cópias de seu código no programa quantas forem as
chamadas a ela.
17. Funções inline:

a) poupam memória;
b) poupam tempo de execução;

c) aumentam a legibilidade do programa;


d) u sam mais memória.

18. Uma função recursiva:

a) é definida dentro de outra função;


b) contém grandes recursos;

c) contém uma chamada a ela mesma;


d) solicita recursos de outros programas.

19. As funções recursivas:

a) poupam memória;
b) poupam tempo de execução;
c) aumentam a legibilidade do programa;
d) usam mais memória.

20. A classe de armazenamento de uma variável determina:

a) tamanho, endereço e classificação;


b) tempo de vida, visibilidade e inicialização;

c) valor armazenado, nível de declaração e forma de armazenamento;


d) valores default, palavras-chave e automatização.
184 Treinamento em Linguagem C++ Cap. 5

21. As variáveis das classes e são criadas em


tempo de compilação.
22. As variáveis das classes e são criadas em
tempo de execução.
23. A palavra-chave extem:

a) solicita que a variável seja criada em tempo de execução;


b) cria variáveis externas;
c) informa ao compilador que a variável foi criada em outro fonte;
d) a variável em questão manterá o valor zero.
24. Verdadeiro ou Falso:
a) variáveis externas são visíveis até mesmo a códigos de outros arquivos;
b) variáveis estáticas externas são visíveis até mesmo a códigos de outros
.
arquivos;
c) variáveis externas ou estáticas podem ser declaradas em qualquer lugar
do programa;
d) variáveis estáticas podem ser alteradas por qualquer função.
25. As variáveis das classes static e extern são inicializadas com o valor
____ por falta de inicialização explícita.
26. As variáveis das classes auto e register são inicializadas com o valor
_ _ __ por falta de inicialização explícita.
27. O operador de escopo (::) opera em variáveis da classe:
a) extern;
b) static;
c) auto;
d) register.
Cap. 5 Funções 185

28. Considere as seguintes declarações:


int i ;
int& refi(void) ;

Quais das seguintes instruções são válidas:


a) y = ref i( );

b)refi () = y;

c) refi (y);

d) refi () = 1 4 16;

29. Qual das seguintes instruções é incorreta:


a) auto int X - rand () ;

b) static int X - rand () ;

c) extern int X - rand () ;

d) register int X - rand () ;

30. A principal tarefa do pré-processador é:


a) auxiliar no desenvolvimento do programa-fonte;
b) aumentar a velocidade de execução;
c) converter programas para outra linguagem;
d) processar o programa em diversas máquinas.
31. Explique as semelhanças e diferenças entre o uso de #define e do qualifi-
cador const para definir constantes.
32. O que é macro?
a) Uma diretiva #define que admite argumentos;
b) Uma diretiva #define que substitui o uso de qualquer função;
c) Uma diretiva #define que facilita a escrita de funções;
d) Uma diretiva #define que retoma um valor.
186 Treinamento em Linguagem C++ Cap. 5

33. Escreva uma função inline que substitua a macro:


#define TROCA (a , b ) {int t ; t =a ; a =b ; b =t ; )

34. Escreva uma macro que tenha o valor 1 se o seu argumento for um número
ímpar, e o valor O se for par.
35. Escreva uma macro que encontre o maior entre seus três argumentos.
36. Escreva uma macro que tenha valor 1 se o seu argumento for um caractere
entre 'O' e '9', e O se não for.
37. Escreva uma macro que converta um dígito ASCII entre 'O' e '9' a um valor
numérico entre O e 9.
38. Escreva funções inline correspondentes às quatro macros dos exercícios
anteriores.
39. Um número primo é qualquer inteiro positivo divisível apenas por si
próprio e por 1. Escreva uma função que receba um inteiro positivo e, se
este número for primo, retorne 1, caso contrário retorne O.
40. A famosa conjetura de Goldbach diz que todo inteiro par maior que 2 é a
soma de dois números primos. Testes extensivos foram feitos sem contudo
ser encontrado um contra-exemplo. Escreva um programa mostrando que
a afirmação é verdadeira para todo número par entre 700 e 1100. O
programa deve imprimir cada número e os seus correspondentes primos.
Use a função do exercício anterior.
41. Escreva uma função que receba como argumento o ano e retorne 1 se for
um ano bissexto e O se não for um ano bissexto. Um ano é bissexto se for
divisível por 4, mas não por 100. Um ano também é bissexto se for divisível
por 400.
42. Escreva uma função que receba dia, mês e ano e calcule o dia da semana.
Esta função retoma O se for domingo, 1 se for segunda-feira etc. Consulte
o programa DIASEMAN.CPP no capítulo anterior.
43. Escreva um programa que solicite ao usuário um ano e imprima o calendá-
rio desse ano. Utilize as funções dos dois exercícios anteriores.
Cap. 5 Funções 187

44. Escreva uma função que desenhe um retângulo de 5 linhas por 20 colunas
usando os caracteres '+', '-' e ' I '. O número de linhas, o de colunas e os
caracteres do desenho são argumentos "default" da função. Quando a
função é chamada sem nenhum argumento, desenha o seguinte retângulo:
+--------------------------- +

+---------------------------+
45. Escreva uma função que receba um número float como argumento e
retorne, em outros dois argumentos passados por referência, a parte inteira
e a parte decimal desse número.
46. Escreva uma função que ordene o valor de três argumentos do tipo char.
Por exemplo, se ch1, ch2 e ch3 são variáveis do tipo char com valores 'B',
'A' e ' C' respectivamente, após a chamada à função as variáveis conterão
'A', 'B' e 'C' respectivamente. Utilize a passagem dos argumentos por
referência.
47. Escreva uma família de funções sobrecarregadas para ler uma variável de
qualquer dos tipos: char, int, float ou double. Utilize a passagem dos
argumentos por referência.
48. Escreva uma função recursiva chamada potencia() que aceite dois argu-
mentos inteiros positivos i e j. A função retoma o i elevado à potência j. Por
exemplo: potencia(2,3) é igual a 8. Use a seguinte definição:
Um número i elevado à potência j é igual a i elevado à potência j-1 vezes i.
49. Escreva uma função recursiva que receba como argumento o número do
termo de uma seqüência de Fibonacci e retorne o seu valor. Por exemplo:
se o argumento for 7, a função retorna 13. Use a seguinte definição:
Os dois primeiros termos da seqüência têm valor. Cada um dos próximos
termos vale a soma dos dois anteriores.
50. Escreva uma função recursiva de nome soma() que receba um número
inteiro positivo n como argumento e retorne a soma dos n primeiros números
inteiros. Por exemplo, se a função receber n=5, deve retornar 15, pois
15 = 1 + 2 + 3 + 4 + 5
Capítulo 6

MATRIZES

Matriz é um tipo de dado em C++ usado p ara representar uma coleção de


variáveis de mesmo tipo.
Imagine o seguinte problema: Calcular a média aritmética das notas de
prova de cinco alunos. Você poderia escrever o seguinte programa:
//NOTAS.CPP
//Ca l cula a média das notas de cinco alunos
#include <ios tream . h>
void ma in ()
{
i nt nota0 , no tal, not a2, nota3, nota4 ;

<< " Digite no ta a luno 1 " . .


c J.n >> nota0 ;
cout a do I

cout << "Digite a nota do aluno 2 ". I



cJ.n >> natal ;
"Digite ". .
cout << a nota do aluno 3 I cJ.n >> nota2 ;
". .
cout << "Digite a nota do aluno 4 I CJ.n >> nota3 ;
<< "Digite no ta a luno " . .
CJ.n >> nota4 ;
cout a do 5 '

i nt media= (nota 0+notal+nota2+ nota3+nota4) / 5 ;


cout << " \nMédia das notas : " << media ;
}

188
Cap. 6 Matrizes 189

Imagine agora se você pretendesse encontrar a média aritmética das


notas de uma classe de 50 alunos ou da escola toda com 2000 alunos? Seria uma
tarefa bastante volumosa!
É evidente que precisamos de uma maneira conveniente para referen-
ciar tais coleções de dados similares. Matriz é o tipo de dado oferecido por C++
para esse propósito.
Uma matriz é um conjunto de variáveis, do mesmo tipo, referenciadas
por um único nome, onde cada variável é diferenciada por meio de um número
chamado "índice". Os colchetes são usados para conter o índice.
A declaração
int notas [S];

aloca memória para armazenar cinco variáveis do tipo int e anuncia que notas
é uma matriz de cinco elementos.
Vamos reescrever o programa anterior usando uma matriz:
//NOTAS.CPP
//Cal c ula a média das notas de cinco alunos usando matriz
#include <iostream . h>
void ma in ()
{

i nt notas[S ] , media=0 ;

f or ( i n t i =0 ; i <S; i ++)
{
cout << '' Digite a nota do aluno '' <<(i+l}<< '': '';
c1n >> notas[ i];

media += no t as [i ] ;
}

cout << '' \n\nMédia das notas : '' << (mediaiS} ;


)

Veja um exemplo da execução do programa:


Digi t e a nota do al uno 1 : 7 5
190 Treinamento em Linguagem C++ Cap. 6

Digite a nota do aluno 2 : 55


Digit e a not a do a l uno 3 : 60
Digite a nota do aluno 4 : 80
Digite a nota do aluno 5 : 90

Média das nota s: 70

...
DECLARAÇAO DA MATRIZ

Em C++, as matrizes precisam ser declaradas, como quaisquer outras variáveis,


para que o compilador conheça o tipo de seus elementos e reserve espaço de
memória suficiente para armazená-las.
Os elementos da matriz são guardados numa seqüência contínua de
memória, isto é, um seguido ao outro, o que não ocorre quando criamos
variáveis separadas.
O que diferencia a declaração de uma matriz da declaração de qualquer
outra variável é a parte que segue o nome, isto é, o par de colchetes ([ e ]) que
envolve um número inteiro indicando o tamanho da matriz.
A instrução
int notas [5] ;

informa que a matriz notas é formada por cinco elementos do tipo int. Por
definição, uma matriz é composta por elementos de um único tipo.
O valor que dimensiona a matriz na sua declaração deve ser uma
constante inteira. Assim, não podemos dimensionar uma matriz por meio de
uma variável.
Cap. 6 Matrizes 191

REFERENCIANDO OS ELEMENTOS DA MATRIZ

Cada um dos elementos da matriz é referenciado individualmente por meio de


um número inteiro entre colchetes seguindo o nome da matriz. Este número
tem um significado diferente quando referenda um elemento da matriz e na
declaração da matriz, onde indica o seu tamanho.
Quando referendamos um elemento da matriz, este número especifica
a posição do elemento na matriz. Os elementos da matriz são sempre numerados
por índices iniciados por zero. Por exemplo, a instrução
notas [2) = 90;

atribui o valor 90 ao terceiro elemento da matriz, pois a numeração começa em


zero. Assim, o último elemento da matriz possui um índice de uma unidade
menor que o tamanho da matriz.
O índice utilizado para referenciar elementos de uma matriz pode ser
o valor de uma variável inteira ou uma constante. Em nosso programa,
utilizamos a variável i como índice. Observe a instrução
cin >> notas[i ];

Quando escrevemos notas[i], estamos escrevendo o nome de uma


variável do tipo int como outra qualquer. Assim, em todo lugar onde possamos
utilizar o nome de uma variável int, podemos usar notas[i] .

MATRIZES DE OUTROS TIPOS DE ELEMENTOS

O fato de uma matriz ser composta por uma série de elementos de um dado
tipo permite a escolha de qualquer tipo de variável para a matriz. Suponhamos
que você queira que as notas dos seus alunos fiquem no intervalo de O a 10 e
que não seja desprezada a parte fracionária. A solução seria usar uma matriz
de elementos do tipo float.
//NOTAS.C PP
//Ca l c u l a a médi a da s notas de a l unos usando ma t riz floa t
#include <i ostream.h>
192 Treinamento em Linguagem C++ Cap. 6

#include <iomanip.h>

void ma in ()
{

const TAMANH0 =5;

float notas[TAMANHO],media =0 .0;

cout << setprecision(2) ;

f or( i nt i=0 ; i < TAMANHO ; i ++ )


{

cout << ''Di gite a not a do a l uno '' <<(i +l )<< ": '';
cin >> notas[i ];

media += notas[i];
}

cout << " \n\nHédia das notas : " << (media / TAMANHO) ;
}

Eis um exemplo da execução do programa:


Di gite a nota do aluno l : 7.5
Di gite a nota do aluno 2 : 5.5
Digite a nota do aluno 3 : 6.0
Digite a not a do aluno 4 : 8.0
Digite a nota do aluno 5 : 9 .0

Média das notas : 7.20

O programa apresenta um novo detalhe: o uso do qualificador const


para criar a constante que dimensiona a matriz e controla o limite do laço:
const TAMANH0 =5 ;

Usar o qualificador const no lugar de um número constante facilita a


alteração do tamanho da matriz. Se você desejar calcular a média das n otas de
Cap. 6 Matrizes 193

mais alunos, somente uma linha do programa deve ser alterada. Por exemplo,
para calcular a média das notas de 30 alunos, devemos alterar somente a
instrução de declaração da constante:
const TAMANH0=30 ;

,
UM NUMERO DESCONHECIDO DE ELEMENTOS

Nos exemplos anteriores, utilizamos um número fixo de notas. Como faríamos


se não conhecêssemos de antemão quantos itens entrariam na matriz?
O programa seguinte aceita até 50 notas e pode ser facilmente modifi-
cado para aceitar qualquer número de notas.
//NOTAS . CPP
//Ca lcu l a a média das notas de qua l quer número de alunos
#include <i ostream.h>
#include <iomani p.h>

void ma in ()
{
const TAMANH0=50 ;

float notas[ TAMANHO] ,media =0 . 0;

cout << setprecision(2) ;

int i =0 ;

do
{
cout << '' Di gite a nota do a l uno '' <<(i +l) << '': '';
c1n >> notas[i ];
} while (notas[i++] > = 0) ;


1-- ;
194 Treinamento em Linguagem C++ Cap. 6

.
for ( i nt j = 0 ; j < l ; j++}
media += notas [ j] ;

cout << " \n\nMédia das notas : " << (media/i} ;


}

Eis um exemplo da execução do programa:


Digite a nota do aluno 1 ; 71. 3(/J
Digite a not a do aluno 2 : 80 . 90
Digite a nota do aluno 3 ; 89 . 2
Di g it e a nota do aluno 4: -1

Média das notas : 80. 47

O laço for foi substituído pelo laço d o-while. Este laço repete a
solicitação da nota ao usuário, armazenando-a na matriz n otas[], até que seja
fornecido um valor menor que zero.
Quando o último item for digitado, a variável i terá alcançado um valor
acima do total de itens. Isto é verdadeiro, pois é contado o número negativo de
finalização da entrada. Assim, devemos subtrair 1 do valor contido em i para
encontrar o número correto de itens.

CHECANDO LIMITES

A nossa matriz foi dimensionada em 50 e este número permite a entrada de até


50 notas. Suponha, agora, que o usuário decida inserir mais de 50 notas. Como
expulsar os dados excedentes?
A linguagem C++ não realiza verificação de limites em matrizes, por
isso nada impede que você vá além do fim de uma matriz.
Se você transpuser o fim da matriz durante uma operação de atribuição,
então os valores sobressalentes irão sobrepor outros dados da memória. Estes
valores serão armazenados em seqüência, seguindo os elementos da matriz na
memória. Como não foi reservado espaço para guardá-los, eles sobreporão
outras variáveis ou até mesmo uma parte do código do próprio programa que
Cap. 6 Matrizes 195

por acaso esteja nesta memória. Isto acarretará resultados imprevisíveis, e


nenhuma mensagem de erro do compilador avisará o que está ocorrendo.

C++ não avisa a você quando o limite de uma matriz foi excedido.

Providenciar a verificação do limite de uma matriz é de responsabili-


dade do programador. A solução é não permitir que o usuário digite dados,
para elementos da matriz, acima do limite. Para isso, modificaremos o laço
do-while, do programa anterior, como segue:
do
{
i f ( i > = TAMANHO )
{

cout << "BUFFER LOTADO .\n "i



J. ++ i
break i // Sa i do l aço do - whil e
}

cout << '' Digit e a nota do aluno '' <<(i+l)<< '': ''i
cin >> notas[i ] i
} while (nota s [ i+ + l > = @) i

Com esta modificação, quando i atingir 50, que é um acima do último


índice da matriz, a mensagem "BUFFER LOTADO." será impressa e o comando
break fará com que o controle saia do laço do-while e passe p ara a segunda
parte do programa.

INICIALIZANDO MATRIZES

Você pode fornecer valores a cada elemento da matriz na mesma instrução de


sua declaração. Veja um exemplo que calcula o número de dias transcorridos a
partir do início do ano até a data especificada pelo usuário. O programa verifica
se o ano é ou não bissexto.
196 Treinamento em Ling uagem C++ Cap. 6

//DIAS.CPP
//Imprime o núme r o de d ias do ano até a data e s pecif i cada
#include <iostream . h>

void ma i n ()
{

int dmes[12 ] ={ 31,28, 31 , 3 0 , 31, 30 , 31 , 31, 3 0 , 31 ,3 0 , 31} ;

i nt d i a , mes , a no ;

cout << " \ nDi gite a data no f ormato DD/ MM/AAAA: ";

{
char ch ;
c i n >> dia >> ch >> me s >> c h >> ano;
}

if(ano%4 == 0 && ano%100 l l ano%4 00 == 0)


dmes (l]=29 ; / /Ano bissex to

i nt total=dia ;

f o r( i n t i =0 ; i < mes - 1 ; i ++ }
t ota l+ =dmes[ i] ;

cout << "Tota l de dias tran scorr i dos : " << total ;
}

Veja dois exemplos da execução do programa:


Digi t e a data no formato DD/MM/ AAAA : 14/ 6 / 1994
Total de dias transcorridos : 165

Digite a da t a no f ormato DD/MM/AAAA : 1 /3 / 1992


Total de dias transcorridos: 61
Cap. 6 Matrizes 197

O programa inicializa a matriz dmes[] na instrução:


int dmes [12 ]= { 31,28,3 1 , 30 , 31 , 30,31 , 31 , 30 ,3 1 , 30 , 31) ;

A lista de valores é colocada entre chaves e os valores são separados


por vírgulas. Os valores são atribuídos na seqüência em que são escritos. Isto
é, dmes[O] terá o valor inicial 31, dmes[l] 28 e assim por diante.
Observe o ponto-e-vírgula após fechar as chaves. Em C++, as estruturas
de programação como laços, funções e comandos de decisão não admitem um
ponto-e-vírgula após a chave de seus blocos de código, enquanto as estruturas
de dados sempre terminam por ponto-e-vírgula após a chave de fechamento.
Matrizes de qualquer classe de armazenamento podem ser inicializadas
em C++. Em linguagem C, somente podemos inicializar matrizes das classes
static ou extern.

A instrução de definição de uma matriz inicializada pode suprimir a


dimensão da matriz, restando apenas um par de colchetes vazios:
i nt dmes []=( 3 1 ,28 , 31,30 , 31 ,30, 31,31 , 30,3 1, 30,31} ;

Se nenhum número for fornecido para dimensionar a matriz, o compi-


lador contará o número de valores inicializadores e o fixará como dimensão da
matriz.
Se você especificar a dimensão da matriz e colocar menos inicializado-
res que esse tamanho, os elementos não inicializados conterão zeros. Se for
colocado um número de inicializadores maior que o necessário, o compilador
emitirá um erro.
Lamentavelmente, em C++, não há como especificar a repetição de um
inicializador nem de inicializar um elemento no meio de uma matriz sem
inicializar todos os anteriores.

..
MATRIZES DE MAIS DE UMA DIMENSAO

Os elementos de uma matriz podem ser de qualquer tipo, incluindo matrizes.


Os exemplos vistos até agora são de matrizes de uma dimensão, isto é, em que
198 Treinamento em Linguagem C++ Cap. 6

os elementos são de tipos simples. Diremos que uma matriz é de duas dimensões
quando seus elementos forem matrizes de uma dimensão.
Na verdade, em C++, o termo duas dimensões não faz sentido, pois
todas as matrizes são armazenadas na memória de forma linear. Usaremos este
termo para indicar matrizes em que os elementos são outras matrizes.
Com dois pares de colchetes obtemos uma matriz de duas dimensões
e com cada par de colchetes adicionais obtemos matrizes com uma dimensão a
o

mais.
Para ilustrar este conceito, apresentaremos um programa que usa uma
matriz de duas dimensões para criar uma grade do jogo-da-velha.
Inicialmente, a matriz é preenchida com pontos. Depois, o programa
forma um ciclo por meio de um laço while onde a matriz é impressa, verifica-se
se algum jogador já ganhou ou se houve empate, solicita-se ao jogador que
digite um par de coordenadas e finalmente atribui-se o caractere 'o' ou 'x' ao
elemento da matriz correspondente às coordenadas entradas.
Executando este programa, você verá como trabalha um sistema de
coordenadas de duas dimensões. Digite pares de números como ( O O ), ( 1 2),
(2 2) etc. A coordenada horizontal, ou seja, o número da linha, é fornecida
primeiro. Não esqueça que os índices começam em zero.
I /VELHA. CPP
//J ogo-da-velha . Mostra matri z de duas dimensões
#include <ios tream.h>

void ma in ()
{
unsigned char v [3 ) [3 ); // Ma t riz de duas dimensões

cons t int TRUE = 1;


const char O= fof f X _
-
f X f •
f

cout << '' Digite coordenadas na forma lin col . " .


o f
Cap. 6 Matrizes 199

f or ( l in = 0 i l in < 3 i lin+ + }
f o r(col = 0 ; col < 3; col++ }
v(lin) (col)= ' . 'i

wh i l e (TRUE)
{
c out << "\n \ n ";
f or (lin= 0i l in < 3 i l i n ++)
{
for(col= 0i col < 3 ; col+ +)
cou t << v ( l in ) [ c o l ) << I I •
I

c out << ' \ n' i

/ /Verifica se primeiro jogador ganhou


i f ( (v [ 0) [ 0) ==0 && v(0) [ 1 ) ==0 && v[0 ) (2 )==0 ) li
(v[l) [ 0) = =0 && v[l ] [ 1 ) ==0 && v[ l ] ( 2] = =0 ) li
(v [ 2 ) [0 ) ==0 && v[2) [ 1 ] ==0 && v[ 2 ] [2 ] ==0 ) li
(v ( 0] [0 ] ==0 && v ( 1] [ 0] ==0 && v [2 ] [ 0 ] ==0 ) li
(v ( 0] [1 ] ==0 && v [ 1] [ 1] ==0 && v [2 ] [1 ] ==0) li
(v [ 0)[2 ) ==0 && v [ 1] [ 2) ==0 && v[2 ] [2 ] ==0 ) 11
(v [ 0] [ 0] ==0 && v [ 1) [ 1 ] ==0 && v [ 2 J [ 2 J = =O l I I
(v [ 0][2 ] ==0 && v [ 1) [ 1 J ==0 && v[ 2 ] [ 0 ] ==0) )
{

cou t << " \n \aVo c e ganh o u, primeiro jogador! ! !'';


break i
)

//Veri f ica se segundo j ogador g anhou


i f ( (v [ 0] [ 0] = = X && v[0] [1 ] == X && v[0 ] [ 2 ] = = X) li
(v [1 ] [ 0]= = X && v[1 ) [ 1 ]== X && v[ 1] [2 ] = = X ) li
(v (2 ] [ 0] ==X && v (2) [ 1) == X && v [2 ] [2 ] ==X) li
(v ( 0][ 0 ] ==X && v [ 1] [ 0 ] == X && v [ 2 J [ 0 ] ==X) I I
(v[0 ][ 1 ] = = X && v [ 1] [ 1 ] == X && v[ 2 ] [ l ] = = X) li
(v [ 0] [ 2] = = X && v[1 J [ 2 ] == X && v[ 2] [ 2J = = X) li
200 Treinamento em Linguagem C++ Cap. 6

(v(0 ][0 ]==X && v(l] (l ] ==X && v( 2][2] ==X) li


(v[0] [2 ] ==X && v[l] [l] == X && v[2 ] [(/)] ==X))
{
cout << " \n \ aVoce ganhou, segundo jogador !!!";
bre a k ;
}

if (x== 9)
{
cout << ''\n\aEmpatou !!! '';
break;
}

cout << '' \nCoordenadas : '';


cin >> lin >> col ;

i f (v ( lin] [col ) --
-- I
. I ) //Casa l i vre ?
{
if(x%2)
v [lin) [col ) =X ;
else
v [ 1 in ) [co 1) =0 ;
X++ ;
}
}

Eis uma execução do programa:


Digi t e coorde nadas na f orma lin co1 :

• • •

• •

• •

Coor dena das : 0 0


Cnp. 6 Matrizes 201

o . .

• • •

Coor dena das : 1 1

o
• X •

Coorde nadas : 1 2

o . .
X O
• •

Coorde nadas : 0 2

O . X
X O

• • •

Coordenadas : 2 1

O . X
X O
o .

Coordenadas : 2 0
202 Treinamento em Linguagem C++ Cnp. 6

O X

X O
X O .

Voce ganh ou , segundo jogador! !!

...
INICIALIZANDO MATRIZES DE DUAS DIMENSOES

As matrizes de duas dimensões são inicializadas da mesma maneira que as de


dimensão única, isto é, os elementos são colocados entre as chaves depois do
sinal de igual e separados por vírgulas. Como cada elemento de uma matriz de
duas dimensões é por sua vez uma matriz, então cada elemento deve estar entre
chaves e os elementos internos devem ser separados por vírgulas.
Como exemplo, vamos reescrever o programa VELHA.CPP inicializan-
do a matriz com pontos.
//VELHA.CPP
//Jogo - da -ve lha .
//Mostra matriz de duas dimensões inicia lizada
#inc l ude <i ost ream . h>

v oid ma in ()
{
const char PT= ' . ' i

unsigned char v [3 ] [3 ]= // In i cializa matr iz


{ {PT PT PT}
I I I PT PT PT }{ PT PT PT}I I I { I I }i

const int TRUE = l i


const char O= ' o' , X - I X I •
- I

cout << "Digi te coordenadas na f orma li n co l •



11 •
I

int lin, col, x=0 ;


Cap. 6 Matrizes 203

vvhile (TRUE)
{

cout << " \ n \n" i


for(lin=0i lin < 3 i l in++ )
{

for(col= 0i col < 3i col++)


cout << v [lin] [ co l ] << I I •

'
cout << ' \ n'i
)

. .
I /Verifica se pr1me1ro jogador ganhou
i f ( (v[0] [0 ]= =0 && v[0 ] [ l ] ==0 && v[0 ] [2 ] = =0 ) li
(v [ 1][0 ] = =0 && v [ 1] [ 1 ] ==0 && v[ 1] [2 ] = =0) li
(v [2 ] [0 ] ==0 && v [2) [ 1) ==O && v ( 2 1 ( 2 1= =0) I I
(v [ 0) [0 ] ==0 && v [ 1) [ 0 ) ==0 && v[2) (0]==0) l i
(v (0 ][1] = =0 && v(1 ) [1 ) ==0 && v(2 ) [1 ) ==0) l i
(v ( 0] (2 ) = =0 && v [ 1] [ 2 ] ==0 && v(2 ) [2 ] = =0 ) li
(v [([) ] [0 ] ==0 && v [ 1] [ 1] ==0 && v[ 2] [2 ] ==0) l i
(v [0 ](2 ] ==0 && v(1] [ 1] ==0 && v(2 ] [0 ] ==0))
{

cout << "\n \ aVoce ganhou , primeiro jogador!! !"i


breaki
)

//Verifica se segundo jogador ganhou


i f (( v(([)] [QJ ] ==X && v[QJ] [1 )== X && v [0) [2 ) ==X) l i
(v [1 ) [QJ ) ==X && v [1) [1 ) ==X && v(1) [2 )= =X ) li
(v ( 2] [0 ) = =X && v[2 ] [1 ) == X && v[2 ] [2 ) = =X ) l i
(v (0 )[0 ] = =X && v ( 1] [ 0 ] = = X && v[2 ] [QJ ] ==X) l i
(v [0 ] [1 ] = =X && v [ 1] [ 1 ) == X && v[2] [1 ] = =X) l i
(v [0 ][2]==X && v[ l ] [2 )==X && v[2 ] [2 ] ==X) l i
(v [0) [ QJ) ==X && v [ 1) [ 1) == X && v [2 ) [2 ) ==X) li
(v (0 ] (2 ] ==X && v[1] [ 1 J==X && v (2 ] [QJ ] ==X))
{
204 Treinamento em Linguagem C++ Cap. 6

cout << " \n\ aVoce ganho u, segundo j ogador! !!";


break ;
}

i f (x== 9)
{
cou t << ''\ n\aEmpatou !! !'' ;
break ;
}

cout << " \nCoordenadas : " ;


cin >> lin >> c ol ;

i f (v (lin) [col ) == PT ) I /Casa livre ?


{
i f(x%2)
v[ lin ) [col ) =X ;
e lse
v [ lin) [co 1 ) =0;
X+ + ;
}
}
}

A matriz v[J tem três elementos: v[O], v[l] e v[2]. Cada elemento de v[]
é, por sua vez, uma matriz de três elementos do tipo char. Assim, v[O], v[l] e
v[2] são nomes de matrizes de elementos do tipo char.
Para inicializar uma matriz, devemos colocar a lista de elementos em
ordem, entre chaves e separados por vírgulas, exatamente como fizemos ao
inicializar uma matriz de uma dimensão:
uns igned char v[3 ] [3]=
{ {PT, PT , PT} {PT , PT , PT}
I I {PT , PT , PT } };
v[0 ] • I
v[l ] ----------------~

v[2J ----------------------------~
Cap. 6 Matrizes 205

A lista de valores usada para inicializar a matriz é uma lista de


constantes separadas por vírgulas e envolta por chaves.

..
INICIALIZANDO MATRIZES DE TRES DIMENSOES
"

Uma matriz de três dimensões é uma matriz em que cada elemento é uma matriz
de duas dimensões. Observe o fragmento de programa a seguir que inicializa
uma matriz de três dimensões:
i nt tresd[3] [2 ][ 4] =

{
{1,2 , 3 ,4},
{5, 6 ,7,8}
}

{7 , 9 , 3 , 2},
{4 , 6 , 8,3 }
}

{
{7 , 2 , 6 , 3},
{0 , 1 , 9 ,4}
}

} ;

A matriz tresd[] tem três elementos: tresd[O], tresd[l] e tresd[2]. Cada


um de seus elementos é uma matriz de duas dimensões.
Como você representaria o único valor zero da declaração anterior?
O primeiro índice é [2], pois o zero pertence ao terceiro grupo. O segundo
índice é [1], pois o zero está na segunda matriz do terceiro grupo. O
terceiro índice é [O], pois é o primeiro dos quatro números.
206 Treinamento em Linguagem C++ Cap. 6

Então:
tre sd [2) [1 ) [ 0 ] 0

,.,
MATRIZES COMO ARGUMENTOS DE FUNÇOES

Temos visto exemplos da passagem de vários tipos de variáveis como argumen-


tos de funções. As matrizes também podem ser passadas como argumento para
uma função.
O programa seguinte é uma variação do programa NOT AS.CPP, usan-
do uma função para calcular a média aritmética dos valores de uma matriz.
//MEDIA. CPP
//Most r a passagem d e matrizes para fu nções c omo argumento
#include <i os t r e a m. h>

i nt me d i a( int lis t a [ ) , int tamanho);

void ma in ()
{

con st MAXI =20 ;

i nt not as [MAXI ] i

for (int i=0 i i <MAXI i i+ +)


{

c ou t << "Dig it e a not a do aluno " <<(i +l }<<": "i

ci n >> not as [ i] i

i f (notas[i ] < 0 ) break i


}

int m- me dia (notas,i ) i


Cap. 6 Matrizes 207

cout << " \n\nMédia da s notas: " << rn ;


)

int media(int lista [ ] , i nt tamanho )


{

i nt m=0 ;

f o r(in t i =0 ; i < t a manho ; i ++) rn += l i sta [ i];

return ( m/tamanho) ;
)

A primeira parte deste programa lê a lista das notas enquanto não for
digitada uma nota negativa. O único elemento novo deste programa é a
instrução:
i n t m = med i a(notas , i) ;

ela é uma chamada à função media() que retoma a média das notas armazena-
das na matriz.
A parte crítica a ser considerada aqui é como foi passada a matriz para
a função: usamos unicamente o nome da matriz.
Para referenciar um elemento da matriz, já sabemos que a sintaxe é
notas[i]; mas o que representa o nome da matriz sem colchetes?

O nome de uma matriz desacompanhado de colchetes representa o endereço


de memória onde a matriz foi armazenada.

O nome de uma variável simples representa o valor nela contido,


entretanto o nome de uma matriz representa seu endereço de memória. Este
endereço é o endereço do primeiro elemento da matriz. Em outras palavras,
notas é o endereço de notas[O], que é uma variável int.
Assim, a função media() recebe um endereço de uma variável int e não
um valor inteiro e deve declará-lo de acordo. O tipo
i nt [ l

indica um endereço de uma variável int.


208 Treinamento em Linguagem C++ Cap. 6

O bom entendimento de endereços tornar-se-á imprescindível quando


estudarmos ponteiros. Analisaremos detalhadamente este assunto no capítulo
11, módulo 2.

AS MATRIZES SÃO PASSADAS PARA FUNÇÕES POR REFERÊNCIA

As matrizes são consideradas um tipo de dado bastante grande, pois são


formadas por diversas variáveis. Por causa disto, a linguagem C++ determina
ser mais eficiente existir uma única cópia da matriz na memória, sendo portanto
irrelevante o número de funções que a acessem. Assim, não são passados os
valores contidos na matriz, somente o seu endereço de memória.
O que ocorre quando o endereço de uma matriz é passado para uma
função como argumento?
A função usa o endereço para acessar os elementos da própria matriz
da função que chama. Isto significa que as alterações que forem feitas na matriz
pela função afetarão a matriz original.

Passando o nome de uma matriz para uma função, não é criada uma nova cópia
da matriz. A passagem é por referência.

ORDENANDO OS VALORES DE UMA MATRIZ

No exemplo anterior, a função media() não altera os valores dos elementos da


matriz. Vamos analisar um programa que ordena os valores de uma matriz e
ao mesmo tempo observar que a mudança da ordem é feita na matriz original,
criada em main().
//ORDNUM. CPP
#include <iostream . h>

void or dena( int[] , int) ;

vo id ma in ()
Cap. 6 Matrizes 209

const MAXI=20 i
int tab[MAXI ] i

f or( i nt i =0i i <MAXI i i++)


{
cout << "Digit e nómero ou z e r o para t e rminar : '' i
c in >> tab [i] i

if( ! tab[i ] } breaki


}

o rdena ( tab , i) i

for(int j=0 i j < i i j++ )


cout << " \n\t\ t'' << tab [j)i
}

void ordena( in t li sta [], int tamanho)


{

for(int i=0i i < tamanho - 1 i i++)


fo r(int j=i+l i j < t amanho i j++)
if( lis ta [ i] > lista [ j] )
{
i nt temp - lista[j ] i
lista[ j] - lista[i ] i
lis ta[i] - temp i
}
}

Eis um exemplo da execução do programa:


Digite '
numero ou zero para terminar : 46
Dig i te '
numero ou zero para terminar : 25
,
Dig i te numero ou zero para terminar : 73
Digite '
numero ou zero para te rminar : 58
Digite '
numero ou zero para t erminar : 33
210 Treinamento em Linguagem C++ Cap. 6

Dig i te número ou zero para t erminar: 18


Dig it e núme r o o u z e ro para terminar : 0

18
25
33
46
58
73

A ORDENAÇAO BOLHA

O processo de ordenação utilizado na função ordena() merece alguma explanação.


A função começa considerando a primeira variável da matriz, lista[O] .
O objetivo é colocar o menor item da lista nesta variável. Assim, a função
percorre um por um dos itens seguintes a fim de encontrar o menor deles.
Sempre que encontra um item menor, eles são trocados. Terminada esta
operação, é tomado o próximo item, lista[l]. Este item deverá conter o próximo
menor valor. Novamente, são realizadas as comparações e trocas. O processo
continua até que a lista toda esteja ordenada.
O processo de ordenação é feito por meio de dois laços. O laço mais
externo determina qual elemento da matriz será usado como base de compara-
ção. O laço mais interno compara cada item seguinte com o de base e, quando
encontra um item menor que o de base, faz a troca. A troca é feita no corpo do
if por meio de uma variável temporária.
Este método é chamado ordenação bolha. Sua popularidade vem de
sua simplicidade. No entanto, existem algoritmos bem mais eficientes.
A função main() imprime os valores dos elementos da matriz após o
retorno da função ordena(). Observe como a matriz foi alterada.
Cap. 6 Matrizes 21 1

"' "'
MATRIZES DE DUAS DIMENSOES COMO ARGUMENTO DE FUNÇOES

Para ilustrar o uso de uma matriz de duas dimen sões passada como argumento
para uma função, escreveremos um programa para avaliar a eficiência de
funcionários de uma loja quanto ao número de peças vendidas por cada um em
três meses.
O primeiro índice da matriz indica o número de funcionários da loja e
o segundo, o número de meses a serem considerados.
//HI STOGR . CPP
// I mpr ime um h ist ogra ma hor izon t a l
//Mos t ra ma triz de d uas dimensõe s como argume nto de função

#include <iostream. h>


#incl ude <i oman i p . h>

con s t MES=3 ;

vo i d hi stograma( int pecas [ ] [MES] , int nfunc};

void ma i n ()
{

c o nst FUNC = 5;
int p e c as[FUNC] [MES] ;

for ( int i= 0 ; i<FUNC ; i ++)


for( i n t ]=0; ] <MES ; ]+ +}
{
c out << ''Funcio nari a '' << (i +l} <<
" mes " < < ( j +l } << " : ";
cin >> p ecas[i ] [j ] ;
}
h is togr ama (p ecas,FUNC ) ;
)
212 Treinamento em Linguagem C++ Cap. 6

void histograma( int p ecas[] [MES] I int nfunc }


(

const float MAXBARRA=50 .0;


i nt max=0;

for(int i=0 ; i<nfunc ; i+ +)


{

int temp= 0;

for( int j=0; j<MES ; j++)


{
temp += pecas [ i ] [ j ] ;
)
if (ma x < temp ) max=temp ;
}

for( i =0 ; i <nfunc; i+ +)
(
int temp= 0;

for( int j=0; j<MES ; j++) temp += pecas [ i] [ j) ;

OI
cout << setw(2) << (i+ l) << ''
<< setw (S) << temp << ": 11 ;

int tam = int(float( temp )/float(max)*MAXBARRA);

for(j= 0 ; j<tam; j++} cout << I * I •


I

cout << "\n \n OI;


}
}
Cap. 6 Matrizes 213

Eis um exemplo da execução do programa:


Funci onaria 1 me s 1: 1144
Funcionaria 1 mes 2: 12 00
Func ionaria 1 me s 3: 120 0
Funci onaria 2 me s 1: 8 0 (/)
Func i onar ia 2 me s 2: 6 3 (/)
Func i onaria 2 me s 3: 750
Funci onaria 3 mes 1: 2345
Funcionaria 3 mes 2: 24 00
Func i o naria 3 mes 3: 25 67
Func i onaria 4 mes 1: 1789
Funcionar ia 4 me s 2: 187 6
Funciona ria 4 me s 3: 1654
Funcionaria 5 mes 1: 3456
Funci o naria 5 mes 2: 32 14
Funci ona r i a 5 me s 3: 2999

1 - 3544 :* *** **** ** ** * ** ***

2 - 2180 : ***** *** ** *

3 - 73 12 :* *** **** ******** ** **** ****** ** **** ***

4 - 5319 : *** *** ** ** **** **** ** ** ** ***

5 - 9669 :*** *** ********** *** *********** ** ***** **** ** *** ** **

O método de passagem do endereço da matriz para a função é idêntico


ao da passagem de uma matriz de uma dimensão, não importando quantas
dimensões tem a matriz, visto que sempre passamos o seu endereço.
histagrama (pecas , nfunc ) ;

Entretanto, a declaração da matriz na função e no seu protótipo é um


tanto misteriosa:
int p e c as [ ] [MES]
214 Treinamento em Linguagem C++ Cap. 6

Por que só estamos informando a segunda dimensão da matriz? Como


não há verificação de limites, uma matriz com a primeira dimensão de qualquer
valor pode ser passada para a função chamada. Mas uma função que recebe
uma matriz bidimensional deverá ser informada do comprimento da segunda
dimensão para poder operar com declarações do tipo:
pecas [2 ] [1]

pois, para encontrar a posição de memória onde pecas[2][1] está guardada, a


função multiplica o primeiro índice (2) pelo número de elementos da segunda
dimensão (MES) e adiciona o segundo índice (1), para finalmente somar ao
endereço da matriz (pecas).
Caso o comprimento da segunda dimensão não seja conhecido, será
impossível saber onde estão os valores.
Neste ponto, você já está apto a trabalhar com matrizes. Você sabe como
declarar matrizes de diferentes dimensões e tipos, como inicializar matrizes,
como referenciar um elemento particular da matriz e como passar uma matriz
para uma função.
A próxima seção deste capítulo mostrará um uso especial de matrizes:
manipulação de cadeias de caracteres (strings) que são, simplesmente, um tipo
de matriz.

STRINGS

O uso mais importante de matrizes é aplicado à criação de tipos de dados para


armazenar e manipular textos como palavras, nomes e sentenças.
String é uma matriz do tipo char que armazena um texto formado de
caracteres e sempre terminado pelo caractere zero ('\0'). Em outras palavras,
string é uma série de caracteres, onde cada um ocupa um byte de memória,
armazenados em seqüência e terminados por um byte de valor zero ('\0'). Cada
caractere é um elemento independente da matriz e pode ser acessado por meio
de um índice.
Cap. 6 Matrizes 215

STRINGS CONSTANTES

Sempre que o compilador encontra qualquer coisa entre aspas duplas, ele
reconhece que se trata de uma string constante.
Ao longo deste livro, já mostramos vários exemplos de strings cons-
tantes. Veja mais um exemplo:
cou t << '' Saudações !'';

"Saudações!" é uma string constante.


Na memória, a cadeia de caracteres "Saudações!" é armazenada da
seguinte forma:

1 449

1 450 s
1 451 a

1 452 u

1 4 53 d

1 45 4 a

1 455 ç

1456 ô

1 457 e

1 45 8 s

1 459

146 0 \0

1 4 61
216 Treinamento em Linguagem C++ Cnp. 6

Observe que o caractere '\0', também chamado NULL, tem o valor zero
decimal, e não o caractere '0', que tem valor 48 decimal.
A terminação '\0' é importante, pois é a única maneira que as funções
possuem para poder reconhecer onde é o fim da string.

,
STRINGS VARIAVEIS

Observe um exemplo de como definir uma string variável para receber um


nome do teclado.
// STRl.CPP
//Mostra o uso de strings
#include <iostream . h>

void ma in ()
{
c har nome [80 ];

cout << '' \nDigite o seu nome : '';



Cln >> nome ;

cout << " \nSeu nome é " << nome;


}

A instrução
.
Cln >> nome ;

lê cada caractere do teclado e os armazena a partir do byte de endereço nome.


A leitura termina quando a tecla ENTER é pressionada. O caractere '\0' é
inserido automaticamente no final da entrada. Observe que você não poderá
ultrapassar o limite estipulado na criação da matriz e deverá prever espaço para
o caractere '\0'.
Cap. 6 Matrizes 217

É possível limitar o número de caracteres a partir da seleção do número


desejado. Veja o exemplo:
//STR2 . CPP
//Mostra o uso de setw() com strings
#include <iostream . h>
#inc l ude <iomanip. h>

void ma in ()
(
char nome[8([) ];

cout << " \nDi g it e o s e u nome: ";


cin >> setw (8(/)} >> nome;

cout << " \nSeu nome é " << nome ;


}

Eis uma execução do programa:


Digite o seu nome: Viviane Mizrahi
Seu nome é Viviane

O programa subitamente eliminou o último nome. Por quê?


O objeto cin, quando usado desta forma, entende que um espaço em
branco termina a entrada. O resultado é que não existe uma forma de digitar
um texto de múltiplas palavras.

A FUNÇÃO gets(}

A função gets(), com protótipo no arquivo stdio.h, é mais conveniente para a


leitura de textos. O seu propósito é unicamente ler uma cadeia de caracteres do
teclado enquanto não for pressionada a tecla ENTER. Todos os caracteres são
armazenados na string e é incluído o caractere NULL no final.
218 Treinamento em Linguagem C++ Cap. 6

Caracteres brancos, como espaços e tabulações, são perfeitamente


aceitáveis como parte da cadeia. Veja o programa modificado:
//STR3 . CPP
//Mostra o uso de gets()
#include <iostream .h>
#inc l ude <stdio .h>

void ma in ()
(
char nome[8([) ];

cout << " \nDigite o s e u nome: ";


gets (nome) ;

cout << "\nSeu nome é " << nome;


}

Eis uma execução do programa:


Digite o seu nome : Viviane Mizrah i
Seu nome é Viviane Mizrahi

INICIALIZANDO STRINGS

Qualquer matriz pode ser inicializada, inclusive strings que são matrizes do
tipo char.
Podemos substituir a inicialização padrão:
char nome [ J = { A
I I I In I I I a I I I \(/)I } ;

por
char nome [ J = "Ana ";

consideravelmente mais simples e conveniente.


Cap. 6 Matrizes 219

// STR4.CPP
//Mostra o uso de strings ini cializadas
#i nc l ude <ios t ream . h>
#include <Stdio . h>

vo id ma in ()
{
char salute[ ]=" Saudações , '' ;
char nome[8(/J );

cout << " \ nDigit e o s e u nome: ";


gets (nome} ;

cout << sa l ute << nome ;


}

Eis uma execução do programa:


Digi t e o s e u nome: Viviane Miz rahi
Saudaçõe s, Vivi ane Mi zrahi

,
ARITMETICA COM ENDEREÇOS

Já sabemos que o nome de uma matriz é um endereço. Este endereço é o


endereço do primeiro elemento da matriz. Em outras palavras, salute é o
endereço de salute[O], que é uma variável char. Ou seja, salute é o endereço de
uma variável do tipo char. O que significa salute + 1?
O número 1 desta soma tem uma unidade estranha: significa um byte
se o endereço é de uma variável char, 2 bytes se o endereço é de uma variável
int, 4 bytes se o endereço é de uma variável float e assim por diante. Portanto,
se somarmos um ao endereço de uma matriz de elementos do tipo int, estaremos
obtendo o endereço da próxima variável int da memória. Em regra geral, se M
é o nome de uma matriz e i é uma variável int, então
M + i

é equivalente ao endereço da variável M[i].


220 Treinamento em Linguagem C++ Cap. 6

Utilizando este conceito, podemos extrair uma substring de uma string


somando ao seu endereço um número inteiro que indique o byte onde começará
nossa substring. Veja o exemplo:
//STRS . CPP
//Most ra o uso da aritmética c om endereços
#include <i ostream. h>
#include <std io . h>

void ma in ()
{
char salute[ ] = '' Saudações , ";
char nome[80 ];

cout << " \nDigite o seu nome : ";

gets (nome) ;

c o ut << (sa l ute} << (nome +8 } ;


}

Eis uma execução do programa:


Digite o seu nome : Viviane Mi z rahi
Saudações, Mi zra h i

~ ~

OUTRAS FUNÇOES DE MANIPULAÇAO DE STRINGS

Os compiladores oferecem, em suas bibliotecas, várias funções para trabalhar


com strings. A seguir, analisaremos algumas delas.
Cap. 6 Matrizes 221

A FUNÇÃO strlen()

A função strlen(), declarada no arquivo string.h, requer o endereço de uma


string como argumento e retoma o seu tamanho (o número de caracteres
armazenados na string).
O programa seguinte examina cada posição de memória ocupada pela
string e imprime o que encontrou.
//EXAMEM. CPP
//Most r a o uso de s t rlen()
#inc l ude <i ostr e am. h>
#include <stdio .h>
#i nc l ude <str i ng . h>

void ma in ()
{
uns i g ne d char nome [ 80) ;

c o ut << '' \nDigit e o seu nome: '';


gets (nome) ;

i n t l e n=strlen( no me) ;

f o r(int i=0 ; i <l e n + 4 ; i++ )


cout << '' \nEndereço = " << uns i gned (nome +i ) <<
" \tChar = " << nome [ i ] <<
''\ t Dec - " << int (nome [ i]) ;
}

Eis uma execução do programa:


Dig i te o seu nome : And r é

Ende r eço - 65 444 Char - A De c - 65


Ende r e ço - 65445 Char - n Dec - 110
Endereço -- 65446 Ch a r -- d De c -- 1 00
Endereço -- 6544 7 Ch a r -- r De c -- 114
222 Treinamento em Linguagem C++ Cnp. 6

Endereço -- 65448 Char -- e' Dec -- 13@


Endereço - 65449 Ch ar - De c -- 0
Endereço - 6 545 0 Char - < Dec - 60
Endereço - 6545 1 Char - # Dec - 35
Endereço -- 65452 Char -- @ Dec -- 64

Imprimimos quatro caracteres além do final da string. O primeiro é o


NULL, que não aparece, pois tem valor zero. Os outros são caracteres conside-
rados lixo.
Em nosso programa, a instrução:
int len=strlen(nome);

atribui o valor 5 à variável len se o nome "André" for inserido. Observe que
strlen() não conta o caractere NULL.

A FUNÇÃO strcat()

A função strcat(), declarada no arquivo string.h, concatena uma cadeia de


caracteres em outra. Isto significa que ela acrescenta uma cadeia ao final de
outra. Toma dois endereços de strings como argumentos e concatena a segunda
na primeira. A segunda cadeia não é alterada.
Cuidado! Esta função não verifica se a segunda cadeia cabe no final da
. .
pnme1ra.
//SOMASTR.C PP
//Mostra o uso de strcat()
#include <i ostream .h>
#include <std io .h>
#inc lude <string. h>

void maio ()
{
char salute[] = ''Saudações , '' ;
char no me[80 ];
Cap. 6 Matrizes 223

cout << " \nDi gite o seu nome : ";


ge t s( nome ) ;

strcat(salute , nome);

cout << ' \n ' << salute ;

Digite o seu nome : Viviane Mizrah i


Saudações, Viviane Mizrah i

A FUNÇAO strcmp()

Suponhamos que você queira comparar uma cadeia de caracteres, digitada pelo
usuário, com alguma string interna no programa e decida escrever o seguinte
programa:
//ERRADO.CPP
#include <i ostream. h>
#include <stdio . h>
#include <string .h>

void ma in ()
{
char r esposta [ )= "BRANCO " ;
char r esp[4(/)) ;

cout << " \nQual é a cor do cavalo branco de Napoleão? " ;


gets (resp) ;

while (resp != resposta)


{

cout << " \nResposta errada . Tente de novo . '';


gets (resp) ;
224 Treinamento em Linguagem C++ Cap. 6

cou t << '' \nCorre to! '' ;


)

Este programa não trabalhará corretamente, pois resp e resposta são


endereços de variáveis char, então a expressão
while( r e s p != r espo s t a}

realmente não pergunta se as duas cadeias são diferentes e sim se os dois


endereços são diferentes. Como resp e resposta são endereços distintos, o laço
while é infinito.
Para comparar os caracteres contidos nas duas cadeias, é necessário
utilizar uma função para a tarefa. A função strcmp(), declarada no arquivo
string.h, recebe dois endereços de strings e retoma um número inteiro que
indica a diferença numérica do primeiro caractere diferente da primeira cadeia
com o da segunda. Então, se este número for:
menor que zero --+ strl é menor que str2
igual a zero - strl é igual a str2
maior que zero - strl é maior que str2
Neste contexto, "menor que" ou "maior que" indica que, se strl e str2
forem colocados em ordem alfabética, o que aparecer primeiro é o menor.
Vamos reescrever o programa anterior corretamente.
//NAPOLEAO. CPP
//Mo s t ra o uso d e strcmp ()
# i nc l ude <ios t ream. h>
#inc l ude <stdio . h >
# include <String .h>

void ma in ()
{

char r esposta [ ) = "BRANCO ";


c ha r r e s p [4 0 ];

c out << " \ nQua l é a c or d o cavalo branco de Napol e ã o?";


gets (re sp) ;
Cap. 6 Matrizes 225

vvhile (strcmp(res p~resp os ta } != Ql }


{

cout << '' \nResposta errada . Tente de novo . '';


gets (resp} ;
}
cout << '' \nCorreto! '';
)

Veja um exemplo que imprime o valor retornado por strcmp() em várias


situações.
// STRCMP.CPP
//Testa a função strcmp()
#include <iostream . h>
#include <string .h>

void ma in (}
{
cout << \ n << s trcmp ( "A"
I I "A" } ;
I

cout << 1\n l << s trcmp ( "A " "B" ) ;


I

cout << \n << s trcmp ( "B " "A" ) ;


I I I

cout << \n << strcmp ("C " "A");


I I I

cout << \n << strcmp( "casas" " casa"} ;


I I I

Eis a saída:
Q)

-1
1
2
1 15
226 Treinamento em Linguagem C++ Cap. 6

A FUNÇÃO strcpy(}

A função strcpy(), declarada no arquivo string.h, recebe dois endereços de


strings e copia o conteúdo da segunda na primeira.
Para ilustrar o seu uso, escreveremos uma função que apaga um
caractere de uma cadeia de caracteres.
//STRDEL .CPP
//Mostra o uso de strcpy()
#include <iostream . h>
#include <string .h>

void strdel(char s [], int pos) ;

vo id ma in ()
{

char str[] - ''Carrta ";

cout << ' \n ' << str ;


strdel(str , 2 );
cout << ' \n ' << str ;
}

void strdel (char s[], i nt pos)


(
strcpy(str+pos , str+pos+l );
)

A função strdel() move, um espaço à esquerda, todos os caracteres que


estão à direita do caractere sendo apagado. Para esta movimentação, a função
utiliza strcpy().
Cap. 6 Matrizes 227

AS FUNÇÕES strncat(), strncmp(), strncpy()

Estas funções são semelhantes às que acabamos de analisar. A diferença é que elas
trabalham com um número fixo de caracteres. Todas recebem um terceiro argu-
mento indicando o número de caracteres a processar. Por exemplo, a função
stmcat() concatena n caracteres da segunda cadeia na primeira; stmcmpO compara n
caracteres das cadeias; e stmcpyO copia n caracteres da segunda cadeia para a primeira.

UMA MATRIZ DE STRINGS

No decorrer deste capítulo, vimos vários exemplos de matrizes bidimensionais.


Como uma string é uma matriz, u ma matriz de strings é na realidade uma matriz
de matrizes, ou uma matriz de duas dimensões.
O nosso programa de exemplo é uma melhoria do programa DIASE-
MAN.CPP do capítulo de comandos de decisão. Solicita que seja digitada uma
data e imprime o dia da semana.
11 DSEMAN . CPP
/1 Imprime o dia da semana a partir de uma data
11 Mostra o uso de uma matriz de strings
#include <i ostream. h>
#include <c onio .h>

i nt dsemana (int d i a, i n t me s, int a no } ;

void ma i n(}
{
c har diasema na [ 7] [14]= { "Domi ng o '',
"Segunda - f eir a",
"Te rç a -f eira " ,
"Quarta -f eira " ,
"Quinta-f eira ",
"Sex ta - fe ira " ,
"Sá bado "
);
228 Treinamento em Linguagem C++ Cap. 6

int d i a, mes, ano;


con s t char ESC =27 ;

do
{

cou t << "\nDigite a data na f orma dd mm a aa a : ";


c in >> di a >> mes >> ano;

cout << '\n ' << diasemana[dsemana(dia , mes , anol] ;

} while (ge tch () !=ESC) ;


}

//Encontra o dia da semana a partir de uma data


//Retorna 0 para domingo , 1 para segunda-fe i ra etc .
i nt ds e ma na ( i nt d ia, i n t me s, i n t a no)
{

i nt f = ano + dia + 3 * (mes - 1) - 1 ;


i f (mes < 3) ano -- ;
else f -= int( 0. 4 *mes+2 . 3) ;
f += int(ano /4) - int (( ano /10 0 + 1 )*0. 75 );
f %= 7 ;
r eturn(f) ;
}

Repare como a matriz de strings é inicializada. Cada nome entre aspas


é uma matriz de uma dimensão.
Cap. 6 Matrizes 229

...
REVISA O

1. Matriz é um tipo de dado que armazena uma coleção de variáveis de um


mesmo tipo.
2. Cada elemento de uma matriz é diferenciado por meio de um índice, entre
colchetes, colocado após o nome da matriz. Os índices de matrizes começam
em zero.
3. Os elementos de uma matriz são armazenados em seqüência contínua de
memória, um seguido ao outro.
4. O número que dimensiona uma matriz na sua declaração deve ser uma
constante, enquanto o índice de acesso a um elemento da matriz pode ser
uma variável.
5. Uma matriz pode conter elementos de qualquer tipo, contanto que todos
tenham o mesmo tipo.
6. A linguagem C++ não avisa quando o limite de dimensionamento de uma
matriz foi excedido.
7. Matrizes podem ser inicializadas independentemente da classe de armaze-
namento escolhida na sua declaração.
8. O termo "mais de uma dimensão" indica matrizes em que os elementos são
matrizes.
9. O nome de uma matriz é o endereço de memória de seu primeiro elemento.
10. Matrizes são passadas como argumento para funções por referência.
11. String é uma matriz do tipo char.
12. Toda string, em C++, termina pelo caractere '\0'.
13. A função gets() lê um cadeia de caracteres do teclado e os armazena numa
string.
14. Quando somamos um ao endereço de uma matriz, estamos somando o
tamanho em bytes do tipo de seus elementos. Assim, M+i é o endereço do
elemento M[i].
15. A função strlen() retoma o tamanho de uma string.
230 Treinamento em Linguagem C++ Cnp. 6

16. A função strcat() concatena uma string a outra. Em outras palavras,


acrescenta uma string ao final de outra.
17. A função strcmp() compara duas strings.
18. A função strcpy() copia uma string em outra.
19. As funções strncat(), strncmp() e strncpy() são diferentes das anteriores por
operarem sobre um número fixo de caracteres e não sobre a string toda.
20. Uma matriz de strings é uma matriz de duas dimensões.

,
EXERCICIOS

1. Uma matriz é uma coleção de variáveis de:


a) diferentes tipos de dados distribuídos pela memória;
b) tipos de dados similares distribuídos pela memória;
c) tipos de dados similares em seqüência na memória;
d) diferentes tipos de dados em seqüência na memória.
2. Em uma declaração de matriz, devem ser especificados o t , o
n eot da matriz.
3. A declaração da matriz seguinte é correta?
i n t mat(25 ) i

4. Qual é o elemento da matriz referenciado por esta expressão?


mat[ 4)

5. Qual é a diferença entre os números "3" destas duas instruções?


int mat[3] i
mat [3 J = 5 i

a) o primeiro especifica um elemento particular e o segundo, um tipo;


b) o primeiro especifica um tamanho e o segundo, um elemento particular;
Cap. 6 Matrizes 231

c) o primeiro especifica um elemento particular e o segundo, o tamanho


da matriz;
d) os dois especificam elementos da matriz.
6. O que faz a combinação das instruções seguintes?
c o nst LIM 5 0;
char coleta[LIM];

a) torna LIM um índice;


b) torna LIM uma variável tipo float;
c) torna coleta[] uma matriz do tipo LIM;
d) torna coleta[] uma matriz de tamanho LIM.
7. Se uma matriz é declarada como:
float prec o [MAX];

a instrução abaixo é correta para acessar todos os elementos da matriz?


f o r(int j =0; j <= MAX ; j++ )
cin >> preco [ j] ;

8. A instrução seguinte é correta para inicializar uma matriz de uma dimensão?


i n t matriz = {1, 2 , 3 , 4} ;

9. O que acontecerá se você colocar tantos valores em uma matriz na sua


inicialização a ponto de o seu tamanho ser ultrapassado?
a) nada;
b) possível mau funcionamento do sistema;
c) uma mensagem de erro do compilador;
d) outros dados podem ser sobrepostos.
10. O que acontecerá se você colocar poucos valores em uma matriz na sua
inicialização de forma que o seu tamanho não seja atingido?
a) nada;
232 Treinamento em Linguagem C++ Cnp. 6

b) possível mau funcionamento do sistema;


c) uma mensagem de erro do compilador;
d) os elementos não atingidos serão preenchidos com zeros.

11. O que acontecerá se você atribuir um valor a um elemento da matriz cujo


índice ultrapassa o tamanho da matriz?
a) o elemento conterá o valor zero;
b) nada;

c) outros dados serão sobrepostos;


d) mau funcionamento do sistema.

12. A inicialização abaixo é correta?

in t matriz [ 3 ] [ 3 ] = { { 1 1 2 3 }
I I

{4 1 5 1 6} ,
{7 ,8,9 } };

13. Na matriz da questão 12, como poderíamos referenciar o elemento de valor 4?

14. Se uma matriz foi declarada como:


int matriz[12] ;

o que representa a palavra matriz?


15. Se você não inicializar uma matriz, o que os seus elementos conterão?

a) zeros;
b) valores indeterminados;

c) números em ponto flutuante;


d) caracteres '\0'.
16. Quando uma matriz é passada para uma função como argumento, o que
realmente é passado?
a) o endereço da matriz;
b) os valores dos elementos da matriz;
Cap. 6 Matrizes 233

c) o endereço do primeiro elemento da matriz;


d) o número de elementos da matriz.
17. Verdadeiro ou Falso: Quando uma função recebe uma matriz do tipo int
passada como argumento, coloca os valores da matriz em uma posição
separada de memória, conhecida somente por esta função.
18. Em que uma string é semelhante a uma matriz?
a) ambas são matrizes de caracteres;
b) a matriz é um tipo de string;
c) acessam funções do mesmo modo;
d) a string é um tipo de matriz.
19. Quais das seguintes afirmações são corretas?
a) o operador >> encerra a leitura de uma string quando encontra um
espaço em branco;
b) o operador>> lê um número fixo de caracteres de uma string;
c) o operador >> termina a leitura de uma string somente quando é
pressionada a tecla [ENTER];
d) o operador>> não lê strings.
20. Uma string é:
a) uma lista de caracteres;
b) uma coleção de caracteres;
c) uma matriz de caracteres;
d) um conjunto de caracteres.
21. "A" é um _ _ _ _ _ enquanto 'A' é um _ _ _ __

22. O que é a expressão seguinte?


"Mesopotamia\ n "

a) uma variável string;


234 Treinamento em Linguagem C++ Cnp. 6

b) uma string matriz;

c) uma string constante;


d) uma string de caracteres.

23. Uma string é terminada pelo caractere ___ , que é chamado _____ .
24. A função ______ é projetada especificamente para ler uma string do
teclado.
25. Se você tem declarado uma string como:
char nome[10 ] ;

e em seu programa você solicita que o usuário forneça o seu nome, o


máximo de caracteres que ele deverá digitar é _ _ .
26. O que é mais apropriado para ler a string str do teclado?
a) cin >> str;

b) gets (str) ;

c) getch () ;

d) cout << str;

27. Assuma a seguinte inicialização:


c har str [ ] = "Brasileira";

Como você se refere à string "leira" ?


28. Qual a expressão que você usaria para encontrar o comprimento da string str?
29. Escreva a função de protótipo:
void strmaius (char s[ ] );

que converte uma string em letras maiúsculas.


30. Escreva a função de protótipo:
vo i d strminus(c har s[] );

que converte uma string em letras minúsculas.


Cap. 6 Matrizes 235

31. Escreva a função de protótipo:


int strch r ( char s [] , c h a r ch) ;

que procure a primeira ocorrência do caractere ch em s. A função retoma


um número inteiro indicando o índice do caractere se for encontrado, ou
-1 em caso contrário.
32. Escreva uma função de protótipo:
int stricmp (c har sl[ ) , c h ar s2[)l ;

que compare duas cadeias de caracteres independentemente de letras


maiúsculas ou minúsculas e retorne a diferença ASCIT dos primeiros
caracteres diferentes ou zero se as cadeias forem iguais.
33. Escreva uma função de protótipo:
void strnset ( char s[) , char ch , int n );

que inicialize a string com n vezes o caractere ch.


34. Escreva uma função de protótipo:
void s t r i nv(char s [] );

que inverta os caracteres de uma string. Por exemplo: se a string for


"ABCDEF", deve ser convertida a "FEDCBA".
35. Escreva uma função de protótipo:
int rep lace(char s [] , c h ar atua l , c h ar novo ) ;

que substitua todo caractere atual de s pelo novo. A função retoma o


número de substituições.
36. Escreva uma função de protótipo:
void stri ns(cha r s[) , char ch, int pos);

que insira o caractere ch na posição pos da string s.


37. Escreva uma função de protótipo:
void s t r i nss(char s l[ ] , char s2 [] , int pos);

que insira a string s2 em sl na posição pos. Utilize a função do exercício


anterior.
236 Treinamento em Linguagem C++ Cap. 6

38. Escreva uma função de protótipo:


v o id l ef t (char origem[ ), char dest [), int n) i

que copie os n primeiros caracteres da string origem na string dest. Utilize


a função strncpy().
39. Escreva uma função de protótipo:
void right (char origem [), char de st [ ) , int n) i

que copie os n últimos caracteres da string origem na string dest. Utilize a


função strncpy().
40. Escreva uma função de protótipo:
vo id mid(char origem[ ] , char de st[) , int inicio, int n ) i

que copie os n caracteres a partir da posição inicio da string origem na


string dest. Utilize a função strncpy().
41. Escreva uma função de protótipo:
void trim( char s [ ],int modo ) i

que elimine os caracteres em branco iniciais e finais se modo for zero,


somente os iniciais se modo for um e somente os finais se modo for dois.
42. Escreva uma função de protótipo:
void justi fy(cha r s[) ,int modo, int n)i

que acrescente brancos ao final de s, de modo que fique com tamanho n se


modo for igual a zero; insira brancos no início e no final de 5 1 de modo que
fique com tamanho n e os caracteres fiquem centralizados se modo for igual
a um; finalmente, insira caracteres brancos no início de s, de modo que fique
com tamanho n se modo for igual a dois.
43. Escreva uma função de protótipo:
int strblank(char s[)) i

que verifique se s é uma string em branco. A função retoma o primeiro


caractere não-branco ou zero se a string for toda formada somente por
caracteres brancos.
Capítulo 7

ESTRUTURAS

Neste capítulo exploraremos outra maneira de representar dados em C++: as


estruturas.
Há cinco tipos de dados simples que estão predefinidos no compilador
e que nós já conhecemos e já utilizamos. São eles: char, int, float, double e void.
Estes tipos representam um único item de informação e, baseados neles,
podemos definir tipos complexos que possibilitam agrupar um conjunto de
variáveis de tipos diferentes sob um único nome.
Estruturas são tipos de variáveis que agrupam dados geralmente
desiguais; enquanto matrizes são tipos de variáveis que agrupam dados simi-
lares. Os itens de dados de uma estrutura são chamados membros, enquanto
os itens de uma matriz são chamados elementos.
A linguagem C++ oferece quatro meios de criar novos tipos de d ados:
matrizes, estruturas, uniões e classes. Dentre estes, os mais importantes são:
estruturas, que agrupam itens de dados, e classes, que agrupam itens de dados
e funções. A sintaxe para criar estruturas é a mesma da de classes. Assim,
aprender a lidar com estruturas é o caminho para entender classes e objetos.

237
238 Treinamento em Linguagem C++ Cnp. 7

CRIANDO NOVOS TIPOS DE DADOS COM struct

Por meio da palavra-chave struct definimos um novo tipo de dado. Definir um


tipo de dado significa informar ao compilador o seu nome, o seu tamanho em
bytes e o formato em que ele deve ser armazenado e recuperado da memória.
Após ter sido definido, o novo tipo existe e pode ser utilizado para criar
variáveis de modo similar a qualquer tipo simples.
O exemplo a seguir cria um tipo de dado que pode armazenar as
informações de um aluno. Observe a listagem.
//ALUNO.CPP
//Mostra o uso de es truturas
#include <ios tream.h>

struct aluno //Definição da estrutura


{
int nmat; //Número da matrícula
float nota[3]; //Notas
float media; //Média
};

void ma in ()
{

aluno ana ; //Declara variável do tipo aluno

ana . nmat -- t156·


- '
ana.nota [0) = 7.5;
ana.nota[l ) = 5 . 2 ;
ana. nota[2 ) = 8 .4;
ana.media = (ana. nota[0)+ana . nota[l )+ ana . nota[2))/3.0 ;

cout << " \ nMatricula : " << ana.nmat ;


cout << " \ nMedi a << ana.media;
:
11

}
Cap. 7 Estruturas 239

DEFININDO A ESTRUTURA

A definição da estrutura informa como ela é organizada e quais são seus


membros.
Palavra- Nome do
chave Tipo

struct aluno
{

int nmat;

haves f 1o a t nota [ 3 ] ; •I Membros


float media ;

Ponto-e-vírgula aqui

Definir uma estrutura não cria nenhuma variável, somente informa ao


compilador as características de um novo tipo de dado. Não há nenhuma reserva
de memória.
A palavra struct indica que um novo tipo de dado está sendo definido
e a palavra aluno será o seu nome.
No nosso exemplo, definimos o tipo aluno antes de main(), o que
permite um acesso global a todas as funções definidas no programa. Poderíamos
colocar esta definição dentro de uma função, restringindo o acesso às instruções
do mesmo bloco e escritas abaixo dela.
//ALUNO .CPP
//Mostra o u so de estruturas
#include <i ostream. h>
void ma in()
{

struct aluno //De fin ição da estrutura


240 Treinamento em Linguagem C++ Cnp. 7

{ //Aces so l oca l
int nmat ; //Número da matrícula
float nota [3) ; //Notas
float media ; //Média
} i

aluno ana ; //Declara variáve l do tipo aluno

ana . nmat = 456;


ana . nota[0)= 7 . 5 ;
ana . nota[l)= 5 . 2 ;
ana.nota [2] = 8. 4;
ana.media = (ana . nota[0 ] +ana.nota [l ]+ana.nota[2 ])/3 .0;

cout << '' \nMatricula : '' << ana . nmat ;


cout << '' \ nMedia : " << ana .media ;
}

Uma estrutura é um tipo de dado cujo formato é definido pelo programador.

,
DECLARANDO UMA VARIAVEL DO TIPO DEFINIDO

A instrução
aluno ana ;

declara uma variável de nome ana, do tipo aluno. Esta declaração reserva
espaço de memória suficiente para armazenar todos os membros da estrutura:
2 bytes para nmat, 12 bytes para a matriz nota e 4 bytes para media.
Os membros de uma variável estrutura são armazenados em seqüência
contínua de memória.
Cnp. 7 Estruturas 241

Observe a similaridade entre a declaração de variáveis de tipos simples


e de variáveis de tipos definidos pelo usuário:
aluno ana ;
i nt val;

ACESSANDO OS MEMBROS DA ESTRUTURA

Uma vez criada a variável estrutura, seus membros podem ser acessados por
meio do operador ponto.
A instrução
ana . nmat = 45 6 ;

atribui o valor 456 ao primeiro membro da variável ana.

O operador ponto conecta o nome de uma variável estrutura a um membro dela.

A linguagem C++ trata os membros de uma estrutura como quaisquer


outras variáveis simples. Por exemplo, ana.nmat é o nome de uma variável do tipo
int e pode ser utilizada em todo lugar onde possamos utilizar uma variável int.

....
COMBINANDO DECLARAÇOES

No exemplo anterior, definimos a estrutura e declaramos a variável em duas


instruções distintas. Estas duas instruções podem ser combinadas em uma única.
struct //Não é neces sário o nome
{
int nmat ;
float nota [ 3];
float media ;
} ana; //Dec l aração da variáve l é a qu i
242 Treinamento em Linguagem C++ Cnp. 7

Observe que o nome do tipo na definição da estrutura pode ser


suprimido se nenhuma outra variável for declarada mais adiante. Diversas
variáveis podem ser declaradas de uma única vez separadas por vírgulas:
struct //Não é necessário o nome
{

int nmat ;
float nota [3 ] ;
float media ;
} ana , jose~joao ; //Dec laração de diversas variáveis

A combinação da definição da estrutura com a declaração das variáveis


torna a escrita mais compacta, entretanto menos clara e flexível que o uso de
instruções separadas.

INICIALIZANDO ESTRUTURAS

A inicialização de estruturas é semelhante à inicialização de uma matriz. Veja


um exemplo:
struct data
{

int d ia;
char me s [1 0 ] ;
i nt ano;
} i

data natal - { 251 ''Dezembro ''~ 1 9 94} ~


. . - { 3 0 "Julho " 1 9 7 8} ;
anlversarlo 1 1

As variáveis natal e aniversario estão sendo inicializadas na mesma


instrução de suas declarações. Os valores a serem atribuídos a seus membros
devem ser colocados na ordem em que foram definidos, separados por vírgulas
e entre chaves.
Cnp. 7 Estruturas 243

..
ATRIBUIÇOES ENTRE ESTRUTURAS

Uma variável estrutura pode ser atribuída a outra variável do mesmo tipo por
meio de uma atribuição simples:
d a t a andre;

and r e = a niversario ;

Certamente constatamos que esta é uma estupenda capacidade quando


pensamos a respeito: todos os valores dos membros da estrutura estão realmente
sendo atribuídos de uma única vez aos correspondentes membros da outra
estrutura.
Uma expressão de atribuição tão simples não pode ser usada para
matrizes, que devem ser atribuídas elemento a elemento.
Note que a atribuição só é permitida entre estruturas do mesmo tipo.
Se for atribuída uma variável de um certo tipo a outra de outro tipo, o
compilador acusará um erro .

.
OPERAÇOES ENTRE ESTRUTURAS

Para exemplificar como executar operações entre estruturas, vamos montar um


tipo de dado que armazena o número de peças vendidas por uma loja num certo
dia e o valor total da venda. Em seguida, criaremos duas variáveis com os dados
de dois dias e uma terceira variável para armazenar o total de vendas.
s t r uct v enda
{

i nt pec as ;
float preco ;
};

vend a A= { 2~ , 11@ .~ },
B = { 3 , 16 . 5 } , Tot al ;
244 Treinamento em Linguagem C++ Cnp. 7

Você poderia pensar em adicionar os valores das variáveis A e B por


meio de uma instrução simples como:
Total = A + 8; //ERRADO

Operações simples como a soma não estão definidas para tipos criados
com a palavra struct. A soma deve ser efetuada membro a membro:
Total . p ecas - A. p ecas + B. pecas ;
Total . preco - A. p reco + B.preco ;

Um dos maiores benefícios em usar classes, como veremos, é a possi-


bilidade de implementar outras operações em tipos definidos pelo programador.

ESTRUTURAS ANINHADAS

Exatamente como podemos ter matrizes em que cada elemento é outra matriz,
podemos definir estruhtras com membros que sejam outras estruturas.
// STRNI NHO . CPP
//Mostra estruturas aninhadas
#include <i ostream. h>

struct data
{
int d i a;
char mes [ 10 J ;
int ano ;
} i

struct venda
{
int pecas ;
float preco ;
da ta d iavenda ;
} i
Cap. 7 Estruturas 245

vo id ma in ()
(
venda A = ( 20 , 110.0, {7 , Novembro ", l993} };
11

cout << '' \ nPeças : '' << A.pecas;


cout << '' \ nPreço: '' << A. preco ;
cout << " \ nData : " << A. d i ave nda . d ia << 11
de "
<< A. diavenda .mes << de 11 11

<< A. diavenda . ano ;


)

Eis a saída:
Peç as : 20
Preço : 110
Data : 7 de Novembro de 1993

Neste exemplo, adicionamos um membro do tipo data à estrutura


venda, e criamos a variável A do tipo venda.
A variável A tem três membros dos quais um deles é uma estrutura do
tipo data. Portanto, A.diavenda é o nome de uma variável estrutura do tipo data
e, para acessar seus membros, devemos aplicar o operador ponto novamente.
Logicamente, este processo não pára neste nível; podemos ter uma
estrutura dentro de outra quantas vezes desejarmos.

INICIALIZANDO ESTRUTURAS ANINHADAS

A variável A foi inicializada na instrução:


venda A = { 2 0, 110 . (/) , {7 , Novembro " , 19 9 3 } } ;
11

Observe que o membro diavenda, por ser uma estrutura, é inicializado


colocando seus membros entre chaves e separando-os por vírgulas.
246 Treinamento em Linguagem C++ Cap. 7

...
PASSANDO ESTRUTURAS PARA FUNÇOES

As estruturas podem ser passadas como argumento de funções da mesma forma


que variáveis simples. O nome de uma estrutura em C+ + não é um endereço,
portanto ela pode ser passada por valor. Vamos exemplificar com uma função
que recebe duas estruturas como argumento e imprime os valores da soma de
seus membros.
//STRUCV . CPP
// Mostra passagem de estruturas para funções por valor
#incl ude <i ostream . h>

struct venda
{

int pecas;
float preco ;
};

void l i stavenda( venda C, venda D} ;

void main(}
{
venda A,B;

cout << " \nVenda A\n------- \n" ·


------- I

cout << " Insira o numero


' de pecas : " . I

.
c 1n A. pecas ;
>>
cout << " Insira o preco : " . I

.
c1n >> A. preco;

cout << " \nVenda B\n- ------\n "·


------- I

cout << " Insira o número de pecas: " . I


c 1n >> B. pecas ;
cout << " Insira o preco : " . I


c1n >> B.preco;
Cap. 7 Estruturas 247

listavenda( A,B};//Estrutur as como argumento


}

vo id listavenda(venda C, venda D)
{

cout << '' \ n\nVenda total\n==========='';


cout << '' \ nTotal de pecas : " << (C . pecas+D.pecas) ;
cout << '' \nPreco total : '' << (C . prec o+D . preco) ;
}

Eis a saída:
Venda A
-------
-------
Insira o número de pecas : 58
Insira o prece : 1234 . 5

Venda B
-------
Entre o número de pecas : 350
Entre o preco : 45678 . 9

Venda total
-----------
Tota l de pecas: 408
Prece tota l : 46913 . 398437

O protótipo da função listavenda() e as instruções de seu corpo tratam


as variáveis argumentos como qualquer tipo simples. A função cria as novas
variáveis C e D para conter os dados das variáveis A e B de main() enviadas
como argumento, como faria com qualquer tipo de variável simples passada
por valor. Então, as variáveis C e D não são as mesmas das de mainO; a função
poderia alterá-las sem contudo alterar as originais.
248 Treinamento em Linguagem C++ Cnp. 7

,.., 1\

PASSANDO ESTRUTURAS PARA FUNÇOES POR REFERENCIA

A sintaxe da passagem de estrutura para funções por referência é a mesma da


passagem de variáveis simples por referência. No entanto, a conveniência de
passar estruturas por referência é pelo fato de elas ger almente serem dados que
ocupam uma grande quantidade de memória. Usando este mecanismo, não h á
a criação de uma cópia da variável na função.
Vamos alterar o programa anterior para que a função Iistavenda()
receba seus argumentos por referência:
//STRUCF.CPP
//Mostra passagem de estruturas para funçõ es por referência
#include <i ostream . h>

struct venda
{
i nt pecas;
float preco;
} i

vo id listavenda( venda& C, venda& D) ;

void ma in ()
{
venda A, B;

cout << " \nVenda A\n-------\n" ·


------- f

cout << " Insira o numero


' de pecas : " '.
. >> A.pecas;
c1n
cout << "Insira o preco : " .
. '
c1n >> A. preco ;

cout << " \nVenda B\n======= \ n ";


cout << " Insira o número de p ecas : ";
cin >> B.pecas ;
Cap. 7 Estruturas 249

cout << '' Ins ira o prece : '';


cin >> B. preco ;

listavenda( A, B} ; //Estruturas como argumento


}

void listavenda(ve nda& C, ve nda& D)


{

cout << " \ n\nVenda tota l \n==== ======= ";


cout << '' \nTotal de pecas : '' << (C . pecas +D . pecas} ;
cout << '' \ nPreco total : '' << (C. preco+D. p reco};
}

Agora as variáveis C e D da função listavenda() são as mesmas das


variáveis A e B de main() .

.
FUNÇOES QUE RETORNAM UMA ESTRUTURA

Suponhamos que você queira usar uma chamada a uma função para obter os
dados sobre as vendas. C++ permite que as funções retornem uma estrutura
completa para outra função.
// STRUCVND. CPP
//Mo stra uma função que retorna uma estrutura
#i nc l ude <ios t ream . h>

struct ve nda
{

int pecas;
fl oat prece ;
) ;

venda novavenda(void};

void l i stavenda( venda& C, venda& D);


250 Treinamento em Linguagem C++ Cnp. 7

void ma i n ()
(
venda A, B;

A=novavenda{) i
B=novavenda() ;
listavenda( A, B} ; //Estruturas como argume nto
}

v e nda novavenda(}
{

venda X;

----------
cout << " \nNova Venda\n-- --- -----\n ''·,
cout << "Ins ira o numero
' de p ecas : " '.

Cl O >> X.pecas;
cout << "Insira o preco : " '.
.
C lO >> X. preco ;

return(X) i //retorna uma estrutura


}

void l ist avenda( v enda& C, venda& D)


{

cout << " \n\nVenda tota l \n=========== ";


cout << ' \nTotal de pecas :
1
<< (C . pecas +D . pecas} ;
11

cout << " \nPr eco to tal << (C . preco+D.preco);


:
11

Evidentemente, o programa fica mais compacto com a inclusão da


função novavenda() . Esta função é chamada pelo programa principal para obter
as informações do usuário sobre as vendas. Estas informações são guardadas
numa variável interna da função e são retornadas por meio do comando return,
da mesma forma que faríamos para retornar uma variável simples. A função
novavenda() deve ser declarada como sendo do tipo venda, visto que ela retoma
uma variável deste tipo.
Cnp. 7 Estruturas 251

MATRIZES DE ESTRUTURAS

Certamente, uma lista de peças e preços é composta por várias vendas (provavel-
mente mais de duas). Cada venda é descrita por uma variável do tipo venda. Para
tratar de várias vendas, é perfeitamente correto pensar numa matriz de estruturas.
O programa seguinte, além de realizar o nosso objetivo principal de
criar uma matriz de estruturas, onde cada elemento da matriz representa uma
venda, proporcionará uma simples interface com o u suário constituída da
escolha entre duas opções assinaladas pelas letras 'E' e 'L'.
Se o usuário pressionar 'E', o programa permitirá a entrada das
informações de uma venda. Se o usuário pressionar 'L', o programa listará todas
as vendas e imprimirá os totais.
Vamos ainda aumentar as informações de cada venda acrescentando a
data de venda.
Usaremos duas novas funções de biblioteca C++, atoi() e atof(). A
primeira recebe uma string como argumento e a converte num número inteiro
correspondente à cadeia recebida. Por exemplo, se enviarmos "1234" ela retoma
o número inteiro 1234. A segunda faz a mesma coisa, mas com variáveis float.
//STRMAT . CPP
//Mostra mat rizes de estruturas
#include <iostream . h>
#inc l ude <iomanip.h>
#incl ude <stdlib. h > //Pa ra atoi (), atof {) e ex i t {)
#include <conio . h> //Para getch ()
#include <stdio . h> //Para gets ()

struct data
{

int dia ;
char mes(l(/)) ;
int ano ;
} i

struct venda
{
252 Treinamento em Linguagem C++ Cap. 7

data diavenda;
int pecas;
float preco ;
);

vo id novave nda(vo i d);


void listave nda(void);

venda vendas[50 ];
venda Tota1 ={{0 ,"'',0 } ,0, 0 . 0} ;
i nt n=QJ;

void ma in ()
{

const TRUE=l ;
con st char ESC=2 7;
char ch;

whil e (TRUE)
{
cout << "\nDigite E para adicionar uma venda ";
cout << "\n L para l i star as vendas'';
cout << " \n ESC para t e rminar\n";

ch=getch () ;

switch(ch)
{
case ' E ': novavenda( ) ;break;
case 'L' : listavenda() ;break ;
case ESC: exit( 0) ;
default : cout << "\nOpcao invalida!!";
}

}
Cap. 7 Estruturas 253

vo id nova venda ()
{
char temp[8QJ ];
cout << "Dia : 11
gets(temp) ;
;

v e ndas [ n] . diave nda. d i a =atoi(temp);


cout << '' Mes : ''; gets(vendas [n] . diavenda . mes);
cout << "Ano : gets(temp);
11
;

vendas [ n] . diavenda.ano=atoi( temp);


cout << " Peças : ; gets(temp) ;
11

v e ndas[n] . pecas=atoi(temp );
cout <<"Preço: ";get s(t emp) ;
vendas [ n] . pre co=ato f(temp );
Tota l.pecas += vendas [n] .pecas;
Total . preco += vendas[n++ l . preco ;
)

void listavenda()
{
if(!n )
{
cout << ''\nLista vazia .'';
return;
)
cout << setprecision (2) ;
f or (int i=0; i<n ; i+ +)
{
cout << ''\n'' << setw(2 ) << vendas [i ] . diavenda.dia
<< de
11
<< setw( lflJ) << vendas [i ] .diavenda . me s
11

<< de
11
<< setw(4) << vendas[i ] .diavenda.ano;
11

cout << setw ( 10) << vendas[ i ] . pecas;


254 Treinamento em Linguagem C++ Cap. 7

cout << setw(20) << vendas[i] . preco ;


}

cout << " \n\n ";


cout << setw (3 4) << Tota l. pecas;
cout << s etw(20) << Tota l.preco;
cout << " \ n\n";
)

A seguir, mostraremos uma simples execução do programa:


Dig i te E para adic i o nar uma venda
L para listar as vendas
ESC para terminar
Dia : 10
Mes : JANEIRO
Ano : 1994
Peças : 20
Preço : 234.6

Dig i te E para adicionar uma venda


L para listar as vendas
ESC para termi nar
Dia : 14
Mes: FEVEREI RO
Ano : 1994
Peças: 32
Preço : 345

Dig i te E para adicionar uma venda


L para listar as v endas
ESC para t e r minar
Dia : 12
Mes : MAIO
Ano : 1994
Peças: 45
Preço: 987.2
Cap. 7 Estruturas 255

Digi te E para adi cionar uma v enda


L para listar as vendas
ESC para terminar
Dia : 16
Mes: JUNHO
Ano: 199 4
Peças : 3 5
Preço : 567 . 8

Digi te E para adic i o nar uma venda


L para listar as venda s
ESC para terminar

1 0 de JANE IRO de 1994 2(/J 234 . 6


1 4 de FEVERE IRO de 1994 32 345
12 de MAI O de 1994 45 987 . 2
16 de JUNHO de 1 994 35 567 . 8

132 2 . 13e+03

DECLARANDO A MATRIZ DE ESTRUTURAS

O processo de declaração de urna matriz de estruturas é perfeitamente análogo


à declaração de qualquer outro tipo de matriz. A instrução
venda vendas[5 0) ;

declara vendas corno sendo urna matriz de 50 elementos. Cada elemento da


matriz é urna estrutura do tipo venda. Então vendas[O] é a primeira estrutura
do tipo venda, vendas[l] é a segunda estrutura do tipo venda e assim por diante.
O nome vendas é o nome de urna matriz em que os elementos são
estruturas. Observe que, a partir desta instrução, o compilador providencia
espaço de memória contínua para armazenar 50 estruturas do tipo venda.
256 Treinamento em Linguagem C++ Cnp. 7

Para simplificar, declaramos a matriz como externa, assim todas as


funções do programa poderão acessá-la.

ACESSANDO MEMBROS DA MATRIZ DE ESTRUTURAS

Membros individuais de cada estrutura são acessados aplicando-se o operador


ponto seguido do nome da variável, que neste caso é um elemento da matriz.
v en da s [ n] . preco

Observe que o subscrito da matriz é associado a vendas e não ao


membro. A expressão acima refere-se ao membro preco da n-ésima estrutura
da matriz.
O esquema global deste programa pode ser aplicado a uma grande
variedade de situações. Por exemplo, poderá ser usado para controle de um
estoque, onde cada variável estrutura conterá dados sobre um item do estoque,
como número do material, preço, tipo, número de peças do estoque etc.

AS FUNÇÕES atoi() E atof(J

Decidimos utilizar duas novas funções da biblioteca C++ para que voce as A

conheça.
A função atoi(), com protótipo no arquivo stdlib.h, recebe o endereço
de uma string como argumento e o converte a um valor inteiro. Caso a string
não contenha um número válido, ela retornará zero. Espaços em branco iniciais
são ignorados.
A função atof(), com protótipo no arquivo stdlib.h, recebe o endereço
de uma string como argumento e o converte a um valor double. Caso a string
não contenha um número válido, ela retornará zero. Espaços em branco iniciais
são ignorados.
Cnp. 7 Estruturas 257

..
A FUNÇAO exit(J

A função exit() da biblioteca padrão, com protótipo no arquivo stdlib.h, permite


o término imediato do programa e passa o controle ao sistema operacional.

A função exit() finaliza o programa inteiro.

O seu argumento é um número inteiro que é retornado ao sistema


operacional e pode ser acessado por meio do subcomando ERRORLEVEL de
um programa .BAT. O arquivo .BAT pode conter uma linha como:
IF ERRORLEVEL 1 GOTO ERRl

o que provoca uma mudança de operação dependendo do valor de retorno


indicado pelo término do programa.
O zero é geralmente usado para indicar o término normal do programa.

ESTRUTURAS ECLASSES

A linguagem C++ expande as capacidades das estruturas além do exposto aqui.


É certo que elas são geralmente usadas para armazenar somente dados, da
mesma forma que são definidas na linguagem C.
Entretanto, as estruturas C++ podem, de fato, armazenar dados e
funções. A diferença na sintaxe entre estruturas e classes é mínima e fixa-se na
possibilidade de as classes definirem membros privados por default, enquanto
as estruturas têm membros públicos por default.
Por outro lado, a maior parte dos programadores C++ utiliza estruturas
como as vistas neste capítulo, exclusivamente para dados e classes para dados
e funções.
As classes serão analisadas detalhadamente no capítulo 8, no módulo 2.
258 Treinamento em Linguagem C++ Cap. 7

TIPOS DE DADOS ENUMERADOS: enum

Outra maneira de definir novos tipos de dados em C++ é por meio da


palavra-chave enum. O tipo enum é usado para tornar clara e simples a escrita
do programa, não sendo de conhecimento obrigatório para desenvolver programas
C++. Entretanto, os programadores C++ utilizam o tipo enum freqüentemente.
Tipos enumerados são usados quando conhecemos o conjunto de
valores que uma variável pode assumir. A variável deste tipo é sempre int e,
para cada um dos valores do conjunto, atribuímos um nome significativo.
A palavra enum enumera a lista de nomes automaticamente, dando-
lhes números em seqüência (O, 1, 2 etc.).
A vantagem é que utilizamos estes nomes no lugar de números, o que
torna o programa mais claro .
Vamos escrever um programa que cria uma variável enum para guar-
dar o mês do ano.
//MESENUM. CPP
//Mostra o uso de enum

#incl ude <iostream . h>

enum mes {Jan=l , Fev, Mar , Abr , Mai, Jun,


Jul , Ago , Set , Out , Nov, De z} ;

void ma in()
{
mes ml,m2 ;

ml - Abr ;
m2 - Jun ;

mes m3 - m2 - ml ; //Operações aritméticas permitidas


Cnp. 7 Estruturas 259

cout << '' \nA diferença entre os meses é '' << m3 ;

i f (ml < m2) //Comparações permit i das


cout << ''\nml é anterior a m2 '';
}

A palavra enum define um conjunto de nomes com valores permitidos


para esse tipo e enumera esses nomes a partir de zero (default) ou, como em
nosso programa, a partir do primeiro valor fornecido.
Se fornecermos um valor a alguns nomes e não a outros, o compilador
atribuirá o próximo valor inteiro aos que não tiverem valor.
Uma variável de um tipo enumerado pode ter qualquer valor listado
na definição. Não podemos atribuir valores não-listados.
ml = sabado ; // ERRADO . É ilega l

Tipos enumerados são tratados internamente como inteiros, portanto


qualquer operação possível com inteiros é permitida com eles.
Outro exemplo:

enum sexo {feminino , masculino) ;


enum chave ( OFF , ON};

Se o modo como o compilador atribui valores não se adapta ao seu tipo,


você pode especificar os seus próprios valores:
enum direcao {Norte =50 , Sul=80 , Leste =92 , Oeste=l00} ;

"'
UNIOES

A palavra union é usada, de forma semelhante a struct, para agrupar um


número de diferentes variáveis sob um único nome. Entretanto, uma union
utiliza um mesmo espaço de memória a ser compartilhado com um número de
diferentes membros, enquanto uma struct aloca um espaço diferente de memó-
ria para cada membro.
260 Treinamento em Linguagem C++ Cap. 7

Em outras palavras, uma union é o meio pelo qual um pedaço de


memória ora é tratado como uma variável de um certo tipo, ora como outra
variável de outro tipo.
Uniões são usadas para poupar memória.
Quando você declara uma variável de um tipo union, automaticamente
é alocado espaço de memória suficiente para conter o seu maior membro.
Eis um exemplo:
//UNION.CPP
//Mostra o uso de uniões
#include <iostream . h>
#include <string.h>
#include < i omanip . h>

.
un1on num
{
c har str[2@] ;
int i ;
float f ;
} x ; //Cria variável

enum datatipo { s t rtipo,intt ipo , floattipo} tipo ;

void in i tnum(ch ar n[]}


{

tipo=strtipo;
strcpy(x . str,n};
}
void initnum(float n}
{

tipo=floattipo;
x . f =n ;
}
void in i tnum(int n)
{
Cnp. 7 Estruturas 261

tipo=int tipo ;
.
x . ~=n ;

)
void printfunc(void );

vo id ma in ()
{
float y =34 . 56;
int z = 345 ;

initnum( "VVB- TREINAMENTO");


printfunc() ;

initnum(z) ;
printfunc() ;

i n i tnum (y} ;
printfunc();
)
void printfunc()
{

switch (tipo)
{
cas e str tipo :
cout << \nStr -
11
<< x.str;
11

break ;
case inttipo :

cout << " \ nint - << x.~;
11

break ;
case float tip o:
cout << setprecision (2} ;
cout << \ nFloa t = " << x . f ;
11

break ;
}

}
262 Treinamento em Linguagem C++ Cap. 7

A sintaxe da definição de tipos usando union é idêntica à de struct. As


semelhanças terminam aqui.
Uniões são tipos de dados que armazenam um único membro por vez.
Os membros de uma union representam os diversos tipos de dados que ela
pode conter.

O OPERADOR sizeof

Uma variável de um tipo union tem o tamanho do maior membro. Para verificar
isto, usaremos um novo operador C++: sizeof.
O operador sizeof opera sobre o nome de um tipo de dado ou sobre o
nome de uma variável e resulta o seu tamanho em bytes. Veja um exemplo:
//S I ZEOF . CPP
//Mo stra o uso do ope rador s i z e o f
#inc l ude <io s t r e am.h>

un~on
. num
{
char str[2(fJ] ;
int i;
flo at f ;
} x; //Cria v ariável

void ma in ()
{
cout << s iz eo f(num ) << ' \n ';
cout << si z eo f(x);
}

Eis a saída:
2(/J

2(/J
Cap. 7 Estruturas 263

A expressão
siz e o f (num )

é equivalente a
sizeof( x )

e resulta o tamanho do tipo num .

~ "
UNIOES ANONIMAS

Uniões anônimas são uniões definidas sem a especificação do nome do tipo. Eis
um exemplo:
//UNION . CPP
//Mo stra o uso de u n iões anôn imas
#inc l ude <i o s tream . h>
#inc l ude <string.h>
#inc l ude < i o ma n ip.h>

s t atic union / / União a nôn i ma


{
c h ar str [ 2 0 ] ;
i nt i;
fl o at f ;
} ; // Cria v ariáve l

e num datatipo { strtipo,int t i po , floatti po} tipo;

voi d in i tnum( c h ar n[] )


{
tipo=strtipo ;
strcpy(s tr ,n);
}

v oid i nitnum(float n)
{
264 Treinamento em Linguagem C++ Cap. 7

tipo=floattipo;
f =n ;
)
void initnum(int n)
{

tipo=inttipo;
.
l. =n ;
}

void pr intfunc(void );

void ma in ()
{

float y =34 . 56 ;
int z = 345 ;

i n i tnum ( "VVB-TREINAMENTO" ) ;
printfunc();

initnum(z) ;
printfunc();

in i tnum (y) ;
p r intfunc();

void pr intfunc()
{

switch(tipo)
{

case strtipo :
cout << \nSt r =
11 11
<< str;
break;
case inttipo:
Cnp. 7 Estruturas 265


cout << " \ nint -11
<< l i
break ;
case floattip o :
cout << setprecision (2} ;
cout << ''\nFloat = " << f;
break ;

}
}

Uma união anônima não define um novo tipo de dado e sim declara
uma variável. Se esta variável for externa, deve obrigatoriamente ser também
estática.
A variável é acessada diretamente por meio dos nomes dos membros.
O operador ponto não é usado.
Quando criamos uma união anônima, devemos garantir que não haverá
conflito entre o nome dos membros e os nomes de variáveis de mesmo escopo.

O OPERADOR DE ENDEREÇOS: &

O endereço de memória de cada membro de uma união é o mesmo, visto que


todos compartilham o mesmo espaço. Podemos verificar isto utilizando o
operador de endereços.
// ENDERECO . CPP
//Mostra o uso do operador de endereço
#include <iostream . h>

.
unlOn num
{

char ch ;
int i ;
fl oat f ;
266 Treinamento em Linguagem C++ Cnp. 7

vo id ma in ()
(
num X i

cout << " \ nEnde r eço de c h -- " << unsign ed( &x. ch ) i
" \ nEnder eço . --
cout << de l " < < unsigned( &x. i ) i
cout << " \ nEnde r e ço de f - " < < unsigned( &x . f ) i
cou t << " \ nEndere ço de r ~
-- " << unsigned( &x. f ) i

cout << " \nEndereço de X - " << unsigned ( &x ) i


)

Eis a saída:
Ende r eço de ch
.
- 65522
Endereço de l - 65522
Endereço de f - 65522
Endereço de f - 65522
Endereço de X -- 65522

A memória de seu computador é dividida em bytes, e estes bytes são


numerados de O até o limite de memória de sua máquina. Estes números são
chamados "endereços" de bytes. Um endereço é a referência que o computador
usa para localizar variáveis.
Toda variável ocupa uma certa localização na memória, e seu endereço
é o do primeiro byte ocupado por ela.
O operador de endereços, referenciado pelo símbolo &, é um operador
unário e seu operando deve ser o nome de uma variável, resulta o seu endereço.
Não confunda o operador de endereços com o operador de referências
usado para criar referências. A falta de símbolos, devida à grande quantidade
de operadores em C++, faz com que vários operadores diferentes tenham o
mesmo símbolo.
Cap. 7 Estruturas 267

No programa, usamos o operador de endereços com cada um dos


membros da união e também com o próprio nome da variável união.
A expressão
&x

resulta o endereço do primeiro byte ocupado pela variável x.


Endereços serão abordados com mais detalhes no capítulo 11, módulo 2.

..
UNIOES DE ESTRUTURAS

Uma união pode ter membros de qualquer tipo, inclusive estruturas ou outras
uniões. Uma união também pode ser membro de uma estrutura.
Veja um exemplo:
//UNISTRUC . CPP
//Mostra união de e struturas
#include <iostream.h>

vo id ma in ()
{
struct doisint
{

int nl;
int n2 ;
};

union intf l o
{
doisint x ;
float f;
}unex ;

cout << " \ n sizeof(intf lo) - '' << sizeof( i ntf l o) ;


268 Treinamento em Linguagem C++ Cap. 7

une x.x. nl - 734;


une x . x . n2 = 333 ;

cout << 11
\nunex . x . nl -
11
<< unex . x . nl ;
cout << 11
\nunex.x.n2 -
11
<< unex .x. n2;

une x . f = 345 . 22 ;

cout << 11
\nunex . f =" << unex . f ;
)

A saída será:
s iz eof(intflo ) - 4
unex . x . nl = 734
unex . x.n2 = 333
unex . f - 345 . 22 1])(/)QJl

Observe o uso do operador ponto duas vezes para acessar os membros


da estrutura x.

A ROM BIOS

Os computadores da família IBM-PC oferecem uma coleção de funções internas


chamadas ROM BIOS. Estas funções são parte permanente da máquina,
revelando-se mais hardware do que software.
Nossos programas C++ podem usar estas funções para executar uma
ampla variedade de tarefas.
Várias funções da ROM BIOS estão duplicadas na biblioteca de funções
C++, entretanto outras não têm similares C++.
Cap. 7 Estruturas 269

CONHECENDO A BIBLIOTECA DA ROM BIOS

A maior parte das rotinas da ROM BIOS destina-se a imprimir em tela, escolher
o modo de vídeo, controlar o tamanho do cursor, ler e imprimir caracteres,
colocar um ponto em tela gráfica etc.
São fornecidas também funções para outros periféricos: manipulação
de discos, portas seriais, joysticks, teclado, impressoras etc.
Não exploraremos todas as rotinas da ROM BIOS. Para a completa
explanação de todas as rotinas, consulte o manual IBM Technica1 Reference ou
livros relacionados ao assunto.

ACESSANDO A ROM BIOS

Quando chamamos uma função C++ por meio de um programa, podemos


passar valores usando argumentos colocados entre os parênteses que seguem
o nome da função. Estes valores são armazenados numa área de memória
chamada stack, onde a função pode encontrá-los e operá-los.
Quando usamos C++ para chamar uma função da BIOS, o processo é
um pouco diferente. Em vez de os argumentos serem colocados numa área de
memória, eles são colocados num dispositivo de hardware chamado registra-
d or. Isto é semelh ante a uma posição de memória, com a vantagem de os
argumen tos serem acessados muito mais rapidamente.
Os registradores são o coração do microprocessador, sendo usados para
executar operações aritméticas e várias outras. Aqui vamos concentrar-nos
somente em usá-los como local de passagem de argumentos e retorno de valores
da BIOS.
Há vários registradores no microprocessador. Os registradores que nos
interessam são quatro, nomeados pelo DOS como AX, BX, CX e DX, e têm espaço
suficiente para armazenar um valor int.
270 Treinamento em Linguagem C++ Cap. 7

OS PRINCIPAIS REGISTRADORES DO 8086

1 byte 1 byte

Registrador AX

1 byte 1 byte

Registrador BX

1 byte 1 byte

Registrador CX

1 byte 1 byte

Registrador DX

Um registrador pode ser acessado de duas formas diferentes: ou como


um int de dois bytes, ou corno dois char de um byte cada um.
Cada registrador é dividido em metade alta e metade baixa. Ou seja, o
primeiro byte do registrador é chamado metade baixa e o segundo, metade alta.
Os nomes de acesso a esses registradores de um byte são:
Cap. 7 Estruturas 271

1 byte 1 byte
Registrador AH Registrador AL

1 byte 1 byte
Registrador BH Registrador BL

1 byte 1 byte
Registrador CH Registrador CL

1 byte 1 byte
Registrador DH
D D Registrador DL

A idéia de usar urna mesma variável acessada corno dois tipos diferen-
tes parece familiar; ela é similar à nossa descrição de union.
De fato, union é o mecanismo usado para a comunicação com registra-
dores. Mas, antes de mostrarmos um exemplo, vamos explorar outro conceito.

NÚMERO DE INTERRUPÇÕES

As funções da ROM BIOS são acessadas por meio de um número que define
um grupo de funções chamadas interrupções. Cada grupo tem um número de
interrupção diferente. Por exemplo, todas as funções de tela usam a interrupção
Ox10, e todas as que fazem transações com discos usam a de número Ox13.
Portanto, para chamar urna função da ROM, precisamos primeiro conhecer seu
número de interrupção.
272 Treinamento em Linguagem C++ Cnp. 7

A FUNÇÃO C+ + int86() EO ARQUIVO dos.h

Na realidade, não acessamos nenhum registrador em C++. Existe uma função


de biblioteca C++ que faz isso por nós. Essa função é uma espécie de interface
entre o programador C++ e as funções da ROM BIOS.
A função int86() toma três argumentos. O primeiro é o número da
interrupção que queremos acessar. O segundo é o endereço de uma variável de
um tipo union, definida logo a seguir, que contém os dados que serão colocados
nos registradores antes da chamada à interrupção (estes dados são os argumen-
tos de entrada). O terceiro é o endereço de uma variável union onde gostaríamos
que a int86() colocasse os resultados ou dados de retorno tomados após a
execução da interrupção.
- - - - - - - - - - - - - - - - - Número da interrupção
(valor inteiro)
; - - - - - - - - - - - - -- Argumentos da chamada
,- - - - - - - - Retornos ou resultados

int86(INT , &inregs , &outregs) ;

Observe que esta função requer os endereços dos dois argumentos


finais, e não seus nomes.
As variáveis inregs e outregs devem ser do tipo REGS definido no
arquivo dos.h. Observe o fragmento do arquivo que define esse tipo de dado:
struct WORDREGS
{
unsigned int ax ;
unsigned int bx;
unsigned int ex ;
unsigned int dx ;
.
unsigned int s~ ;

unsigned int di ;
un s i g ned int cflag ;
unsigned int f l ags;
};
Cnp. 7 Estruturas 273

s t ruc t BYTEREGS
(
unsigned char al ;
uns i gned c h ar ah ;
unsigned c h ar bl;
unsigned c h ar bh;
un s i g ne d char cl ;
unsigned c h ar c h;
unsigned c h ar dl ;
un s i g ned char dh;
} i

un l• on REGS
(
struct WORDREGS x;
struct BYTEREGS h ;
} i

,
DESCOBRINDO O TAMANHO DA MEMORIA PRINCIPAL

O nosso primeiro exemplo mostra o uso de uma função da ROM que retoma o
tamanho da memória principal instalada no seu computador.
Os dados requeridos por esta função estão no quadro a seguir:

ROTINA DA ROM BIOS: Tamanho da memória.

Interrupção Ox12 Tamanho da memória


Registradores de entrada: Nenhum
Registradores de saída:
AX = Tamanho da memória em Kbytes
274 Treinamento em Linguagem C++ Cap. 7

//TAMMEM.CPP
//Imprime o tamanho da memór i a principal
#include <iostream . h>
#include <dos . h> // Para int86 () e REGS

vo id ma in ()
{
const MEM - 0xl2;
REGS regs;

int86( MEM , &regs , &regs) ;

cout << " \nTamanho da memór ia: " << reg s.x.ax;
)

Observe que a interrupção Ox12 não requer nenhum registrador de


entrada, mas a função C++ int86() recebe três argumentos independentemente
de serem usados os valores armazenados neles ou não. Em nosso exemplo, não
houve necessidade de colocar nenhum valor na variável regs antes da chamada
à int86().
Geralmente, utilizamos a mesma variável regs para conter os valores
de entrada e os resultados. A int86() toma os valores contidos nela e os coloca
nos registradores correspondentes, executa a interrupção solicitada e finalmente
armazena os resultados na própria variável regs.

LIMPANDO A TELA

Já vimos que uma interrupção é um conjunto de funções. Se desejarmos acessar


uma das funções do grupo, seu número deve ser colocado no registrador AH.
Por exemplo, a função Ox06 ou a função Ox07 da interrupção OxlO limpam a tela
e posicionam o cursor no canto esquerdo. Na verdade, a função Ox06 rola a tela
para cima e a função Ox07 rola a tela para baixo.
Cnp. 7 Estruturas 275

Qualquer uma das duas pode ser chamada para limpar a tela toda ou
somente uma janela da tela.
Os dados requeridos por estas funções estão nos quadros a seguir:

ROTINA DA ROM BIOS: Rola a tela para cima.

Interrupção OxlO Vídeo


Registradores de entrada:
AH = Ox06
AL =Número de linhas a rolar
(O para limpar a tela toda)
BH = Atributo (7 para normal)
CH = Linha de início
CL = Coluna de início
DH = Linha de fim
DL = Coluna de fim
Registradores de saída: Nenhum

ROTINA DA ROM BIOS: Rola a tela para baixo.

Interrupção OxlO Vídeo


Registradores de entrada:
AH = Ox07
AL =Número de linhas a rolar
(O para limpar a tela toda)
BH = Atributo ( 7 para normal)
CH = Linha de início
276 Treinamento em Linguagem C++ Cap. 7

CL = Coluna de início
DH = Linha de fim
DL = Coluna de fim
Registradores de saída: Nenhum
No nosso exemplo, usaremos a função Ox07 para escrever uma função
que limpa a tela toda e posiciona o cursor no canto esquerdo.
#include <dos . h>

cons t VI DEO = 0x l0 ;

void cls ()
{
REGS regs ;

//Prepara dados de entrada


r egs. h . ah - 0x(/J7 ;
regs . h . al -- 0;

regs . h . bh - 7. '
regs . h . ch -- 0;
regs . h . cl -- 0;

r egs . h . dh -- 24;
regs . h . dl -- 79;

int86(VIDEO , &regs , &regs );


}

MONTANDO O TAMANHO DO CURSOR

O próximo exemplo chama a rotina da ROM que muda o tamanho do cursor.


Em vídeos CGA, o cursor é um bloco de oito linhas numeradas de O a 7. O
cursor default usa somente as linhas 6 e 7.
Cap. 7 Estruturas 277

linhas do cursor CGA


linha O
linha 1
linha 2
linha 3
linha 4
linha 5
linha 6
linha 7
Para escolher o tamanho do cursor, chamaremos a função OxOl da
interrupção OxlO da BIOS.
Os dados requeridos por esta função estão no quadro a seguir:

ROTINA DA ROM BIOS: Seleciona tamanho do cursor.

Interrupção OxlO Vídeo


Registradores de entrada:
AH =OxOl
CH =Linha de início (O a 7)
CL =Linha de fim (O a 7)

Registradores de saída: Nenhum


// SELECUR. CPP
// Selec iona o tamanho do cu rsor

#inc l ude <iostream . h >


#inc l ude <dos . h >

const VIDEO = 0x 1 0;
278 Treinamento em Linguagem C++ Cap. 7

v o i d s e l ecur ( un s i gned char linhai , unsign ed cha r l i nha f )


{

REGS regs ;

r e gs.h . ah - 0x01 ;
regs . h . ch - l inhai ;
r egs . h . cl - linhaf ;
int86(VIDEO ,& r egs , &r egs) ;
}

vo id ma i n ()
{
i nt li, lf;

while ( 1 )
{

cout << " \ nEntre (i ni c i o f i m) ''


"ou um número negat i vo para t e r mina r : ";

cin >> li >> l f ;

if (l i < 0) brea k ;

s e l ecur( l i, l f ) ;
}

Para o cursor ter o tamanho do bloco máximo, digite:


I nsira (i ni cio f i m) ou um número negativo par a te r minar : 0 7

Para retornar ao cursor normal, digite:


Insira (inicio fim ) ou um número negativo para terminar : 6 7

Especificar a linha de início maior que a linha de fim causa a impressão


do cursor em duas partes: