Você está na página 1de 127

Linguagem C++ - Notas de Aula

Prof. Armando Luiz N. Delgado


baseado em reviso sobre material de Prof
a
Carmem Hara e Prof. Wagner Zola
Junho 2012
Parte I
Programao Bsica em C++
Estas notas de aula apresentam os conceitos bsicos da Linguagem C++ e se prope a abordar apenas o que
importante para a compreenso bsica de programas de computadores. Assim, conceitos de C++ como obje-
tos, classes, templates e outros conceitos relacionados programao orientada a objetos no so abordados
aqui.
1
1 Programas C++
Essencialmente, um programa C++ consiste de uma ou mais partes chamadas funes
1
. Alm disso, um
programa em C++ deve denir pelo menos uma funo chamada main. Esta funo marca o ponto de incio
de execuo do programa.
Programas C++ tem a seguinte estrutura geral:
#include <iostream>
using namespace std;
denio de constantes
funes
int main()
{
declarao de variveis
....
sentenas
....
}
1.1 Sentenas: simples e compostas
Cada instruo em C++ chamada de sentena. Sentenas simples so terminadas com um ponto e vrgula.
Usando chaves, podemos agrupar sentenas em blocos, chamados de sentenas compostas.
Exemplos de sentenas incluem:
Simples:
x = 3;
Composta:
{
i = 3;
cout << i << endl;
i = i + 1;
}
O corpo da funo main() um exemplo de sentena composta.
1.2 Variveis em C++
Uma varivel uma informao que voc pode usar dentro de um programa C++ . Esta informao est
associada com um lugar especco da memria (isso feito pelo compilador). O nome da varivel e o
endereo da memria onde a informao est armazenada esto associados. O nome e o endereo no
mudam. Mas, o valor da informao pode mudar (o valor do que est dentro da caixa pode mudar, embora o
1
Na verdade, um programa C++ composto pela denio de funes e de elementos estruturais denominados classes. Estes
so tema de estudo em cursos avanados de programao orientada a objetos.
2
tipo seja sempre o mesmo). Cada varivel temumtipo associado. Alguns tipos de variveis que discutiremos
incluem int, char e oat.
Cada varivel usa uma determinada quantidade de armazenamento em memria. A maneira como sabe-
mos quantos bytes so utilizados pelo tipo da varivel. Variveis do mesmo tipo utilizam o mesmo nmero
de bytes, no interessando qual o valor que a varivel armazena.
Um dos tipos utilizados para armazanar nmeros o int. Ele usado para armazenar nmeros inteiros.
Outro tipo o char, usado para armazenar caracteres. Um caracter um smbolo (uma letra do alfabeto,
um dgito, um smbolo de pontuao, etc). Um char armazenado em 1 byte de memria. Cada caracter
associado com um valor entre 0 e 255. O compilador C++ faz a traduo para voc, portanto voc no
precisa saber estes nmeros. Em C++ , um caracter representado entre apstrofes (). Por exemplo, C,
a, 5, $. Note que 5 um caracter, e no o inteiro 5.
A gura acima mostra como um int e um char so armazenados na memria.
Outro tipo existente o oat, usado para armazenar nmeros reais (nmeros com o ponto decimal).
Este nmeros so armazenados em duas partes: a mantissa e o expoente. Eles so armazenados de uma
maneira que se assemelha a notao exponencial. Por exemplo, o nmero 6.023 10
23
escrito como
6.023e23. Neste caso, a mantissa 6.023 e o expoente 23.
Estes nmeros so armazenados de uma forma padro, tal que a mantissa tem apenas um dgito para
a esquerda do ponto decimal. Desta forma, 3634.1 escrito como 3.6341e3, e 0.0000341 escrito 3.41e-
5. Note tambm que a preciso limitada pela mantissa. Somente os 6 dgitos mais signicativos so
armazenados. Em Code::Blocks um oat ocupa 4 bytes de memria. H muitos outros tipos ( short, long,
double), que sero descritos no futuro.
1.3 Denio de Varivel em C++
Se voc usa variveis no programa, voc deve deni-las. Isto envolve especicar o tipo da varivel e o seu
nome. As regras para formar nomes de variveis em C++ so:
qualquer sequncia de letras, digitos, e _, MAS DEVE COMEAR com uma letra ou com _. Por
exemplo, hora_inicio, tempo, var1 so nomes de variveis vlidos, enquanto 3horas, total$ e
azul-claro no so nomes vlidos;
Maisculas = Minsculas;
No so permitidos nomes ou palavras reservadas da linguagem.
sempre uma boa idia ter certas regras (para voc mesmo) para nomear variveis para tornar o pro-
grama mais legvel:
D nomes signicativos as variveis (mas no muito longos);
3
auto break case char const continue
default do double else enum extern
oat for goto if int long
main register return short signed sizeof
static struct switch typedef union unsigned
void volatile while
Tabela 1: Palavras Reservadas da Linguagem C++
Use nomes de variveis do tipo i, j, k somente para variveis tipo contadores;
Pode-se usar letras maisculas ou _ para juntar palavras. Por exemplo, horaInicio ou hora_inicio.
Use o que voc preferir, mas SEJA CONSISTENTE em sua escolha.
Os tipos bsicos de dados existentes em C++ so:
Tipo de Dado Bits Faixa de Valores
char 8 -128 a 127
bool 8 true ou false
int 32 -2.147.483.647 a 2.147.483.647
oat 32 7 dgitos signicativos
double 64 15 dgitos signicativos
Abaixo est um exemplo de um programa com diversas denies de variveis:
int main()
{
int pera;
char qualidade;
oat peso;
pera = 3;
qualidade = A;
peso = 0.653;
...
}
Quando variveis so denidas, elas no possuem valores ainda. Ns damos valores s variveis usando
o operador de atribuio (=). Variveis tambm podem ser inicializadas para conter valores quando so
denidas. Usando esta forma, o program acima caria:
int main()
{
int pera = 3;
char qualidade = A;
oat peso = 0.653;
...
}
4
Para resumir: quando um programa executado, uma varivel associada com:
um tipo: diz quantos bytes a varivel ocupa, e como ela deve ser interpretada.
um nome: um identicador.
um endereo: o endereo do byte menos signicativo do local da memria associado a varivel.
um valor: o contedo real dos bytes associados com a varivel; o valor da varivel depende do tipo
da varivel; a denio da varivel no d valor a varivel; o valor dado pelo operador de atribuio,
ou usando a funo cin. Ns veremos mais tarde que a funo cin atribui a uma varivel um valor
digitado no teclado.
Em C++ , nomes de variveis devem ser declarados antes de serem usados. Se no for declarado,
ocorrer um erro de compilao.
Devem ser dados valores s variveis antes que sejam utilizadas. Se voc tentar utilizar a varivel
antes de especicar o seu valor, voc obter lixo (o que quer que esteja armazenado no endereo da
varivel na memria quando o programa comea sua execuo), culminando com falha na execuo
do programa.
1.4 Constantes
Em C++ , alm de variveis, ns podemos usar tambm nmeros ou caracteres cujos valores no mudam.
Eles so chamados de constantes. Constantes no so associados a lugares na memria.
Assim como variveis, constantes tambm tm tipos. Uma constante pode ser do tipo int, char, etc.
Voc nao tem que declarar constantes, e pode utiliz-las diretamente (o compilador reconhece o tipo pela
maneira que so escritos). Por exemplo, 2 do tipo int, e 2.0 do tipo double. Por conveno, todas as
constantes reais so do tipo double.
1.5 Caracteres Constantes
Um constante caracter escrita entre apstrofes, como em A. Todas as letras, nmeros e smbolos que
podem ser impressos so escritos desta forma em C++ . s vezes precisamos de caracteres que no podem
ser impressos, por exemplo, o caracter de nova linha, que no tem uma tecla especca no teclado. Neste
caso, usa-se caracteres de escape. Tais caracteres so escritos no somente como um smbolo entre aps-
trofes, mas como um sequncia de caracteres entre apstrofes. Por exemplo, \n o caracter para nova
linha (uma sequncia que inicia com a barra invertida chamada de sequncia de escape). Se quisermos
representar o caracter de barra invertida, temos que escrever \\. Note que \n o caracter de nova linha
- embora use-se dois smbolos para represent-lo. A barra invertida chamada de escape. Ele diz ao com-
pilador que o n que segue no a letra n, mas que a sequncia completa de caracteres deve ser interpretada
como o caracter de nova linha.
Cada caracter constante tem um valor inteiro igual ao seu valor numrico do seu cdigo ASCII. Por
exemplo, considere a constante A, que tem cdigo ASCII 65, e B que tem cdigo 66. Ns podemos usar
a expresso A + 1. O resultado o valor 66. E se o tipo da expresso resultante for char, ento o resultado
da expresso B.
1.6 Entrada e Sada
Se quisermos que um programa C++ mostre alguns resultados, ou se quisermos que o programa pea ao
usurio que entre com alguma informao, ns podemos usar os elementos cout e cin
2
. Se voc quiser
usar estes elementos em seu programa, voce deve incluir as seguintes linhas no incio do seu cdigo fonte:
2
cout e cin so na verdade objetos das classes ostream e istream. Mas este detalhe no abordado nestas notas de aula. Ser
visto apenas o uso destes objetos como primitivas simples para Entrada e Sada de dados.
5
#include <iostream>
using namespace std;
Isto faz com que o arquivo header chamado iostream seja includo no seu arquivo fonte durante a
compilao. Este arquivo contm denies de diversas funes e classes (por exemplo, cout e cin).
Ele declara ao compilador o nome das funes e algumas informaes adicionais necessrias para que as
instrues sejam executadas corretamente.
1.6.1 Exibindo informaes na tela: cout
cout pode ser utilizado para imprimir mensagens e valores em uma variedade de formatos. Por enquanto,
cout melhor descrito atravs de exemplos.
cout << "Al todo mundo" << endl;
Imprimir Al todo mundo em uma linha na tela do computador. O valor endl representa a mudana
de linha.
Para o comando cout fazer o que deve, ns devemos especicar o que ser impresso. Ns devemos dar
ao comando o que chamamos de argumentos. No exemplo acima, Al todo mundo e endl so argumentos
para cout.
Os argumentos de cout podem ser uma varivel, uma expresso ou um string (uma srie de caracteres
entre aspas (")).
Ns tambm podemos colocar caracteres de escape no string para imprimir caracteres especiais. Por
exemplo, colocando \n no string causa que o restante do string seja impresso na linha seguinte. Outros
caracteres de escape sero apresentados no futuro.
Considere o seguinte programa:
#include <iostream>
using namespace std;
#dene PRECO 1.99
int main()
{
int pera = 3;
char qualidade = A;
oat peso = 2.5;
cout << "Existem " << pera << "peras de qualidade " << qualidade
<< "pesando " << peso << "quilos." << endl;
cout << "O preco por quilo eh R$" << PRECO
<< ", o total eh R$" << peso * PRECO << endl;
}
A sada do programa ser:
Existem 3 peras de qualidade A pesando 2.5 quilos.
O preco por quilo eh 1.99, o total eh 4.975
A linha #dene PRECO 1.99 no incio do programa dene uma macro. Ou seja, denimos que
PRECO um sinnimo para 1.99 e, portanto, toda ocorrncia de PRECO no programa substitudo por
1.99 antes que ele seja compilado.
6
1.6.2 Lendo informao: cin
cin pode ser usado para ler valores digitados no teclado.
Considere o seguinte programa:
#include <iostream>
using namespace std;
int main()
{
int idade;
cout << "Entre sua idade: ";
cin >> idade
cout << "Voce tem " << idade << "anos." << endl;
}
Este programa mostrar no monitor: Entre sua idade: e aguardar que um nmero seja digitado e a
tecla ENTER. Depois disso, a varivel idade conter o valor digitado pelo usurio.
Mais de um valor pode ser lido por um mesmo cin. Considere o seguinte exemplo:
#include <iostream>
using namespace std;
int main()
{
int dia, mes, ano;
cout << "Entre com a data do seu aniversario (dd mm aa): ";
cin >> dia >> mes >> ano;
cout << "Voce nasceu em " << dia << "/" << mes << "/" << ano << endl;
}
Este exemplo funciona exatamente como o exemplo anterior. Um nico cin l os 3 nmeros quando
estes nmeros so separados por espaos (espaos em branco, tabulao, novas linhas). Ento voc pode
teclar ENTER depois de cada nmero, ou colocar espaos ou tabulaes entre os nmeros. Os espaos so
ignorados pelo cin.
1.7 Algoritmo X Programa
ALGORITMO PERIMETRO_AREA
/
*
Calcula o permetro e a area de uma circunferencia
de raio R (fornecido pelo usuario)
*
/
/
*
Definir variaveis
*
/
int Raio;
float Perim, Area, PI;
PI = 3.14159;
7
/
*
Obter Raio da circunferencia
*
/
Escreva("Entre com o valor do raio:");
Leia(Raio);
/
*
Calcular Perimetro do Circulo
*
/
Perim = 2
*
PI
*
Raio;
/
*
Calcular Area da Circunferencia
*
/
Area = PI
*
Raio
**
2;
/
*
Exibir Resultados
*
/
Escreva("O perimetro da circunferencia de raio", Raio, "eh", Perim);
Escreva("e a area eh ",Area);
/
*
Terminar Programa
*
/
FIM_ALGORITMO PERIMETRO_AREA
Programa em C++
/
*
programa que calcula o permetro e a rea de uma
circunferncia de raio R (fornecido pelo usurio)
*
/
#include <iostream> /
*
inclui diretivas de entrada-sada
*
/
#include <cmath> /
*
inclui diretivas das funes matemticas
*
/
using namespace std;
#define PI 3.14159
int main( )
{
/
*
Definir variaveis
*
/
int Raio;
float Perim, Area;
/
*
Obter Raio da circunferencia
*
/
cout << "Entre com o valor do raio: ";
cin >> Raio;
/
*
Calcular Perimetro do Circulo
*
/
Perim = 2
*
PI
*
Raio;
/
*
Calcular Area da Circunferencia
*
/
Area = PI
*
pow(Raio, 2);
/
*
Exibir Resultados
*
/
cout << "O perimetro da circunferencia de raio " << Raio
<< " eh " << Perim << endl;
cout << "e a area eh " << Area << endl;
8
}
9
2 Operaes Aritmticas e Expresses.
Operaes Relacionais.
2.1 Operaes Aritmticas
Em C++ , ns podemos executar operaes aritmticas usando variveis e constantes. Algumas operaes
mais comuns so:
+ adio
- subtrao
* multiplicao
/ diviso
% resto (mdulo)
Estas operaes podem ser usadas como mostram os exemplos abaixo, assumindo que as variveis ne-
cessrias j esto declaradas:
celsius = (fahrenheit - 32)
*
5.0 / 9.0;
forca = massa
*
aceleracao;
i = i + 1;
2.1.1 Precedncia de Operadores
Em C++ , assim como em lgebra, h uma ordem de precedncia de operadores.
Assim, em (2 +x)(3x
2
+1), expresses em parntesis so avaliadas primeiro, seguidos por exponenci-
ao, multiplicao, diviso, adio e subtrao.
Da mesma forma, em C++ , expresses entre parntesis so executadas primeiro, seguidas de
*
, / e %
(que tem todos a mesma precedncia), seguido de + e - (ambos com a mesma precedncia).
Quando operaes adjacentes tm a mesma precedncia, elas so associadas da esquerda para a direita.
Assim, a
*
b / c
*
d % e o mesmo que ((((a
*
b) / c)
*
d) % e).
2.1.2 A Operao de Resto (%)
Esta operao usada quando queremos encontrar o resto da diviso de dois inteiros. Por exemplo, 22
dividido por 5 4, com resto 2 (4 5 + 2 = 22).
Em C++ , a expresso 22 % 5 ter valor 2.
Note que % s pode ser utilizados entre dois inteiros. Usando ele com um operando do tipo float
causa um erro de compilao (como em 22.3 % 5).
2.1.3 Expresses e Variveis
Expresses aritmticas podemser usadas na maior parte dos lugares emque uma varivel pode ser usada.
O exemplo seguinte vlido:
int raio = 3
*
5 + 1;
cout << "circunferencia = " << 2
*
3.14
*
raio << endl;
10
Exemplos de lugares onde uma expresso aritmtica NO pode ser usada incluem:
int yucky + 2 = 5;
cin >> oops
*
5;
Este exemplo ilegal e causar erro de compilao.
2.2 Operadores Relacionais
Em C++ , h operadores que podem ser usados para comparar expresses: os operadores relacionais.
H seis operadores relacionais em C++ :
< menor que
> maior que
<= menor ou igual que ()
>= maior ou igual que ()
== igual a
!= no igual a (=)
Os resultados deste operadores 0 (correspondendo a falso), ou 1 (correspondendo a verdadeiro). Va-
lores como esses so chamados valores booleanos. Algumas linguagens de programao como Pascal tem
um tipo de varivel distinto para valores booleanos. Este no o caso do C++ , onde valores booleanos so
armazenados como variveis numricas tais como o int.
Considere o seguinte programa:
int main()
{
int idade;
idade = 17;
cout << "Pode tirar carteira de motorista? " << (idade >= 18) << endl;
idade = 35;
cout << "Pode tirar carteira de motorista? " << (idade >= 18) << endl;
}
A sada deste programa ser:
Pode tirar carteira de motorista? 0
Pode tirar carteira de motorista? 1
Na primeira linha, idade 17. Logo, 17 >= 18 falso, que 0.
Depois disso, idade 35. Logo, 35 >= 18 verdadeiro, que 1.
Note tambm que o operador de igualdade escrito com sinais de igual duplo, ==, no =. Tenha
cuidado com esta diferena, j que colocar = no lugar de == no um erro sinttico (no gera erro de
compilao), e no signica o que voc espera.
11
2.2.1 Precedncia dos operadores relacionais
Operadores aritmticos tem precedncia maior que os operadores relacionais. Por exemplo, a expresso
3 + 5 < 6
*
2 o mesmo que (3 + 5) < (6
*
2).
Se por alguma razo voc quer que o resultado do uma operao relacional em uma expresso aritmtica,
necessrio usar parntesis. Por exemplo, a expresso score + (score == 0) ser sempre igual ao
valor de score, exceto quando o valor de score seja 0. Neste caso, o valor da expresso 1 (porque
(score == 0) igual a 1).
Uma observao sobre valores booleanos embora voc possa assumir que o valor de uma operao
relacional 0 ou 1 em C++ , qualquer valor diferente de zero considerado verdadeiro. Falaremos
sobre isso mais tarde durante o curso.
2.3 Reviso de Expresses:
O que impresso pelos dois programas abaixo?
#include <iostream>
using namespace std;
int main() {
int score = 5;
cout << 5 + 10
*
5 % 6; // 7
cout << 10 / 4; // 2
cout << 10.0 / 4.0; // 2.5
cout << A + 1 // B
cout << score + (score == 0); // 5
}
#include <iostream>
using namespace std;
int main() {
int n1, n2, n3;
cout << "Entre com um numero inteiro: ";
cin >> n1;
n2 = n1 / 5;
n3 = n2 % 5
*
7;
cout << n2 << " " << n3 << " " << (n2 != n3 + 21) << endl;
}
Como a seguinte expresso completamente parentizada ?
a
*
b / c + 30 >= 45 + d
*
3 ++e == 10
2.4 Exemplo de programas
Exemplo 1: escreva um programa que leia um nmero inteiro e imprima 0 se o nmero for par e 1 se o
nmero for mpar.
12
#include <iostream>
using namespace std;
int main() {
int numero;
cout << "Entre com um numero inteiro: ";
cin >> numero;
cout << "\nPar? " << numero % 2 << endl;
}
Exemplo 2: escreva um programa que leia 3 nmeros inteiros e calcule a soma, mdia, e produto.
#include <iostream>
#include <iomanip> // necessario para usar setw() e setf() em cout
using namespace std;
int main() {
int n1, n2, n3;
int soma;
cout << "Entre com 3 numeros inteiros: ";
cin >> n1 >> n2 >> n3;
soma = n1 + n2 + n3;
cout << "Soma = " << soma << endl;
cout.setf (ios::fixed | ios::showpoint); // reais em ponto fixo
cout.precision(2); // 2 casa decimais
// setw(8) fixa tamanho da representao em 8 digitos
cout << "Media = " << setw(8) << soma / 3.0 << endl;
cout << "Produto = " << (unsigned) n1
*
n2
*
n3 << endl;
}
2.5 Precedncia e associatividade de operadores
Operador Associatividade
() esquerda para direita
- (unrios) direita para esquerda
*
/ % esquerda para direita
+ - esquerda para direita
< <= > >= esquerda para direita
== != esquerda para direita
13
3 Expresses como valores
Em C++ , todas as expresses so avaliadas. O resultado da avaliao um valor e pode ser usado em
quaisquer lugares.
3.1 Expresses aritmticas, relacionais e lgicas
Como voc j sabe, expresses usando operadores aritmticos, relacionais e lgicos
3
so avaliados. O valor
resultante um nmero. Para os operadores relacionais e lgicos, este nmero pode ser 0 (que signica
falso) ou 1 (que signica verdadeiro). Por exemplo:
3 + 5
*
4 % (2 + 8) tem valor 3;
3 < 5 tem valor 1;
x + 1 tem valor igual ao valor
da varivel x mais um;
(x < 1) || (x > 4) tem valor 1 quando o va-
lor da varivel x fora do
intervalo [1,4], e 0 quando
x est dentro do intervalo.
3.2 Expresses envolvendo o operador de atribuio (=)
O formato do operador de atribuio :
lvalue = expressao (1)
Um lvalue (do ingls left-hand-side value - valor a esquerda) um valor que se refere a um endereo
na memria do computador. At agora, o nico lvalue vlido visto no curso o nome de uma varivel. A
maneira que a atribuio funciona a seguinte: a expresso do lado direito avaliada, e o valor copiado
para o endereo da memria associada ao lvalue. O tipo do objeto do lvalue determina como o valor da
expressao armazenada na memria.
Expresses de atribuio, assim como expresses, tm valor. O valor de uma expresso de atribuio
dado pelo valor da expresso do lado direito do =. Por exemplo:
x = 3 tem valor 3;
x = y+1 tem o valor da expresso
y+1.
Como consequncia do fato que atribuies serem expresses que so associadas da direita para es-
querda, podemos escrever sentenas como:
i = j = k = 0;
Que, usando parnteses, equivalente a i = (j = (k = 0)). Ou seja, primeiro o valor 0 atri-
budo a k, o valor de k = 0 (que zero) atribudo a j e o valor de j = (k = 0) (que tambm zero)
atribudo a i.
Uma caracterstica muito peculiar de C++ que expresses de atribuio podem ser usados em qualquer
lugar que um valor pode ser usado. Porm voc deve saber que us-lo dentro de outros comandos produz
um efeito colateral que alterar o valor da varivel na memria. Portanto, a execuo de:
int quadrado, n = 2;
cout << "Quadrado de " << n << " eh menor que 50? " << ((quadrado = n
*
n) < 50) << endl;
3
Operadores lgicos && e || sero vistos na prxima aula.
14
causa no apenas que o valor 4 seja impresso, como a avaliao da expresso relacional dentro do cout
faz com que o nmero 4 seja copiado para o endereo de memria associado com a varivel quadrado.
Note que necessrio usar parnteses em quadrado = n
*
n j que = tem menor precedncia que o
operador relacional <.
Agora compare o exemplo anterior com o prximo, no qual o valor 4 impresso, mas sem nenhum
efeito colateral:
int quadrado, n = 2;
cout << "Quadrado de " << n << " eh menor que 50? " << (n
*
n < 50) << endl;
Note que agora no h necessidade de parnteses para a expresso n
*
n porque
*
tem maior prece-
dncia que o operador relacional <.
15
4 Ordem sequencial de execuo de sentenas
o comando condicional: if e if - else
A execuo de um programa C++ comea com a funo main(). Em todos os exemplos que vimos at este
momento, sentenas so executadas sequencialmente. A ordem sequencial de execuo de senteas pode
ser alterada se certas condies forem satisfeitas durante a execuo do programa. Isto chamado desvio
condicional.
Todas as linguagens de programao oferecem comandos para o desvio condicional. O mais simples a
sentea if. Em C++ , ele tem o formato:
if (expressao)
corpododesvio
O corpo do desvio, por sua vez, pode ser uma sentena simples ou composta (veja Seo 1.1).
Quando uma sentena if encontrada em um programa,
1. O teste na expressao em parnteses avaliada.
2. Se o valor da expresso de teste for DIFERENTE de zero, as sentenas que compem o corpo do
desvio que segue a expresso de teste so executadas.
Figura 1: O comando if
Considere o seguinte exemplo que converte uma frao digitada pelo usurio (numerador e denomina-
dor) em decimal e imprime o resultado:
#include <iostream>
using namespace std;
int main( ){
int a, b;
cout << "Entre com uma fracao (numerador and denominador): ";
cin >> a >> b;
cout << "A fracao em decimal eh " << 1.0
*
a / b << endl;
}
16
No exemplo acima, escrevemos 1.0
*
a / b, j que a e b so do tipo int, e portanto a / b uma
diviso de inteiros e a parte fracional do resultado seria truncado, o que certamente no o que desejamos.
Voce v algo errado neste programa ? Uma coisa a ser notada que se o usurio digitar um denominador
igual a 0, ns teremos um erro de execuo, j que o programa tentaria executar uma diviso por zero. O
que necessrio fazer testar se o denominador igual a zero e dividir s no caso dele for diferente de zero.
Poderamos reescrever o programa acima da seguinte forma:
Exemplo 1:
#include <iostream>
using namespace std;
int main( ){
int a, b;
cout << "Entre com uma fracao (numerador e denominador): ";
cin >> a >> b;
if (b != 0)
cout << "A fracao em decimal eh " << 1.0
*
a / b << endl;
}
Exemplo 2: Programa que l dois nmeros e ordena o par caso o primeiro nmero digitado for maior que
o segundo.
#include <iostream>
using namespace std;
int main( ){
int num1, num2, aux;
cout << "Entre com dois numeros inteiros: ";
cin >> num1 >> num2;
if (num1 > num2) {
aux = num1;
num1 = num2;
num2 = aux;
cout << "Trocou \n";
}
cout << "Os numeros ordenados: " << num1 << " " << num2 << endl;
}
O programa do Exemplo 1 acima caria ainda melhor se ao invs de no fazer nada no caso do denomi-
nador ser zero, imprimirmos uma mensagem de erro ao usurio, explicando o que h de errado.
A sentena em C++ que permite fazermos isso o if - else. O formato do if-else :
17
if (expressao)
sentenca
1
else
sentenca
2
Figura 2: O comando if-else
Primeiro, a expressao (que usualmente chamamos de condio) avaliada. Caso a condio seja ver-
dadeira (o que equivalente a dizer que o valor diferente de zero), entao a sentenca
1
executada. Caso
contrrio, a sentenca
2
executada.
Note que uma sentena pode ser simples ou composta. Se voc quiser agrupar diversas sentenas para
serem executadas, voc pode coloc-las entre chaves ({ e }).
Por hora, vamos continuar com nosso exemplo simples e torn-lo mais explicativo:
Exemplo 3:
#include <iostream>
using namespace std;
int main( ){
int a, b;
cout << "Entre com uma fracao (numerador and denominador): ";
cin >> a >> b;
if (b != 0)
cout << "A fracao decimal eh " << 1.0
*
a / b << endl;
else
cout << "Erro: denominador zero!\n";
}
Exemplo 4: Considere agora o exemplo j visto que pede que um usurio entre com um nmero e verique
se o nmero par. Porm agora, queremos que o programa imprima o numero e par ou o numero e
impar.
#include <iostream>
18
using namespace std;
int main( ){
int num;
// obtem um numero do usuario
cout << "Entre com um inteiro: ";
cin >> num;
// imprime uma mensagem dizendo se o numero e par ou impar
if (num % 2 == 0)
cout << "O numero eh par.\n";
else
cout << "O numero eh impar.\n";
}
4.1 Um erro comum
muito frequente utilizar o operador relacional == em expresses condicionais da sentena if. Por exem-
plo:
int saldo = 2000;
if (saldo == 1)
cout << "Voce esta quebrado! " << endl;
else
cout << "Seu saldo eh " << saldo << endl;
Como a sentena saldo = 2000 inicializa o valor da varivel saldo com 2000, a expresso
saldo == 1 tem valor 0. Portanto, a sentea que segue o else ser executada, e a mensagem
Seu saldo e 2000
ser impressa.
Agora, suponha que, devido a um erro, voc tenha colocado = ao invs de ==:
int saldo = 2000;
if (saldo = 1)
cout << "Voce esta quebrado! " << endl;
else
cout << "Seu saldo eh " << saldo << endl;
Agora, a expresso saldo = 1 tem valor 1. Portanto, a sentena que segue o if ser executada, e
a mensagem
Voce esta quebrado!
19
ser impressa. Alm disso, a atribuio causar um efeito colateral, e alterar o valor de saldo para 1.
Tal uso do operador de atribuio no ilegal, e no ser detectado pelo compilador como erro. Portanto,
tome cuidado com o uso de atribuio no lugar de igualdade. Tal erro muito comum, e no fcil de achar.
Como regra geral, NO utilize atribuies dentro de outras sentenas.
5 Aninhando senteas if e if-else
Como era de se esperar, possvel colocar uma sentena condicional dentro de outra. Por exemplo, se
quisermos imprimir uma mensagem apropriada caso um nmero seja positivo ou negativo e par ou mpar,
ns poderamos escrever o seguinte:
#include <iostream>
using namespace std;
int main( ){
int num;
// Obtem um numero do usuario
cout << "Entre com um inteiro: ";
cin >> num;
// Imprime uma mensagem dizendo se o numero e positivo ou negativo,
// positivo ou negativo.
if (num >= 0) {
if (num % 2 == 0)
cout << "O numero e par e positivo\n";
else
cout << "O numero e impar e positivo\n";
}
else {
if (num % 2 == 0)
cout << "O numero e par e negativo\n";
else
cout << "O numero e impar e negativo\n";
}
}
5.1 A ambigidade do else
O aninhamento de sentenas if-else sem usar chaves ({ e }) para delimitar o bloco de senteas a ser
executado pode trazer efeitos indesejados.
H uma regra simples para determinar qual if est associado a qual else.
Regra de associao: Um else est associado com a ltima ocorrncia do if sem else.
O exemplo seguinte est errado porque associa o else ao if "incorreto":
#include <iostream>
using namespace std;
int main( ){
20
int num;
// Obtem um numero do usuario
cout << "Entre com o numero de peras: ";
cin >> num;
// Imprime uma mensagem dizendo se o numero de peras e 0 ou 1
// (
***
isto esta errado !!
***
)
if (num != 0)
if (num == 1)
cout << "Voce tem uma pera.\n";
else
cout << "Voce nao tem nenhuma pera.\n";
}
Neste exemplo, o if tem o seguinte signicado, segundo a regra de associao:
#include <iostream>
using namespace std;
int main( ){
int num;
// Obtem um numero do usuario
cout << "Entre com o numero de peras: ";
cin >> num;
// Como a sentenca if e vista pelo compilador
if (num != 0)
if (num == 1)
cout << "Voce tem uma pera.\n";
else
cout << "Voce nao tem nenhuma pera.\n";
}
Para evitar este problema, chaves ({ e }) devem ser usadas para tirar a ambiguidade. O exemplo abaixo
mostra como as chaves podem ser inseridas para corrigir o programa acima.
#include <iostream>
using namespace std;
int main( ){
int num;
// Obtem um numero do usuario
cout << "Entre com o numero de peras: ";
cin >> num;
21
// Como corrigir o problema (este programa funciona)
if (num != 0) {
if (num == 1)
cout << "Voce tem uma pera.\n";
}
else
cout << "Voce nao tem nenhuma pera.\n";
}
Exerccio 1: Faa um programa que leia 3 nmeros e imprima o maior.
6 Operadores Lgicos
Todos os programas at agora consideraram if com condies de teste simples. Alguns exemplos de testes
simples: b != 0, contador <= 5. Estas expresses testam uma condio. Portanto, quando mais de
uma condio precisa ser testada, precisamos usar sentenas if e if-else aninhadas.
A linguagem C++ , assim como a maioria das linguagens de programao de alto nvel suportam ope-
radores lgicos que podem ser usados para criar operaes lgicas mais complexas, combinando condies
simples. O valor de uma expresso lgica ou VERDADEIRO ou FALSO. Lembre que no h constan-
tes lgicas VERDADEIRO e FALSO em C++ ; em expresses lgicas 0 interpretado como FALSO, e
qualquer valor diferente de zero interpretado como VERDADEIRO.
Os operadores lgicos so
! NO lgico, operao de negao (operador unrio)
&& E lgico, conjuno (operador binrio)
|| OU lgico, disjuno (operador binrio).
Por exemplo, se quisermos testar se um nmero num positivo e par, e imprimir uma mensagem como
no exemplo anterior, podemos escrever:
if (num >= 0)
if (num % 2 == 0)
cout << "Numero par nao negativo." << endl;
Com os operadores lgicos isso pode ser simplicado:
if ((num>=0) && (num%2 == 0))
cout << "Numero par nao negativo." << endl;
A operao de negao, !, pode ser usado da seguinte forma:
!expresso lgica: O valor a negao lgica da expresso dada. Por exemplo:
!0 1
!1 0
Ns podemos usar o operador de negao lgica e escrever o exemplo acima como:
if (num>0 && !(num%2))
cout << "Numero par nao negativo." << endl;
22
Os dois operadores binrios operam sobre duas expresses lgicas e tem o valor 1 (verdadeiro) or 0
(falso). Os exemplos abaixo mostram o seu uso:
a==0 && b==0 (verdadeiro se ambos a == 0 e b == 0, portanto se a e b so 0)
a==0 || b==0 (verdadeiro se pelo menos uma das variveis a or b for 0)
Uma expresso usando && verdadeira somente se ambos os operadores forem verdadeiros (no
zero).
Uma expresso usando || falsa somente se ambos os operadores forem falsos (zero).
Verique na Tabela 2 o resultado do uso de operadores lgicos:
expr
1
expr
2
expr
1
&& expr
2
expr
1
|| expr
2
verdadeiro verdadeiro verdadeiro verdadeiro
verdadeiro falso falso verdadeiro
falso verdadeiro falso verdadeiro
falso falso falso falso
Tabela 2: Resultado de uso de Operadores Lgicos
A precedncia do operador de negao lgica a mais alta (no mesmo nvel que o - unrio). A
precedncia dos operadores lgicos binrios menor que a dos operadores relacionais, e mais alta que a
operao de atribuio. O && tem precedncia mais alta que o ||, e ambos associam da esquerda para a
direita (como os operadores aritmticos).
Como a precedncia dos operadores lgicos menor que a dos operadores relacionais, no necessrio
usar parnteses em expresses como:
x >= 3 && x <= 50
x == 1 || x == 2 || x == 3
A Tabela 3 mostra o quadro completo de precedncia de operadores aritmticos, relacionais e lgicos.
Operador Associatividade
() esquerda para direita
! - (unrios) direita para esquerda
*
/ % esquerda para direita
+ - esquerda para direita
< <= > >= esquerda para direita
== != esquerda para direita
&& esquerda para direita
|| esquerda para direita
Tabela 3: Precedncia e associatividade de operadores
No prximo exemplo, o programa verica se as trs variveis lado1, lado2, e lado3, podem ser
lados de um tringulo reto. Ns usamos o fato que os trs valores devem ser positivos, e que o quadrado de
um dos lados deve ser igual a soma dos quadrados dos outros lados (Teorema de Pitgoras) para determinar
se o tringulo reto.
23
#include <iostream>
using namespace std;
int main( ){
int lado1, lado2, lado3;
int s1, s2, s3;
cout << "Entre com o tamanho dos lados do triangulo: ";
cin >> lado1 >> lado2 >> lado3;
// calcula o quadrado dos lados
s1 = lado1
*
lado1;
s2 = lado2
*
lado2;
s3 = lado3
*
lado3;
// testa a condicao para um triangulo reto
if ( lado1>0 && lado2>0 && lado3 > 0 ) {
if (s1==s2+s3 || s2==s1+s2 || s2==s1+s3) ) {
cout << "Triangulo reto!\n";
}
else {
cout << "Nao pode ser um triangulo!\n";
}
}
Na utilizao de expresses lgicas, as seguintes identidades so teis. Elas so chamadas de Lei de
DeMorgan:
!(x && y) equivalente a !x || !y
e
!(x || y) equivalente a !x && !y
7 Exemplos
7.1 IF - ELSE
Assuma as seguintes declaraoes de variveis:
int x = 4;
int y = 8;
O que impresso pelos seguintes programas ?
1. if (y = 8)
if (x = 5)
cout << "a ";
else
cout << "b ";
cout << "c ";
cout << "d" << endl;
==> a c d
24
2. mude = para ==
==> b c d
3. altere o programa acima para produzir a seguinte saida:
Assuma x = 5 e y = 8
(a) a
(b) a d
Assuma x = 5 e y = 7
(a) b c d
7.2 Operadores lgicos
O que impresso pelas seguintes sentenas?
1. Assuma x = 5 e y = 8.
if (x == 5 && y == 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> a
2. Assuma x = 4 e y = 8.
if (x == 5 || y == 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> a
if !(x == 5 || y == 8) // equiv. (x != 5 && y != 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> b
if !(x == 5 && y == 8) // equiv. (x != 5 || y != 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> a
3. Precedncia: ! > && > ||
if (x == 5 || y == 8 && z == 10)
equiv.
if (x == 5 || (y == 8 && z == 10))
25
8 A construo else-if
Embora ela no seja um tipo diferente de sentena, a seguinte construo bastante comum para programar
decises entre diversas alternativas:
if (expressao
1
)
sentenca
1
else if (expressao
2
)
sentenca
2
else if (expressao
3
)
sentenca
3
.
.
.
else if (expressao
n1
)
sentenca
n1
else
sentenca
n
As expresses lgicas so avaliadas em ordem, comeando com a expressao
1
. Se uma das expres-
ses for verdadeira, a sentena associada ser executada. Se nenhuma for verdadeira, ento a sentena,
sentenca
n
, do ltimo else ser executada como opo default. Se a opo default no for necessria,
ento a parte
else
sentenca
n
pode ser removida.
Exemplo 9: O seguinte exemplo mostra um else-if de trs opes. O programa l dois nmeros e diz
se eles so iguais ou se o primeiro nmero menor ou maior que o segundo.
#include <iostream>
using namespace std;
int main( ){
int num1, num2;
// obtem 2 numeros do usuario
cout << "Entre um numero: ";
26
cin >> num1;
cout << "Entre com um outro numero: ";
cin >> num2;
// mostra a mensagem de comparacao
if (num1 == num2)
cout << "Os numeros sao iguais\n";
else if (num1 < num2)
cout << "O primeiro numero e menor\n";
else
cout << "O primeiro numero e maior\n";
}
No programa acima, se (num1 == num2) for verdadeiro, ento os nmeros so iguais. Seno,
vericado se (num1 < num2). Se esta condio for verdadeira, ento o primeiro nmero menor. Se
isso no for verdadeiro, ento a nica opo restante que o primeiro nmero maior.
Exemplo 10: Este programa l um nmero, um operador e um segundo nmero e realiza a operao
correspondente entre os operandos dados.
#include <iostream>
using namespace std;
int main( ){
float num1, num2;
char op;
// obtem uma expressao do usuario
cout << "Entre com numero operador numero\n";
cin >> num1 >> op >> num2;
// mostra o resultado da operacao
if (op == +)
cout << " = " << setprecision(2) << num1 + num2;
else if (op == -)
cout << " = " << setprecision(2) << num1 - num2;
else if (op == /)
cout << " = " << setprecision(2) << num1 / num2;
else if (op ==
*
)
cout << " = " << setprecision(2) << num1
*
num2;
else
cout << " Operador invalido.";
cout << endl;
}
Exemplos da execuo deste programa:
Entre com numero operador numero:
5
*
3.5
= 17.50
27
Entre com numero operador numero:
10 + 0
= 10.00
Entre com numero operador numero:
10 x 5.0
Operador invalido.
28
9 Funes
9.1 Funes: o que so e por que us-las
Quando queremos resolver um problema, em geral tentamos dividi-lo em subproblemas mais simples e re-
lativamente independentes, e resolvemos os problemas mais simples um a um. A linguagem C++ dispe de
construes (abstraes) que auxiliam o projeto de programas de maneira top-down. Uma funo cria uma
maneira conveniente de encapsular alguns detalhes de processamento, ou seja, como algum resultado ob-
tido. Quando esta computao necessria, a funo chamada, ou invocada. Desta forma, quando uma
funo chamada o usurio no precisa se preocupar como a computao realizada. importante saber
o que a funo faz (qual o resultado da execuo de uma funo) e tambm como se usa a funo. Criando
funes, um programa C++ pode ser estruturado em partes relativamente independentes que correspondem
as subdivises do problema.
Voc j viu algumas funes: cin.get(), sqrt(). Elas so funes de uma biblioteca padro (do
C++ ). Voc no sabe como elas foram escritas, mas j viu como utiliz-las. Ou seja, voc sabe o nome das
funes e quais informaes especcas voc deve fornecer a elas (valores que devem ser passados para as
funes) para que a funo produza os resultados esperados.
Quando nos referirmos a uma funo neste texto usaremos a maneira frequentemente utilizada que o
nome da funo seguido de ().
Tomemos como exemplo o programa abaixo, que recebe 2 conjuntos de 3 nmeros e soma o maior valor
de cada conjunto:
Observe que o cdigo que verica o maior valor dentre 3 nmeros teve que ser reproduzido dentro do
programa por duas vezes (para descobrir o maior valor de dois conjuntos diferentes de 3 nmeros).
Um dos benefcios mais bvios de usar funes que podemos evitar repetio de cdigo. Em outras
palavras, se voc quiser executar uma operao mais de uma vez, voc pode simplesmente escrever a funo
uma vez e utiliz-la diversas vezes ao invs de escrever o mesmo cdigo vrias vezes. Outro benefcio que
se voc desejar alterar ou corrigir alguma coisa mais tarde, mais fcil alterar em um nico lugar.
O exemplo acima poderia ser simplicado pela criao de uma funo chamada maior, que dados trs
nmeros a, b, e c, d como resultado o maior valor dentre os trs valores fornecidos:
O exemplo pode ser ento alterado e simplicado com o uso da funo maior():
Como pode ser observado, sejam quais forem os conjuntos de 3 nmeros fornecidos, no precisa escre-
ver um cdigo similar ao mostrado na funo maior acima para cada nmero. Basta chamar a funo
maior(), passar os valores necessrios para vericar o maior valor de cada conjunto, e utilizar os resulta-
dos.
Evitar repetio de cdigo a razo histrica que funes foram inventadas (tambm chamado de proce-
dimento ou subrotinas em outras linguagens de programao). A maior motivao para utilizar funes nas
linguagens contemporneas a reduo da complexidade do programa e melhoria da modularidade do pro-
grama. Dividindo o programa em funes, muito mais fcil projetar, entender e modicar um programa.
Por exemplo, obter a entrada do programa, realizar as computaes necessrias e apresentar o resultado ao
usurio pode ser implementado como diferentes funes chamadas por main() nesta ordem.
Funes podem ser escritas independentemente uma da outra. Isto signica que, em geral, variveis
usadas dentro de funes no so compartilhadas pelas outras funes. Assim sendo, o comportamento da
funo previsvel. Se no for assim, duas funes completamente no relacionadas podem alterar os dados
29
uma da outra. Se as variveis so locais a uma funo, programas grandes passam a ser mais fceis de serem
escritos. A comunicao entre funes passa a ser controlada elas se comunicam somente atravs pelos
valores passados as funes e os valores retornados.
9.2 Denindo funes
Um programa C++ consiste de uma ou mais denies de funes (e variveis). H sempre uma funo
chamada main. Outras funes tambm podem ser denidas. Cada uma pode ser denida separadamente,
mas nenhuma funo pode ser denida dentro de outra funo. Abaixo, mostramos um exemplo simples
de um programa que consiste de duas funes: main() e alo(). Quando executado, este programa
imprimir a mensage Alo! trs vezes.
#include <iostream>
using namespace std;
// definicao da funcao alo()
void alo(void)
{
cout << "Alo!" << endl;
}
// definicao da funcao main()
int main ()
{
int i;
i = 1;
while (i <= 3)
{
alo();
i = i + 1;
}
}
Todas as funes devem ser declaradas ou denidas antes de serem usadas. As funes da biblioteca
padro, tais como cin.get(), so pr-denidas, mas mesmo assim devem ser declaradas (deve ser anun-
ciado ao compilador que elas existem). por isso que inclumos a linha #include <iostream> no
incio do cdigo fonte.
O formato geral da denio de uma funo
tipo-do-resultado nome-da funo (lista-de-argumentos)
{
declaraes e sentenas
}
A primeira linha da denio o cabealho da funo. Ela tm trs partes principais: o nome da
funo, o tipo do resultado (que um valor) que a funo computa e retorna, e entre parnteses uma lista
de parmetros (tambm chamado de argumentos formais). Se a funo no retorna nenhum valor, o tipo
chamado de void, e esta palavra escrita no cabealho na frente do nome da funo. Se a funo no
tiver argumentos formais, a palavra void pode ser escrita no lugar da lista de argumentos formais entre os
30
parnteses. Para simplicar a exposio, falaremos sobre o tipo do retorno e os argumentos formais mais
tarde. Eles servem para permitir que as funes troquem informaes entre si.
9.3 Funes simples
Para comear, vamos utilizar funes na seguinte forma:
void nome-da-funo(void)
{
declaraes e senteas (corpo da funo)
}
O primeiro void signica que esta funo no tem tipo de retorno (no retorna um valor), e o segundo
signica que a funo no tem argumentos (ela no precisa de nenhuma informao externa para ser exe-
cutada). Isso no signica que a funo no faz nada. Ela pode realizar alguma ao, como imprimir uma
mensagem. O exemplo abaixo mostra um programa que usa uma funo como essa:
#include <iostream>
using namespace std;
// DEFINIO da funo alo()
void alo(void)
{
cout << "Alo." << endl;
}
// Programa Principal
int main()
{
alo();
}
Neste exemplo, o programa consiste de duas funes, main() e alo().
A funo alo() imprime a mensagem Alo. quando chamada. A sentena cout o corpo da funo.
Dentro da funo main() h uma chamada a funo alo(). A funo chamada pelo seu nome seguido
de () (j que a funo alo no tem argumentos, nenhuma expresso escrita dentro dos parnteses).
A funo alo() no retorna um valor, ela chamada simplesmente para realizar uma ao (imprimir a
mensagem). A chamada de funo uma sentena vlida em C++ , portanto deve ser terminada por ponto e
vrgula (;).
alo();
Observe que a ordem em que as funes so denidas dentro do cdigo-fonte importante, sendo que
uma funo deve sempre ser denida ANTES das funes em que ela CHAMADA. No nosso exemplo,
como a funo alo() chamada pela funo main(), ento a DEFINIO da funo alo() deve vir
antes da denio da funo main(). O uso de prottipos pode ser usado para denir as funes em
qualquer ordem dentro do cdigo-fonte, o que ser visto na Seo 9.9.
Outra coisa que voc deve ter notado que main() tambm uma funo. A funo main() no
difere em nada das demais funes, com a exceo de que contm o programa principal, isto , ao se
executar um programa, ela a primeira funo a ser executada. As demais funes so executadas somente
quando chamadas a partir da execuo da funo main().
31
9.3.1 Argumentos
Nosso prximo exemplo pede que o usurio digite suas iniciais, e ento chama a funo cumprimenta()
para imprimir a mensagem Ola junto com as iniciais digitadas. Estas iniciais (seus valores) so passadas
para a funo cumprimenta(). A funo cumprimenta() denida de forma que ela imprimir a
mensagem incluindo quaisquer iniciais passadas.
#include <iostream>
using namespace std;
void cumprimenta(char inic1, char inic2)
{
cout << "Ola, " << inic1 << inic2 << "!" << endl;
}
int main()
{
char primeiro, segundo;
cout << "Entre com duas iniciais (sem separacao): ";
cin >> primeiro >> segundo ;
cumprimenta(primeiro, segundo);
}
A funo main() chama a funo cumprimenta(). Ao fazer esta chamada, main() passa para
cumprimenta() os valores dos dois caracteres para serem impressos. Veja um exemplo de execuo do
programa:
Entre com duas iniciais (sem separacao): YK
Alo, YK!
Note que h uma correspondncia entre a quantidade, a ordem e tipo dos valores que main() passa (estes
so chamados de parmetros reais ou argumentos reais) e os argumentos listados no cabealho da funo
cumprimenta() (denominados argumentos formais).
9.4 Funes que retornam um valor
Funes que no retornam nenhum valor (como alo(), main()) possuem tipo void.
Alm de executarem aes (como imprimir) uma funo tambm pode retornar um valor para o pro-
grama que o chamou. Uma funo que retorna um valor tem no cabealho o nome do tipo do resultado. O
valor retornado pode ser de qualquer tipo, incluindo int, float e char ( claro que uma vez denida,
a funo s de um tipo especco). Uma funo que retorna um tipo diferente de void executa alguns
clculos, e retorna o resultado (que um nico valor) para quem a chamou. A funo chamadora pode ento
usar o resultado. Para retornar um valor para a funo chamadora, a funo usa a sentena return.
O formato da sentena return a seguinte:
return expresso;
A expresso avaliada e o seu valor convertido ao tipo de retorno da funo (o tipo da funo dado
no cabealho da funo antes do nome da funo).
Considere o seguinte exemplo. O programa consiste de duas funes: main() e quadrado. O
programa pede que o usurio digite trs nmeros e verica se eles podem ser os lados de um tringulo reto.
32
// programa que verifica se 3 numeros podem ser os lados de um
// triangulo reto.
//
#include <iostream>
using namespace std;
// funcao que calcula o quadrado de um numero
int quadrado(int n)
{
return n
*
n;
}
int main()
{
int s1, s2, s3;
cout << "Entre tres inteiros: ";
cin >> s1 >> s2 >> s3;
if ( s1 > 0 && s2 > 0 && s3 > 0 &&
(quadrado(s1) + quadrado(s2) == quadrado(s3) ||
quadrado(s2) + quadrado(s3) == quadrado(s1) ||
quadrado(s3) + quadrado(s1) == quadrado(s2)) )
{
cout << " " << s1 << " " << s2 << " " << s3
<< " podem formar um triangulo reto\n";
}
else
{
cout << " " << s1 << " " << s2 << " " << s3
<< " nao podem formar um triangulo reto\n";
}
}
Note que quando chamamos a funo quadrado() passamos o valor no qual desejamos executar o
clculo, e tambm usamos o valor retornado pela funo em expresses. O valor de quadrado(s1) o
valor que a funo quadrado() retorna quando chamado com o valor do argumento sendo igual ao valor
da varivel s1.
Os valores retornados pelas chamadas de funes podem ser usados em todos os lugares onde valores
podem ser usados. Por exemplo,
y = quadrado(3);
Aqui quadrado(3) tem o valor 9, portanto 9 pode ser atribudo a varivel y;
x = quadrado(3) + quadrado(4);
atribuir 25 a varivel x, e
area = quadrado(tamanho);
atribuir a varivel area o valor da varivel tamanho elevado ao quadrado.
O prximo exemplo tem uma funo chamada cinco:
33
#include <iostream>
using namespace std;
int cinco(void)
{
return 5;
}
int main()
{
cout << "cinco = " << cinco() << endl;
}
A sada do programa ser
cinco = 5
porque o valor de cinco() dentro da sentena cout 5. Olhando na sentena return, 5 a
expresso retornada para o chamador.
Outro exemplo:
#include <iostream>
using namespace std;
int obtem_valor(void)
{
int valor;
cout << "Entre um valor: ";
cin >> valor;
return valor;
}
int main()
{
int a, b;
a = obtem_valor();
b = obtem_valor();
cout << "soma = " << a + b << endl;
}
Este programa obtm dois inteiros do usurio e mostra a sua soma. Ele usa a funo obtem valor()
que mostra uma mensagem e obtm o valor do usurio.
Um exemplo de sada deste programa :
Entre um valor: 15
Entre um valor: 4
soma = 19
34
9.5 Mais sobre o return
Quando uma funo return executada, a funo imediatamente acaba mesmo que haja cdigo na
funo aps a sentena return. A execuo do programa continua aps o ponto no qual a chamada de
funo foi feita. Sentenas return podem ocorrer em qualquer lugar na funo no somente no nal.
Tambm vlido ter mais de um return dentro de uma funo. A nica limitao que return retorna
um nico valor.
O seguinte exemplo mostra uma funo (uma verso para int da funo obtem valor) que pede
para usurio um valor e se o usurio digitar um valor negativo, imprime uma mensagem e retorna um valor
positivo.
int obtem_valor_positivo(void)
{
int valor;
cout << "Entre um valor: ";
cin >> valor;
if (valor >= 0)
return valor;
cout << "Tornando o valor positivo..." << endl;
return -valor;
}
Em uma funo void, return; (s com ;) pode ser usado para sair de uma funo. O exemplo
seguinte, pede instrues ao usurio. Se o usurio reponder nao, a funo termina. Do contrrio, ele
imprime as instrues e depois termina.
void instrucoes(void)
{
int ch;
cout << "Voce quer instrucos? (s/n): ";
ch = cin.get();
/
*
Termina se resposta for n
*
/
if (ch == n || ch == N)
return;
/
*
Mostra instrucoes
*
/
cout << "As regras do jogo sao . . . ";
.
.
.
return;
}
O return nal (antes de fechar as chaves do corpo da funo) na funo opcional. Se omitido, a
funo atingir o nal da funo e retornar automaticamente. Note que o return opcional somente para
funes void.
35
9.6 Mais sobre Argumentos
A comunicao entre uma funo e o chamador pode ser nas duas direes. Argumentos podem ser usados
pelo chamador para passar dados para a funo. A lista de argumentos denida pelo cabealho da funo
entre parnteses.. Para cada argumento voc precisa especicar o tipo do argumento e o nome do argumento.
Se houver mais de um argumento, eles so separados por vrgula. Funes que no possuem argumentos
tem void como lista de argumento. No corpo da funo os argumentos (tambm chamados de argumentos
formais ou parmetros formais) so tratados como variveis. erro deni-los dentro do corpo da funo
porque eles j esto denidos no cabealho. Antes da execuo da funo os valores passados pelo chamador
so atribudos aos argumentos da funo.
Considere o seguinte programa com a funo abs() que calcula o valor absoluto de um nmero.
#include <iostream>
using namespace std;
/
*
Definicao da funcao abs
*
/
int abs(int x)
{
if (x < 0)
x = -x;
return x;
}
int main()
{
int n;
cout << "Entre um numero: ";
cin >> n;
cout << "Valor absoluto de " << n << " eh " << abs(n) << endl;
}
A funo abs() tem um argumento do tipo int, e seu nome x. Dentro da funo, x usado como
uma varivel x.
Uma vez que abs() tem um nico argumento, quando ela chamada, h sempre um valor dentro do
parnteses, como emabs(n). O valor de n passado para a funo abs(), e antes da execuo da funo,
o valor de n atribudo a x.
Aqui est um exemplo de uma funo que converte uma temperatura de Farenheit para Celsius:
float fahr_para_cels(float f)
{
return 5.0 / 9.0
*
(f - 32.0);
}
Como voc pode ver, esta funo tem somente um argumento do tipo float. Um exemplo de chamada
desta funo poderia ser:
fervura = fahr_para_cels(212.0);
O resultado da funo fahr para cels(212.0) atribudo a fervura. Portanto, depois da
execuo desta sentena, o valor de fervura (que do tipo float) ser 100.0.
36
O exemplo seguinte possui mais de um argumento:
float area(float largura, float altura)
{
return largura
*
altura;
}
Esta funo possui dois argumentos do tipo float. Para chamar uma funo com mais de um argu-
mento, os argumentos devem ser separados por vrgula. A ordem em que os argumentos so passados deve
ser na mesma em que so denidos. Neste exemplo, o primeiro valor passado ser a largura e o segundo a
altura. Um exemplo de chamada seria
tamanho = area(14.0, 21.5);
Depois desta sentena, o valor de tamanho (que do tipo float) ser 301.0.
Quando passar os argumentos, importante ter certeza de pass-los na ordem correta e que eles so do
tipo correto. Se isso no for observado, pode ocorrer erro ou aviso de compilao, ou resultados incorretos
podem ser gerados.
Uma ltima observao. Os argumentos que so passados pelo chamador podem ser expresses em geral
e no somente constantes e varivies. Quando a funo chamada durante a execuo do programa, estas
expresses so avaliadas, e o valor resultante passado para a funo chamada.
9.7 Chamada por valor
Considere novamente a funo quadrado(). Se esta funo chamada de main() como
p = quadrado(x);
somente o valor (no o endereo) de x passado para quadrado. Por exemplo, se a varivel tem valor
5, para a funo quadrado(), quadrado(x) ou quadrado(5) so o mesmo. De qualquer forma,
quadrado() receber somente o valor 5. quadrado() no sabe se na chamada da funo o 5 era uma
constante inteira, o valor de uma varivel do tipon int, ou alguma expresso como 625/25 - 4
*
5.
Quando quadrado() chamado, no interessa qual a expresso entre parnteses, ela ser avaliada e o
valor passado para quadrado().
Esta maneira de passar argumentos chamada de chamada por valor. Argumentos em C++ so passados
por valor. Portanto, a funo chamada no pode alterar o valor da varivel passada pelo chamador como
argumento, porque ela no sabe em que endereo de memria o valor da varivel est armazenado.
9.8 Variveis locais
Como voc provavelmente j reparou em alguns exemplos, possvel denir variveis dentro de funes, da
mesma forma que temos denido variveis dentro da funo main(). A declarao de variveis feita no
incio da funo.
Estas variveis so restritas a funo dentro da qual elas so denidas. S esta funo pode enxergar
suas prprias variveis. Por exemplo:
#include <iostream>
using namespace std;
void obtem_int(void)
{
37
int x;
cout << "Entre um valor: ";
cin >> x;
cout << "Obrigado!\n";
}
int main()
{
obtem_int();
/
* ****
Isto esta errado
**** *
/
cout << "Voce digitou " << x << endl;
}
A funo main() usou um nome x, mas x no denido dentro de main; ele uma varivel local a
get int(), no a main(). Este programa gera erro de compilao.
Note que possvel ter duas funes que usam variveis locais com o mesmo nome. Cada uma delas
restrita a funo que a dene e no h conito. Analise o seguinte programa (ele est correto):
#include <iostream>
using namespace std;
int obtem_novo_int(void)
{
int x;
cout << "Entre um valor: ";
cin >> x;
cout << "Obrigado!\n";
return x;
}
int main()
{
int x;
x = obtem_novo_int();
/
* ****
Isto nao esta errado !!
**** *
/
cout << "Voce digitou " << x << endl;
}
A funo obtem novo int() usa uma varivel local chamada x para armazenar o valor digitado e
retorna como resultado o valor de x. main() usa outra varivel local, tambm chamada de x para receber
o resultado retornado por obtem novo int(). Cada funo tem sua prpria varivel x.
38
9.9 Prottipos
Os prottipos servempara dar ao compilador informaes sobre as funes. Isso para que voc possa chamar
funes antes que o compilador tenha a denio (completa) das funes. O prottipo de uma funo
idntico ao cabealho da funo, mas o nome dos argumentos podem ser omitidos e ele terminado com
um ponto e vrgula. Prottipos declaram uma funo ao invs de deni-las. O formato de um prottipo :
tipo-de-retorno nome-da-funo(lista-dos-tipos-dos-argumentos);
Denindo prottipos, voc no precisa se preocupar com a ordem em que dene as funes dentro do
cdigo-fonte do programa. A principal vantagem de denir prottipos que erros de chamada de funes
(como chamar uma funo com o nmero incorreto de argumentos, ou com argumentos de tipo errado) so
detectados pelo compilador. Sem prottipos, o compilador s saberia que h erro depois de encontrar a
denio da funo.
Abaixo, mostramos a denio de duas funes e seus respectivos prottipos:
float volume(float, float, float);
float dinheiro(int, int, int, int);
float volume(float comprimento, float largura, float altura)
{
return comprimento
*
largura
*
altura;
}
float dinheiro(int c25, int c10, int c5, int c1)
{
return c25
*
0.25 + c10
*
0.10 +
c5
*
0.05 + c1
*
0.01;
}
9.10 Documentao de funes
Voc deve documentar as funes que escreve. Na documentao voc deve especicar as seguintes infor-
maes:
Ao o que a funo faz
Entrada descrio dos argumentos passados para a funo
Sada descrio do valor retornado pela funo
Suposies o que voc assume ser verdade para que a funo funcione apropriadamente
Algoritmo como o problema resolvido (mtodo)
Estas informaes devem ser colocadas como comentrio antes da denio da funo.
39
9.11 Comentrios
Voc pode colocar comentrios no seu programa para documentar o que est fazendo. O compilador ignora
completamente o que quer esteja dentro de um comentrio.
Comentrios em C++ so textos que comeam com // em cada linha, ou so delimitados por /
*
e
*
/.
Os smbolos // no possuem espao entre si. Alguns exemplos:
// Este um comentrio sem graa
// Este um comentrio um pouco
// maior que tem diversas linhas
/
*
Este um outro comentrio maior
ainda e que tem vrias linhas
explicando qualquer aspecto mais detalhado
do programa
*
/
Regras para comentrio
sempre uma boa idia colocar comentrios em seu programa das coisas que no so claras. Isto vai
ajudar quando mais tarde voc olhar o programa que escreveu j h algum tempo ou vai ajudar a entender
programas escritos por outra pessoa.
Um exemplo de comentrio til:
/
*
converte temperatura de farenheit para celsius
*
/
celsius = (fahrenheit - 32)
*
5.0 / 9.0;
O comentrio deve ser escrito em portugus e no em C++ . No exemplo abaixo
/
*
usando scanf, obter valor de idade e multiplicar por 365 para
*
obter dias
*
/
cin >> idade;
dias = idade
*
365;
o comentrio basicamente uma transcrio do cdigo do programa. Em seu lugar, um comentrio
como
/
*
obtem idade e transforma em numero de dias
*
/
seria mais informativo neste ponto.
Em outras palavras, voc deve comentar o cdigo, e no codicar o comentrio.
Voc tambm deve evitar comentrios inteis ou bvios. Por exemplo:
// Incrementa i
i = i + 1;
No h necessidade de comentrios j que i = i + 1 j auto explicativo.
Abaixo est um exemplo de como voc deve comentar uma funo.
40
/
*
funo instrucoes()
*
acao: mostra instrucoes do programa
*
entrada: nenhuma
*
saida: nenhuma
*
suposicoes: nenhuma
*
algoritmo: imprime as instrucoes
*
/
void instrucoes(void)
{
/
*
mostra instrucoes
*
/
cout << "O processo de purificacao do Uranio-235 e . . . ";
.
.
}
41
10 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues. Estas estruturas de repeti-
o, tambm conhecidas como laos (do ingls loops). Nesta seo veremos a estrutura while, Sendo que
as demais estruturas de repetio em C++ , for e do ... while sero vistas na Seo 19.
10.1 O comando de repetio while
O comando de repetio while tem duas partes: a expresso de teste e o corpo da repetio. O formato do
while :
while (expresso teste )
corpo da repetio
A expresso teste inicialmente avaliada para vericar se o lao deve terminar. Caso a expresso seja
verdadeira (isto , diferente de 0 (zero)), o corpo da repetio executado. Depois desta execuo, o
processo repetido a partir da expresso teste. O corpo do lao, por sua vez, pode ser uma sentena simples
ou composta (veja Seo 1.1).
O exemplo abaixo mostra o uso do comando de repetio while:
#include <iostream>
using namespace std;
int contador;
contador = 0;
while( contador < 5 )
{
cout << "contador = " << contador << endl;
contador = contador + 1;
}
cout << "ACABOU !!!!" << endl;
Sada:
contador = 0
contador = 1
contador = 2
contador = 3
42
contador = 4
ACABOU !!!!
Neste exemplo, a expresso de teste contador < 5, e o corpo do lao a sentena cout.
Se examinarmos cuidadosamente este exemplo, veremos que a varivel contador inicializada com 0
(zero). Depois disso, a expresso de teste vericada e, como 0 < 5 verdadeiro, o corpo da repetio
executado. Assim, o programa imprime contador = 0, e incrementa contador. Em seguida, a expresso
de teste vericada novamente e todo o processo se repete at que contador seja 4 e contador = 4 seja
impresso.
Depois disso, contador incrementado para 5 e o teste executado. Mas desta vez, 5 < 5 falso,
ento a repetio no continua. A execuo do programa continua na sentena que segue o lao (no caso,
imprimir a frase ACABOU !!!).
Imediatamente aps a execuo do while, a varivel contador tem valor 5.
O exemplo seguinte mostra um uso mais apropriado do comando while: Em situaes onde o nmero
de repeties no conhecido antes do inico do comando while.
Exemplo 1: Este programa pede nmeros ao usurio at que a soma de todos os nmeros digitados for
pelo menos 20.
#include <iostream>
using namespace std;
int main( ){
int total, num;
total = 0;
while( total < 20 ) {
cout << "Total = " << total << endl;
cout << "Entre com um numero: ";
cin >> num;
total = total + num;
}
cout << "Final total = " << total << endl;
}
Exemplo de sada:
Total = 0
Entre com um numero: 3
Total = 3
Entre com um numero: 8
Total = 11
Entre com um numero: 15
Final total = 26
Inicialmente, dado o valor 0 varivel total, e o teste verdadeiro ( 0 < 20). Em cada iterao, o
total impresso e o usurio digita um nmero que somado a total. Quanto total for maior ou igual a 20,
o teste do while torna-se falso, e a repetio termina.
43
10.2 Estilo de formatao para estruturas de repetio
A regra principal ser consistente. Assim, seu programa ser mais legvel.
10.2.1 Colocao das chaves
H trs estilos comuns de colocar as chaves:
while (expressao)
{
sentenca;
}
while (expressao)
{
sentenca;
}
while (expressao) {
sentenca;
}
APENAS UM DESTES ESTILOS deve ser consistentemente usado para as sentenas de repetio ( for,
while e do ... while). Use o estilo com o qual voc se sentir mais confortvel.
10.2.2 Necessidade ou no das chaves
Foi mencionado anteriormente que o corpo da repetio pode ser uma sentena composta (conjunto de
sentenas delimitadas por chaves ( { e }) ou ums sentena simples. Por exemplo:
while( i < 5 )
i = i + 1;
Embora as chaves possam ser omitidas, h uma nica razo para coloc-las sempre. Considere o caso
simples abaixo:
while( i < 5 ) {
i = i + 1;
}
Quando voc adicionar algo ao programa, voc poder adicionar uma sentena para um lao com apenas
uma sentena. Se voc zer isso, vital que voc tambm adicione chaves. Se voc no zer isso, a segunda
sentena do lao no ser considerada como parte do lao. Por exemplo:
while( i < 5 )
i = i + 1;
j = j + 1;
na verdade o mesmo que:
while( i < 5 )
i = i + 1;
j = j + 1;
44
enquanto a inteno era na realidade:
while( i < 5 ) {
i = i + 1;
j = j + 1;
}
10.2.3 Uso de espao em branco
A outra questo de formato se deve ser colocado um espao em branco depois do while e antes do abre
parnteses ( (). Por exemplo:
while (i<5)
ou
while (i<5)
ou
while( i < 5 )
Isto tambm uma escolha pessoal. Porm seja consistente em sua escolha !
10.2.4 Laos aninhados
possvel colocar um lao dentro de outro (lao aninhado).
Exemplo 2:
#include <iostream>
#include <iomanip> // Necessrio para se usar a funo setw() em cout
using namespace std;
int main( ){
int linha, coluna;
linha = 1;
while (linha < 5)
{
coluna = 1;
while (coluna < 5)
{
cout << setw(3) << linha
*
coluna;
coluna = coluna + 1;
}
linha = linha + 1;
}
cout << endl;
}
Sada:
45
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
No exemplo acima, para cada iterao do lao externo, o lao interno imprime uma linha com nmeros
e depois pula de linha.
Exemplo 3: Este exemplo parecido com o anterior, exceto que o cout que produz a mudana de nal
de linha colocado dentro do lao interno. Como era de se esperar uma nova linha impressa aps cada
valor ao invs de ser depois de 4 valores.
#include <iostream>
#include <iomanip> // Necessrio para se usar a funo setw() em cout
using namespace std;
int main( ){
int linha, coluna;
linha = 1;
while (linha < 5)
{
coluna = 1;
while (coluna < 5)
{
cout << setw(3) << linha
*
coluna;
cout << endl;
coluna = contador + 1;
}
linha = linha + 1;
}
}
Sada:
1
2
3
4
2
4
6
8
3
6
9
12
4
8
46
12
16
Exemplo 4: Este exemplo imprime um tringulo de asteriscos, de forma que a quantidade de asteriscos
em uma linha igual ordem da linha (na linha 1, 1 asterisco, na linha 2, 2 asteriscos, etc.)
#include <iostream>
using namespace std;
int main( ){
int linha, coluna;
cout << endl;
linha = 1;
while (linha < 8)
{
cout << "\t";
coluna = 1;
while (coluna < linha)
{
cout << "
*
";
coluna = coluna + 1;
}
cout << endl;
linha = linha + 1;
}
}
Sada:
*
**
***
****
*****
******
*******
********
47
11 Mais sobre funes: Quando return no suciente
Considere o programa abaixo que pede ao usurio dois inteiros, armazena-os em duas variveis, troca seus
valores, e os imprime.
#include <iostream>
using namespace std;
int main()
{
int a, b, temp;
cout << "Entre dois numeros: ";
cin >> a >> b;
cout << "Voce entrou com " << a << " e " << b << endl;
/
*
Troca a com b
*
/
temp = a;
a = b;
b = temp;
cout << "Trocados, eles sao " << a << " e " << b << endl;
}
Aqui est um exemplo de execuo do programa:
Entre dois numeros: 3 5
Voce entrou 3 e 5
Trocados, eles sao 5 e 3
O seguinte trecho do programa executa a troca de valores das variveis a e b:
temp = a;
a = b;
b = temp;
possvel escrever uma funo que executa esta operao de troca? Considere a tentativa abaixo de escrever
esta funo:
#include <iostream>
using namespace std;
void troca(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
48
int main()
{
int a, b;
cout << "Entre dois numeros: ";
cin >> a >> b;
cout << "Voce entrou com " << a << " e " << b << endl;
// Troca a com b
troca(a, b);
cout << "Trocados, eles sao " << a << " e " << b << endl;
}
Se voc executar este programa, ver que ele no funciona:
Entre dois numeros: 3 5
Voce entrou 3 e 5
Trocados, eles sao 3 e 5
Como voc j viu nas notas anteriores, em C++ os argumentos so passados por valor. Uma vez que
somente os valores das variveis so passados, no possvel para a funo troca() alterar os valores de a
e b porque troca() no sabe onde na memria estas variveis esto armazenadas. Alm disso, troca()
no poderia ser escrito usando a sentena return porque podemos retornar APENAS UM valor (no dois)
atravs da sentena return.
11.1 Usando referncia
A soluo para o problema acima ao invs de passar os valores de a e b, passar uma referncia s variveis
a e b. Desta forma, troca() saberia que endereo de memria escrever, portanto poderia alterar os valores
de a e b.
Lembre-se que em C++ a cada varivel est associado: (i) um nome; (ii) um tipo; (iii) um valor; e (iv)
um endereo. Assuma que existam as seguintes denies de variveis.
int i = 5;
char c = G;
Na memria, eles podem estar armazenados da forma indicada na Figura 11.1:
A varivel inteira i est armazenada no endereo 1342. Ela usa dois bytes de memria (quando um
objeto usa mais de um byte, seu endereo onde ele comea neste caso, 1342 e no 1343). A varivel do
tipo char c est armazenada no endereo 1346 e usa um byte de memria. O compilador que controla
do local de armazenamento destas variveis em memria.
11.2 Argumentos por referncia em funes
Considere novamente o exemplo da funo troca(). Quando a e b so passados como argumentos para
troca(), na verdade, somente seus valores so passados. A funo no podia alterar os valores de a e
b porque ela no conhece os endereos de a e b. Mas se referncias para a e b forem passados como
argumentos ao invs de a e b, a funo troca() seria capaz de alterar seus valores; ela saberia ento
49
Figura 3: Variveis em memria
em que endereo de memria escrever. Na verdade, a funo no sabe que os endereos de memria so
associados coma e b, mas ela pode modicar o contedo destes endereos. Portanto, passando uma varivel
por referncia (ao invs do valor da varivel), habilitamos a funo a alterar o contedo destas variveis na
funo chamadora.
A denio da funo troca() deve ser alterada, e a lista de parmetros formais deve ter argumentos
no do tipo int, mas referncias para int, ou seja, int & . Quando chamamos a funo troca(), ns
continuamos passando parmetros reais a e b, mas desta vez, o compilador sabe que o que ser passado para
a funo troca() so as referncias a estas variveis, e no seus valores. Dentro da funo troca() no
dever haver mudanas. Uma vez que agora os parmetros formais so referncias, o acesso aos objetos
deve ser escrito normalmente, mas deve-se ter em mente que qualquer alterao nos valores dos parmetros
formais da funo implica em alterar o valor dos argumentos passados para a funo no momento de sua
chamada. Assim, a funo troca() capaz de alterar os valores de a e b remotamente.
O programa abaixo a verso correta do problema enunciado para a funo troca():
#include <iostream>
using namespace std;
/
*
funo troca(px, py)
*
ao: troca os valores inteiros apontados por px e py
*
entrada: apontadores px e py
*
saida: valor de px e py trocados na origem da chamada da funo
*
suposies: px e py sao apontadores validos
*
algoritmo: primeiro guarda o primeiro valor em um temporario e
*
troca
*
/
void troca(int & px, int & py)
{
int temp;
temp = px;
px = py;
py = temp;
}
int main()
50
{
int a, b;
cout << "Entre dois numeros: ";
cin >> a >> b;
cout << "Voce entrou com " << a << " e " << b << endl;
// Troca a com b -- passa argumentos por referencia
troca(a, b);
cout << "Trocados, eles sao " << a << " e " << b << endl;
}
A sada deste programa :
Entre dois numeros: 3 5
Voce entrou com 3 e 5
Trocados, eles sao 5 e 3
Basicamente, se a funo precisa alterar o valor de uma varivel no ponto de chamada da funo, ento
passamos o nome da varivel como parmetro real, e escrevemos a funo indicando os parmetros como
sendo de SADA ou PASSADOS POR REFERNCIA.
51
12 O pr-processador
O pr-processador um programa que faz alguns processamentos simples antes do compilador. Ele exe-
cutado automaticamente todas as vezes que seu programa compilado, e os comandos a serem executados
so dados atravs de diretivas do pr-processador.
Estas diretivas so colocadas em linhas que contm somente a diretiva (elas no so cdigo da lingua-
gem C++ , portanto as regras para elas so um pouco diferentes). As linhas que comeam com um # so
comandos para o pr-processador. A linha inteira reservada para este comando (nenhum cdigo C++ pode
aparecer nesta linha e comandos do pr-processador no podem estar separados em diversas linhas).
12.1 A diretiva #define
Uma diretiva que usada frequentemente o #define. Esta diretiva usada para fazer substituio
de macros. Por enquanto, mostraremos uma utilizao simples do #define, que simplestemente uma
substituio no texto.
O uso mais frequente desta diretiva dar nomes simblicos a uma constante (voc j viu outra maneira
de denir contantes que colocar a palvavra const antes da denio de uma varivel). Por exemplo,
seria conveniente usar PI em seus programas ao invs de digitar 3.1415926535 toda hora. Como outro
exemplo, se voc quiser escrever um programa sobre estudantes de uma turma de 81 alunos, voc poderia
denir NUM_ALUNOS como 81. Assim, se o nmero de alunos mudar, voc no precisaria modicar todo
o seu programa onde o nmero de alunos (81) utilizado, mas simplesmente alterar a diretiva #define.
Estas duas diretivas so denidas da seguinte forma:
#define PI 3.1415926535
#define NUM_ALUNOS 81
Por conveno, nomes introduzidos por um #define so geralmente em letra maiscula (e variveis
so emletra minscula, ou uma mistura de letras minsculas e maisculas). Assim, quando voc v umnome
em um programa, voc sabe se o nome refere-se a uma varivel ou um nome denido por um #define.
Considere o seguinte programa exemplo que usa PI:
#define PI 3.14159265
int main()
{
double raio;
cout << "Entre com o raio: ";
cin >> raio;
cout << "Circunferencia = " << 2.0
*
PI
*
raio << endl;
}
Lembre-se que o nome PI no um nome de varivel. Ele um nome que o pr-processador substituir
pelo texto especicado pelo #define (mais ou menos da mesma forma que o comando pesquisa-e-substitui
do editor de texto). O compilador nunca v ou sabe sobre PI. O compilador v o seguinte cout do
programa acima depois do pr-processador ser executado:
cout << "Circunferencia = " << 2.0
*
3.14159265
*
raio << endl;
12.2 A diretiva #include
Agora imagine que estamos escrevendo uma biblioteca geomtrica: um conjunto de funes para calcular
a rea de cilindros, cones, esferas. Se diferentes pessoal esto escrevendo cada uma das funes, eles
52
provavelmente colocaro suas funes em diferentes arquivos. Mas todas as funes usam o numero , e
algumas outras constantes podem ser necessrias tambm. Ao invs de colocar o #define no incio de
cada arquivo, um nico arquivo geom.h pode ser criado. Este arquivo conter a linha
#define PI 3.14159265
Assim, se todos os arquivos de funes geomtricas puderem enxergar geom.h, eles compartilharo as
mesmas denies. para isso que usamos a diretiva #include, para incluir em seu programa, informa-
es que esto em outro arquivo. Estas diretivas geralmente esto no incio do programa fonte, antes da
denio de funes e varveis. Por exemplo, a diretiva
#include "geom.h"
colocada nos arquivos fontes que contm as funes geomtricas far com que todos eles usem o nome
simblico PI ao invs de 3.14159265. O fato do nome do arquivo estar em aspas signica que o ar-
quivo geom.h est no mesmo diretrio que os arquivos fontes (ao invs do diretrio onde se encontram as
bibliotecas padro de C++ ).
A diretiva
#include <iostream>
colocada no incio do programa fonte para incluir informaes (como prottipos de funes) que so ne-
cessrios quando cout e cin so chamados dentro do programa. O arquivo entre < > est em algum
diretrio padro conhecido pelo pr-processador. Este arquivo iostream comum a todas as implemen-
taes da linguagem C++ e contm infomaes necessrias para executar operaes de entrada e sada da
entrada e sada padro (teclado e monitor).
12.3 Comentrios
De um modo geral, o pr-processador dos compiladores existentes remove todos os comentrios do arquivo
fonte antes do programa ser compilado. Portanto, o compilador nunca v realmente os comentrios.
53
13 Vetores ou Arrays
Considere o seguinte programa. Este programa pede ao usurio notas de 4 estudantes, calcula a mdia e
imprime as notas e a mdia.
int main()
{
int nota0, nota1, nota2, nota3;
int media;
cout << "Entre a nota do estudante 0: ";
cin >> nota0;
cout << "Entre a nota do estudante 1: ";
cin >> nota1;
cout << "Entre a nota do estudante 2: ";
cin >> nota2;
cout << "Entre a nota do estudante 3: ";
cin >> nota3;
media = (nota0 + nota1 + nota2 + nota3) / 4;
cout << "Notas: " << nota0 << " " << nota1 << " " << nota2 << " "
<< nota3 << endl;
cout << "Media: " << media << endl;
}
Este programa bem simples, mas ele tem um problema. O que acontece se o nmero de estudantes
aumentar ? O programa caria muito maior (e feio !!). Imagine o mesmo programa se existissem 100
estudantes.
O que precisamos uma abstrao de dados para agrupar dados relacionados. Este o objetivo de arrays
em C++ .
Um array uma coleo de um ou mais objetos, do mesmo tipo, armazenados em endereos adjacentes
de memria. Cada objeto chamado de elemento do array. Da mesma forma que para variveis simples,
damos um nome ao array. O tamanho do array o seu nmero de elementos. Cada elemento do array
numerado, usando um inteiro chamado de ndice. Em C++ , a numerao comea com 0 e aumenta de um
em um. Assim, o ltimo ndice igual ao nmero de elementos do array menos um.
Por exemplo, podemos denir um array nota de tamanho 100 para armazenar as notas dos cem estu-
dantes:
int nota[100];
Quando o compilador encontra esta denio, ele aloca 200 bytes consecutivos de memria (dois bytes
referente a cada int para cada nota). Cada nota pode ser acessada dando o nome do array e o ndice entre
colchetes: como nota[0] (para a primeira nota), nota[1] para a segunda nota, e assim por diantes, at
a ltima nota, nota[99].
13.1 Denindo arrays e acessando seus elementos
A denio de arrays muito parecida com a denio de variveis. A nica diferena que em array
necessrio especicar seu tamanho (quantos elementos ele tem).
Os colchetes [ e ] so usados na denio do tamanho, como mostra os exemplos a seguir:
54
int total[5];
float tamanho[42];
O primeiro exemplo um array de 5 inteiros (o tipo int) com o nome total. Como a numerao de
arrays comea com 0, os elementos da array so numerados 0, 1, 2, 3 e 4.
O segundo exemplo um array de 42 elementos do tipo float com ndices de 0 a 41.
Cada elemento do array total do tipo inteiro e pode ser usado do mesmo jeito que qualquer varivel
inteira. Para nos referirmos a um elemento do array, usamos colchetes tambm ([ e ]). O valor dentro
dos colchetes pode ser qualquer expresso do tipo inteiro. Quando um array denido, armazenamento
suciente (bytes contnuos na memria) so alocados para conter todos os elementos do array.
Note na tabela de precedncia abaixo que [ ] tem precedncia maior que todos os demais operadores.
Operador Associatividade
() [] esquerda para direita
! - & direita para esquerda
*
/ % esquerda para direita
+ - esquerda para direita
< <= > >= esquerda para direita
== != esquerda para direita
&& esquerda para direita
|| esquerda para direita
= direita para esquerda
, esquerda para direita
Verique se voc entende as sentenas do programa abaixo.
int i, x, sala, total[5];
float area;
float tamanho[42];
x = total[3];
i = 4;
total[i] = total[i-1] + total[i-2];
total[4] = total[4] + 1;
tamanho[17] = 2.71828;
sala = 3;
area = tamanho[sala]
*
tamanho[sala];
cin >> tamanho[41];
Agora, podermos reescrever o programa que calcula a mdia de uma classe de 4 alunos:
int main()
{
int indice, nota[4];
55
float total;
indice = 0;
while (indice < 4)
{
cout << "Entre a nota do estudante " << indice << ": ";
cin >> nota[indice];
indice = indice + 1;
}
cout << "Notas: ";
total = 0;
indice = 0;
while (indice < 4)
{
cout << nota[indice] << " ";
total = total + nota[indice];
indice = indice + 1;
}
cout << endl << "Media: " << total / 4 << endl;
}
Exemplo de Sada:
Entre a nota do estudante 0: 93
Entre a nota do estudante 1: 85
Entre a nota do estudante 2: 74
Entre a nota do estudante 3: 100
Notas: 93 85 74 100
Media: 88
O cdigo-fonte do programa consideravelmente mais curto.
O nico problema que ainda no fcil modicar o programa para cem alunos porque 4 est em vrios
pontos do programa. Ns podemos usar o #define para manter o tamanho do array como uma constante
simblica ao invs de utilizar uma constante numrica.
#define ESTUDANTES 4
int main()
{
int indice, nota[ESTUDANTES];
float total;
indice = 0;
while (indice < ESTUDANTES)
{
cout << "Entre a nota do estudante " << indice << ": ";
cin >> nota[indice];
indice = indice + 1;
}
56
cout << "Notas: ";
total = 0;
indice = 0;
while (indice < ESTUDANTES)
{
cout << nota[indice] << " ";
total = total + nota[indice];
indice = indice + 1;
}
cout << endl << "Media: " << total / ESTUDANTES << endl;
}
13.2 Inicializao de arrays
Os arrays podem ser inicializados quando so denidos. Se o array no for inicializado, ento ele contem
valores indenidos (tambm conhecidos como lixo).
Para inicializar um array, um valor para cada elemento deve ser especicado. Estes valores devem estar
entre chaves ({ e }) e so separados por vrgula (,). Alguns exemplos:
int valor[4] = { 1, 42, -13, 273 };
// o tamanho do array pode ser omitido
int peso[] = { 153, 135, 170 };
No primeiro exemplo, valor um array de 4 inteiros onde valor[0] e 1, valor[1] e 42,
valor[2] e -13, e valor[3] e 273.
Note que no segundo exemplo, o tamanho do array foi omitido. Neste caso, o compilador calcula o
tamanho como sendo o nmero de elementos listados. Quando um array denido, se ele no for iniciali-
zado, o tamanho do array deve ser especicado. Se o array for inicializado, o tamanho pode ser omitido. O
segundo exemplo acima equivalente a
int peso[3] = { 153, 135, 170 };
Se o tamanho no for omitido, o nmero de elementos presentes no deve exceder o tamanho. Se
exceder, o compilador gerar uma mensagem de erro. Se houver menos elementos na lista de inicializao,
ento os elementos dados so usados para inicializar os primeiros elementos do array. Qualquer elemento
no inicializado conter lixo.
Note que este tipo de inicializao s vlido no contexto onde o array denido. Uma sentena como a
seguinte produzir um erro do compilador, uma vez que arrays s podem ser inicializados quando denidos.
int erro[5];
erro = { 2, 4, 6, 8, 10 }; // ISTO ESTA ERRADO
H mais uma restrio na inicializao de um array. Os valores devem ser todos constantes nenhuma
varivel ou expresso permitida. O seguinte trecho de programa produz um erro porque um dos valores de
inicializao uma varivel:
int x = 21;
int yy[3] = { 1, 2, x }; // ISTO ESTA ERRADO
57
13.3 Vericao de Limite
Quando um array denido, alocado espao em memria para conter todos os elementos do array (no
mais). O tamanho do array dado explicitamente escrevendo o tamanho, ou implicitamente, inicializando o
array. Embora arrays tenham tamanhos especcos, possvel que um programa tente acessar endereos de
memria de elementos ctcios, ou seja, endereos de memria que no pertencem ao array. Isto acontece
quando usamos um ndice que no esteja entre 0 e n-1 para um array de tamanho n. O compilador no
gera nenhum aviso quando isto acontece. Quando executamos um acesso fora dos limites do array, o
resultado pode ser desastroso. Isto siginica que o programa pode no fazer nada, cancelar a execuo,
travar o computador, entrar em um loop innito, etc.
Se voc executar uma atribuio a um elemento do array fora do seu limite, voc estar escrevendo
em um endereo de memria que pode conter algo importante, destruindo-o. Em geral, erros como estes
so difceis de encontrar, j que o programa pode at executar, s que faz algo estranho. Se voc estiver
usando o Code::Blocks , voc poder ver uma mensagem como Esta aplicao violou a integridade do
sistema devido a execuo de uma instruo invlida e ser cancelada.. No entre em pnico !! Voc
provavelmente ter que reinicializar o seu computador e examinar o seu programa cuidadosamente para
achar acessos a array fora do seu limite. claro que ao reinicializar o seu computador, voc perder todo o
seu trabalho se no tiver salvado antes. MORAL: depois que seu programa compilar com sucesso, salve o
seu programa em disco antes de execut-lo.
Por exemplo, considere o seguinte programa:
#include <iostream>
using namespace std;
#define TAM 10
int main()
{
int ops[TAM], i;
// Acesso fora dos limites quando i == TAM
i = 0;
while (i <= TAM)
{
ops[i] = 0;
i = i + 1;
}
}
Este programa inicializa cada elemento do array com 0. O problema ocorre quando i tem o valor 10.
Neste ponto, o programa coloca 0 em ops[10]. Isto pode produzir resultados indenidos (e desastrosos)
embora o compilador no gere nenhum erro. O problema est na condio do while, que no deveria permitir
que o corpo da repetio fosse executado quando i assumisse o valor 10.
13.4 Arrays como argumentos de funes
Para passar um array como argumento (com todos os seus elementos) de uma funo passamos o nome do
array. Considere o exemplo abaixo:
58
Aqui est um exemplo de execuo deste programa
Entre um inteiro: 73
Entre um inteiro: 85
Entre um inteiro: 42
Entre um inteiro: -103
Entre um inteiro: 15
O maior e 85
Em main() a chamada para array max() tem valor como seu argumento, que copiado para o
parmetro formal a, que um array de inteiros. Note que o tamanho no foi especicado, somente o nome
do array, a. Porm tambm correto incluir o tamanho (isto uma questo de estilo escolha o que voc
preferir):
int array_max(int a[TAMANHO])
{
...
}
A incluso do tamanho de um array unidimensional na denio da funo somente por razes de
legibilidade.
At este ponto, parece que no h diferena entre passar uma varivel simples e um array como ar-
gumento para uma funo. Mas h uma diferena fundamental: QUANDO DEFINIMOS UM ARRAY
COMO ARGUMENTO FORMAL, ALTERAES NO ARRAY FEITAS DENTRO DA FUNO
ALTERAM O CONTEDO DO ARRAY PASSADO COMO PARMETRO REAL NA CHAMDA
DAFUNO. EMOUTRAS PALAVRAS, QUANDOSOPARMETROS DEFUNES, ARRAYS
SO PASSADOS POR REFERNCIA (sem a necessidade do & na denio do parmetro formal,
como foi visto na Seo 11).
Para ilustrar este conceito, considere o exemplo seguinte:
A sada deste programa :
x=10
v[0]=60 v[1]=70 v[2]=80
O valor da varivel x do programa principal no se altera porque como j vimos nas notas de aula 7,
quando a funo troca chamada, o valor do argumento real x avaliado, que 10, este valor copiado
para o parmetro formal a da funo troca e a funo ento executada. O parmetro a da funo
tratada como varivel local, portanto quando atribumos 20 a a, estamos atribuindo 20 a uma varivel
local. Terminada a funo, a execuo retorna ao programa principal, que imprime o valor de x, que no foi
alterado, ou seja, imprime x=10.
Quando a funo troca_vet chamada, o array v passado como argumento e copiado para o
parmetro formal vet. A funo ento executada, e os elementos do array so alterados para 60, 70,
80. Como mencionado anteriormente, quando passamos um array como parmetro, as alteraes feitas no
array dentro da funo alteram o array passado como parmetro. Portanto, quando a funo termina e a
execuo continua no programa principal com a impresso dos valores dos elementos de v, ser impresso
60, 70, 80, os novos valores alterados de dentro da funo troca_vet.
Vamos entender por que quando passamos s o nome do array como argumento as alteraes afetam
o array passado como parmetro real. Como j mencionamos anteriormente, quando um array denido,
como v no programa principal acima, alocado espao suciente na memria para conter todos os elementos
do array. Na ilustrao abaixo, so alocados 6 bytes de memria a partir do endereo 1342 para conter
59
o array. O array como um todo no tem um valor, mas cada elemento do array tem (neste caso, foram
inicializados com 30, 40, 50). O nome do array, na verdade, contm o endereo onde comea o array,
neste caso, o endereo 1342.
Portanto, quando passamos o nome do array como argumento para uma funo estamos na realidade
passando como argumento o endereo de memria onde comea o array. No exemplo anterior, 1342
passado como argumento para o parmetro formal vet da funo troca_vet. Portanto, da mesma forma
que no caso da varivel simples, o valor de v, que o endereo 1342, copiado para o parmetro vet
de troca_vet. Ento, quando a funo troca_vet executada, vet um array de elementos do tipo
int que comea no endereo 1342. Quando atribumos o valor 60 a vet[0], estamos atribuindo 60 ao
primeiro elemento do array que comea no endereo 1342. Como este o mesmo endereo onde comea
o array v do programa principal, quando a funo troca_vet termina, o array v enxergar o valor dos
elementos do array que comea no endereo 1342, que foram alterados pela funo.
Quando passamos variveis simples como argumento para uma funo estamos passando somente o
valor da varivel, portanto, de dentro da funo no possvel saber qual o endereo da varivel para poder
alter-la.
Lembre-se que o endereo s passado para a funo quando passamos o array COMO UM TODO
(ou seja, o nome do array, sem ser indexado por um elemento). Se passarmos como argumento apenas um
elemento do array, o comportamento o mesmo que se passssemos uma varivel simples. Ou seja, o nome
do array indexado por um valor entre colchetes refere-se ao valor do elemento do array, enquanto o nome
do array sozinho refere-se ao endereo onde comea o array. Assim, no programa abaixo:
A sada do programa :
v[0]=30
v[0]=60 v[1]=70 v[2]=80
Outro exemplo: a funo inicializaArray abaixo inicializa todos os elementos do array valor
com um valor passado como argumento pelo programa principal.
Como as alteraes feitas por inicializaArray so vistas do programa principal, depois da funo
inicializaArray ser executada, no programa principal todos os elementos do array valor tero o
valor 42.
60
13.5 Exemplo: pesquisa linear de um array
Pesquisar (procurar) em um array um determinado valor (chamado de chave) um problema muito comum
em programao. Ele tem diversas aplicaes. Por exemplo, podemos pesquisar um array de notas para ve-
ricar se algum aluno tirou 100 na prova. H diversos algoritmos de pesquisa: cada um com suas vantagens
e desvantagens. Nestas notas de aula, discutiremos um algoritmo simples, chamado de pesquisa linear. A
pesquisa feita usando uma repetio e examinando cada elemento do array a cada repetio e comparando
o elemento com a chave que buscamos. A pesquisa termina quando um elemento do array que casa com
a chave encontrada, ou quando o array todo percorrido e a chave procurada no encontrada.
13.5.1 O Problema
Escreva uma funo pesquisa linear que tem como argumento de entrada: um array de inteiros a
ser pesquisado, o tamanho do array, e uma chave (um valor inteiro) a ser procurado. A funo retorna um
inteiro: o ndice do elemento do array (se a chave for achada) ou -1 caso contrrio.
1. Prottipo:
int pesquisa_linear(int [], int, int);
2. Denio:
/
*
Procura uma chave em um array
*
entrada: array a ser pesquisado (arr ), tamanho do array (tam),
*
chave a ser procurada (chave)
*
saida: o indice do elemento que e igual a chave ou -1 caso nao ache
*
suposicao: nao assume que o array esteja ordenado
*
/
int pesquisa_linear(int arr[], int tam, int chave)
{
int i;
i = tamanho - 1;
while (i >= 0)
{
if (arr[i] == chave)
{
return i;
}
i = i - 1;
}
return -1;
}
13.6 Exemplo: somar os elementos de dois arrays
13.6.1 O Problema
Escrever uma funo que some dois arrays de floats, do mesmo tamanho. Dar o resultado em um terceiro
array. O tamanho dos arrays tambm passado para a funo.
61
1. Prottipo:
void soma_array( float [], float [], float [], int );
2. Denio de soma array():
void soma_array( float arr1[], float arr2[], float arr3[], int tam )
{
int i;
i = 0
while ( i < tam )
{
arr3[i] = arr1[i] + arr2[i];
i = i + 1;
}
}
13.7 Exemplo: Ordenao de um vetor - Verso 1
Um outro programa muito popular com arrays orden-lo de acordo com algum critrio. Por exemplo,
um array de inteiros pode ser ordenado em ordem crescente ou decrescente. O apresentado a seguir um
algortmo bsico e nem um pouco eciente, denominado Select sort.
Ele usa o fato simples de comparar cada elemento de um array com o restante deste. Quando se acha o
menor, ocorre uma troca de valores entre o elemento sob anlise e o outro elemento do array que o menor.
Por exemplo, se comearmos com um array: 9 5 2 7 3 8 1 4 6, (o primeiro elemento 9 e o
ltimo elemento 6) isto o que acontece com os elementos do array depois de cada passagem sobre ele (e
consequente troca de valores):
passagem conteudo do array depois da passagem
~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 --> 9 5 2 7 3 8 1 4 6
1 --> 1 5 2 7 3 8 9 4 6
2 --> 1 2 5 7 3 8 9 4 6
3 --> 1 2 3 7 5 8 9 4 6
4 --> 1 2 3 4 5 8 9 7 6
5 --> 1 2 3 4 5 8 9 7 6
6 --> 1 2 3 4 5 6 9 7 8
7 --> 1 2 3 4 5 6 7 9 8
8 --> 1 2 3 4 5 6 7 8 9
Note que mesmo que se comessemos com um array ordenado de 9 elementos, ainda assim o algoritmo
dado faz 8 passagens sobre o array.
62
13.7.1 Prottipo da funo e denio
1. Prottipo
void selectSort(int [], int);
2. Denicao
13.8 Exemplo: Ordenao de um vetor - Verso 2
O algoritmo abaixo ligeiramente melhor que o anterior e chamado Bubble sort. Ele bastante simples,
porm ainda no muito eciente.
Basicamente, o algoritmo funciona da seguinte forma:
na primeira passagem sobre o array: comeando do ltimo elemento do array at o segundo elemento,
compare o valor de cada elemento como valor do elemento anterior a ele. Se os elementos comparados
estiverem fora de ordem, trocar os seus valores. Depois que esta primeira passada terminar, o que
acontece que o menor elemento do array torna-se o primeiro elemento do array.
na segunda passagem pelo array: comeando com o ltimo elemento do array at o terceiro elemento,
compare o valor de cada elemento com o valor do elemento anterior a ele. Se os dois elementos
comparados estiverem fora de ordem, trocar os seus valores. Depois que esta passagem sobre o array
terminar, o segundo menor elemento do array ser o segundo elemento do array.
repetir a passagem sobre o array de maneira similar at que a ltima passagem ser simplesmente uma
comparao dos valores do ltimo elemento com o elemento anterior.
Por exemplo, se comearmos com um array: 9 5 2 7 3 8 1 4 6, (o primeiro elemento 9 e o
ltimo elemento 1) isto o que acontece com os elementos do array depois de cada passagem sobre ele (e
troca de valores adjacentes):
passagem conteudo do array depois da passagem
~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 --> 9 5 2 7 3 8 1 4 6
1 --> 1 9 5 2 7 3 8 4 6
2 --> 1 2 9 5 3 7 4 8 6
3 --> 1 2 3 9 5 4 7 6 8
4 --> 1 2 3 4 9 5 6 7 8
5 --> 1 2 3 4 5 9 6 7 8
6 --> 1 2 3 4 5 6 9 7 8
7 --> 1 2 3 4 5 6 7 9 8
8 --> 1 2 3 4 5 6 7 8 9
63
Note que, tambm aqui, mesmo que se comessemos com um array ordenado de 9 elementos, ainda
assim o algoritmo dado faz 8 passagens sobre o array.
Isto pode ser melhorado da seguinte forma: Antes de comear cada passagem, inicializamos uma vari-
vel ordenado com 1. Se durante a passagem uma troca de valores ocorrer, trocamos o valor da varivel
para 0. Assim, se depois da passagem, o valor da varivel continuar sendo 1, isso signica que nenhuma
troca ocorreu e que o array est ordenado.
13.8.1 Algoritmo Bubble Sort otimizado
Enquanto o array nao estiver ordenado
1. inicializar ordenado com 1
2. comparar pares adjacentes do array
troque seus valores se estiver fora de ordem
ordenado = 0.
13.8.2 Prottipo da funo e denio
1. Prottipo
void bubbleSort(int [], int);
2. Denicao
13.9 Comentrios Finais
Neste curso, um dos nicos lugares que veremos o nome do array sem estar indexado quando passamos
o array (como um todo) para uma funo. Para outras nalidades, veremos sempre o array indexado. Por
exemplo, o seguinte trecho de programa est errado:
int main(){
int arr1[4] = {10, 20, 30, 40};
int arr2[4];
arr2 = arr1; // ERRADO: NO copia arr1 em arr2
// tem que copiar elemento por elemento
if( arr1 == arr2 ) // ERRADO: NO podemos comparar arrays inteiros
cout << "X"; // tem que comparar elemento por elemento
}
64
14 Matrizes ou Arrays Multidimensionais
Nas notas de aula anteriores, apresentamos arrays unidimensionais. Em C++ , possvel tambm denir
arrays com 2 ou mais dimenses. Eles so arrays de arrays. Um array de duas dimenses podem ser
imaginado como uma matriz (ou uma tabela).
Como voc deve ter imaginado, para denir e acessar arrays de dimenses maiores, usamos colchetes
adicionais ([ e ]). Por exemplo:
int tabela[3][5];
Dene um array bidimensional chamado tabela que uma matriz 3 por 5 de valores do tipo int (15
valores no total). Os ndices da primeira dimenso vo de 0 a 2, e os ndices da segunda dimenso vo de 0
a 4.
Abaixo apresentamos um programa que imprime os elementos de um array bidimensional.
#include <iostream>
using namespace std;
#define ALTURA 5
#define LARGURA 5
int main()
{
int x; // numero da coluna
int y; // numero da linha
char matriz [ALTURA] [LARGURA]; // array 2-D [num_lins, num_cols]
// preenche a matriz com zeros
y = 0;
while(y < ALTURA)
{
x = 0;
while(x < LARGURA)
{
matriz[y][x] = 0;
x= x + 1;
}
y= y + 1;
}
// Imprime a matriz com zeros e a coordenada escolhida com 1
cout << endl << "Entre coordenadas na forma \"y x\"." << endl;
cout << "Use valores negativos para sair do programa." << endl;
cout << "Coordenadas: ";
cin >> y >> x;
while (x >= 0 && y >= 0)
65
{
matriz[y][x] = 1; // coloca 1 no elemento escolhido
y = 0;
while (y < ALTURA) // imprime o array todo
{
x = 0;
while (x < LARGURA)
{
cout << matriz[y][x] << " ";
x = x + 1;
}
cout << endl << endl;
y = y + 1;
}
cout << endl;
cout << "Coordenadas: ";
cin >> y >> x;
}
}
Neste exemplo, matriz umarray bidimensional. Ela temnmero de elementos igual a ALTURAxLARGURA,
sendo cada elemento do tipo int.
O exemplo abaixo preenche os elementos de um array bidimensional com os valores que representam a
taboada e imprime a matriz.
// Exemplo de array 2-D - taboada
#include <iostream>
#include <iomanip>
using namespace std;
#define LIN 10
#define COL 10
int main()
{
int x; // numero da coluna
int y; // numero da linha
int tabela[LIN] [COL]; // tabela de taboada
// preenche a tabela
y = 0;
while (y < LIN)
{
x = 0;
while (x < COL)
{
66
tabela[y][x] = y
*
x;
x = x + 1;
}
y = y + 1;
}
cout << endl << " Tabela de Multiplicacao" << endl;
// Imprime o numero das colunas
cout << setw(6) << 0;
x = 1;
while (x < COL)
{
cout << setw(3) << x;
x = x + 1;
}
cout << endl;
// Imprime uma linha horizontal
cout << " ";
x = 0;
while (x < 3
*
COL)
{
cout << "-";
x = x + 1;
}
cout << endl;
// Imprime as linhas da tablea.
// Cada linha a precedida pelo indice de linha e uma barra vertical
y = 0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x = 0;
while (x < COL)
{
cout << setw(3) << tabela[y][x];
x = x + 1;
}
cout << endl;
y = y + 1;
}
}
A sada do programa :
Tabela de Multiplicacao
67
0 1 2 3 4 5 6 7 8 9
------------------------------
0| 0 0 0 0 0 0 0 0 0 0
1| 0 1 2 3 4 5 6 7 8 9
2| 0 2 4 6 8 10 12 14 16 18
3| 0 3 6 9 12 15 18 21 24 27
4| 0 4 8 12 16 20 24 28 32 36
5| 0 5 10 15 20 25 30 35 40 45
6| 0 6 12 18 24 30 36 42 48 54
7| 0 7 14 21 28 35 42 49 56 63
8| 0 8 16 24 32 40 48 56 64 72
9| 0 9 18 27 36 45 54 63 72 81
14.1 Inicializao
Arrays multidimensionais podem ser inicializados usando listas aninhadas de elementos entre chaves. Por
exemplo, um array bidimensional tabela com trs linhas e duas colunas pode ser inicializado da seguinte
forma:
double tabela[3][2] = { {1.0, 0.0}, // linha 0
{-7.8, 1.3}, // linha 1
{6.5, 0.0} // linha 2
};
Quando o array inicializado, o tamanho da primeira dimenso pode ser omitido. A denio de array
abaixo equivalente a dada anteriormente.
double tabela[][2] = { {1.0, 0.0}, // linha 0
{-7.8, 1.3}, // linha 1
{6.5, 0.0} // linha 2
};
14.2 Arrays Multidimensionais arrays de arrays
O formato da denio de um array de dimenso k, onde o nmero de elementos em cada dimenso
n
0
, n
1
, . . . , n
k1
, respectivamente, :
nome_tipo nome_array[n
0
][n
1
]...[n
k1
];
Isto dene um array chamado nome_array consistindo de um total de n
0
n
1
. . . n
k1
elementos,
sendo cada elemento do tipo nome_tipo.
Arrays multidimensionais so armazenados de forma que o ltimo subscrito varia mais rapidamente.
Por exemplo, os elementos do array
int tabela[2][3];
so armazenados (em endereos consecutivos de memria) como
tabela[0][0], tabela[0][1], tabela[0][2], tabela[1][0], tabela[1][1], tabela[1][2].
Um array de dimenso k, onde o nmero de elementos em cada dimenso n
0
, n
1
, . . . , . . . , n
k1
, respec-
tivamente, pode ser imaginado como um array de dimenso n
0
cujos elementos so arrays de dimenso
k 1.
Por exemplo, o array bidimensional tabela, com 20 elementos do tipo int
68
int tabela[4][5] = { {13, 15, 17, 19, 21},
{20, 22, 24, 26, 28},
{31, 33, 35, 37, 39},
{40, 42, 44, 46, 48} };
pode ser imaginado como um array unidimensional de 4 elementos do tipo int[], ou seja, arrays de int;
cada um dos 4 elementos um array de 5 elementos do tipo int:
tabela[0] ---> {13, 15, 17, 19, 21}
tabela[1] ---> {20, 22, 24, 26, 28}
tabela[2] ---> {31, 33, 35, 37, 39}
tabela[3] ---> {40, 42, 44, 46, 48}
14.3 Arrays Multidimensionais como argumento para funes
Quando o parmetro formal de uma funo um array multidimensional (um array com dimenso maior que
um), todas as dimenses deste array, exceto a primeira, precisa ser explicitamente especicada no cabealho
e prottipo da funo.
tipo_do_resultado nome_da_funcao ( nome_do_tipo nome_do_array[ ][n
1
]...[n
k1
], ...... )
Quando uma funo com um parmetro formal do tipo array chamada, na chamada da funo somente
o nome do array passado como parmetro real. O tipo (e portanto a dimenso) do array passado como
parmetro real deve ser consistente com o tipo (e portanto a dimenso) do array que o parmetro formal.
O programa abaixo mostra o exemplo da tabela de multiplicao escrita usando funes.
// Exemplo de array 2-D - tabela de multiplicacao
#include <iostream>
#include <iomanip>
using namespace std;
#define LIN 10
#define COL 10
// Inicializa o array com a tabela de multiplicacao
void inicializa_arr (int arr[][COL])
{
int x; // numero da coluna
int y; // numero da linha
// preenche o array
y=0;
while (y < LIN)
{
x=0;
while(x < COL)
{
69
arr[y][x] = y
*
x;
x = x + 1;
}
y = y + 1;
}
}
// imprime um array LIN x COL
void imprime_arr(int arr[][COL])
{
int x; // numero da coluna
int y; // numero da linha
// imprime o numero das colunas
cout << setw(6) << 0;
x = 1;
while (x < COL)
{
cout << setw(3) << x;
x = x + 1;
}
cout << endl;
// imprime uma linha horizontal
cout << " ";
x = 0;
while (x < 3
*
COL)
{
cout << "-";
x = x + 1;
}
cout << endl;
// imprime as linhas do array. cada linha e precedida
// pelo numero da linha e uma barra vertical
y = 0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x = 0;
while (x < COL)
{
cout << setw(3) << arr[y][x];
x = x + 1;
}
70
cout << endl;
y = y + 1;
}
}
int main()
{
int tabela[LIN] [COL];
inicializa_arr(tabela);
cout << endl << " Tabela de Multiplicacao" << endl;
imprime_arr(tabela);
}
Outro exemplo com funoes de manipulao de arrays bidimensionais:
// funcoes com argumentos tipo array 2-D
#include <iostream>
using namespace std;
#define ALTURA 7
#define LARGURA 7
//
***
DEFINICAO DE FUNCOES
*******
// funcao que imprime um array 2-D ALTURA X LARGURA
void imprime_matriz(char matriz[][LARGURA])
{
int x,y;
y = 0;
while (y < ALTURA)
{
x = 0;
while (x < LARGURA)
{
cout << matriz[y][x] << " ";
x = x + 1;
}
cout << endl << endl;
y = y + 1;
}
cout << endl;
}
71
// funcao que preenche uma matriz ALTURA X LARGURA com pontos
void pontos( char matriz[][LARGURA])
{
int x,y;
y = 0;
while (y < ALTURA)
{
x = 0;
while (x<LARGURA)
{
matriz[y][x] = .;
x = x + 1;
}
y = y + 1;
}
}
/
*
funcao que preenche os elementos selecionados da matriz com um
*
quadrado e imprime a matriz
*
/
void seleciona_elem(char matriz[][LARGURA])
{
int x, y;
cout << endl << "Entre com as coordenadas na forma \"y x\"." << endl;
cout << "Use numeros negativos para terminar." << endl;
cout << "Coordenadas: ";
cin >> y >> x;
while (x >= 0 && y >= 0)
{
matriz[y][x]=@; // preenche o elemento com quadrado
imprime_matriz(matriz); // imprime a matriz
cout << "Coordenadas: ";
cin >> y >> x;
}
}
/
*
funcao que marca todos os elementos abaixo da diagonal principal de
*
um array ALTURA X LARGURA com quadrados
*
/
void marca_triang(char matriz[][LARGURA])
{
int x, y;
cout << "Triangulo" << endl;
pontos(matriz);
y = 0;
72
while (y < ALTURA)
{
x = 0;
while (x <= y)
{
matriz[y][x] = @;
x = x + 1;
}
y = y + 1;
}
}
// funcao que rotaciona (flip) cada linha array tendo o elemento da
// diagonal principal como centro da rotao
void flip(char matriz[][LARGURA])
{
int x, y;
int temp;
cout << "Flip ao longo da diagonal principal." << endl;
y = 0;
while (y < ALTURA)
{
x = 0;
while (x <= y)
{
temp = matriz[y][x];
matriz[y][x] = matriz[x][y];
matriz[x][y] = temp;
x = x + 1;
}
y = y + 1;
}
}
// funcao que espera ate que uma tecla qualquer seja digitada
void pausar() {
char c;
cin.get(c);
}
//
*********
MAIN
***********
// alguns exemplos de chamadas de funcoes com argumentos array 2-D
int main()
{
char matriz [ALTURA] [LARGURA];
pontos(matriz);
seleciona_elem(matriz);
73
pausar();
flip(matriz);
imprime_matriz(matriz);
pausar();
marca_triang( matriz);
imprime_matriz( matriz);
pausar();
flip( matriz);
imprime_matriz(matriz);
pausar();
}
74
Parte II
Tpicos Avanados
As sees seguintes apresentam temas mais avanados da linguagem C++ , no abordadas em sala de aula.
Elas podem ser estudadas pelo aluno como atividade complementar, pois apresentam mecanismos bastantes
teis em programas mais complexos (tratamento de arquivos e textos, manipulao dinmica de memria,
etc.).
75
15 Operadores e Expresses Especiais
15.1 Operao de Atribuio Aritmtica
freqente em programas C++ expresses do tipo:
tudo = tudo + parte;
tamanho = tamanho
*
2.5;
x = x
*
(y + 1);
j = j - 1;
C++ fornece operadores adicionais que podem ser usados para tornar estes tipos de atribuies mais
curtos.
H um operador de atribuio para cada operao aritmtica listada anteriormente:
+= operao de atribuio de adio
-= operao de atribuio de subtrao
*= operao de atribuio de multiplicao
/= operao de atribuio de diviso
%= operao de atribuio de resto
Cada uma dessas operaes podem ser usadas para tornar as expresses anteriores mais curtas:
tudo += parte;
tamanho
*
= 2.5;
x
*
= y + 1;
j -= 1;
15.2 Operadores de Incremento e Decremento
H alguns operadores em C++ que so equivalentes as seguintes expresses (que so bastante comuns
em programas):
k = k + 1;
j = j - 1;
Estes operadores adicionais, que so ++ e --, podem ser usados para encurtar as operaes acima:
k++;
j--;
Estes operadores tambm podem ser colocados depois do nome da varivel:
76
++k;
--j;
Ofato do operador de incremento ser colocado antes ou depois da varivel no altera o efeito da operao
o valor da varivel incrementada ou decrementada de um. A diferena entre os dois casos QUANDO
a varivel incrementada. Na expresso k++, o valor de k primeiro usado e ento incrementada isto
chamado ps-incremento. Na expresso ++k, k incrementado primeiro, e ento o valor (o novo valor) de
k usado isso chamado pr-incremento.
A diferena ilustrada nos seguintes exemplos:
int main()
{
int k = 5;
cout << "k1 = " << k << endl;
cout << "k2 = " << k++ << endl;
cout << "k3 = " << k << endl;
}
O programa acima (que usa ps-incremento) imprimir o seguinte:
k1 = 5
k2 = 5
k3 = 6
A segunda linha impressa com o valor de k 5 porque o valor de k++ era 5, e k 6 depois da impresso.
Para o programa:
int main()
{
int k = 5;
cout << "k1 = " << k << endl;
cout << "k2 = " << ++k << endl;
cout << "k3 = " << k << endl;
}
O programa, que usa pr-incremento, ter a seguinte sada:
k1 = 5
k2 = 6
k3 = 6
A segunda linha impressa 6 porque o valor de ++k 6.
Os operadores de atribuio no podem ser usados com expresses aritmticas. Por exemplo, as expres-
ses
(ack + 2)++;
(nope + 3) += 5;
resultaro em erros de compilao.
Finalmente, quando usar o operador de incremento em um cout, tome cuidado para no fazer o se-
guinte:
77
cout << ++uhoh << uhoh
*
2 << endl;
Embora isso seja perfeitamente legal em C++ , os resultados no so garantidados que sejam consis-
tentes. A razo para isso que no h garantia que os argumentos do cout sejam avaliados em uma
determinada ordem. O resultado do cout ser diferente dependendo se ++uhoh avaliado primeiro ou
depois de uhoh
*
2.
A soluo para este problema escrever o seguinte:
++uhoh;
cout << uhoh << uhoh
*
2 << endl;
15.3 Expresses como Valor com Operadores de incremento e decremento
J que incremento e decremento so formas de atribuio, o operando deve ser um lvalue. O valor de
uma expresso de incremento ou decremento depende se o operador usado na notao PR ou PS xada
(x++, ++x, x--, --x). Se for pr-xada, o valor da expresso o novo valor aps o incremento ou
decremento. Se for ps-xada, o valor da expresso o valor antigo (antes do incremento ou decremento).
Por exemplo no caso de incremento, a expresso:
x++ tem o valor de x
++x tem o valor de x + 1
Note que no importando a notao usada, o valor de x (o contedo do endereo de memria associada
a x) ser x + 1. A diferena est no valor das expresses x++ e ++x, no no valor de x (em ambos os
casos o valor de x ser incrementada de um).
15.4 Ambiguidade em certas expresses
s vezes, problemas podem acontecer devido o fato que C++ no especica a ordem de avaliao dos
operadores em uma operao binria. Em outras palavras, em expresses como a + b ou a < b, no h
maneira de saber se o valor de a ser avaliado antes ou depois de b (pense em a e b como sendo qualquer
expresso, no somente variveis.) Qual deles ser avaliado primeiro particular de cada compilador, e
diferentes compiladores em mquinas diferentes podem ter resultados diferentes. Portanto, se a avaliao
de um dos operadores pode alterar o valor do outro, o resultado pode ser diferente dependendo da ordem
de avaliao. Portanto, em expresses do tipo x + x++, o valor pode diferir dependendo do compilador
utilizado. Isto porque no sabemos quando exatamente o incremento de x ocorre. Outros maus exemplos:
y = x + x-- e x = x++. De forma geral, para evitar este problema, no utilize senteas como estas.
15.4.1 Valor de expresses envolvendo atribuio aritmtica
Como podemos ver, os operadores de incremento/decremento, e os operadores de atribuio aritmtica vistos
at aqui funcionam de forma similar ao comando de atribuio. O lado esquerdo da expresso de atribuio
aritmtica e o operando de incremento/decremento devem ser um lvalue. O valor da expresso da igual ao
valor da sentena de atribuio correspondente. Por exemplo:
x += 3 igual a x = x + 3 e tem valor x + 3
x
*
= y + 1 igual a x = x
*
(y + 1) e tem valor x
*
(y + 1)
y = i++ igual a y = i, i = i + 1; e tem valor i
y = ++i igual a i = i + 1, y = i; e tem valor i + 1
15.5 Exerccio de xao
O que impresso pelos dois programas abaixo?
78
#include <iostream>
using namespace std;
int main() {
int n1, n2, n3;
cout << "Entre com um numero inteiro: ";
cin >> n1;
n1 += n1
*
10;
n2 = n1 / 5;
n3 = n2 % 5
*
7;
n2
*
= n3-- % 4;
cout << n2 << " " << n3 << " " << (n2 != n3 + 21) << endl;
}
15.6 Precedncia de Operadores
Atabela de precedncia abaixo mostra a posio dos operadores vistos aqui, incluindo a atribuio aritmtica
e decremento/incremento.
Operador Associatividade
() [] -> . esquerda para direita
! - ++ --
*
\& direita para esquerda
*
/ % esquerda para direita
+ - esquerda para direita
< <= > >= esquerda para direita
== != esquerda para direita
&& esquerda para direita
|| esquerda para direita
= += -=
*
= /= %= direita para esquerda
, esquerda para direita
79
16 Mais sobre tipos: converso implcita e explcita
Expresses no tem somente um valor, mas tambm tem um tipo associado.
Se ambos os operandos de uma operao aritmtica binria so do mesmo tipo, o resultado ter o mesmo
tipo. Por exemplo:
3 + 5 8, e o tipo int
3.5 + 2.25 5.75, e o tipo double
O nico comportamento no bvio a da diviso de inteiros:
30 / 5 6
31 / 5 6
29 / 5 5
3 / 5 0
Lembre-se de evitar escrever algo como 1 / 2
*
x signicando
1
2
x. Voc sempre obter o valor 0
porque 1 / 2
*
x (1 / 2)
*
x que 0
*
x que 0. Para obter o resultado desejado, voc poderia
escrever 1.0 / 2.0
*
x.
16.1 Converso de tipos
Valores podem ser convertidos de um tipo para outro implicitamente, da forma j comentada anteriormente.
Em expresses envolvendo operadores binrios com operandos de tipos diferentes, os valores dos ope-
randos so convertidos para o mesmo tipo antes da operao ser executada: tipos mais simples so promo-
vidos para tipos mais complexos. Portanto, o resultado da avaliao de uma expresso com operandos de
tipos diferentes ser o tipo do operando mais complexo. Os tipos em C++ so (do mais simples para o mais
complexo):
char < int < long < float < double
O sinal de < signica que o tipo da esquerda promovido para o tipo da direita, e o resultado ser do
tipo mais a direita. Por exemplo:
3.5 + 1 4.5
4
*
2.5 10.0
Esta regra estende-se para expresses envolvendo mltiplos operadores, mas voc deve se lembrar que
a precedncia e associatividade dos operadores pode inuenciar no resultado. Vejamos o exemplo abaixo:
int main()
{
int a, b;
cout << "Entre uma fracao (numerador e denominador): ";
cin >> a >> b;
cout << "A fracao em decimal e " << 1.0
*
a / b << endl;
}
80
Multiplicando por 1.0 assegura que o resultado da multiplicao de 1.0 por a ser do tipo real, e
portanto, a regra de converso automtica evitar que o resultado da diviso seja truncado. Note que se ti-
vssemos primeiro feito a diviso a/b e depois multiplicado por 1.0, embora o tipo da expresso a/b
*
1.0
seja do tipo double, o valor da expresso seria diferente do valor de 1.0
*
a/b. Por que ?
Em atribuies, o valor da expresso do lado direito convertido para o tipo da varivel do lado esquerdo
da atribuio. Isto pode causar promoo ou rebaixamento de tipo. O rebaixamento pode causar perda
de preciso ou mesmo resultar em valores errados.
Em operaes de atribuio, atribuir um int em um float causar a converso apropriada, e atribuir
um float em um int causar truncamento. Por exemplo:
float a = 3; equivalente a a = 3.0
int a = 3.1415; equivalente a a = 3 (truncado)
Basicamente, se o valor da expresso do lado direito da atribuio de um tipo que no cabe no tamanho
do tipo da varivel do lado esquerdo, resultados errados e no esperados podem ocorrer.
16.2 Modicadores de tipos
Os tipos de dados bsicos em C++ podem estar acompanhados por modicadores na declarao de vari-
veis. Tais modicadores so: long, short, signed e unsigned. Os dois primeiros tm impacto no tamanho
(nmero de bits) usados para representar um valor e os dois ltimos indicam se o tipo ser usado para
representar valores negativos e positivos (signed) ou sem este modicador) ou apenas positivos (unsigned).
A Tabela 4 mostra uma lista completa de todos os tipos de dados em C++ , com e sem modicadores:
Modicador Tamanho em bits Faixa de valores
char 8 -127 a 127
unsigned char 8 0 a 255
int 16 -32767 a 32767
unsigned int 16 0 a 65535
short int 16 -32767 a 32767
unsigned short int 16 0 a 65535
long int 32 -2147483647 a 2147483647
unsigned long int 32 0 a 4294967295
oat 32 Mantissa de 6 dgitos
double 64 Mantissa de 10 dgitos
long double 80 Mantissa de 10 dgitos
Tabela 4: Modicadores de Tipos de Dados
16.3 Cast de tipos
C++ tem um operador para alterar o tipo de um valor explicitamente. Este operador chamado de cast.
Executando um cast de tipos, o valor da expresso forado a ser de um tipo particular, no importando a
regra de converso de tipos.
O formato do cast de tipos :
(nome-do-tipo)expressao
81
O parnteses NO opcional na expresso acima.
Podemos usar o cast de tipos da seguinte forma:
int fahr = 5;
float cels;
cout << "Valor = " << (float) fahr << endl;
cels = (float)5 / 9
*
(fahr - 32);
cout << "celsius = " << (int) cels << endl;
Agora que conhecemos o operador de cast de tipo podemos reescrever o programa que faz a converso
de frao para decimal.
int main()
{
int a, b;
cout << "Entre com uma fracao (numerador e denominador): ";
cin >> a >> b;
cout << "A fracao em decimal e " << (float) a / b << endl;
}
O cast de tipo tem a maior precedncia possvel, portanto podemos fazer o cast de a ou de b para ser do
tipo float, e no h necessidade de parnteses extra. No exemplo acima, o cast causa o valor da varivel
a ser convertido para float, mas no causa mudana no tipo da varivel a. O tipo das variveis denido
uma vez na declarao e no pode ser alterado.
82
17 A sentena switch
A sentena switch outra maneira de fazer decises mltiplas. Ele pode ser usado para testar se uma dada
expresso igual a um valor constante e, dependendo do valor, tomar determinadas aes.
O formato da sentena switch :
switch (expressao) {
case expressao-constante 1:
sentencas 1
case expressao-constante 2:
sentencas 2
.
.
.
default:
sentencas n
}
A sentena switch primeiro avalia a expresso. Se o valor da expresso for igual a uma das expresses
constantes, as sentenas que seguem o case so executados. Se o valor da expresso no for igual a
nenhuma das constantes, as sentenas que seguem default so executadas.
As sentenas que seguem o case so simplesmente uma lista de sentenas. Esta lista pode conter mais
de uma sentena e no necessrio coloc-las entre chaves ({ e }). A lista de sentenas tambm pode ser
vazia, isto , voc pode no colocar nenhuma sentena seguindo o case.
Tambm no obrigatrio colocar o default. S o use quando for necessrio.
Note no diagrama acima que TODAS as sentenas que seguem a constante com o valor igual ao da
expresso sero executados. Para que se execute APENAS as sentenas que seguem o case que seja igual
ao valor da expresso precisamos usar a sentena break, que veremos em seguida.
18 A sentena break
O break faz com que todas as sentenas que o seguem dentro da mesma sentena switch sejam ignora-
dos. Ou seja, colocando a sentena break no nal de uma sentena case faz com que as sentenas que
seguem os cases subsequentes no sejam executadas. Em geral, este o comportamento desejado quando
se usa o switch, e cases sem o break no nal so de pouca utilidade. Portanto, o uso de sentenas
case sem o break devem ser evitados e quando utilizados devem ser comentados ao lado com algo como
/
*
continua proxima sentenca - sem break
*
/.
Com a sentena break o diagrama de uxo ca:
83
Note a similaridade com o diagrama da sentena else-if e a diferena com o diagrama da sentena
switch acima.
O prximo programa tem a mesma funo de calculadora do programa anterior, porm utilizando a
sentena switch.
Exemplo 11:
#include <iostream>
using namespace std;
int main( ){
float num1, num2;
char op;
// obtem uma expressao do usuario
cout << "Entre com numero operador numero\n";
cin >> num1 >> op >> num2;
switch (op) {
case +:
cout << " = " << setprecision(2) << num1 + num2;
break;
case -:
cout << " = " << setprecision(2) << num1 - num2;
break;
case
*
:
cout << " = " << setprecision(2) << num1
*
num2;
break;
case /:
cout << " = " << setprecision(2) << num1 / num2;
break;
default:
cout << " Operador invalido.";
break;
84
}
cout << endl;
}
Como mencionado anteriormente, possvel no colocar nenhuma sentena seguindo um case. Isso
til quando diversas sentenas case (diversas constantes) tm a mesma ao.
Por exemplo, podemos modicar o programa acima para aceitar x e X para multiplicao e \ para
diviso. O programa ca ento:
#include <iostream>
using namespace std;
int main( ){
float num1, num2;
char op;
// obtem uma expressao do usuario
cout << "Entre com numero operador numero\n";
cin >> num1 >> op >> num2;
switch (op) {
case +:
cout << " = " << setprecision(2) << num1 + num2;
break;
case -:
cout << " = " << setprecision(2) << num1 - num2;
break;
case
*
:
case x:
case X:
cout << " = " << setprecision(2) << num1
*
num2;
break;
case /:
case \\:
cout << " = " << setprecision(2) << num1 / num2;
break;
default:
cout << " Operador invalido.";
break;
}
cout << endl;
}
Exerccio 2: Ler mes e ano e imprimir o numero de dias do mes no ano digitado.
85
19 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues. Estas estruturas de repeti-
o, tambm conhecidas como laos (do ingls loops). A primeira construo (while) foi vista na Seo 10.
Agora veremos for e de do ... while.
19.1 A Estrutura de Repetio for
Considere o lao while abaixo:
int i;
i = 0; /
*
valor inicial da varivel de controle da repetio
*
/
while (i <= 10) /
*
Testa varivel de controle para saber se haver
repetio ou no do corpo do "while"
*
/
{
....
....
i += 1; /
*
expresso de incremento da varivel de controle da
repetio
*
/
}
Este lao pode ser expresso de forma diferente utilizando a estrutura de repetio for. A estrutura acima
pode ser expressa de forma equivlente com um for da seguinte forma:
int i;
for (i = 0; i <= 10; i += 1)
{
....
....
}
Como pode-se observar, h 4 partes no lao for: inicializao, expresso de teste, expresso de incre-
mento e o corpo do lao. O formato do lao for :
for (inicializao ; expresso de teste ; incremento ){
corpo da repetio
}
A inicializao executada uma nica vez no incio do lao. A expresso teste ento avaliada para
vericar se o lao deve terminar. Caso a expresso seja verdadeira (isto , diferente de Zero), o corpo da
repetio executado. Depois desta execuo, a expresso de incremento executada e o processo repetido
a partir da expresso teste. O corpo da repetio, por sua vez, pode ser uma sentena simples ou composta.
86
Veja abaixo um exemplo simples do lao for:
int contador;
for( contador = 0; contador < 5; contador += 1 )
cout << "contador = " << contador << endl;
cout << "ACABOU !!!!\n";
Sada do programa:
contador = 0
contador = 1
contador = 2
contador = 3
contador = 4
ACABOU !!!!
Se voc examinar cuidadosamente este exemplo, poder ver precisamente o que est acontecendo. Pri-
meiro, a inicializao executada, que a sentena contador = 0. Isso modica o valor da varivel con-
tador para 0. Ento, o teste executado. como 0 < 5 verdadeiro, o lao continua. Assim, o corpo da
repetio executado, imprimindo a primeira linha da sada, contador = 0. Depois disso, o incremento
executado, que a sentena contador++, que altera o valor da varivel contador para 1.
Esta a 1
a
iterao do lao. Ento, o teste executado novamente (como 1 < 5 verdadeiro, o lao
continua), o corpo da repetio mostra contador = 1, e contador incrementado novamente.
Este processo continua at que contador seja 4 e contador = 4 seja impresso. Depois disso, conta-
dor incrementado para 5 e o teste executado. Mas desta vez, 5 < 5 falso, ento o lao no continua.
A execuo do programa continua na sentena que segue o lao (no caso, imprimir a frase ACABOU !!!).
Aps a execuo do lao, a varivel contador tem valor 5.
Ao invs de usar o teste contador < 5, voc poderia tambm ter usado a expresso contador <= 4.
O resultado seria o mesmo. Use a expresso que voc preferir. Outra expresso que tambm poderia ter
sido usada contador != 5. Porm esta expresso torna o programa menos legvel (no to evidente
87
que o valor de contador est sendo incrementado at atingir o valor 5). Alm disso, isso poderia causar
problemas se mudssemos a inicializao para um valor maior que 5. Por exemplo, se a inicializao for
contador = 25 e a expresso teste for contador != 5 o lao nunca terminaria, pois o contador comea com
25 e a cada iterao o valor incrementado, o que nunca tornaria o teste falso.
Tambmpoderamos ao invs de usar contador += 1 como a expresso de incremento, usar ++contador,
contador++ e contador = contador + 1. O resultado seria o mesmo (neste caso, o uso de ps- e pr-
incremento no faz diferena).
Se voc quisesse incrementos de dois, voc poderia escrever contador += 2 (ou contador = contador + 2).
19.1.1 Diversas sentenas dentro de um lao
Como no comando while, o corpo da repetio pode ser denido por uma sentena simples ou composta.
No caso de uma sentena composta (bloco), no se deve esquecer de usar as chaves ( { e }) para delimitar o
bloco da sentena composta.
Em um for tambm podemos ter mais de uma expresso de inicializao ou incremento. Nestes caso,
elas devem ser separadas por vrgula ( ,) o que ilustrado no exemplo abaixo:
Exemplo 1:
#include <iostream>
using namespace std;
int main( ){
int contador, total;
for( contador = 0, total = 0; contador < 10; contador += 1 ){
total += contador;
cout << "contador = " << contador << ", total = " << total << endl;
}
}
Sada:
contador = 0, total = 0
contador = 1, total = 1
contador = 2, total = 3
contador = 3, total = 6
contador = 4, total = 10
contador = 5, total = 15
contador = 6, total = 21
contador = 7, total = 28
contador = 8, total = 36
contador = 9, total = 45
No exemplo acima, contador = 0, total = 0 a inicializao, contador < 10 a expresso teste, e
contador += 1 a expresso de incremento.
Exemplo 2: Um programa que imprime todos os nmeros entre 30 e 5 (nesta ordem) divisveis por 3, e
no nal imprime sua soma.
88
#include <iostream>
#include <iomanip> // Necessrio para uso da funo setw() em cout
using namespace std;
int main( ){
int i, soma;
soma = 0;
for( i = 30; i >= 5; i -= 1 ){
if( (i % 3) == 0 ){
cout << "\t" << setw(2) << i << endl;
soma += i;
}
}
cout << "\t soma = " << soma << endl;
}
Sada do programa:
30
27
24
21
18
15
12
9
6
soma = 162
19.2 Usando while e for
Embora qualquer lao possa ser escrito usando while ou for, a escolha baseada principalmente no estilo.
Por exemplo, se o lao precisa de uma inicializao e um incremento, ento o for geralmente usado. No
caso em que o nmero de repeties no pr-determinado em geral usa-se o while.
Como o comando for:
for( inicializacao; teste; incremento )
sentenca;
equivalente a:
inicializacao;
while( teste ) {
sentenca;
incremento;
};
voc pode escolher o que preferir, a princpio.
89
19.3 A Estrutura de Repetio do...while
H outro comando de repetio em linguagem C++ . O do...while bastante parecido com while, com a
diferena que a expresso de teste avaliada DEPOIS que o corpo da repetio executado.
O formato do do...while :
do
corpo da repetio
while (expresso teste )
O exemplo abaixo usa o do...while:
int contador = 0;
do {
cout << "contador = " << contador << endl;
contador += 1;
} while( contador < 5 );
cout << "ACABOU !!!!\n";
A execuo deste programa idntico ao primeiro exemplo mostrado para o comando while, com a
expresso de teste mudada para o nal.
Sada:
contador = 0
contador = 1
contador = 2
contador = 3
contador = 4
ACABOU !!!!
O do...while usado quando o corpo da repetio deve ser executado pelo menos uma vez. Um exemplo
comum disto o processamento da entrada de um programa.
Exemplo 3: Neste exemplo, o teste do lao baseado no valor digitado pelo usurio. O lao deve ser
executado pelo uma vez antes que o teste sobre o valor seja executado.
#include <iostream>
using namespace std;
90
int main( ){
int num;
cout << "Entre com um numero par:\n";
do{
cin >> num;
} while( num % 2 != 0 );
cout << "Obrigado.\n";
}
Exemplo de execuo:
Entre com um numero par:
3
1
5
4
Obrigado.
Neste caso, o valor da varivel num digitado pelo usurio. Depois disso, o teste executado para
vericar se o nmero par (o teste num % 2 != 0 falso se num par j que o resto da diviso de
qualquer nmero par por 2 zero).
possvel escrever o programa acima usando while:
#include <iostream>
using namespace std;
int main( ){
int num; // Atribui um numero impar a num
cout << "Entre com um numero par:\n";
num = 1;
while( num % 2 != 0 ){
cin >> num;
}
cout << "Obrigado.\n";
}
O problema com este programa que a varivel num deve ser inicializada com um valor que torne
o teste do lao verdadeiro. Neste exemplo, simples encontrar tal valor. Para uma expresso teste mais
complicada, isso pode no ser to fcil.
20 A sentena break
Em uma estrutura de repetio, o break faz com que todas as sentenas que o seguem dentro sejam igno-
rados. Alm disso, o break tambm TERMINA a repetio, fazendo com que o programa continue sua
execuo APS o bloco da repetio. A expresso da repetio e a reinicializao (no caso do for) no
so avaliadas aps a execuo de um break.
91
21 A sentena continue
Em uma estrutura de repetio, o continue faz com que todas as sentenas que o seguem sejam ignorados.
Alm disso, esta sentena faz com que a reinicializao e a expresso da repetio sejam avaliadas e a
execuo do bloco de repetio iniciado novamente.
Essencialmente, o continue signica ignore o restante do bloco de repetio e parta para a prxima
interao.
92
22 Tipo Enumerado
Em muitos programas, variveis do tipo int so utilizadas no por suas propriedades numricas, mas para
representar uma escolha dentre um pequeno nmero de alternativas. Por exemplo:
int sexo; // masculino = 1 , feminino = 2
int cor; // vermelho = 1 , amarelo = 2 , verde = 3
A utilizao de cdigos para representar os valores que uma varivel poder assumir, certamente com-
promete a clareza da estrutura de dados do programa, tornando sua lgica obscura e inconsistente. Por
exemplo:
cor = 3;
if( sexo == 2 ) ...
cor = cor + sexo;
for( cor = 1; cor < 10; cor ++ )...
Um tipo enumerado permite denir uma lista de valores que uma varivel deste tipo poder assumir. A
denio de um tipo enumerado feita da seguinte forma:
enum Nome_do_tipo { valor
1
, valor
2
, . . ., valor
n
};
Exemplos de denio de tipos enumerados:
enum TpCores {VERMELHO, AMARELO, VERDE};
enum TpDias {SEG, TER, QUA, QUI, SEX, SAB, DOM};
enum TpSexos {MASCULINO, FEMININO};
Variveis destes tipos so denidas da seguinte forma:
enum TpCores var1, var2;
enum TpDias var3;
Agora, possvel dar valores a estas variveis, por exemplo:
var1 = AMARELO;
var3 = QUI;
um erro usar valores no denidos na declarao do tipo. A expresso var2 = AZUL; causa erro de
compilao.
Internamente, o compilador trata variveis enumeradas como inteiros. Cada valor na lista de valores
possveis corresponde a um inteiro, comeando com 0 (zero). Portanto, no exemplo enum TpCores,
VERMELHO armazenado como 0, AMARELO armazenado como 1, e VERDE armazenado como 2.
Utilizao de tipos enumerados
Variveis de tipos enumerados so geralmente usados para claricar a operao do programa. Considere
o seguinte trecho de programa que codica dias da semana como inteiros (sendo sabado = 5 e domingo
= 6) para vericar se o dia do pagamento cai no nal de semana e altera a dia para a segunda-feira seguinte.
#include <iostream>
using namespace std;
// prototipo da funcao que dada a data, retorna o dia da semana.
// seg=0, ter=1, qua=2, qui=3, sex=4, sab=5, dom=6
93
int diaDaSemana( int dia, int mes, int ano );
int main(){
int diaPgto, mesPgto, anoPgto;
int diaSem;
cout << "Entre com a data de pagamento (dd mm aa): ";
cin >> diaPgto >> mesPgto >> anoPgto;
diaSem = diaDaSemana( diaPgto, mesPgto, anoPgto );
if( diaSem == 5 )
diaPgto = diaPgto + 2;
else if( diaSem == 6 )
diaPgto++;
cout << "Data do pagamento: " << diaPgto << "/" << mesPgto << "/"
<< anoPgto << endl;
}
Este programa caria mais legvel se ao invs de codicar os dias da semana como inteiros e colocar a
codicao como comentrio, utilizar tipos enumerados. O programa caria ento
#include <iostream>
using namespace std;
enum TpSemana {SEG, TER, QUA, QUI, SEX, SAB, DOM};
// prototipo da funcao que dada a data, retorna o dia da semana
enum TpSemana diaDaSemana( int dia, int mes, int ano );
int main(){
int diaPgto, mesPgto, anoPgto;
int diaSem;
cout << "Entre com a data de pagamento (dd mm aa): ";
cin >> diaPgto >> mesPgto >> anoPgto;
diaSem = diaDaSemana( diaPgto, mesPgto, anoPgto );
if( diaSem == SAB )
diaPgto = diaPgto + 2;
else if( diaSem == DOM )
diaPgto++;
cout << "Data do pagamento: " << diaPgto << "/" << mesPgto << "/"
<< anoPgto << endl;
}
Note que a funo diaDaSemana agora retorna apenas um dos valores da lista SEG, TER, QUA,
QUI, SEX, SAB, DOM e portanto, no programa principal ao invs de testar se o diaSem == 5 pode-
mos escrever diaSem == SAB, o que torna o programa muito mais legvel.
94
23 Mais sobre funes
A nfase aqui ser em como funes funcionam. O que acontece quando uma funo chamada ? A que
varivel um nome est se referenciando?
O tratamento em tempo de execuo de um nome de varivel em C++ simples: um nome de varivel
ou uma varivel local (a funo) ou uma varivel global (denida fora de qualquer funo).
Em C++ , todas as funes tem que ser denidas. Para cada funo deve ser denido um prottipo. O
prottipo escrito fora de qualquer funo. Desta forma, nomes de funes so visveis para todas as outras
funes que podem ento invoc-las. A funo main() especial: onde a execuo do programa comea,
e o prottipo de main() pode ser omitido.
Uma denio de funo consiste de quatro partes:
1. o nome da funo;
2. a lista de parmetros formais (argumentos) com seus nomes e tipos. Se no houver argumentos, a
palavra void escrita entre os parnteses.
3. o tipo do resultado que a funo retorna atravs da sentena return ou void se a funo no retorna
nenhum valor. Lembre-se que somente um valor pode ser retornado por uma sentena return.
4. o corpo da funo, que uma sentena composta (comea e termina com chaves ({ }) contendo
denio de variveis e outras sentenas. Em C++ , no se pode denir uma funo dentro de outra.
Para funes com argumentos: uma funo chamada dando o seu nome e uma lista de argumentos
(expresses que so avaliadas e cujos valores so atribudos para os correspondentes parmetros formais da
funo).
Por exemplo, suponha que triang area() e circ area() sejam funes que calculam a rea de
tringulos e crculos, respectivamente. Seus prottipos so:
float triang_area(float , float);
float circ_area(float);
Estas funes podem chamadas de dentro de outras funes. Os argumentos reais com os quais elas so
chamadas podem ser expresses constantes, or variveis locais, ou qualquer expresso cuja avaliao resulte
em valores do tipo float (inteiros so convertidos para float da mesma forma que ocorre com atribuio
de inteiros para variveis do tipo float). Alguns exemplos de chamadas:
float area2, area3, area4, area5, base, altura, raio;
cout << "area do triangulo = " << triang_area(0.03, 1.25);
base = 0.03;
altura = 1.25;
area2 = triang_area(base, altura);
area3 = triang_area(1.6, altura);
area4 = triang_area( 0.03 + base, 2
*
altura);
raio = base + altura;
area5 = triang_area(raio, circ_area(raio));
A ltima sentena do exemplo acima atribui a varivel area5 a rea de um tringulo cuja base igual
ao valor da varivel raio e a altura igual a area de um crculo de raio igual ao valor da varivel raio.
Quando um programa executado, somente uma nica funo tem o controle em determinado momento.
Falaremos mais sobre o que acontece quando uma funo chamada mais tarde nestas notas de aula.
95
Variveis Locais Variveis que so denidas dentro de uma funo so variveis locais desta funo.
Parmetros formais de uma funo so variveis locais da funo. Variveis locais so privativas a
funo na qual so denidas. Somente esta funo pode enxerg-las (ela conhece o endereo das variveis e
pode usar e modicar o seu contedo). Nenhuma outra funo pode acessar variveis locais de outra funo
sem permisso (uma funo pode acessar variveis locais de outra se esta passar o endereo da varivel
local como argumento este assunto ser tratado em notas de aula futuras). O fato de cada funo manter
variveis locais escondidas do resto do mundo torna mais fcil a tarefa de escrever programas estruturados
e modulares. Quando voc est escrevendo uma funo, voc pode dar as suas variveis locais o nome que
quiser. Voc tambm no precisa se preocupar se outra pessoa escrevendo outra funo ter acesso ou altera
variveis locais a sua funo.
Variveis locais que so denidas dentro da funo devem ser inicializadas com algum valor antes
de serem usadas. Caso contrrio, o seu valor indenido.
J que parmetros formais (argumentos) so variveis locais da funo, eles podem ser usados no corpo
da funo. Eles no devem ser denidos dentro da funo (sua denio j est no cabealho da funo). Os
parmetros formais no precisam ser inicializados. Seus valores so fornecidos pelo chamador da funo
atravs dos argumentos reais.
Considere o seguinte exemplo:
/
*****************************************************************
*
Um programa que calcula a area de triangulos e circulos.
*
A base, altura e raio sao fornecidos pelo usuario.
*
A saida do programa e a area do triangulo e circulo.
*****************************************************************
/
#include <iostream>
using namespace std;
#define PI 3.1415
/
*******************
prototipos
*******************
/
float triang_area(float, float);
float circ_area(float);
/
*******************
definicao de funcoes
*******************
/
main()
{
/
*
definicao das variaveis locais
*
/
float base, altura, raio;
/
*
dialogo de entrada
*
/
cout << "\nEntre com a base e altura do triangulo: ";
cin >> base >> altura;
cout << "\nEntre com o raio do circulo: ";
cin >> raio;
/
*
chama as funcoes e imprime o resultado
*
/
96
cout << "Area do triagulo com base e altura " << base << " e "
<< altura << " = " << triang_area(base, altura) << endl;;
cout << "Area do circulo com raio " << raio
<< " = " << circ_area(raio) << endl;
}
/
*****************************************************************
*
funcao: triang_area
*
calcula a area de um triangulo dada a base e altura
*
Entrada: base e altura do triangulo
*
Saida: area do triangulo
*****************************************************************
/
float triang_area(float base, float alt)
{
return 0.5
*
base
*
alt;
}
/
*****************************************************************
*
funcao: circ_area
*
calcula a area de um circulo dado o raio
*
Entrada: raio do circulo
*
Saida: area do circulo
*****************************************************************
/
float circ_area(float r)
{
return PI
*
r
*
r;
}
Este programa C++ consiste de trs funes, main(), triang_area(), e circ_area(). main()
tem variveis locais chamadas base, altura e raio; triang_area() tem como variveis locai seus
parmetros formais, base e alt; circ_area() tem como varivel local seu parmetro formal r.
Em geral, uma varivel local s existe durante a execuo da funo na qual ela est denida. Portanto,
variveis locais existem desde o momento que a funo chamada at o momento em que a funo
completada. Tais variveis so chamadas de automatic. Em C++ , uma varivel pode ser denida como
sendo static. Neste caso, uma varivel local no visvel de fora do corpo da funo, mas ela no
destruda no nal da funo como variveis automticas so. Cada vez que a funo chamada, o valor das
variveis static o valor nal da varivel da chamada anterior.
Variveis Globais
At este momento, todas as variveis que vimos so denidas dentro de funes (no corpo da funo
ou como parmetros formais). possvel tambm denir variveis fora das funes. Tais variveis so
chamadas de variveis globais ou externas. O formato da denio de variveis globais o mesmo da
denio de variveis locais. A nica diferena onde a varivel denida: variveis globais so denidas
fora de qualquer funo. Ao contrrio das variveis locais, variveis globais podem ser vistas por todas as
funes denidas aps a denio das variveis globais.
Ns temos usado declaraes globais este tempo todo por exemplo, as declaraes de prottipos de
funes. Elas so declaradas fora de qualquer funo e podem ser vistas por qualquer funo que esto aps
sua declarao.
No exemplo seguinte, uma varivel saldo que atualizada por trs funes diferentes denida como
uma varivel global. As trs funes que a atualizam no chamam uma a outra.
97
/
*****************************************************************
*
Caixa eletronico simples
*
o saldo e o valor a ser alterado e entrado pelo usuario
*
a saida do programa e o saldo atualizado, incluindo juros
*****************************************************************
/
#include <iostream>
using namespace std;
#define JUROS 0.07
/
*******************
prototipos
*******************
/
void credito(float);
void debito(float);
void juros(void);
/
*******************
globais
*******************
/
float saldo; /
*
saldo atual;
*
Alterada em: credito(), debito(), juros(), main()
*
Lida em:
*
/
/
***********************
definicao de funcoes
***********************
/
main()
{
float valor; // valor a ser depositado/retirado
cout << "Entre com o saldo atual: ";
cin >> saldo;
cout << "Deposito: ";
cin >> valor;
credito(valor);
cout << "Retirada: ";
cin >> valor;
debito(valor);
juros();
cout << "Juros " << JUROS
*
100 << "%.\n";
cout << "Saldo = " << saldo << endl;
}
/
*****************************************************************
*
Deposita um valor; atualiza a variavel global saldo
98
*
Entrada: valor a ser depositado
*
Saida: nenhum
*****************************************************************
/
void credito(float val)
{
saldo += val;
}
/
*****************************************************************
*
Debita um valor; atualiza a variavel global saldo
*
Entrada: valor a ser debitado
*
Saida: nenhum
*****************************************************************
/
void debito(float val)
{
saldo -= val;
}
/
*****************************************************************
*
Acumula juros; atualiza a variavel global saldo; juros: RATE
*
Entrada: nenhuma
*
Saida: nenhuma
*****************************************************************
/
void juros(void)
{
saldo += (saldo
*
JUROS);
}
Um exemplo de execuo do programa:
Entre com o saldo atual: 1000
Deposito: 200
Retirada: 80
Juros 7%.
Saldo = 1198.40
Variveis globais devem ser usadas SOMENTE quando muitas funes usam muito as mesmas vari-
veis. No entanto, o uso de variveis globais perigoso (e no recomendado) porque a modularidade do
programa pode ser afetada. Uma varivel global pode ser alterada de dentro de uma funo, e esta alterao
pode inuir no resultado de uma outra funo, tornando-a incorreta (em um exemplo dado posteriormente
nestas notas, duas chamadas a funo soma_y() com o mesmo argumento (zero) produz resultados dife-
rentes, 100 e 300).
Quando variveis globais so utilizadas, deve ser dado a elas nomes descritivos e um breve comentrio
qual a nalidade da varivel e quais funes a acessam.
Neste curso, voc utilizar variveis globais SOMENTE QUANDO FOR DADO PERMISSO PARA
FAZ-LO. Caso contrrio, no permitido utiliz-las (ou seja, sero descontados pontos).
Escopo de Variveis
99
Como j discutimos anteriormente, uma varivel uma abstrao de dados que ns usamos em um
programa. A varivel representa um endereo de memria onde os valores so armazenados. Durante a
execuo do programa, valores diferentes poder ser armazenados neste endereo. Quando uma varivel
denida, o nome da varivel atrelada a um endereo especco na memria. At este momento, j
discutimos o que o nome de uma varivel, seu endereo, tipo e valor. Outra caracterstica que apresenta-
resmo agora o escopo. O escopo de uma varivel refere-se a parte do programa onde podemos utilizar a
varivel. Em outras, palavras, uma varivel visvel dentro do seu escopo.
O escopo de uma varivel local a funo na qual ela denida. Os parmetros formais de uma funo
tambm so tratados como variveis locais.
O escopo de uma varivel global a poro do programa depois da denio da varivel global (a partir
do ponto onde ela denida at o nal do programa).
Se o nome de uma varivel global idntico a uma varivel local de uma funo, ento dentro desta
funo em particular, o nome refere-se a varivel local. (Embora tais conitos devem ser evitados para
evitar confuso).
Por exemplo, considere o seguinte programa:
int valor = 3; /
*
definicao da variavel global
*
/
int main()
{
/
*
definicao local de valor
*
/
int valor = 4;
cout << valor << endl;
}
A sada do programa acima ser 4 j que valor refere-se a denio local.
Considere outro exemplo:
#include <iostream>
using namespace std;
int soma_y(int);
int soma_yy(int);
int y = 100; // variavel global
main()
{
int z = 0; // variavel local
cout << soma_y(z) << endl;
cout << soma_yy(z) << endl;
cout << soma_y(z) << endl;
}
int soma_y(int x)
{
return x + y; // x e variavel local, y e global
}
int soma_yy(int x)
{
100
y = 300; // y e variavel global
return x + y; // x e variavel local
}
Vamos seguir a execuo deste programa. Primeiro, a varivel global y criada e inicializada com 100.
Ento, a execuo da funo main() comeca: alocado espao na memria para a varivel local z. Esta
varivel inicializada com 0. Considere a primeira sentena cout :
cout << soma_y(z) << endl;
Esta uma chamada para cout . Os parmetros reais desta chamada a expresso soma_y(z).
Ela consiste da chamada da funo soma_y(). O valor desta expresso o resultado retornado por
soma_y(). Qual o resultado? A funo soma_y chamada com o parmetro real z. Como z = 0,
este o valor que ser passado para a funo soma_y; o 0 copiado para o parmetro formal x da funo
soma_y(). Portanto, durante a excuo da primeira chamada a funo soma_y(), o valor da expresso x
+ y ser 0 + 100, que 100. Portanto, o valor da primeira chamada soma_ y(z) 100, e este nmero
ser impresso com o primeiro cout em main(). Agora considere a segunda sentena:
cout << soma_yy(z) << endl;
Quando a funo soma_yy(z) chamada, o valor de z (a varivel local z) ainda 0, portanto
novamente 0 copiado para o parmetro formal int x da funo soma_yy. Quando a execuo de
soma_yy() comea, ela primeiro troca o valor da varivel global y para 300 e ento retorna o valor de x
+ y, que neste caso 0 + 300. Portanto, o valor desta chamada a soma_yy(z) 300, e este nmero
ser impresso pelo segundo cout em main().
Por ltimo, considere a terceira sentena:
cout << soma_y(z) << endl;
Quando a funo soma_y(z) chamada, o valor de z ainda 0, portanto, 0 copiada para o parmetro
formal int x da funo soma_y(). Quando soma_ y() executada pela segunda vez, a varivel
global y foi modicada para 300, portanto o valor de x + y 0 + 300. Portanto, o valor da chamada
soma_yy(z) 300, e este nmero ser impresso pelo terceiro cout em main().
Portanto, a sada da execuo deste programa ser
100
300
300
Neste exemplo, o escopo da varivel global y o programa todo.
Oescopo da varivel local z, denida dentro de maio o corpo da funo main. Oescopo do parmetro
formal x da funo soma_y o corpo de soma_y. O escopo do parmetro formal x da funo soma_yy
o corpo de soma_yy.
23.1 Outro exemplo
Aqui apresentamos um exemplo de uma funo mais complicada. Esta funo calcula a raiz quadrada
inteira de um nmero (o maior inteiro menor ou igual a raiz quadrada do nmero).
Este programa usa o algoritmo divide e calcula mdia (uma aplicao do mtodo de Newton). Ele
executa o seguinte:
Dado x, achar

x computando sucessivamente
101
a
n
=

1 se n = 0
x
a
n1
+a
n1
2
caso contrrio
para todo n N
Os valores de a
n
convergem para

x a medida que n cresce.


Para achar a raiz quadrada inteira, este algoritmo repetido at que
a
2
n
x < (a
n
+ 1)
2
Por exemplo, para achar a raiz quadrada inteira de 42 (usando diviso inteira que trunca a parte fracional
do nmero)
a
0
= 1, a
1
= (42/1 + 1)/2 = 21, a
2
= (42/21 + 21)/2 = 11, a
3
= (42/11 + 11)/2 = 7, a
4
=
(42/7 + 7)/2 = 6.
Uma vez que a
2
4
= 6
2
= 36 42 < (a
4
+ 1)
2
= 7
2
= 49, o processo termina e a resposta 6.
(No necessrio voc entender por que este algoritmo funciona portanto no se preocupe se no
conseguir entend-lo)
102
int raizInteira(int); /
*
prototipo
*
/
/
**************************************************************
*
function: raizInteira(x)
*
acao: dado x, retorna a raiz quadrada inteira de x
*
in: inteiro positivo x
*
out: raiz quadrada inteira de x
*
suposicoes: x >= 0
*
algoritmo: metodo de dividr e calcular media: comecando com
*
um palpite de 1, o proximo palpite e calculado como
*
(x/palpite_ant + palpite_ant)/2. Isso e repetido
*
ate que palpite^2 <= x < (palpite+1)^2
***************************************************************
/
int raizInteira(int x)
{
int palpite = 1;
/
*
Continue ate que o palpite esteja correto
*
/
while (!(x >= palpite
*
palpite && x < (palpite+1)
*
(palpite+1))) {
/
*
Calcula proximo palpite
*
/
palpite = (x/palpite + palpite) / 2;
}
return palpite;
}
Note que usando a lei de DeMorgan, podemos re-escrever a expresso teste do while em uma forma
equivalente:
x < palpite
*
palpite || x >= (palpite + 1)
*
(palpite + 1)
Deve estar claro neste ponto a diferenca entre ao e algoritmo. Uma pessoa que quer usar esta funo
precisa saber somente a ao, no o algoritmo. tambm importante especicar os dados que so esperados
pela funo e retornados por ela para outras pessoas poderem us-la. As suposies devem esclarecer as
restries da funo sobre quando a funo pode falhar ou produzir resultados errados. Neste caso, um
nmero negativo produziria um erro, j que nmeros negativos no possuem raiz quadrada.
No h necessidade de ir em muitos detalhes em qualquer parte da documentao da funo. Embora ela
deva conter informao suciente para que algum (que no possa ver o cdigo) saber utiliz-la. Detalhes
sobre implementao e detalhes menores sobre o algoritmo devem ser colocados como comentrios no
prprio cdigo.
24 Ativao de funo
Uma funo comea sua execuo assim que for chamada. Cada execuo da funo chamada de ativao
da funo. Como j mencionamos em notas de aula anteriores, variveis locais so locais a ativao da
funo: cada ativao possui suas prprias variveis locais. No comeo da ativao, memria alocada para
as variveis locais e no nal da execuo, elas so dealocadas.
Denies de funes em C++ no podem ser aninhadas, mas ativaes de funo podem: uma funo,
digamos A, pode chamar uma outra funo, digamos B (dizemos que A chama B). Nos referimos a A como
o chamador e B como a funo chamada.
103
O que acontece quando uma funo chama outra (quando A chama B)? Um registro especial, chamado
registro de ativao criado. A informao neste registro necessria para a ativao da funo chamada e
para a reativao do chamador depois que a execuo da funo chamada termina.
1. C++ usa chamada-por-valor, ou seja, o chamador avalia as expresses que so os parmetros reais e
passa seus valores para a funo chamada.
2. A informao necessria para reiniciar a execuo da funo chamadora guardada em um registro
de ativao. Tal informao inclui o endereo da instruo do chamador que ser executada depois
que a funo chamada termine.
3. A funo chamada aloca espao na memria para suas variveis locais.
4. O corpo da funo chamada executado.
5. O valor retornado para a funo chamadora atravs de um return colocado em um lugar especial
para que a funo chamadora possa encontr-lo. O controle retorna a funo chamadora.
O uxo de controle atravs de ativao de funes da forma ltimo-que-entra-primeiro-que-sai. Se A
chama B e B chama C: A ativado primeiro, ento B ativado (um registro de ativao para A chama B
criado e armazenado, A temporariamente suspenso), ento C ativado (um registro de ativao de B
chama C criado e armazenado, A e B so suspensos); C o ltimo a iniciar execuo, mas o primeiro a
terminar (ltimo-a-entrar-primeiro-a-sair). Depois que C termina, B reativado. O registro de ativao B
chama C foi criado por ltimo, mas o primeiro a ser destrudo (no momento que o controle retornada para
B). Depois que B termina, A reativado. O registro de ativao correspondente a A chama B destrudo
no momento em que o controle retorna para A.
104
25 Array de Caracteres
Nas notas de aula anteriores, enfatizamos arrays de nmeros. Em geral, podemos ter arrays com elementos
de qualquer um dos tipos vistos at agora (incluindo arrays visto nas notas de aula 9). Nesta seo,
apresentaremos arrays com elementos do tipo char, usados para representar textos em programas.
Abaixo, apresentamos um exemplo de programa que dene e inicializa um array de caracteres, e depois
imprime o array em ordem reversa.
#include <iostream>
using namespace std;
int main()
{
char arr1[] = {c,i,2,0,8};
int i;
for (i = 4; i >= 0; i -= 1)
cout << arr1[i];
}
Arrays de caracteres so usados para armazenar texto, mas muito inconveniente se tivermos que colocar
cada caractere entre apstrofes. A alternativa dada pela linguagem C++
char arr2[] = "ci208" ;
Neste caso, ci208 um string de caracteres ou uma constante do tipo string. Ns j usamos strings
antes, com as funes cout (constantes do tipo string esto sempre entre aspas - "):
cout << "Entre com a nota para o estudante 2: ";
cin >> gr2;
26 Strings como array de caracteres
Strings so essencialmente arrays de caracteres (arrays com elementos do tipo char) que DEVEM terminar
com \0. Normalmente conveniente denir a constante NULO em seu programa para representar este
terminador: #define NULO \0.
No exemplo acima, embora no tenhamos escrito explicitamente o caracter NULO, o compilador au-
tomaticamente o colocou como o ltimo elemento do array arr2[]. Portanto, o tamanho de arr2[]
6: 5 para os caracteres que indicamos (ci208) e 1 para o caractere NULO que o compilador introduziu
automaticamente. As denies abaixo so equivalentes.
char arr2[] = {c,i, , 2,0,8,\0};
char arr2[] = {c,i, , 2,0,8, NULO};
O caractere NULO marca o nal de um string.
Outros exemplos:
// a maneira tediosa
char name1[] = { j,o,s,e, ,s,i,l,v,a,\0 };
// e a maneira facil
char name2[] = "jose silva";
105
Embora o primeiro exemplo seja um string, o segundo exemplo mostra como strings so geralmente
escritos (como constantes). Note que se voc usar aspas quando escreve uma constante, voc no precisa
colocar \0, porque o compilador faz isso para voc.
Quando voc for criar um array de caracteres de um tamanho especco, lembre-se de adicionar 1 para o
tamanho mximo de caracteres esperado para armazenar o caractere NULO. Por exemplo, para armazenar o
string programar eh divertido, voc precisa de um array de tamanho 22 (21 caracteres + 1 para
o NULO).
26.1 Imprimindo strings com cout
Strings podem ser impressos usando cout . Por exemplo:
int main()
{
char mensagem[] = "tchau";
cout << "ola" << endl << mensagem << endl;
}
A sada deste programa :
ola
tchau
26.2 Lendo strings do teclado com cin.getline() e cin
A funo cin.getline() l uma linha de texto digitado no teclado e a armazena em um vetor indicado
como primeiro argumento. O segundo argumento da funo indica o nmero mximo de caracteres que ser
lido. Veja o exemplo abaixo:
#include <iostream>
using namespace std;
int main()
{
char nome[100];
cout << "Entre seu nome: ";
cin.getline (nome, 100);
cout << "Oi, " << nome << "." << endl ;
}
Exemplo de execuo
Entre seu nome: Jose Silva
Oi, Jose Silva.
Passando um nome de array para a funo cin.getline(), como ilustrado no programa acima,
coloca a linha inteira digitada pelo usurio no array nome (tudo ou mximo de 99 caracteres at que seja
teclado enter). Note que se o usurio digitar caracteres demais (neste caso, mais de 99 caracteres), apenas
os primeiros 99 caracteres digitados sero copiados para o array indicado no primeiro argumento da funo.
A funo cin pode ser usada de maneira similar. A nica diferena que cin l somente a primeira
palavra (tudo at que se digite um separador um espao em branco, tabulao, ou enter).
106
#include <iostream>
using namespace std;
int main()
{
char nome[100];
cout << "Entre seu nome: ";
cin >> nome;
cout << "Oi, " << nome << "." << endl;
}
Exemplo de execuo
Entre seu nome: Jose Silva
Oi, Jose.
Note que somente o primeiro nome lido pelo cin porque a funo pra no primeiro espao em branco
que encontra (enquanto cin.getline() pra quando encontra um enter).
26.3 Array de Strings
Em notas de aula anteriores, vimos alguns exemplos de arrays de arrays (matrizes ou tabelas). Como strings
so tambm arrays, podemos denir arrays de strings. O programa abaixo inicializa um array de strings
com nomes e os imprime.
#include <iostream>
using namespace std;
#define NUM_NOMES 5 // define a quantidade de nomes no array
#define TAM 20 // define o tamanho maximo do nome
int main()
{
char nomes[NUM_NOMES][TAM] = {"Jose Silva",
"Maria Silva",
"Antonio dos Santos",
"Pedro dos Santos",
"Joao da Silva"};
int i;
for(i = 0; i < 5; i++)
cout << nomes[i] << endl;
}
A sada deste programa :
Jose Silva
Maria Silva
Antonio dos Santos
Pedro dos Santos
Joao da Silva
107
26.4 Funes de String
H funes para manipulao de string j denidas na biblioteca padro C++ chamada cstring. Todas as
funes que apresentaremos nesta seo so parte desta biblioteca. Portanto, se seu programa utilizar uma
destas funes voc deve incluir a linha #include <cstring> no incio do seu programa.
O objetivo desta seo mostrar como estas funes poderiam ser implementadas como exemplos de
programas de manipulao de strings.
26.4.1 A funo strlen()
A funo strlen() tem como argumento um string. Ela retorna um inteiro que o comprimento do
string (o nmero de caracteres do string, no contando o caractere NULL). Por exemplo, o comprimento do
string alo 3.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char nome[100];
int comprimento;
cout << "Entre seu nome: ";
cin.getline(nome, 100);
comprimento = strlen(nome);
cout << "Seu nome tem " << comprimento << " caracteres." << endl;
}
Um exemplo de execuo:
Entre seu nome: Dostoevsky
Seu nome tem 10 caracteres.
Abaixo, mostramos como a funo strlen() poderia ser implementada.
int strlen( char str[] )
{
int comprimento = 0;
while ( str[comprimento] != NULL )
++comprimento;
return comprimento;
}
26.4.2 A funo strcmp()
A funo strcmp() usada para comparar dois strings. Lembre que no podemos usar ==, como em
str1 == str2, para comparar dois strings, uma vez que strings so arrays. Strings devem ser compara-
dos caractere por caractere. A funo strcmp() tem como argumento dois strings e retorna um inteiro.
108
Strings so ordenados de forma similar a maneira como palavras so ordenadas em um dicionrio. Orde-
namos palavras em um dicionrio alfabeticamente, e ordenamos strings respeitando a ordem dos caracteres
no conjunto de caracteres da mquina. A ordenao abaixo vlida em qualquer computador:
0 < 1 < ... < 8 < 9
A < B < ... < Y < Z
a < b < ... < y < z
A ordem relativa do trs conjuntos (dgitos, letras maisculas e letras minsculas) depende do computador
utilizado.
Se s1 e s2 so strings, o resultado da chamada de funo strcmp(s1, s2) :
se s1 =
s
s2, strcmp() retorna 0
se s1 <
s
s2, strcmp() retorna um nmero negativo (< 0)
se s1 >
s
s2, strcmp() retorna um inteiro positivo (> 0)
(onde =
s
, <
s
e >
s
so =, < e > para strings)
s1 <
s
s2 signica s1 vem antes de s2 no dicionrio. Exemplos: tudo menor que xadrez,
calor menor que calorao, frio menor que quente, e claro o string vazio , NULL,
menor que qualquer string.
Considere o exemplo abaixo que usa strcmp():
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char palavra1[100], palavra2[100];
int resultado;
cout << "entre com uma palavra: ";
cin >> palavra1;
cout << "entre outra palavra: ";
cin >> palavra2;
resultado = strcmp(palavra1, palavra2);
if (resultado == 0)
cout << "igual" << endl;
else if (resultado > 0)
cout << "o primeiro e maior" << endl;
else
cout << "o segundo e maior" << endl;
}
Aqui est um exemplo de como a funo strcmp() poderia ser implementada.
int strcmp( char s1[], char s2[] )
{
int i = 0;
while (1)
{
109
if (s1[i] == NULL && s2[i] == NULL)
return 0;
else if (s1[i] == NULL)
return -1;
else if (s2[i] == NULL)
return 1;
else if (s1[i] < s2[i])
return -1;
else if (s1[i] > s2[i])
return 1;
else
++i;
}
}
Na biblioteca padro, a funo strcmp() faz distino entre letras maisculas e minsculas. Se voc
no quer que a funo faa esta distino, voc pode modicar o seu string para ter apenas letras minsculas
(ou maisculas) antes de pass-lo como argumento para a funo strcmp(). Para fazer isso, voc pode
usar a funo da biblioteca padro tolower(), que tem como argumento um caractere. Se o caractere
passado uma letra maiscula, ele retorna esta letra minscula; caso contrrio, retorna o mesmo caractere.
Por exemplo: tolower(A) a, tolower(1) 1, tolower(a) a.
26.4.3 A funo strcpy()
A funo strcpy() usada para copiar o contedo de um string para outro. Ela tem dois argumentos:
strcpy(s1, s2) copia o contedo do string s2 para o string s1. A funo strcpy() que apresenta-
mos abaixo no retorna um valor. Seu prottipo
void strcmp(char [], char []);
O exemplo abaixo mostra a utilizao do strcpy().
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char pal[100], palCopia[100];
cout << "entre com uma palavra: ";
cin >> pal;
strcpy(palCopia, pal);
cout << "entre outra palavra: ";
cin >> pal;
cout << "voce entrou primeiro: " << palCopia << endl;
}
Embora este programa pudesse ter sido escrito sem usar strcpy(), o objetivo mostrar que se pode
usar strcpy() para fazer atribuio de strings.
A funo strcpy() poderia ter sido implementada da seguinte forma:
110
void strcpy( char s1[], char s2[] )
{
int i = 0;
while ( s2[i] != NULL )
{
s1[i] = s2[i];
++i;
}
s1[i] = s2[i];
}
27 O tipo String
Em C++ possvel uma forma alternativa de lidar com textos, usando a classe String.
111
28 Estruturas
A estrutura de dados array usada para conter dados do mesmo tipo junto. Dados de tipos diferentes
tambm podem ser agregados em tipos chamados de estruturas ou registros (tipo struct em linguagem
C). Primeiro, o tipo estrutura declarado (precisamos especicar que tipos de variveis sero combinados
na estrutura), e ento variveis deste novo tipo podem ser denidas (de maneira similar que usamos para
denir variveis do tipo int ou char).
28.1 Declarao de Estruturas
Uma declarao de estrutura declara um tipo struct. Cada tipo struct recebe um nome (ou tag). Refere-
se quele tipo pelo nome precedido pela palavra struct. Cada unidade de dados na estrutura chamada
membro e possui um nome de membro. Os membros de uma estrutura podem ser de qualquer tipo. Declara-
es de estrutura no so denies. No alocada memria, simplesmente introduzida um novo tipo de
estrutura.
Geralmente declaraes de estruturas so globais. Elas so colocadas prximas ao topo do arquivo com
o cdigo fonte do programa, assim elas so visveis por todas as funes (embora isto dependa de como a
estrutura est sendo usada).
A forma padro de declarao de uma estrutura :
struct nome-estrutura {
declarao dos membros
} denio de variveis (optional);
Abaixo se apresenta um exemplo de um tipo estrutura que contm um membro do tipo int e um outro
membro do tipo char.
struct facil {
int num;
char ch;
};
Esta declaracao cria um novo tipo chamado struct facil que contm um inteiro chamado num e
um caracter chamado ch.
28.2 Denio de variveis de um tipo estrutura declarado
Como acontece com qualquer outro tipo de dados, variveis de tipos de estruturas so denidas fornecendo
o nome do tipo e o nome da varivel. Considere a denio abaixo relativa a uma varivel com o nome
fac1 que do tipo struct facil:
struct facil fac1;
Tal denio est associada com a alocao de memria: memria suciente ser alocada para guardar
um int e um char (nesta ordem). Como qualquer outra varivel, fac1 tem um nome, um tipo, e um
endereo associados.
Variveis de estruturas possuem tambm valores, e como outras variveis locais, se elas no tem atribu-
das um valor especco, seu valor indenido.
possvel denir variveis durente a declarao do tipo estrutura:
struct facil {
int num;
char ch;
} fac1;
112
Note-se que sem conito, nomes de membros (tais como num e ch) podem ser usados como nomes de
outras variveis independentes (fora do tipo estrutura denido) or como nomes de membros em outros tipos
estrutura. No entanto, deve-se evitar situaes que criem confuso.
28.3 Acesso a membros de uma estrutura: ponto (.), o operador membro de estrutura
Dada uma varivel de estrutura, um membro especco referenciado usando o nome da varivel seguida de
. (ponto) e pelo nome do membro da estrutura. Assim, as seguintes referncias a membros de uma estrutura
so vlidas:
fac1.num se refere ao membro com nome num na estrutura fac1;
fac1.ch se refere ao membro com nome ch na estrutura fac1.
Membros de estrutura (como fac1.num) so variveis, e podem ser usadas como valores (no lado
direito de uma atribuio, emexpresses como argumentos para funes), ou como lvalues (no lado esquerdo
de atribuies, com operadores de incremento/decremento ou com o operador de endereo (&)). O exemplo
abaixo mostra alguns exemplos do uso de membros de estrutura:
fac1.ch = G;
fac1.num = 42;
fac1.num++;
if (fac1.ch == H) {
cout << fac1.num << endl;
}
Tentar acessar um nome de membro que no existe causa um erro de compilao.
28.4 Operadores usados com variveis de estrutura: valores e lvalues
Uma varivel de estrutura pode ser tratada como um objeto simples no todo, com um valor especco
associado a ela (a estrutura fac1 tem um valor que agrega valores de todos os seus membros). Note a
diferena com arrays: se arr[] um array de tamanho 2 denedo como int arr[2] = {0,1};,
o nome arr2 no se refere ao valor coletivo de todos os elementos do array. Na verdade, arr2 um
apontador constante e se refere ao endereo de memria onde o array se inicia. Alm disso arr2 no um
lvalue e no pode ser mudado. Variveis de estrutura so diferentes. Elas podem ser usadas como valores e
lvalues, mas com certas limitaes.
Os nicos usos vlidos de uma varivel de estrutura so dos dois lados de um operador de atribui-
o (=), como operando do operador de endereo & (obtendo o endereo da estrutura), e referenciando
seus membros.
De todas as variaes de atribuio (incluindo o incremento e decremento) atribuio de estruturas pode
ser usada APENAS com =. O uso de outros operadores de atribuio ou de incremento causar um erro de
compilao A atribuio de um valor de estrutura para outro copia todos os membros de uma estrutura para
outra. Mesmo que um dos membros seja um array ou outra estrutura, ela copiada integralmente. As duas
estruturas envolvidas na atribuio devem ser do mesto tipo struct. Considere o seguinte exemplo:
struct facil {
int num;
char ch;
};
void main(void)
{
113
struct facil fac1, fac2;
fac1.num = 3;
fac1.ch = C;
/
*
Atribuindo fac1 a fac2
*
/
fac2 = fac1;
}
Lembre-se que este tipo de atribuio ilegal com arrays. Tentar fazer isto com dois arrays causa um
erro de compilao (uma vez que nomes de arrays so apontadores constantes).
int a[5], b[5];
/
*
Est errado -- No ir compilar
*
/
a = b;
28.5 Inicializao de estruturas
Variveis de estruturas no-inicializadas contm valores indenidos em cada um de seus membros. Como
em outras variveis, variveis de estruturas podem ser inicializadas ao serem declaradas. Esta inicializao
anloga ao que feito no caso de arrays. O exemplo abaixo ilustra a inicializao de estruturas:
struct facil {
int num;
char ch;
};
void main(void)
{
struct facil fac1 = { 3, C }, fac2;
fac2 = fac1;
}
Uma lista de valores separados por vrgula ca entre chaves ({ e }). Os valores de inicializao devem
estar na mesma ordem dos membros na declarao da estrutura.
28.6 Estruturas como argumentos de funo e valores de retorno
Como qualquer outro valor do tipo int ou float, valores de estruturas podem ser passados como argu-
mentos para funes, e podem ser retornados de funes. O exemplo abaixo ilustra tal prorpiedade:
No exemplo acima, a estrutura struct endereco contm dois arrays de tamanho 50. Dentro da
funo obtem_endereco(), a varivel ender declarada como sendo do tipo struct endereco.
Aps usar cin.getline() para o fornecimento da informao, o valor de ender retornado para
main(), de onde a funo obtem_endereco() foi chamada. Este valor ento passado para a funo
imprime_endereco(), onde o valor de cada membro da estrutura exibido na tela.
Este programa pode ser comparado ao programa abaixo, que usa valores do tipo int no lugar de valores
do tipo struct endereco (claro que a informao lida e exibida um simples valor numrico, e no
um nome de rua, etc.):
114
int obtem_int(void);
void imprime_int(int);
int obtem_int(void)
{
int i;
cout << "Entre valor: ";
cin >> i;
return i;
}
void imprime_int(int i)
{
cout << i << endl;
}
void main(void)
{
int valor;
valor = obtem_int();
cout << "\nSeu valor:\n";
imprime_int(valor);
}
28.7 Arrays de estruturas
Arrays de estruturas so como arrays de qualquer outro tipo. Eles so referenciados e denidos da mesma
forma. O exemplo abaixo anlogo ao exemplo de endereo apresentado anteriormente, exceto que uma
quantidade de NUM endereos armazenada ao invs de apenas um.
#define LEN 50
#define NUM 10
struct endereco {
char rua[LEN];
char cidade_estado_cep[LEN];
};
void obtem_endereco(struct endereco [], int);
void imprime_endereco(struct endereco);
void obtem_endereco(struct endereco aender [], int index)
{
cout << "Entre rua: ";
cin.getline(aender[index].rua, LEN);
cout << "Entre cidade/estado/cep: ";
cin.getline(aender[index].cidade_estado_cep, LEN);
115
}
void imprime_endereco(struct endereco ender)
{
cout << ender.rua << endl;
cout << ender.cidade_estado_cep << endl;;
}
void main(void)
{
struct endereco residencias[NUM];
int i;
for (i = 0; i < NUM; i++) {
cout << "Entre o endereco da pessoa " << i << ":\n";
obtem_endereco(residencias,i);
}
for (i = 0; i < NUM; i++) {
cout << "endereco da pessoa " << i << ":\n";
imprime_endereco(residencias[i]);
}
}
Neste programa, o array residencias passado para obtem_endereco(), juntamente com o in-
dice onde deve ser guardado o novo endereo. Depois, cada elemento do array passado para imprime_endereco()
um por vez.
Observe-se ainda na funo obtem_endereco() como os membros de cada elemento do array po-
dem ser acessados. elements da estrutura em can be accessed as well. Por exemplo, para acessar a rua do
elemento residencias[0] usa-se:
cout << residencias[0].rua << endl;
cout << residencias[0].cidade_estado_cep << endl;
28.8 Estruturas aninhadas
Como denido anteriormente, membros de estruturas podem ser de qualquer tipo. Isto inclui outras estrutu-
ras. Abaixo dene-se duas estruturas, a segunda tendo membros que so tambm estruturas:
#define LEN 50
struct endereco {
char rua[LEN];
char cidade_estado_cep[LEN];
};
struct student {
char id[10];
int idade;
struct endereco casa;
struct endereco escola;
116
};
struct student pessoa;
Dadas estas denies, pode-se potencialmente acessar os seguintes campos de pessoa, uma varivel
do tipo struct student:
pessoa.id
pessoa.casa.rua
pessoa.casa.cidade_estado_cep
pessoa.escola.rua
pessoa.escola.cidade_estado_cep
Note o uso repetido de . quando se acessa membros dentro de membros.
117
29 Entrada e Sada Padro
A forma com que um programa em C++ se comunica com o mundo externo atravs de entrada e sada de
dados: o usurio fornece dados via teclado e o programa imprime mensagens na tela. Todos os programas
vistos at agora lem suas entradas do teclado e produzem suas sadas na tela.
Em C++ toda entrada e sada feita com uxos (streams) de caracteres organizados em linhas. Cada
linha consiste de zero ou mais caracteres e termina com o caracter de nal de linha. Pode haver at 254
caracteres em uma linha (incluindo o caracter de nal de linha). Quando um programa inicia, o sistema
operacional automaticamente dene quem a entrada padro (geralmente o teclado) e quem a sada
padro (geralmente a tela).
As facilidades de entrada e sada no fazem parte da linguagem C++ . O que existe uma biblioteca
padro de classes e funes (mtodos) para manipular a transferncia de dados entre programa e os dis-
positivos (devices) de sada e entrada padro: cin, cout, cin.get(), cin.put(), puts(),
gets(). Estas classes e funes so declaradas no arquivo <iostream>. Existem funes teis para
converso e teste de caracteres declaradas no arquivo <ctype.h>.
As funes de entrada e sada operam sobre streams (uxos) de caracteres. Toda vez que uma funo
se entrada chamada (por exemplo, cin, cin.get()) ela verica pela prxima entrada disponvel na
entrada padro (por exemplo, texto digitado no teclado). Cada vez que uma funo de sada chamada, ela
entrega o dado para a sada padro (por exemplo, a tela).
As funes para leitura da entrada padro e para escrita na sada padro que tm sido usadas at agora
so:
1. Entrada e sada de caracteres:
int cin.get( void );
int cin.put( int );
2. Entrada e sada de strings:
char
*
gets(char
*
);
int puts( char
*
);
3. Entrada e sada formatada:
int cin >> arg1 >> arg2 >> ...;
int cout << arg1 << arg2 << ...;
29.1 Comandos de entrada e sada: cin.get() e cin.put()
Vamos discutir algumas funes de entrada de dados (diferente do cin). A entrada de texto considerada
como um uxo de caratecteres. Um uxo texto uma sequncia de caracteres dividida em linhas; cada linha
consiste de zero ou mais caracteres seguido do caractere de nova linha ( \n). Como programador, voc
no quer se preocupar em como as linhas so representadas fora do programa. Quem faz isso por voc so
funes de uma biblioteca padro.
Suponha que voc queira ler um nico caractere, sem fazer qualquer tipo de converso para um tipo de
dados especco (o que feito por cin). Isso pode ser feito usando a funo cin.get().
A funo cin.get() l o caracter do teclado e mostra o que foi digitado na tela.
#include <iostream>
using namespace std;
118
int main()
{
char ch;
cout << "Digite algum caracter: ";
cin.get(ch);
cout << "\n A tecla pressionada eh " << ch << endl;
}
O Resultado deste programa na tela :
Digite algum caracter: A
A tecla pressionada eh A.
A funo cin.put() aceita um argumento de entrada, cujo valor ser impresso como caracter:
#include <iostream>
using namespace std;
int main()
{
char ch;
cout << "Digite algum caracter: ";
cin.get(ch);
cin.put(ch);
}
29.2 Consideraes sobre Leitura de Dados pelo Teclado
29.2.1 Lendo o teclado usando cin.get()
cin.get() uma funo vinculada primitiva principal de entrada cin. Cada vez que chamada, esta funo
l um caractere teclado; cin.get comea a ler depois que a tecla RETURN digitada no nal de uma
sequncia de caracteres (dizemos que a entrada para a funo cin.get() est no uxo de entrada). A funo
cin.get() retorna um valor, o caractere lido (mais precisamente, o cdigo inteiro ASCII correspondente ao
caractere).
Vejamos o que acontece quando um programa trivial executado.
#include <iostream>
using namespace std;
int main(){
char ch;
119
cin.get(ch);
}
cin.get() obtm sua entrada do teclado. Portanto, quando o programa acima executado, o programa
espera que o usurio digite alguma coisa. Cada caractere digitado mostrado no monitor. O usurio pode
digitar diversos caracteres na mesma linha, inclusive backspace para corrigir caracteres j digitados. No
momento que ele teclar RETURN , o primeiro caractere da sequncia digitada o resultado da funo
cin.get(). Portanto, na instruo do programa acima o caractere (ou melhor, o seu cdigo ASCII) atribudo
a varivel ch. Note que o usurio pode ter digitado diversos caracteres antes de teclar RETURN , mas a
funo cin.get() s comear a ler o que foi digitado depois que for teclado RETURN . Alm disso, com
uma chamada da funo cin.get() s o primeiro caractere da sequncia digitada lida.
Voc deve saber que o caractere de nova linha, \n, que tem o cdigo ASCII 10, automaticamente
adicionado na sequncia de caracteres de entrada quando o RETURN teclado. Isso no tem importncia
quando a funo cin.get() chamada uma nica vez, mas isto pode causar problemas quando ele usado
dentro de um lao.
No iniccio de qualquer programa que usa cin.get(), voc deve incluir
#include <iostream>
using namespace std;
Esta diretiva do pr-processador diz ao compilador para incluir informaes sobre cin, cin.get() e EOF
(mais sobre EOF adiante.).
Considere o seguinte programa:
#include <iostream>
using namespace std;
int main(){
char ch;
cout << "Entre com uma letra: ";
cin.get(ch);
if( ch < A || ch > z )
cout << "Voce nao teclou uma letra!";
else
cout << "Voce teclou " << ch
<< ", e seu codigo ASCII eh " << (int) ch << endl;
}
Um exemplo da execuo do programa:
Entre com uma letra: A
Voce teclou A, e seu codigo ASCII eh 65.
No exemplo de execuo acima o usurio teclou A e depois RETURN .
Outro exemplo de execuo do programa:
Entre com uma letra: AbcD
Voce teclou A, e seu codigo ASCII eh 65.
120
Neste caso o usurio digitou quatro caracteres e depois teclou RETURN . Embora quatro caracteres
tenham sido digitados, somente uma chamada a funo cin.get() foi feita pelo programa, portanto s um
caractere foi lido. O valor atribudo ao argumento da funo o cdigo ASCII do primeiro caractere lido.
O tipo do resultado da funo cin.get() int e no char. O valor retornado pela funo o cdigo
ASCII do caractere lido.
29.2.2 Marcando o nal da entrada
Frequentemente quando voc est digitando a entrada para o programa, voc quer dizer ao programa que
voc terminou de digitar o que queria. Em ambiente Unix, digitando ^D (segure a tecla de Ctrl e pressione
D) voc diz ao programa que terminou a entrada do programa. Em ambiente MS-Windows, voc faz isto
digitando ^Z (segure a tecla de Ctrl e pressione Z).
Isto envia uma indicao para a funo cin.get(). Quando isso ocorre, o valor de ch depois de executar
cin.get(ch); ser umvalor especial do tipo inteiro chamado EOF (que signica end of le nal do arquivo).
Considere o seguinte programa exemplo que conta o nmero de caracteres digitados (incluindo o carac-
tere de prxima linha):
#include <iostream>
using namespace std;
int main()
{
int total = 0;
char ch;
// Le o proximo caractere em ch e para quando encontrar
// final do arquivo
cin.get(ch);
while( ! cin.eof() ) {
total++;
cin.get(ch);
}
cout << endl << total << " caracteres digitados" << endl;
}
S para esclarecer: voc deve teclar RETURN depois de entrar com o comando ^D (ou ^Z no MS-
Windows).
29.2.3 Para evitar problemas com a entrada...
(Observao: nesta seo, espaos em branco so relevantes e so mostrados como )
Quando voc executa um programa, cada caractere que voc digita lido e considerado como parte do
uxo de entrada. Por exemplo, quando voc usa cin.get(), voc deve teclar RETURN no nal. Como
mencionado anteriormente, o primeiro caractere digitado lido pelo cin.get(). Mas, o caractere de nova
linha continua no uxo de entrada (porque voc teclou RETURN ).
De qualquer forma, se voc executar um cin.get() depois de um cin ou de um cin.get() voc ler o
caractere de nova linha deixado no uxo de entrada.
Da mesma forma, quando voc usa cin para ler informaes, ele somente l o que necessrio. Se voce
usar cin para ler um nmero inteiro e digitar 42 (seguido de RETURN ), o cin l 42, mas deixa (e
o caractere de nova linha do RETURN ) no uxo de entrada.
121
Outro caso problemtico quando o cin usado num lao. Se voc digitar um valor do tipo errado,
o cin ler o valor errado e a execuo do lao continuar na sentena aps o cin . Na prxima iterao do
lao o cin vai tentar ler novamente, mas o lixo deixado da iterao anterior ainda estar l, e portanto a
chamada corrente do cin tambm no dar certo. Este comportamento resultar num lao innito (um lao
que nunca termina), ou terminar e ter um resultado errado.
H uma maneira simples de resolver este problema; toda vez que voc usar cin.get() (para ler um
caracter s) ou cin , voc deve ler todo o lixo restante at o caractere de nova linha. Colocando as seguinte
linhas aps chamadas a cin.get() ou cin o problema eliminado:
// Pula o restante da linha
while( cin.get(c) != \n );
Note que isso no necessrio aps todas as chamadas a cin.get() ou cin . S depois daquelas chamadas
que precedem cin.get() (ou cin ), especialmente em um lao.
29.3 Validao de entrada
Muitas vezes queremos em nossos programas que eles obtenham um certo tipo de dado do usurio (por
exemplo, valores inteiros) mas queremos tambm tratar a condio em que o usurio digita um dado real ou
texto no lugar, exigindo uma reentrada de dados.
O exemplo abaixo nos mostra como fazer isto, usando a sentena com cin como expresso de um if
ou while.
Exemplo 1:
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
void cleanInput()
{
char cc;
if (cin.fail())
{
cin.clear();
while (cin.get(cc) && cc != \n);
}
}
void printStatInput()
{
cout << "\tGood: " << cin.good()
<< " Fail: " << cin.fail()
<< " Bad: " << cin.bad()
<< " EOF: " << cin.eof() << endl << endl;
}
122
int main ()
{
int b=1111, c=2222, d=3333;
float x=1.111, y=2.222;
void
*
cinerr;
cout << "b c d = " << b << " " << c << " " << d << endl;
cout << "x y = " << x << " " << y << endl;
while (! (cinerr = cin >> b))
{
cleanInput();
cout << "cin 1 = " << cinerr << " b = " << b << endl;
printStatInput();
cout << "Entrada 1: ";
}
cout << "
**
cin 1 = " << cinerr << " b = " << b << endl;
while (! (cinerr = cin >> b >> c >> d))
{
cleanInput();
cout << "cin 2 = " << cinerr << " b c d = " << b << " " << c << " " << d << endl;
printStatInput();
cout << "Entrada 2: ";
}
cout << "
**
cin 2 = " << cinerr << " b c d = " << b << " " << c << " " << d << endl;
cinerr = cin >> x;
cout << "cin 3 = " << cinerr << " x = " << x << endl;
printStatInput();
if (!cinerr)
{
/
*
Limpar condio de erro em cin, se houver.
*
/
cout << "Limpando condies de erro de CIN" << endl;
cin.clear();
printStatInput();
}
cout << "Ultima entrada: ";
cinerr = cin >> x >> y;
cout << "cin 4 = " << cinerr << " x y = " << x << " " << y << endl;
printStatInput();
return 0;
}
123
cin ... retorna um valor especial
4
. Se nulo, a entrada no foi aceita e o valor da varivel em que houve
erro ca inalterado. As variveis posteriores na leitura em que houve erro tambm mantm seus valores
inalterados. Execues subsequentes de cin somente podem ser feitas aps a execuo de cin.clear(), para
eliminar a condio de erro. Caso isto no seja feito, aps o primeiro erro de leitura, todos os cin ...
subsequentes daro erro.
Tambm podem ocorrer problemas de converso de tipos em cin. Observe o exemplo abaixo:
int b;
float x;
cin >> b;
cin >> x;
Neste caso, se usurio digita um oat (por exemplo, 3.7) no 1
o
cin, o 2o.
o
cin no solicitar dado:
b recebe 3, deixando os chars .4 no buffer de leitura. o 2
o
cin, ento, armazena direto 0.4 em x, no
aguardando digitao do usurio. Note que neste caso, cin ... no acusar erro (isto , no retorna valor
nulo).
29.4 Formatao de sada
Para formatar a sada de dados com cout, (por exemplo, restringir a quantidade de casas decimais mostra-
das, denir o tamanho mximo em caracteres, ou imprimir uma matriz de valores alinhados adequadamente
pelas colunas) usam-se a funo setw() e o mtodo setf() (cout.setf(....)).
Os exemplos abaixo mostram como usar estes elementos.
Exemplo 2:
#include <iostream>
#include <iomanip> // Necessrio para usar os manipuladores setw()
using namespace std;
int main() {
int n1, n2, n3;
int soma;
cout << "Entre com 3 numeros inteiros: ";
cin >> n1 >> n2 >> n3;
soma = n1 + n2 + n3;
cout << "Soma = " << soma << endl;
/
*
Define impresso de nmeros em ponto fixo e
mostra sempre o ponto decimal seguido por zeros
*
/
cout.setf (ios::fixed | ios::showpoint);
/
*
Outros flags vlidos para setf():
ios::fixed
ios:scientific
ios::showpoint
4
Este valor um ponteiro para um objeto.
124
ios::right
ios::left
*
/
/
*
Define quantidade de algarismos a serem exibidos aps ponto decimal.
Em alguns compiladores, pode indicar a quantidade de algarismos
SIGNIFICATIVOS.
*
/
cout.precision(2);
// setw() fixa a largura do campo de sada.
// Aplica-se apenas ao prximo item exibido na sada.
// Necessrio incluir <iomanip> (vide incio do cdigo)
cout << "Media = " << setw(8) << soma / 3.0 << endl;
cout << "Produto = " << n1
*
n2
*
n3 << endl;
}
Exemplo 3:
// Exemplo de array 2-D - taboada
#include <iostream>
#include <iomanip> // Necessrio para usar os manipuladores setw()
using namespace std;
#define LIN 10
#define COL 10
int main()
{
int x; // numero da coluna
int y; // numero da linha
int taboada[LIN][COL]; // tabela de taboada
// preenche a taboada
y=0;
while(y < LIN)
{
x=0;
while(x < COL)
{
taboada[y][x] = y
*
x;
x = x+1;
}
y = y+1;
}
cout << "\n Taboada de Multiplicacao\n";
125
// Imprime o numero das colunas
cout << setw(6) << 0;
x=1;
while(x < COL)
{
cout << setw(3) << x;
x = x+1;
}
cout << endl;
// Imprime uma "linha horizontal"
cout << " ";
x=0;
while (x < 3
*
COL)
{
cout << "-";
x = x+1;
}
cout << endl;
// Imprime as linhas da tablea.
// Cada linha a precedida pelo indice de linha e uma barra vertical
y=0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x=0;
while(x < COL)
{
cout << setw(3) << taboada[y][x];
x = x+1;
}
cout << endl;
y = y+1;
}
126
Referncias
[1] H. M. Deitel and P. J. Deitel. C++: Como Programar. Prentice-Hall, Inc., 5
a
edition, 2006.
[2] Stanley B. Lippman. C++ Primer. Addison-Wesley Publishing Company, 1991. ISBN: 0-201-54848-8.
Livro bastante didtico sobre C++.
[3] Victorine Viviane Mizrahi. Treinamento em Linguagem C++. Prentice-Hall, Inc., 2
a
edition, 2005.
[4] Walter Savitch. C++ Absoluto. Addison-Wesley Publishing Company, 2004. ISBN: 85-88639-09-2.
Livro bastante didtico sobre C++.
[5] Bjarne Stroustrup. A Linguagem de Programao C++. Bookman, 2000.
127

Você também pode gostar