Anda di halaman 1dari 86

Linguagem C++ - Notas

Subseces
o

o o o

o 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 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 3 Expresses como valores 3.1 Expresses aritmticas, relacionais e lgicas 3.2 Expresses envolvendo o operador de atribuio (=) 4 Ordem sequencial de execuo de sentenas o comando condicional: if e if - else 4.1 Um erro comum 5 Aninhando senteas if e if-else 5.1 A ambigidade do else 6 Operadores Lgicos 7 Exemplos 7.1 IF - ELSE 7.2 Operadores lgicos 8 A construo else-if 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 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 11 Mais sobre funes: Quando return no suficiente 11.1 Usando referncia 11.2 Argumentos por referncia em funes 12 O pr-processador 12.1 A diretiva #define 12.2 A diretiva #include 12.3 Comentrios 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 14 Matrizes ou Arrays Multidimensionais 14.1 Inicializao 14.2 Arrays Multidimensionais - arrays de arrays 14.3 Arrays Multidimensionais como argumento para funes

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 caso, a mantissa 6.023 e o expoente 23.

escrito como

. Neste

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 default float main static void

break do for

case double goto

char else if short

const continue enum int signed extern long sizeof

register return struct

switch typedef union unsigned

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 bool int float double

8 8 32 32 64

-128 a 127 true ou false -2.147.483.647 a 2.147.483.647 7 dgitos significativos 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 "

"Existem " qualidade

pera

" peras de qualidade

" pesando "

peso

" quilos."

endl;

cout

" O preco por quilo eh R$"

PRECO

", o total eh R$"

peso * PRECO

endl;

A sada do programa ser: Existem 3 peras de qualidade A pesando 2.5 quilos. O preco por quilo eh 1.99, o total eh 4.975 A linha #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.99 antes 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

" Entre sua idade: ";

cin

idade

cout }

"Voce tem "

idade

"anos."

endl;

Este programa mostrar no monitor: Entre sua idade: e aguardar que um nmero seja digitado e a tecla ENTER. Depois disso, a varivel idade conter o valor digitado pelo usurio. Mais de um valor pode ser lido por um mesmo cin. Considere o seguinte exemplo:

#include

iostream

using namespace std;

int main() { int dia, mes, ano;

cout

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

cin

dia

mes

ano;

cout " } dia

"Voce nasceu em "/" mes "/" ano endl;

Este exemplo funciona exatamente como o exemplo anterior. Um nico cin l os 3 nmeros quando estes nmeros so separados por espaos (espaos em branco, tabulao, novas linhas). Ento voc pode teclar ENTER depois de cada nmero, ou colocar espaos ou tabulaes entre os nmeros. Os espaos so ignorados pelo cin.

1.7 Algoritmo X Programa


ALGORITMO PERIMETRO_AREA /* Calcula o permetro e a area de uma circunferencia de raio R (fornecido pelo usuario) */ /* Definir variaveis */ int Raio; float Perim, Area, PI; PI = 3.14159; /* 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 >= 18 falso, que 0. Depois disso, idade 35. Logo, 35 >= 18 verdadeiro, que 1. Note tambm que o operador de igualdade escrito com ``sinais de igual duplo'', ==, no =. Tenha cuidado com esta diferena, j que colocar = no lugar de == no um erro sinttico (no gera erro de compilao), e no 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; 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; } // necessario para usar setw() e setf() em

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) 3 < 5

tem valor 3; tem valor 1; tem valor igual ao valor da varivel x mais um; tem valor 1 quando o valor da varivel x fora do intervalo [1,4], e 0 quando x est dentro do intervalo.

x + 1

(x < 1) || (x > 4)

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 armazenada na memria.

Expresses de atribuio, assim como expresses, tm valor. O valor de uma expresso de atribuio dado pelo valor da expresso do lado direito do =. Por exemplo:
x = 3 x = y+1

tem valor 3; 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 a i. Uma caracterstica muito peculiar de C++ que expresses de atribuio podem ser usados em qualquer lugar que um valor pode ser usado. Porm voc deve saber que uslo 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 - else. O formato do if-else :

if

else

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 executada. Caso contrrio, a 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.


#include <iostream> using namespace std; int main() { int a, b, c, maior; cout << "Entre com os tres numeros: "; cin >> a >> b >> c; if (a > b) maior = a; else maior = b; if (maior < c) maior = c; cout << "O Maior numero eh " << maior << endl; }

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 !0 !1

lgica: O valor a negao lgica da expresso dada. Por exemplo:

1 0

Ns podemos usar o operador de negao lgica e escrever o exemplo acima como:


if (num>0 && !(num%2)) cout << "Numero par nao negativo." << endl;

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 a==0 || b==0

(verdadeiro se ambos a == 0 e b == 0, portanto se a e b so 0) (verdadeiro se pelo menos uma das variveis a or b for 0)

Uma expresso usando && verdadeira somente se ambos os operadores forem verdadeiros (no zero). Uma expresso usando || falsa somente se ambos os operadores forem falsos (zero). 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

e
!(x || y)

equivalente a !x && !y

7 Exemplos
7.1 IF - ELSE
Assuma as seguintes declaraoes de variveis:
int x = 4; int y = 8;

O que impresso pelos seguintes programas ?


1. 2. 3. 4. 5. 6. 7. 8. if (y = 8) if (x = 5) cout << "a "; else cout << "b "; cout << "c "; cout << "d" << endl;

9.

==> a c d

10. 11. mude = para ==


12. ==> b c d

13. altere o programa acima para produzir a seguinte saida: o Assuma x = 5 e y = 8 1. a 2. a d o Assuma x = 5 e y = 7 a. b c d

7.2 Operadores lgicos


O que impresso pelas seguintes sentenas? 1. Assuma x = 5 e y = 8.
2. 3. 4. 5. if (x == 5 && y == 8) cout << "a" << endl; else cout << "b" << endl; ==> a 6. Assuma x = 4 e y = 8. 7. if (x == 5 || y == 8) 8. cout << "a" << endl; 9. else 10. cout << "b" << endl; ==> a 11. 12. 13. if !(x == 5 || y == 8) // equiv. (x != 5 && y != 8) 14. cout << "a" << endl; 15. else 16. cout << "b" << endl; ==> b 17. 18. 19. if !(x == 5 && y == 8) // equiv. (x != 5 || y != 8) 20. cout << "a" << endl; 21. else 22. cout << "b" << endl; ==> a 23. Precedncia: ! > && > || 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; }

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

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
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:
/* --------------------------------------------------------------------Recebe 2 conjuntos de 3 nmeros e soma o maior valor de cada conjunto. --------------------------------------------------------------------*/ #include <iostream> #include <cmath> using namespace std; int main() { int a, b, c, maior_1, maior_2; /* L o primeiro conjunto de 3 valores */ cin >> a >> b >> c; /* Verifica o maior dos trs valores informados */ /* Assume inicialmente que a varivel 'a' tem o maior valor */ maior_1 = a; /* Somente muda o valor de 'maior' se os valores em 'b' ou 'c' forem maiores */ if (b > maior_1) { maior_1 = b; } if (c > maior_1) { maior_1 = c; } /* Neste ponto do programa, maior_1 contm o maior valor dentre os 3 primeiros valores informados */ /* L o segundo conjunto de 3 valores */ cin >> a >> b >> c; /* Verifica o maior dos trs valores informados */ /* Algoritmo igual ao acima, exceto pela varivel que recebe o maior valor */ /* Assume inicialmente que a varivel 'a' tem o maior valor */

maior_2 = a; /* Somente muda o valor de 'maior' se os valores em 'b' ou 'c' forem maiores */ if (b > maior_2) { maior_2 = b; } if (c > maior_2) { maior_2 = c; } /* Neste ponto do programa, maior_2 contm o maior valor dentre os 3 valores informados no 2o. conjunto de entrada */ /* Calcula e exibe a soma solicitada */ cout << endl << maior_1 << " + " << maior_2 << " = " << maior_1 + maior_2 << endl; }

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:
int maior (int a, int b, int c) { int maior; /* Assume inicialmente que a varivel 'a' tem o maior valor */ maior = a; /* Somente muda o valor de 'maior' se os valores em 'b' ou 'c' forem maiores */ if (b > maior) { maior = b; } if (c > maior) { maior = c; }

return maior; }

O exemplo pode ser ento alterado e simplificado com o uso da funo maior():
/* --------------------------------------------------------------------Recebe 2 conjuntos de 3 nmeros e soma o maior valor de cada conjunto. --------------------------------------------------------------------*/ #include <iostream> #include <cmath> using namespace std; /* Funo que retorna o maior valor entre x, y e z */ int acheMaior (int x, int y, int z) { int maior; /* Assume inicialmente que a varivel 'x' tem o maior valor */ maior = x; /* Somente muda o valor de 'maior' se os valores em 'y' ou 'z' forem maiores */ if (y > maior) { maior = y; } if (z > maior) { maior = z; } return maior; } int main() { int a, b, c, maior_1, maior_2; /* L o primeiro conjunto de 3 valores */ cin >> a >> b >> c; /* Verifica o maior dos trs valores informados */ maior_1 = acheMaior(a,b,c); /* Neste ponto do programa, maior_1 contm o maior valor dentre os 3 primeiros valores informados */

/* L o segundo conjunto de 3 valores */ cin >> a >> b >> c; /* Verifica o maior dos trs valores informados */ /* Usa a mesma funo, pois o procedimento para encontrar maior valor de 3 nmeros o mesmo. */ maior_2 = acheMaior(a,b,c); /* Neste ponto do programa, maior_2 contm o maior valor dentre os 3 valores informados no 2o. conjunto de entrada */ /* Calcula e exibe a soma solicitada */ cout << endl << maior_1 << " + " << maior_2 << " = " << maior_1 + maior_2 << endl; } o

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 funo maior(), 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 de parmetros (tambm chamado de argumentos formais). Se a funo no retorna nenhum valor, o tipo chamado de void, e esta palavra escrita no cabealho na frente do nome da funo. Se a funo no tiver argumentos formais, a palavra void pode ser escrita no lugar da lista de argumentos formais entre os parnteses. Para simplificar a exposio, falaremos sobre o tipo do retorno e os argumentos formais mais tarde. Eles servem para permitir que as funes troquem informaes entre si.

9.3 Funes simples


Para comear, vamos utilizar funes na seguinte forma:
void {

nome-da-funo(void)

declaraes e senteas (corpo da funo)


}

O primeiro void 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(), main()) possuem tipo void. 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 a e b porque troca() no sabe onde na memria estas variveis esto armazenadas. Alm disso, troca() no poderia ser escrito usando a sentena return porque podemos retornar APENAS UM valor (no dois) atravs da sentena return.

11.1 Usando referncia


A soluo para o problema acima ao invs de passar os valores de a e b, passar uma referncia s variveis a e b. Desta forma, troca() saberia que endereo de memria escrever, portanto poderia alterar os valores de a e b. Lembre-se que em C++ a cada varivel est associado: (i) um nome; (ii) um tipo; (iii) um valor; e (iv) um endereo. Assuma que existam as seguintes 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 b porque ela no conhece os endereos de a e b. Mas se referncias para a e b forem passados como argumentos ao invs de a e b, a funo troca() seria capaz de alterar seus valores; ela saberia ento 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 prprocessador. 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 pr-processador. A linha inteira reservada para este comando (nenhum cdigo C++ pode aparecer nesta linha e comandos do pr-processador no podem estar separados em diversas linhas).

12.1 A diretiva #define


Uma diretiva que usada frequentemente o #define. Esta diretiva usada para fazer substituio de macros. Por enquanto, mostraremos uma utilizao simples do #define, que simplestemente uma substituio no texto. O uso mais frequente desta diretiva dar nomes simblicos a uma constante (voc j viu outra maneira de 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 int main() { double raio;

3.14159265

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 prprocessador 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 prprocessador 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 [ ] tem precedncia maior que todos os demais operadores. Operador Associatividade

() [] ! - & * / % + < <= > >= == != && || =

esquerda para direita direita para esquerda esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita direita para esquerda

esquerda para direita

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 Entre Entre Entre a a a a nota nota nota nota do do do do estudante estudante estudante estudante 0: 1: 2: 3: 93 85 74 100

Notas: 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:
#include <iostream> using namespace std; #define TAMANHO 5 // funo array_max(a) // ao: acha o maior inteiro de um array de TAMANHO elementos // entrada: array a de inteiros // saida: o maior valor do array // suposies: a tem TAMANHO elementos // algoritmo: inicializa max com o primeiro elemento do array; em // uma repeticao compara o max com todos os elementos // do array em ordem e muda o valor de max quando um // elemento do array for maior que o max ja' encontrado. // int array_max(int a[]) { int i, max; // Achar o maior valor do array max = a[0];

i = 1; while (i < TAMANHO) { if (max < a[i]) { max = a[i]; } i = i + 1; } return max; } /* Programa principal */ int main() { int i, valor[TAMANHO]; i = 0; while (i < TAMANHO) { cout << "Entre um inteiro: "; cin >> valor[i]; i = i + 1; } cout << "O maior eh " << array_max(valor) << endl; }

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:
#include <iostream> using namespace std; // Troca o valor de uma variavel void troca( int a ){ a = 20; } // Troca valores de elementos em um vetor void troca_vet( int vet[] ){ vet[0] = 60; vet[1] = 70; vet[2] = 80; } // Programa Principal int main() { int x, y; int v[3]; x = 10; v[0] = 30; v[1] = 40; v[2] = 50; troca( x ); cout << "x=" << x << endl; troca_vet( v ); cout << "v[0]=" << v[0] << " v[1]=" << v[1] << " v[2]=" << v[2] ; }

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, troca_vet.

os novos valores alterados de dentro da funo

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 de troca_vet. Ento, quando a funo troca_vet executada, vet um array de elementos do tipo int que comea no endereo 1342. Quando atribumos o valor 60 a vet[0], estamos atribuindo 60 ao primeiro elemento do array que comea no endereo 1342. Como este o mesmo endereo onde comea o array v do programa principal, quando a funo troca_vet termina, o array v ``enxergar'' o valor dos elementos do array que comea no endereo 1342, que foram alterados pela funo.

Quando passamos variveis simples como argumento para uma funo estamos passando somente o valor da varivel, portanto, de dentro da funo no possvel saber qual o endereo da varivel para poder alter-la. Lembre-se que o endereo s passado para a funo quando passamos o array COMO UM TODO (ou seja, o nome do array, sem ser indexado por um elemento). Se passarmos como argumento apenas um elemento do array, o comportamento o mesmo que se passssemos uma varivel simples. Ou seja, o nome do array indexado por um valor entre colchetes refere-se ao valor do elemento do array, enquanto o nome do array sozinho refere-se ao endereo onde comea o array. Assim, no programa abaixo:

#include <iostream> using namespace std; // Troca o valor de uma variavel void troca( int a ){ a = 20; } // Troca valores de elementos em um vetor void troca_v( int vet[] ){ vet[0] = 60; vet[1] = 70; vet[2] = 80; } // Programa Principal int main(){ int v[] = {30, 40, 50}; troca( v[0] ); cout << "v[0]=" << v[0] << endl; troca_v( v ); cout << "v[0]=" << v[0] << " v[1]=" << v[1] << " v[2]=" << v[2] ; }

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.
#include <iostream> using namespace std; #define TAMANHO 30 // funo inicializaArray(a, k) // ao: inicializa todos os elementos de a com k // entrada: array de inteiros a, inteiro k // saida: nenhum // suposies: a tem TAMANHO elementos // algoritmo: uma repeticao for, inicializando um elemento a // cada repeticao // void inicializaArray(int a[], int k) { int i; i = 0; while (i < TAMANHO) { a[i] = k; i = i + 1; } } // Programa principal int main()

{ int valor[TAMANHO]; // Inicializa todos os elementos do array com 42 inicializaArray(valor, 42); // O resto do programa principal // . // . // . }

Como as alteraes feitas por inicializaArray so vistas do programa principal, depois da funo inicializaArray ser executada, no programa principal todos os elementos do array valor tero o valor 42.

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 de pesquisa linear. A pesquisa feita usando uma repetio e examinando cada elemento do array a cada repetio e comparando o elemento com a chave que buscamos. A pesquisa termina quando um elemento do array que ``casa'' com a chave encontrada, ou quando o array todo percorrido e a chave procurada no encontrada.

13.5.1 O Problema
Escreva uma funo pesquisa linear que tem como argumento de entrada: um array de inteiros a ser pesquisado, o tamanho do array, e uma chave (um valor inteiro) a ser procurado. A funo retorna um inteiro: o ndice do elemento do array (se a chave for achada) ou -1 caso contrrio. 1. Prottipo:
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. 4. void soma_array( float [], float [], float [], int );

3. Definio de soma array():


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 --> 1 --> 2 --> conteudo do array depois da passagem ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 5 2 7 3 8 1 4 6 1 1 5 2 2 5 7 7 3 3 8 8 9 9 4 4 6 6

3 --> 4 --> 5 --> 6 --> 7 --> 8 -->

1 1 1 1 1 1

2 2 2 2 2 2

3 3 3 3 3 3

7 4 4 4 4 4

5 5 5 5 5 5

8 8 8 6 6 6

9 9 9 9 7 7

4 7 7 7 9 8

6 6 6 8 8 9

Note que mesmo que se comessemos com um array ordenado de 9 elementos, ainda assim o algoritmo dado faz 8 passagens sobre o array.

13.7.1 Prottipo da funo e definio


1. Prottipo
2. void selectSort(int [], int);

3. Definicao
4. #include <iostream> 5. 6. using namespace std; 7. 8. #define TAM 9 9. 10. void imprimePassos (int v[], int tam, int passo) 11. { 12. int i; 13. 14. cout << "Passo " << passo << ": --> "; 15. 16. i = 0; 17. while (i < tam) 18. { 19. cout << v[i] << " "; 20. i = i + 1; 21. } 22. cout << endl; 23. } 24. 25. /* Uma funcao que encontra o menor valor em um array entre os indices 26. * "a" e "b" (inclusive) 27. */ 28. int menor_indice(int v[], int a, int b) 29. { 30. int i; 31. int menor; 32. 33. menor = a; 34. i = a+1; 35. 36. while (i <= b) 37. { 38. if ( v[i] < v[menor] ) 39. {

40. 41. 42. 43. 44. 45. 46. 47. 48. 49.

menor = i; } i = i + 1; } return menor; }

/* Uma funcao que troca os valores entre dois elementos de um array */ 50. void troca_v( int vet[], int i, int j) 51. { 52. int aux; 53. 54. aux = vet[i]; 55. vet[i] = vet[j]; 56. vet[j] = aux; 57. } 58. 59. /* Uma funcao que ordena um array de inteiros usando o algoritmo de 60. * Select sort. 61. * Entrada: array a ser ordenado -- lista[] 62. * tamanho do array -- tam 63. */ 64. void selectSort(int lista[], int tam) 65. { 66. int i,j, 67. idx_menor_elem; /* indice do menor valor no array entre i e tam-1 */ 68. 69. i = 0; 70. while (i < tam) 71. { 72. imprimePassos( lista, tam, i ); 73. 74. idx_menor_elem = menor_indice ( lista, i, tam-1 ); 75. troca_v ( lista, i, idx_menor_elem ); 76. i = i + 1; 77. } 78. } 79. 80. int main () 81. { 82. int vetor[TAM], i; 83. 84. i=0; 85. while (i < TAM) 86. { 87. cin >> vetor[i]; 88. i = i + 1; 89. } 90. 91. selectSort(vetor, TAM); 92. 93. }

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 --> 1 --> 2 --> 3 --> 4 --> 5 --> 6 --> 7 --> 8 --> conteudo do array depois da passagem ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 5 2 7 3 8 1 4 6 1 1 1 1 1 1 1 1 9 2 2 2 2 2 2 2 5 9 3 3 3 3 3 3 2 5 9 4 4 4 4 4 7 3 5 9 5 5 5 5 3 7 4 5 9 6 6 6 8 4 7 6 6 9 7 7 4 8 6 7 7 7 9 8 6 6 8 8 8 8 8 9

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. #include <iostream> 5. 6. using namespace std; 7. 8. #define TAM 9 9. 10. void imprimePassos (int v[], int tam, int passo) 11. { 12. int i; 13. 14. cout << "Passo " << passo << ": --> "; 15. 16. i = 0; 17. while (i < tam) 18. { 19. cout << v[i] << " "; 20. i = i + 1; 21. } 22. cout << endl; 23. } 24. 25. /* Uma funcao que troca os valores entre dois elementos de um array */ 26. void troca_v( int vet[], int i, int j) 27. { 28. int aux; 29. 30. aux = vet[i]; 31. vet[i] = vet[j]; 32. vet[j] = aux; 33. } 34. 35. /* Uma funcao que ordena um array de inteiros usando o algoritmo de 36. * Bubble sort. 37. * Entrada: array a ser ordenado -- lista[] 38. * tamanho do array -- tam 39. */ 40. void bubbleSort(int lista[], int tam) 41. { 42. int ordenado, /* se 1 depois da passagem o array esta' ordenado */ 43. elem_final = 1, /* em uma passagem, elementos do ultimo ate' elem_final 44. sao comparados com o elemento anterior */

45. 46. 47. 48.

i,j, temp;

/* enquanto o array nao estiver ordenado, fazer uma passagem sobre ele */ 49. ordenado = 0; 50. while (ordenado == 0) 51. { 52. ordenado = 1; /* assume que array esta' ordenado */ 53. 54. /* Examina o array do ultimo elemento ate elem_final. Compara 55. cada elemento com o anteior e troca seus valores se estiver 56. fora de ordem. */ 57. 58. imprimePassos(lista, tam, elem_final - 1); 59. 60. i = tam - 1; 61. while (i >= elem_final) 62. { 63. if (lista[i] < lista[i - 1]) /* troca os elementos de i e i-1 */ 64. { 65. troca_v (lista, i, i - 1); 66. ordenado = 0; /* marca como nao ordenado */ 67. } 68. i = i - 1; 69. } 70. 71. elem_final = elem_final + 1; 72. } 73. } 74. 75. int main () 76. { 77. int vetor[TAM], i; 78. 79. i=0; 80. while (i < TAM) 81. { 82. cin >> vetor[i]; 83. i = i + 1; 84. } 85. 86. bubbleSort(vetor, TAM); 87. 88. }

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] // preenche a matriz com zeros

// // //

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

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]; // preenche a tabela

// // //

numero da coluna numero da linha tabela de taboada

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| 5| 6| 7| 8| 9|

0 0 0 0 0 0

4 5 6 7 8 9

8 10 12 14 16 18

12 15 18 21 24 27

16 20 24 28 32 36

20 25 30 35 40 45

24 30 36 42 48 54

28 35 42 49 56 63

32 40 48 56 64 72

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 cada dimenso , onde o nmero de elementos em , respectivamente, :

Isto define um array chamado

consistindo de um total de .

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; // // preenche o array

numero da coluna numero da linha

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

// //

numero da coluna numero da linha

cout << setw(6) << 0; x = 1; while (x < COL) { cout << setw(3) << x; x = x + 1; } cout << endl; // imprime uma linha horizontal cout << " "; x = 0; while (x < 3*COL) { cout << "-"; x = x + 1; } cout << endl; // // imprime as linhas do array. cada linha e' precedida pelo numero da linha e uma barra vertical

y = 0; while (y < LIN) { cout << setw(2) << y << "|"; x = 0; while (x < COL) { cout << setw(3) << arr[y][x]; x = x + 1; } cout << endl; y = y + 1; } } int main() { int tabela[LIN] [COL]; inicializa_arr(tabela); cout << endl << " imprime_arr(tabela); } Tabela de Multiplicacao" << endl;

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; 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() { o elemento

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.

Anda mungkin juga menyukai