You are on page 1of 87

1 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 objetos, classes,
templates e outros conceitos relacionados programao orientada a objetos
no so abordados aqui.

1 Programas C++
Essencialmente, um programa C++ consiste de uma ou mais partes chamadas
funes1. Alm disso, um programa em C++ deve definir 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;


definio 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 especfico 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 tipo seja sempre o mesmo). Cada
varivel tem um tipo associado. Alguns tipos de variveis que discutiremos
incluem int, char e float.
Cada varivel usa uma determinada quantidade de armazenamento em
memria. A maneira como sabemos 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 figura acima mostra como um int e um char so armazenados na memria.


Outro tipo existente o float, 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

escrito como
. 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 significativos so
armazenados. Em Code::Blocks um float ocupa 4 bytes de memria. H
muitos outros tipos ( short, long, double), que sero descritos no futuro.

1.3 Definio de Varivel em C++


Se voc usa variveis no programa, voc deve defini-las. Isto envolve
especificar 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.

Tabela 1: Palavras Reservadas da Linguagem C++


auto

break

case

char

const

continue

default

do

double

else

enum

extern

float

for

goto

if

int

long

main

register

return

short

signed

sizeof

static

struct

switch

typedef

union

unsigned

void

volatile

while

sempre uma boa idia ter certas regras (para voc mesmo) para nomear
variveis para tornar o programa mais legvel:
D nomes significativos as variveis (mas no muito longos);
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

-128 a 127

bool

true ou false

int

32

-2.147.483.647 a 2.147.483.647

float

32

7 dgitos significativos

double

64

15 dgitos significativos

Abaixo est um exemplo de um programa com diversas definies de


variveis:
int main()
{
int pera;
char qualidade;
float peso;

pera = 3;
qualidade = 'A';
peso = 0.653;
...
}

Quando variveis so definidas, 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 definidas. Usando esta
forma, o program acima ficaria:
int main()
{
int pera = 3;
char qualidade = 'A';
float peso = 0.653;

...
}

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 identificador.
um endereo: o endereo do byte menos significativo 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 definio 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 especificar 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 especfica no

teclado. Neste caso, usa-se caracteres de escape. Tais caracteres so escritos


no somente como um smbolo entre apstrofes, 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
compilador 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 cin2. Se voc quiser usar estes
elementos em seu programa, voce deve incluir as seguintes linhas no incio do
seu cdigo fonte:
#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 definies 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 especificar 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;

#define PRECO 1.99

int main()

int pera = 3;

char qualidade = 'A';

float peso = 2.5;

cout
qualidade

"Existem "

" pesando "

cout

pera

peso

" peras de qualidade "

" quilos."

" O preco por quilo eh R$"

", o total eh R$"

endl;

PRECO

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 #define PRECO 1.99 no incio do programa define uma macro. Ou
seja, definimos que PRECO um sinnimo para 1.99 e, portanto, toda
ocorrncia de PRECO no programa substitudo por 1.99antes que ele seja
compilado.
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

cin

" Entre sua idade: ";

cout

idade

"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

cin

"Entre com a data do seu aniversario (dd mm aa): ";

dia

cout
"/"

mes

ano;

"Voce nasceu em "


ano

dia

"/"

mes

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;
/* 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;

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 necessrias 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
, expresses em parntesis so avaliadas
primeiro, seguidos por exponenciao, 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 (
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 podem ser usadas na maior parte dos lugares em que
uma varivel pode ser usada.

O exemplo seguinte vlido:


int raio = 3 * 5 + 1;
cout << "circunferencia = " << 2 * 3.14 * raio << endl;

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). Valores 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 =
cout <<
<< endl;
idade =
cout <<
<< endl;
}

17;
"Pode tirar carteira de motorista? " << (idade >= 18)
35;
"Pode tirar carteira de motorista? " << (idade >= 18)

A sada deste programa ser:


Pode tirar carteira de motorista? 0
Pode tirar carteira de motorista? 1

Na primeira linha, idade 17. Logo, 17


Depois disso, idade 35. Logo, 35

>= 18

>= 18

falso, que 0.

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 significa o
que voc espera.
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
cout
cout
cout
cout

<<
<<
<<
<<
<<

5 + 10 * 5 % 6;
10 / 4;
10.0 / 4.0;
'A' + 1
score + (score == 0);

//
//
//
//
//

7
2
2.5
B
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.
#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>
cout
using namespace std;

// necessario para usar setw() e setf() em

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

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
lgicos3 so avaliados. O valor resultante um nmero. Para os operadores
relacionais e lgicos, este nmero pode ser 0 (que significa falso) ou 1 (que
significa 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 valor da


varivel x fora do intervalo
[1,4], e 0 quandox est dentro do
intervalo.

3.2 Expresses envolvendo o operador de atribuio (=)


O formato do operador de atribuio :

(1)

Um
(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
memria.

armazenada na

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 esquerda, podemos escrever sentenas como:
i = j = k = 0;

Que, usando parnteses, equivalente a i = (j = (k = 0)). Ou seja, primeiro


o valor 0 atribudo a k, o valor de k = 0 (que zero) atribudo a j e o valor
de j = (k = 0) (que tambm zero) atribudo ai.
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;

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 precedncia que o operador relacional <.

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

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

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 denominador) em decimal e imprime o resultado:
#include <iostream>
using namespace std;
int main( ){
int a, b;
cout << "Entre com uma
cin >> a >> b;
}

fracao (numerador and denominador): ";

cout << "A fracao em decimal eh " << 1.0 * a / b << endl;

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
cin >> a >> b;

fracao (numerador e denominador): ";

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 ficaria ainda melhor se ao invs de no fazer


nada no caso do denominador 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
do if-else :
if

else

- else.

O formato

Figura 2: O comando if-else

Primeiro, a
(que usualmente chamamos de condio) avaliada.
Caso a condio seja verdadeira (o que equivalente a dizer que o valor
diferente de zero), entao a
a

executada. Caso contrrio,

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 verifique se o nmero par. Porm agora, queremos que o programa
imprima ``o numero e par'' ou ``o numero e impar''.
#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 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 exemplo:
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!

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( ){
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 significado, 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;
// 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.
/usr/local/lib/tex/inputs///Programas/Exercicio_04-1.cpp

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 operadores 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 constantes 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 simplificado:


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

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;

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

a==0 || b==0

(verdadeiro se pelo menos uma das variveis a or b for 0)

== 0

eb

== 0,

portanto se a e b so 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).
Verifique na Tabela 2 o resultado do uso de operadores lgicos:

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.

Tabela 3: 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

&&

esquerda para direita

||

esquerda para direita

No prximo exemplo, o programa verifica 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.
#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;
//
s1
s2
s3

calcula o quadrado dos lados


= lado1*lado1;
= lado2*lado2;
= 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

equivalente a !x

&& !y

e
!(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)

2.
3.
4.
5.
6.
7.
8.
9.

if (x = 5)
cout << "a ";
else
cout << "b ";
cout << "c ";
cout << "d" << endl;
==> a c d

10.
11. mude = para ==
12.

==> b c d

13.altere o programa acima para produzir a seguinte saida:


o Assuma x
1.

2.

a d

ey

= 8

= 5

ey

= 7

o Assuma x

= 5

1.

b c d

7.2 Operadores lgicos


O que impresso pelas seguintes sentenas?
1. Assuma x
2.
3.
4.
5.

ey

= 8.

if (x == 5 && y == 8)
cout << "a" << endl;
else
cout << "b" << endl;

6. Assuma x
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.

= 5

= 4

ey

==> a

= 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)

20.
21.
22.

cout <<

"a" << endl;

else

cout <<

23.Precedncia: !

"b" << endl;

==> a

> && > ||

24.
if (x == 5 || y == 8 && z == 10)
25.
26. equiv.
27.
28.
if (x == 5 || (y == 8 && z == 10))

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

else if

else if

else if

else

As expresses lgicas so avaliadas em ordem, comeando com a


. Se uma das expresses for verdadeira, a sentena associada ser executada.
Se nenhuma for verdadeira, ento a sentena,
, do ltimo else ser
executada como opo default. Se a opo default no for necessria, ento a
parte
else

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: ";
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, verificado 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)
else if (op == '-')
cout << " = " << setprecision(2)
else if (op == '/')
cout << " = " << setprecision(2)
else if (op == '*')
cout << " = " << setprecision(2)
else
cout << " Operador invalido.";
cout << endl;
}

Exemplos da execuo deste programa:


Entre com numero operador numero:
5 * 3.5
= 17.50
Entre com numero operador numero:
10 + 0
= 10.00
Entre com numero operador numero:
10 x 5.0
Operador invalido.

9 Funes

<< num1 + num2;


<< num1 - num2;
<< num1 / num2;
<< num1 * num2;

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 relativamente 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 obtido. 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 especficas 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:
/usr/local/lib/tex/inputs///Programas/somamaiores.cpp

Observe que o cdigo que verifica 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 simplificado pela criao de uma funo
chamada maior, que dados trs nmeros , , e , d como resultado o maior
valor dentre os trs valores fornecidos:
/usr/local/lib/tex/inputs///Programas/maior.cpp

O exemplo pode ser ento alterado e simplificado com o uso da


funo maior():
/usr/local/lib/tex/inputs///Programas/somamaiores-func.cpp

Como pode ser observado, sejam quais forem os conjuntos de 3 nmeros


fornecidos, no precisa escrever um cdigo similar ao mostrado na
funo maior acima para cada nmero. Basta chamar a funomaior(), passar
os valores necessrios para verificar o maior valor de cada conjunto, e utilizar
os resultados.
Evitar repetio de cdigo a razo histrica que funes foram inventadas
(tambm chamado de procedimento 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 programa. Dividindo o programa em funes, muito mais
fcil projetar, entender e modificar 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 significa
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 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 Definindo funes


Um programa C++ consiste de uma ou mais definies de funes (e
variveis). H sempre uma funo chamada main. Outras funes tambm
podem ser definidas. Cada uma pode ser definida separadamente, mas
nenhuma funo pode ser definida 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 definidas antes de serem usadas. As


funes da biblioteca padro, tais como cin.get(), so pr-definidas, mas
mesmo assim devem ser declaradas (deve ser anunciado ao compilador que
elas existem). por isso que inclumos a linha #include <iostream> no incio
do cdigo fonte.
O formato geral da definio de uma funo
tipo-do-resultado nome-da funo (lista-de-argumentos)
{

declaraes e sentenas
}

A primeira linha da definio 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 deparmetros (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
parnteses. Para simplificar a exposio, falaremos sobre o tipo do retorno e
os argumentos formaismais 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 significa que esta funo no tem tipo de retorno (no retorna
um valor), e o segundo significa que a funo no tem argumentos (ela no
precisa de nenhuma informao externa para ser executada). Isso no significa
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 definidas dentro do cdigo-fonte


importante, sendo que uma funo deve sempre ser definida 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 definio da funo main(). O uso de prottipos pode ser usado para
definir 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().
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() definida 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(),
tipo void.

main())

possuem

Alm de executarem aes (como imprimir) uma funo tambm


pode retornar um valor para o programa 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 definida, a funo s de um tipo especfico). 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 verifica se eles podem ser os lados de um tringulo reto.
// 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:
#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

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 final. 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 final (antes de fechar as chaves do corpo da funo) na funo


opcional. Se omitido, a funo atingir o final da funo e retornar
automaticamente. Note que o return opcional somente para funes void.

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 definida pelo cabealho da funo entre
parnteses.. Para cada argumento voc precisa especificar 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 defini-los dentro do corpo da funo porque eles j esto definidos 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 em abs(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.
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 argumento, os argumentos devem ser separados por vrgula.
A ordem em que os argumentos so passados deve ser na mesma em que so
definidos. 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 definir
variveis dentro de funes, da mesma forma que temos definido 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 definidas. S esta
funo pode ``enxergar'' suas prprias variveis. Por exemplo:
#include <iostream>
using namespace std;
void obtem_int(void)
{
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 definido 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 define e no h conflito.
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.

9.9 Prottipos

Os prottipos servem para dar ao compilador informaes sobre as funes.


Isso para que voc possa chamar funes antes que o compilador tenha a
definio (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 defini-las. O formato de um prottipo :
tipo-de-retorno nome-da-funo(lista-dos-tipos-dos-argumentos);
Definindo prottipos, voc no precisa se preocupar com a ordem em que
define as funes dentro do cdigo-fonte do programa. A principal vantagem
de definir 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 definio da funo.
Abaixo, mostramos a definio 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
especificar as seguintes informaes:
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 definio


da funo.

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 codificar 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.


/* 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' . . .
.
.
}

";

10 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues.
Estas estruturas de repetio, 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 verificar 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
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 verificada 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 verificada 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
Entre
Total
Entre
Total
Entre
Final

= 0
com um numero: 3
= 3
com um numero: 8
= 11
com um numero: 15
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.

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 fizer isso, vital
que voc tambm adicione chaves. Se voc no fizer 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;

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:
1
2
3
4

2 3 4
4 6 8
6 9 12
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 final 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
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:
*
**
***
****
*****
******
*******
********

11 Mais sobre funes: Quando return no


suficiente

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;
}
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 ae 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
definies de variveis.
int i = 5;
char c = 'G';

Na memria, eles podem estar armazenados da forma indicada na Figura 11.1:

Figura 3: Variveis em memria

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 bporque 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 em que endereo de memria escrever. Na
verdade, a funo no sabe que os endereos de memria so associados
com a e b, mas ela pode modificar 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 definio 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()
{
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.

12 O pr-processador

O pr-processador um programa que faz alguns processamentos simples


antes do compilador. Ele executado 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 linguagem C++ , portanto as regras para elas so um pouco
diferentes). As linhas que comeam com um # so comandos para o prprocessador. 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 definir contantes que colocar a
palvavra const antes da definio 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
definir NUM_ALUNOS como 81. Assim, se o nmero de alunos mudar, voc no
precisaria modificar todo o seu programa onde o nmero de alunos ( 81)
utilizado, mas simplesmente alterar a diretiva #define. Estas duas diretivas so
definidas 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 em letra minscula, ou uma mistura de letras
minsculas e maisculas). Assim, quando voc v um nome em um programa,
voc sabe se o nome refere-se a uma varivel ou um nome definido 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 especificado 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 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 definies. para isso que usamos a
diretiva #include, para incluir em seu programa, informaes que esto em
outro arquivo. Estas diretivas geralmente esto no incio do programa fonte,
antes da definio 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 significa que o arquivo 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 necessrios 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

implementaes 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.

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
cin >> nota0;
cout << "Entre
cin >> nota1;
cout << "Entre
cin >> nota2;
cout << "Entre
cin >> nota3;

a nota do estudante 0: ";


a nota do estudante 1: ";
a nota do estudante 2: ";
a nota do estudante 3: ";

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 ficaria 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 definir um array nota de tamanho 100 para armazenar
as notas dos cem estudantes:
int nota[100];

Quando o compilador encontra esta definio, 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 Definindo arrays e acessando seus elementos


A definio de arrays muito parecida com a definio de variveis. A nica
diferena que em array necessrio especificar seu tamanho (quantos
elementos ele tem).
Os colchetes [ e ] so usados na definio do tamanho, como mostra os
exemplos a seguir:
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 definido,
armazenamento suficiente (bytes contnuos na memria) so alocados para
conter todos os elementos do array.
Note na tabela de precedncia abaixo que [
todos os demais operadores.
Operador

Associatividade

tem precedncia maior que

() []

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

Verifique 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];
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
Entre a
Entre a
Entre a
Notas:

nota
nota
nota
nota

do
do
do
do

estudante 0:
estudante 1:
estudante 2:
estudante 3:
93 85 74 100

93
85
74
100

Media: 88

O cdigo-fonte do programa consideravelmente mais curto.


O nico problema que ainda no fcil modificar 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;
}
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 definidos. Se o array no for
inicializado, ento ele contem valores indefinidos (tambm conhecidos
como lixo).
Para inicializar um array, um valor para cada elemento deve ser especificado.
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 definido, se ele no for inicializado, o tamanho do array
deve ser especificado. 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
definido. Uma sentena como a seguinte produzir um erro do compilador,
uma vez que arrays s podem ser inicializados quando definidos.
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

13.3 Verificao de Limite


Quando um array definido, 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 especficos, possvel que um programa tente
acessar endereos de memria de elementos fictcios, 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 siginifica que
o programa pode no fazer nada, cancelar a execuo, travar o computador,
entrar em um loop infinito, 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 indefinidos (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:
/usr/local/lib/tex/inputs///Programas/array_max.cpp

Aqui est um exemplo de execuo deste programa


Entre um inteiro:
Entre um inteiro:
Entre um inteiro:
Entre um inteiro:
Entre um inteiro:
O maior e' 85

73
85
42
-103
15

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 especificado, 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 definio da funo


somente por razes de legibilidade.
At este ponto, parece que no h diferena entre passar uma varivel simples
e um array como argumento 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 DA FUNO.
EM OUTRAS PALAVRAS, QUANDO SO PARMETROS DE
FUNES, ARRAYS SO PASSADOS POR REFERNCIA (sem a
necessidade do & na definio do parmetro formal, como foi visto na
Seo 11).
Para ilustrar este conceito, considere o exemplo seguinte:
/usr/local/lib/tex/inputs///Programas/troca_01.cpp

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 definido, como v no
programa principal acima, alocado espao suficiente 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 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 detroca_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:
/usr/local/lib/tex/inputs///Programas/troca_02.cpp

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.
/usr/local/lib/tex/inputs///Programas/inicializa_array.cpp

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.

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 verificar 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 depesquisa 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:
2. int pesquisa_linear(int [], int, int);

3. Definio:
4. /* Procura uma chave em um array
5. * entrada: array a ser pesquisado (arr ), tamanho do array
(tam),
6. *
chave a ser procurada (chave)
7. * saida: o indice do elemento que e' igual a chave ou -1 caso
nao ache
8. * suposicao: nao assume que o array esteja ordenado
9. */
10. int pesquisa_linear(int arr[], int tam, int chave)
11. {
12.
int i;
13.
14.
i = tamanho - 1;
15.
while (i >= 0)
16.
{
17.
if (arr[i] == chave)
18.
{
19.
return i;
20.
}
21.
22.
i = i - 1;
23.
}
24.
return -1;
25. }

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.
1. Prottipo:
2.

void soma_array( float [], float [], float [], int );

3. Definio de soma array():


4.

void soma_array( float arr1[], float arr2[], float arr3[], int


tam )
5.
{
6.
int i;
7.
8.
i = 0
9.
while ( i < tam )
10.
{
11.
arr3[i] = arr1[i] + arr2[i];
12.
i = i + 1;
13.
}
14.
}

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 eficiente, 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
~~~~
0 -->

conteudo do array depois da passagem


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 5 2 7 3 8 1 4 6

1 -->

2 -->

3 -->

4 -->

5 -->

6 -->

7 -->

8 -->

Note que mesmo que se comessemos com um array ordenado de 9


elementos, ainda assim o algoritmo dado faz 8 passagens sobre o array.
13.7.1 Prottipo da funo e definio
1. Prottipo
2. void selectSort(int [], int);

3. Definicao
4. /
usr/local/lib/tex/inputs///Programas/ordena_array_02
.cpp

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 eficiente.
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 com o
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
~~~~
0 -->

conteudo do array depois da passagem


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 5 2 7 3 8 1 4 6

1 -->

2 -->

3 -->

4 -->

5 -->

6 -->

7 -->

8 -->

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 varivel 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 significa 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 definio
1. Prottipo
2. void bubbleSort(int [], int);

3. Definicao

4. /
usr/local/lib/tex/inputs///Programas/ordena_array_01
.cpp

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 finalidades, 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

14 Matrizes ou Arrays
Multidimensionais
Nas notas de aula anteriores, apresentamos arrays unidimensionais. Em C++ ,
possvel tambm definir 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 definir e acessar arrays de dimenses
maiores, usamos colchetes adicionais ([ e ]). Por exemplo:
int tabela[3][5];

Define 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;
int y;
char matriz [ALTURA] [LARGURA];
num_cols]
//

//
//
//

numero da coluna
numero da linha
array 2-D [num_lins,

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)
{
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 um array bidimensional. Ela tem nmero 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;
int y;
int tabela[LIN] [COL];
//

//
//
//

numero da coluna
numero da linha
tabela de taboada

preenche a tabela

y = 0;
while (y < LIN)
{
x = 0;
while (x < COL)
{
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
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},
{-7.8, 1.3},
{6.5, 0.0}
};

//
//
//

linha 0
linha 1
linha 2

Quando o array inicializado, o tamanho da primeira dimenso pode ser


omitido. A definio de array abaixo equivalente a dada anteriormente.
double tabela[][2] = { {1.0, 0.0},
{-7.8, 1.3},
{6.5, 0.0}
};

//
//
//

linha 0
linha 1
linha 2

14.2 Arrays Multidimensionais - arrays de arrays


O formato da definio de um array de dimenso
elementos em cada dimenso

, onde o nmero de

, respectivamente, :

Isto define um array chamado


de
.

consistindo de um total

elementos, sendo cada elemento do 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

, respectivamente, pode ser imaginado como um array

de dimenso

cujos elementos so arrays de dimenso

Por exemplo, o array bidimensional tabela, com 20 elementos do tipo int


int tabela[4][5] = { {13,
{20,
{31,
{40,

15,
22,
33,
42,

17,
24,
35,
44,

19,
26,
37,
46,

21},
28},
39},
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]
tabela[1]
tabela[2]
tabela[3]

--->
--->
--->
--->

{13,
{20,
{31,
{40,

15,
22,
33,
42,

17,
24,
35,
44,

19,
26,
37,
46,

21}
28}
39}
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 especificada no cabealho e prottipo da
funo.

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;
//
int y;
//
//

numero da coluna
numero da linha

preenche o array

y=0;
while (y < LIN)
{
x=0;
while(x < COL)
{
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;
int y;
//

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;
}

numero da coluna
numero da linha

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;
}
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;

// 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;
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
da
// diagonal principal como centro da rotao
void flip(char matriz[][LARGURA])
{
int x, y;
int temp;

o elemento

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);
pausar();
flip(matriz);
imprime_matriz(matriz);
pausar();
marca_triang( matriz);
imprime_matriz( matriz);
pausar();
flip( matriz);
imprime_matriz(matriz);
pausar();

Notas de rodap
... funes1
Na verdade, um programa C++ composto pela definio de funes e
de elementos estruturais denominados classes. Estes so tema de estudo
em cursos avanados de programao orientada a objetos.
2
... cin
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.
... lgicos3
Operadores lgicos && e || sero vistos na prxima aula.
Subseces

o 1 Programas C++
1.1 Sentenas: simples e compostas
1.2 Variveis em C++
1.3 Definio de Varivel em C++
1.4 Constantes
1.5 Caracteres Constantes
1.6 Entrada e Sada
1.6.1 Exibindo informaes na tela: cout
1.6.2 Lendo informao: cin
1.7 Algoritmo X Programa

o 2 Operaes Aritmticas e Expresses.


Operaes Relacionais.
2.1 Operaes Aritmticas
2.1.1 Precedncia de Operadores
2.1.2 A Operao de Resto (%)
2.1.3 Expresses e Variveis
2.2 Operadores Relacionais
2.2.1 Precedncia dos operadores relacionais
2.3 Reviso de Expresses:
2.4 Exemplo de programas
2.5 Precedncia e associatividade de operadores
o 3 Expresses como valores
3.1 Expresses aritmticas, relacionais e lgicas
3.2 Expresses envolvendo o operador de atribuio ( =)
o 4 Ordem sequencial de execuo de sentenas
o comando condicional: if e if - else
4.1 Um erro comum
o 5 Aninhando senteas if e if-else
5.1 A ambigidade do else
o 6 Operadores Lgicos
o 7 Exemplos
7.1 IF - ELSE
7.2 Operadores lgicos
o 8 A construo else-if

o 9 Funes
9.1 Funes: o que so e por que us-las
9.2 Definindo funes
9.3 Funes simples
9.3.1 Argumentos
9.4 Funes que retornam um valor
9.5 Mais sobre o return
9.6 Mais sobre Argumentos
9.7 Chamada por valor
9.8 Variveis locais
9.9 Prottipos
9.10 Documentao de funes
9.11 Comentrios
o 10 Estruturas de Repetio
10.1 O comando de repetio while
10.2 Estilo de formatao para estruturas de repetio
10.2.1 Colocao das chaves
10.2.2 Necessidade ou no das chaves
10.2.3 Uso de espao em branco
10.2.4 Laos aninhados
o 11 Mais sobre funes: Quando return no suficiente
11.1 Usando referncia
11.2 Argumentos por referncia em funes

o 12 O pr-processador
12.1 A diretiva #define
12.2 A diretiva #include
12.3 Comentrios
o 13 Vetores ou Arrays
13.1 Definindo arrays e acessando seus elementos
13.2 Inicializao de arrays
13.3 Verificao de Limite
13.4 Arrays como argumentos de funes
13.5 Exemplo: pesquisa linear de um array
13.5.1 O Problema
13.6 Exemplo: somar os elementos de dois arrays
13.6.1 O Problema
13.7 Exemplo: Ordenao de um vetor - Verso 1
13.7.1 Prottipo da funo e definio
13.8 Exemplo: Ordenao de um vetor - Verso 2
13.8.1 Algoritmo Bubble Sort otimizado
13.8.2 Prottipo da funo e definio
13.9 Comentrios Finais
o 14 Matrizes ou Arrays Multidimensionais
14.1 Inicializao
14.2 Arrays Multidimensionais - arrays de arrays

14.3 Arrays Multidimensionais como argumento para


funes

You might also like