Escolar Documentos
Profissional Documentos
Cultura Documentos
NotasAula PDF
NotasAula PDF
Junho 2012
Parte I
Programao Bsica em C++
Estas notas de aula apresentam os conceitos bsicos da Linguagem C++ e se prope a abordar apenas o que
importante para a compreenso bsica de programas de computadores. Assim, conceitos de C++ como obje-
tos, classes, templates e outros conceitos relacionados programao orientada a objetos no so abordados
aqui.
1
1 Programas C++
Essencialmente, um programa C++ consiste de uma ou mais partes chamadas 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
....
}
Simples:
x = 3;
Composta:
{
i = 3;
i = i + 1;
}
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 6= Minsculas;
sempre uma boa idia ter certas regras (para voc mesmo) para nomear variveis para tornar o pro-
grama mais legvel:
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.
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;
...
}
4
Para resumir: quando um programa executado, uma varivel associada com:
um tipo: diz quantos bytes a varivel ocupa, e como ela deve ser interpretada.
um nome: um 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.
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 " << pera << "peras de qualidade " << qualidade
<< "pesando " << peso << "quilos." << endl;
cout << "O preco por quilo eh R$" << PRECO
<< ", o total eh R$" << peso * PRECO << endl;
}
A 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.
6
1.6.2 Lendo informao: cin
cin pode ser usado para ler valores digitados no teclado.
Considere o seguinte programa:
#include <iostream>
using namespace std;
int main()
{
int idade;
cout << "Voce tem " << idade << "anos." << endl;
}
Este programa mostrar no monitor: Entre sua idade: e aguardar que um nmero seja digitado e a
tecla ENTER. Depois disso, a varivel idade conter o valor digitado pelo usurio.
Mais de um valor pode ser lido por um mesmo cin. Considere o seguinte exemplo:
#include <iostream>
using namespace std;
int main()
{
int dia, mes, ano;
cout << "Entre com a data do seu aniversario (dd mm aa): ";
cin >> dia >> mes >> ano;
cout << "Voce nasceu em " << dia << "/" << mes << "/" << ano << endl;
}
Este exemplo funciona exatamente como o exemplo anterior. Um nico cin l os 3 nmeros quando
estes nmeros so separados por espaos (espaos em branco, tabulao, novas linhas). Ento voc pode
teclar ENTER depois de cada nmero, ou colocar espaos ou tabulaes entre os nmeros. Os espaos so
ignorados pelo cin.
/* Definir variaveis */
int Raio;
float Perim, Area, PI;
PI = 3.14159;
7
/* Obter Raio da circunferencia */
Escreva("Entre com o valor do raio:");
Leia(Raio);
/* 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++
#define PI 3.14159
int main( )
{
/* Definir variaveis */
int Raio;
float Perim, Area;
/* Exibir Resultados */
cout << "O perimetro da circunferencia de raio " << Raio
<< " eh " << Perim << endl;
cout << "e a area eh " << Area << endl;
8
}
9
2 Operaes Aritmticas e Expresses.
Operaes Relacionais.
2.1 Operaes Aritmticas
Em C++ , ns podemos executar operaes aritmticas usando variveis e constantes. Algumas operaes
mais comuns so:
+ adio
- subtrao
* multiplicao
/ diviso
% resto (mdulo)
Estas operaes podem ser usadas como mostram os exemplos abaixo, assumindo que as variveis ne-
cessrias j esto declaradas:
i = i + 1;
Esta operao usada quando queremos encontrar o resto da diviso de dois inteiros. Por exemplo, 22
dividido por 5 4, com resto 2 (4 5 + 2 = 22).
Em C++ , a expresso 22 % 5 ter valor 2.
Note que % s pode ser utilizados entre dois inteiros. Usando ele com um operando do tipo float
causa um erro de compilao (como em 22.3 % 5).
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;
int yucky + 2 = 5;
Em C++ , h operadores que podem ser usados para comparar expresses: os operadores relacionais.
H seis operadores relacionais em C++ :
== igual a
!= no igual a (6=)
int main()
{
int idade;
idade = 17;
cout << "Pode tirar carteira de motorista? " << (idade >= 18) << endl;
idade = 35;
cout << "Pode tirar carteira de motorista? " << (idade >= 18) << endl;
}
11
2.2.1 Precedncia dos operadores relacionais
Operadores aritmticos tem precedncia maior que os operadores relacionais. Por exemplo, a expresso
3 + 5 < 6 * 2 o mesmo que (3 + 5) < (6 * 2).
Se por alguma razo voc quer que o resultado do uma operao relacional em uma expresso aritmtica,
necessrio usar parntesis. Por exemplo, a expresso score + (score == 0) ser sempre igual ao
valor de score, exceto quando o valor de score seja 0. Neste caso, o valor da expresso 1 (porque
(score == 0) igual a 1).
Uma observao sobre valores booleanos embora voc possa assumir que o valor de uma operao
relacional 0 ou 1 em C++ , qualquer valor diferente de zero considerado verdadeiro. Falaremos
sobre isso mais tarde durante o curso.
#include <iostream>
using namespace std;
int main() {
int score = 5;
cout << 5 + 10 * 5 % 6; // 7
cout << 10 / 4; // 2
cout << 10.0 / 4.0; // 2.5
cout << A + 1 // B
cout << score + (score == 0); // 5
}
#include <iostream>
using namespace std;
int main() {
int n1, n2, n3;
a * b / c + 30 >= 45 + d * 3 ++e == 10
12
#include <iostream>
using namespace std;
int main() {
int numero;
Exemplo 2: escreva um programa que leia 3 nmeros inteiros e calcule a soma, mdia, e produto.
#include <iostream>
#include <iomanip> // necessario para usar setw() e setf() em cout
using namespace std;
int main() {
int n1, n2, n3;
int soma;
Operador Associatividade
13
3 Expresses como valores
Em C++ , todas as expresses so avaliadas. O resultado da avaliao um valor e pode ser usado em
quaisquer lugares.
i = j = k = 0;
int quadrado, n = 2;
cout << "Quadrado de " << n << " eh menor que 50? " << ((quadrado = n * n) <
3
Operadores lgicos && e || sero vistos na prxima aula.
14
causa no apenas que o valor 4 seja impresso, como a avaliao da expresso relacional dentro do cout
faz com que o nmero 4 seja copiado para o endereo de memria associado com a varivel quadrado.
Note que necessrio usar parnteses em quadrado = n * n j que = tem menor precedncia que o
operador relacional <.
Agora compare o exemplo anterior com o prximo, no qual o valor 4 impresso, mas sem nenhum
efeito colateral:
int quadrado, n = 2;
cout << "Quadrado de " << n << " eh menor que 50? " << (n * n < 50) << endl;
Note que agora no h necessidade de parnteses para a expresso n * n porque * tem maior prece-
dncia que o operador relacional <.
15
4 Ordem sequencial de execuo de sentenas
o comando condicional: if e if - else
A execuo de um programa C++ comea com a funo main(). Em todos os exemplos que vimos at este
momento, sentenas so executadas sequencialmente. A ordem sequencial de execuo de senteas pode
ser alterada se certas condies forem satisfeitas durante a execuo do programa. Isto chamado desvio
condicional.
Todas as linguagens de programao oferecem comandos para o desvio condicional. O mais simples a
sentea if. Em C++ , ele tem o formato:
if (expressao)
corpododesvio
O corpo do desvio, por sua vez, pode ser uma sentena simples ou composta (veja Seo 1.1).
Quando uma sentena if encontrada em um programa,
2. Se o valor da expresso de teste for DIFERENTE de zero, as sentenas que compem o corpo do
desvio que segue a expresso de teste so executadas.
Figura 1: O comando if
Considere o seguinte exemplo que converte uma frao digitada pelo usurio (numerador e denomina-
dor) em decimal e imprime o resultado:
#include <iostream>
using namespace std;
int main( ){
int a, b;
cout << "Entre com uma fracao (numerador and denominador): ";
cin >> a >> b;
cout << "A fracao em decimal eh " << 1.0 * a / b << endl;
}
16
No exemplo acima, escrevemos 1.0 * a / b, j que a e b so do tipo int, e portanto a / b uma
diviso de inteiros e a parte fracional do resultado seria truncado, o que certamente no o que desejamos.
Voce v algo errado neste programa ? Uma coisa a ser notada que se o usurio digitar um denominador
igual a 0, ns teremos um erro de execuo, j que o programa tentaria executar uma diviso por zero. O
que necessrio fazer testar se o denominador igual a zero e dividir s no caso dele for diferente de zero.
Poderamos reescrever o programa acima da seguinte forma:
Exemplo 1:
#include <iostream>
using namespace std;
int main( ){
int a, b;
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( ){
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 denomi-
nador ser zero, imprimirmos uma mensagem de erro ao usurio, explicando o que h de errado.
A sentena em C++ que permite fazermos isso o if - else. O formato do if-else :
17
if (expressao)
sentenca1
else
sentenca2
Primeiro, a expressao (que usualmente chamamos de condio) avaliada. Caso a condio seja ver-
dadeira (o que equivalente a dizer que o valor diferente de zero), entao a sentenca1 executada. Caso
contrrio, a sentenca2 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>
18
using namespace std;
int main( ){
int num;
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
ser impressa.
Agora, suponha que, devido a um erro, voc tenha colocado = ao invs de ==:
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
19
ser impressa. Alm disso, a atribuio causar um efeito colateral, e alterar o valor de saldo para 1.
Tal uso do operador de atribuio no ilegal, e no ser detectado pelo compilador como erro. Portanto,
tome cuidado com o uso de atribuio no lugar de igualdade. Tal erro muito comum, e no fcil de achar.
Como regra geral, NO utilize atribuies dentro de outras sentenas.
#include <iostream>
using namespace std;
int main( ){
int num;
Regra de associao: Um else est associado com a ltima ocorrncia do if sem else.
O exemplo seguinte est errado porque associa o else ao if "incorreto":
#include <iostream>
using namespace std;
int main( ){
20
int num;
#include <iostream>
using namespace std;
int main( ){
int num;
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;
21
// Como corrigir o problema (este programa funciona)
if (num != 0) {
if (num == 1)
cout << "Voce tem uma pera.\n";
}
else
cout << "Voce nao tem nenhuma pera.\n";
}
6 Operadores Lgicos
Todos os programas at agora consideraram if com condies de teste simples. Alguns exemplos de testes
simples: b != 0, contador <= 5. Estas expresses testam uma condio. Portanto, quando mais de
uma condio precisa ser testada, precisamos usar sentenas if e if-else aninhadas.
A linguagem C++ , assim como a maioria das linguagens de programao de alto nvel suportam ope-
radores lgicos que podem ser usados para criar operaes lgicas mais complexas, combinando condies
simples. O valor de uma expresso lgica ou VERDADEIRO ou FALSO. Lembre que no h constan-
tes lgicas VERDADEIRO e FALSO em C++ ; em expresses lgicas 0 interpretado como FALSO, e
qualquer valor diferente de zero interpretado como VERDADEIRO.
Os operadores lgicos so
! NO lgico, operao de negao (operador unrio)
&& E lgico, conjuno (operador binrio)
|| OU lgico, disjuno (operador binrio).
Por exemplo, se quisermos testar se um nmero num positivo e par, e imprimir uma mensagem como
no exemplo anterior, podemos escrever:
if (num >= 0)
if (num % 2 == 0)
cout << "Numero par nao negativo." << endl;
22
Os dois operadores binrios operam sobre duas expresses lgicas e tem o valor 1 (verdadeiro) or 0
(falso). Os exemplos abaixo mostram o seu uso:
a==0 && b==0 (verdadeiro se ambos a == 0 e b == 0, portanto se a e b so 0)
a==0 || b==0 (verdadeiro se pelo menos uma das variveis a or b for 0)
Uma expresso usando && verdadeira somente se ambos os operadores forem verdadeiros (no
zero).
Uma expresso usando || falsa somente se ambos os operadores forem falsos (zero).
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:
Operador Associatividade
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.
23
#include <iostream>
using namespace std;
int main( ){
7 Exemplos
7.1 IF - ELSE
Assuma as seguintes declaraoes de variveis:
int x = 4;
int y = 8;
O que impresso pelos seguintes programas ?
1. if (y = 8)
if (x = 5)
cout << "a ";
else
cout << "b ";
cout << "c ";
cout << "d" << endl;
==> a c d
24
2. mude = para ==
==> b c d
Assuma x = 5 e y = 8
(a) a
(b) a d
Assuma x = 5 e y = 7
(a) b c d
1. Assuma x = 5 e y = 8.
if (x == 5 && y == 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> a
2. Assuma x = 4 e y = 8.
if (x == 5 || y == 8)
cout << "a" << endl;
else
cout << "b" << endl; ==> a
if (x == 5 || y == 8 && z == 10)
equiv.
if (x == 5 || (y == 8 && z == 10))
25
8 A construo else-if
Embora ela no seja um tipo diferente de sentena, a seguinte construo bastante comum para programar
decises entre diversas alternativas:
if (expressao1 )
sentenca1
else if (expressao2 )
sentenca2
else if (expressao3 )
sentenca3
..
.
else if (expressaon1 )
sentencan1
else
sentencan
As expresses lgicas so avaliadas em ordem, comeando com a expressao1 . Se uma das expres-
ses for verdadeira, a sentena associada ser executada. Se nenhuma for verdadeira, ento a sentena,
sentencan , do ltimo else ser executada como opo default. Se a opo default no for necessria,
ento a parte
else
sentencan
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( ){
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( ){
28
9 Funes
9.1 Funes: o que so e por que us-las
Quando queremos resolver um problema, em geral tentamos dividi-lo em subproblemas mais simples e re-
lativamente independentes, e resolvemos os problemas mais simples um a um. A linguagem C++ dispe de
construes (abstraes) que auxiliam o projeto de programas de maneira top-down. Uma funo cria uma
maneira conveniente de encapsular alguns detalhes de processamento, ou seja, como algum resultado ob-
tido. Quando esta computao necessria, a funo chamada, ou invocada. Desta forma, quando uma
funo chamada o usurio no precisa se preocupar como a computao realizada. importante saber
o que a funo faz (qual o resultado da execuo de uma funo) e tambm como se usa a funo. Criando
funes, um programa C++ pode ser estruturado em partes relativamente independentes que correspondem
as subdivises do problema.
Voc j viu algumas funes: cin.get(), sqrt(). Elas so funes de uma biblioteca padro (do
C++ ). Voc no sabe como elas foram escritas, mas j viu como utiliz-las. Ou seja, voc sabe o nome das
funes e quais informaes 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:
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 a, b, e c, d como resultado o maior valor dentre os trs valores fornecidos:
O exemplo pode ser ento alterado e simplificado com o uso da funo maior():
Como pode ser observado, sejam quais forem os conjuntos de 3 nmeros fornecidos, no precisa escre-
ver um cdigo similar ao mostrado na funo maior acima para cada nmero. Basta chamar a funo
maior(), passar os valores necessrios para verificar o maior valor de cada conjunto, e utilizar os resulta-
dos.
Evitar repetio de cdigo a razo histrica que funes foram inventadas (tambm chamado de proce-
dimento ou subrotinas em outras linguagens de programao). A maior motivao para utilizar funes nas
linguagens contemporneas a reduo da complexidade do programa e melhoria da modularidade do pro-
grama. Dividindo o programa em funes, muito mais fcil projetar, entender e 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
29
uma da outra. Se as variveis so locais a uma funo, programas grandes passam a ser mais fceis de serem
escritos. A comunicao entre funes passa a ser controlada elas se comunicam somente atravs pelos
valores passados as funes e os valores retornados.
#include <iostream>
using namespace std;
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 anun-
ciado 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
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
30
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.
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 exe-
cutada). 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;
// Programa Principal
int main()
{
alo();
}
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().
31
9.3.1 Argumentos
Nosso prximo exemplo pede que o usurio digite suas iniciais, e ento chama a funo cumprimenta()
para imprimir a mensagem Ola junto com as iniciais digitadas. Estas iniciais (seus valores) so passadas
para a funo cumprimenta(). A funo cumprimenta() definida de forma que ela imprimir a
mensagem incluindo quaisquer iniciais passadas.
#include <iostream>
using namespace std;
int main()
{
char 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).
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.
32
// programa que verifica se 3 numeros podem ser os lados de um
// triangulo reto.
//
#include <iostream>
using namespace std;
int main()
{
int s1, s2, s3;
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.
33
#include <iostream>
using namespace std;
int cinco(void)
{
return 5;
}
int main()
{
cout << "cinco = " << cinco() << endl;
}
#include <iostream>
using namespace std;
int obtem_valor(void)
{
int valor;
return valor;
}
int main()
{
int a, b;
a = obtem_valor();
b = obtem_valor();
Este programa obtm dois inteiros do usurio e mostra a sua soma. Ele usa a funo obtem valor()
que mostra uma mensagem e obtm o valor do usurio.
Um exemplo de sada deste programa :
Entre um valor: 15
Entre um valor: 4
soma = 19
34
9.5 Mais sobre o return
Quando uma funo return executada, a funo imediatamente acaba mesmo que haja cdigo na
funo aps a sentena return. A execuo do programa continua aps o ponto no qual a chamada de
funo foi feita. Sentenas return podem ocorrer em qualquer lugar na funo no somente no 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;
if (valor >= 0)
return valor;
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;
/* 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.
35
9.6 Mais sobre Argumentos
A comunicao entre uma funo e o chamador pode ser nas duas direes. Argumentos podem ser usados
pelo chamador para passar dados para a funo. A lista de argumentos 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;
return x;
}
int main()
{
int 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.
36
O exemplo seguinte possui mais de um argumento:
Esta funo possui dois argumentos do tipo float. Para chamar uma funo com mais de um argu-
mento, os argumentos devem ser separados por vrgula. A ordem em que os argumentos so passados deve
ser na mesma em que so 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.
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.
#include <iostream>
using namespace std;
void obtem_int(void)
{
37
int x;
int main()
{
obtem_int();
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;
int main()
{
int x;
x = obtem_novo_int();
A funo obtem novo int() usa uma varivel local chamada x para armazenar o valor digitado e
retorna como resultado o valor de x. main() usa outra varivel local, tambm chamada de x para receber
o resultado retornado por obtem novo int(). Cada funo tem sua prpria varivel x.
38
9.9 Prottipos
Os prottipos 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:
Suposies o que voc assume ser verdade para que a funo funcione apropriadamente
Estas informaes devem ser colocadas como comentrio antes da definio da funo.
39
9.11 Comentrios
Voc pode colocar comentrios no seu programa para documentar o que est fazendo. O compilador ignora
completamente o que quer esteja dentro de um comentrio.
Comentrios em C++ so textos que comeam com // em cada linha, ou so delimitados por /* e */.
Os smbolos // no possuem espao entre si. Alguns exemplos:
41
10 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues. Estas estruturas de repeti-
o, tambm conhecidas como laos (do ingls loops). Nesta seo veremos a estrutura while, Sendo que
as demais estruturas de repetio em C++ , for e do ... while sero vistas na Seo 19.
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).
#include <iostream>
using namespace std;
int contador;
contador = 0;
while( contador < 5 )
{
cout << "contador = " << contador << endl;
contador = contador + 1;
}
Sada:
contador = 0
contador = 1
contador = 2
contador = 3
42
contador = 4
ACABOU !!!!
Neste exemplo, a expresso de teste contador < 5, e o corpo do lao a sentena cout.
Se examinarmos cuidadosamente este exemplo, veremos que a varivel contador inicializada com 0
(zero). Depois disso, a expresso de teste 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( ){
total = 0;
while( total < 20 ) {
cout << "Total = " << total << endl;
cout << "Entre com um numero: ";
cin >> num;
Exemplo de sada:
Total = 0
Entre com um numero: 3
Total = 3
Entre com um numero: 8
Total = 11
Entre com um numero: 15
Final total = 26
Inicialmente, dado o valor 0 varivel total, e o teste verdadeiro ( 0 < 20). Em cada iterao, o
total impresso e o usurio digita um nmero que somado a total. Quanto total for maior ou igual a 20,
o teste do while torna-se falso, e a repetio termina.
43
10.2 Estilo de formatao para estruturas de repetio
A regra principal ser consistente. Assim, seu programa ser mais legvel.
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.
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;
while( i < 5 )
i = i + 1;
j = j + 1;
44
enquanto a inteno era na realidade:
while( i < 5 ) {
i = i + 1;
j = j + 1;
}
while (i<5)
ou
while( i < 5 )
Isto tambm uma escolha pessoal. Porm seja consistente em sua escolha !
Exemplo 2:
#include <iostream>
#include <iomanip> // Necessrio para se usar a funo setw() em cout
int main( ){
linha = 1;
while (linha < 5)
{
coluna = 1;
while (coluna < 5)
{
cout << setw(3) << linha * coluna;
coluna = coluna + 1;
}
linha = linha + 1;
}
cout << endl;
}
Sada:
45
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
No exemplo acima, para cada iterao do lao externo, o lao interno imprime uma linha com nmeros
e depois pula de linha.
Exemplo 3: Este exemplo parecido com o anterior, exceto que o cout que produz a mudana de 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
int main( ){
linha = 1;
while (linha < 5)
{
coluna = 1;
while (coluna < 5)
{
cout << setw(3) << linha * coluna;
cout << endl;
coluna = contador + 1;
}
linha = linha + 1;
}
}
Sada:
1
2
3
4
2
4
6
8
3
6
9
12
4
8
46
12
16
Exemplo 4: Este exemplo imprime um tringulo de asteriscos, de forma que a quantidade de asteriscos
em uma linha igual ordem da linha (na linha 1, 1 asterisco, na linha 2, 2 asteriscos, etc.)
#include <iostream>
int main( ){
Sada:
*
**
***
****
*****
******
*******
********
47
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 << "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;
}
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;
temp = x;
x = y;
y = temp;
}
48
int main()
{
int 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;
}
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.
int i = 5;
char c = G;
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>
temp = px;
px = py;
py = temp;
}
int main()
50
{
int a, b;
cout << "Voce entrou com " << a << " e " << b << endl;
cout << "Trocados, eles sao " << a << " e " << b << endl;
}
Basicamente, se a funo precisa alterar o valor de uma varivel no ponto de chamada da funo, ento
passamos o nome da varivel como parmetro real, e escrevemos a funo indicando os parmetros como
sendo de SADA ou PASSADOS POR REFERNCIA.
51
12 O pr-processador
O pr-processador um programa que faz alguns processamentos simples antes do compilador. Ele exe-
cutado automaticamente todas as vezes que seu programa compilado, e os comandos a serem executados
so dados atravs de diretivas do pr-processador.
Estas diretivas so colocadas em linhas que contm somente a diretiva (elas no so cdigo da lingua-
gem C++ , portanto as regras para elas so um pouco diferentes). As linhas que comeam com um # so
comandos para o pr-processador. A linha inteira reservada para este comando (nenhum cdigo C++ pode
aparecer nesta linha e comandos do pr-processador no podem estar separados em diversas linhas).
#define PI 3.14159265
int main()
{
double raio;
Lembre-se que o nome PI no um nome de varivel. Ele um nome que o pr-processador substituir
pelo texto especificado pelo #define (mais ou menos da mesma forma que o comando pesquisa-e-substitui
do editor de texto). O compilador nunca v ou sabe sobre PI. O compilador v o seguinte cout do
programa acima depois do pr-processador ser executado:
cout << "Circunferencia = " << 2.0 * 3.14159265 * raio << endl;
12.3 Comentrios
De um modo geral, o pr-processador dos compiladores existentes remove todos os comentrios do arquivo
fonte antes do programa ser compilado. Portanto, o compilador nunca v realmente os comentrios.
53
13 Vetores ou Arrays
Considere o seguinte programa. Este programa pede ao usurio notas de 4 estudantes, calcula a mdia e
imprime as notas e a mdia.
int main()
{
int nota0, nota1, nota2, nota3;
int media;
cout << "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 estu-
dantes:
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].
54
int total[5];
float tamanho[42];
O primeiro exemplo um array de 5 inteiros (o tipo int) com o nome total. Como a numerao de
arrays comea com 0, os elementos da array so numerados 0, 1, 2, 3 e 4.
O segundo exemplo um array de 42 elementos do tipo float com ndices de 0 a 41.
Cada elemento do array total do tipo inteiro e pode ser usado do mesmo jeito que qualquer varivel
inteira. Para nos referirmos a um elemento do array, usamos colchetes tambm ([ e ]). O valor dentro
dos colchetes pode ser qualquer expresso do tipo inteiro. Quando um array 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
x = total[3];
i = 4;
total[4] = total[4] + 1;
tamanho[17] = 2.71828;
sala = 3;
int main()
{
int indice, nota[4];
55
float total;
indice = 0;
while (indice < 4)
{
cout << "Entre a nota do estudante " << indice << ": ";
cin >> nota[indice];
indice = indice + 1;
}
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:
#define ESTUDANTES 4
int main()
{
int indice, nota[ESTUDANTES];
float total;
indice = 0;
while (indice < ESTUDANTES)
{
cout << "Entre a nota do estudante " << indice << ": ";
cin >> nota[indice];
indice = indice + 1;
}
56
cout << "Notas: ";
total = 0;
indice = 0;
while (indice < ESTUDANTES)
{
cout << nota[indice] << " ";
total = total + nota[indice];
indice = indice + 1;
}
cout << endl << "Media: " << total / ESTUDANTES << endl;
}
int erro[5];
H mais uma restrio na inicializao de um array. Os valores devem ser todos constantes nenhuma
varivel ou expresso permitida. O seguinte trecho de programa produz um erro porque um dos valores de
inicializao uma varivel:
int x = 21;
int yy[3] = { 1, 2, x }; // ISTO ESTA ERRADO
57
13.3 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>
#define TAM 10
int main()
{
int ops[TAM], i;
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.
58
Aqui est um exemplo de execuo deste programa
Entre um inteiro: 73
Entre um inteiro: 85
Entre um inteiro: 42
Entre um inteiro: -103
Entre um inteiro: 15
O maior e 85
Em main() a chamada para array max() tem valor como seu argumento, que copiado para o
parmetro formal a, que um array de inteiros. Note que o tamanho no foi especificado, somente o nome
do array, a. Porm tambm correto incluir o tamanho (isto uma questo de estilo escolha o que voc
preferir):
x=10
v[0]=60 v[1]=70 v[2]=80
O valor da varivel x do programa principal no se altera porque como j vimos nas notas de aula 7,
quando a funo troca chamada, o valor do argumento real x avaliado, que 10, este valor copiado
para o parmetro formal a da funo troca e a funo ento executada. O parmetro a da funo
tratada como varivel local, portanto quando atribumos 20 a a, estamos atribuindo 20 a uma varivel
local. Terminada a funo, a execuo retorna ao programa principal, que imprime o valor de x, que no foi
alterado, ou seja, imprime x=10.
Quando a funo troca_vet chamada, o array v passado como argumento e copiado para o
parmetro formal vet. A funo ento executada, e os elementos do array so alterados para 60, 70,
80. Como mencionado anteriormente, quando passamos um array como parmetro, as alteraes feitas no
array dentro da funo alteram o array passado como parmetro. Portanto, quando a funo termina e a
execuo continua no programa principal com a impresso dos valores dos elementos de v, ser impresso
60, 70, 80, os novos valores alterados de dentro da funo troca_vet.
Vamos entender por que quando passamos s o nome do array como argumento as alteraes afetam
o array passado como parmetro real. Como j mencionamos anteriormente, quando um array definido,
como v no programa principal acima, alocado espao suficiente na memria para conter todos os elementos
do array. Na ilustrao abaixo, so alocados 6 bytes de memria a partir do endereo 1342 para conter
59
o array. O array como um todo no tem um valor, mas cada elemento do array tem (neste caso, foram
inicializados com 30, 40, 50). O nome do array, na verdade, contm o endereo onde comea o array,
neste caso, o endereo 1342.
Portanto, quando passamos o nome do array como argumento para uma funo estamos na realidade
passando como argumento o endereo de memria onde comea o array. No exemplo anterior, 1342
passado como argumento para o parmetro formal vet da funo troca_vet. Portanto, da mesma forma
que no caso da varivel simples, o valor de v, que o endereo 1342, copiado para o parmetro vet
de troca_vet. Ento, quando a funo troca_vet executada, vet um array de elementos do tipo
int que comea no endereo 1342. Quando atribumos o valor 60 a vet[0], estamos atribuindo 60 ao
primeiro elemento do array que comea no endereo 1342. Como este o mesmo endereo onde comea
o array v do programa principal, quando a funo troca_vet termina, o array v enxergar o valor dos
elementos do array que comea no endereo 1342, que foram alterados pela funo.
Quando passamos variveis simples como argumento para uma funo estamos passando somente o
valor da varivel, portanto, de dentro da funo no possvel saber qual o endereo da varivel para poder
alter-la.
Lembre-se que o endereo s passado para a funo quando passamos o array COMO UM TODO
(ou seja, o nome do array, sem ser indexado por um elemento). Se passarmos como argumento apenas um
elemento do array, o comportamento o mesmo que se passssemos uma varivel simples. Ou seja, o nome
do array indexado por um valor entre colchetes refere-se ao valor do elemento do array, enquanto o nome
do array sozinho refere-se ao endereo onde comea o array. Assim, no programa abaixo:
A sada do programa :
v[0]=30
v[0]=60 v[1]=70 v[2]=80
Outro exemplo: a funo inicializaArray abaixo inicializa todos os elementos do array valor
com um valor passado como argumento pelo programa principal.
Como as alteraes feitas por inicializaArray so vistas do programa principal, depois da funo
inicializaArray ser executada, no programa principal todos os elementos do array valor tero o
valor 42.
60
13.5 Exemplo: pesquisa linear de um array
Pesquisar (procurar) em um array um determinado valor (chamado de chave) um problema muito comum
em programao. Ele tem diversas aplicaes. Por exemplo, podemos pesquisar um array de notas para ve-
rificar 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. Definio:
i = tamanho - 1;
while (i >= 0)
{
if (arr[i] == chave)
{
return i;
}
i = i - 1;
}
return -1;
}
61
1. Prottipo:
void soma_array( float arr1[], float arr2[], float arr3[], int tam )
{
int i;
i = 0
while ( i < tam )
{
arr3[i] = arr1[i] + arr2[i];
i = i + 1;
}
}
1 --> 1 5 2 7 3 8 9 4 6
2 --> 1 2 5 7 3 8 9 4 6
3 --> 1 2 3 7 5 8 9 4 6
4 --> 1 2 3 4 5 8 9 7 6
5 --> 1 2 3 4 5 8 9 7 6
6 --> 1 2 3 4 5 6 9 7 8
7 --> 1 2 3 4 5 6 7 9 8
8 --> 1 2 3 4 5 6 7 8 9
Note que mesmo que se comessemos com um array ordenado de 9 elementos, ainda assim o algoritmo
dado faz 8 passagens sobre o array.
62
13.7.1 Prottipo da funo e definio
1. Prottipo
2. Definicao
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.
1 --> 1 9 5 2 7 3 8 4 6
2 --> 1 2 9 5 3 7 4 8 6
3 --> 1 2 3 9 5 4 7 6 8
4 --> 1 2 3 4 9 5 6 7 8
5 --> 1 2 3 4 5 9 6 7 8
6 --> 1 2 3 4 5 6 9 7 8
7 --> 1 2 3 4 5 6 7 9 8
8 --> 1 2 3 4 5 6 7 8 9
63
Note que, tambm aqui, mesmo que se comessemos com um array ordenado de 9 elementos, ainda
assim o algoritmo dado faz 8 passagens sobre o array.
Isto pode ser melhorado da seguinte forma: Antes de comear cada passagem, inicializamos uma vari-
vel ordenado com 1. Se durante a passagem uma troca de valores ocorrer, trocamos o valor da varivel
para 0. Assim, se depois da passagem, o valor da varivel continuar sendo 1, isso significa que nenhuma
troca ocorreu e que o array est ordenado.
2. Definicao
int main(){
int arr1[4] = {10, 20, 30, 40};
int arr2[4];
64
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; // numero da coluna
int y; // numero da linha
char matriz [ALTURA] [LARGURA]; // array 2-D [num_lins, num_cols]
y = 0;
while(y < ALTURA)
{
x = 0;
while(x < LARGURA)
{
matriz[y][x] = 0;
x= x + 1;
}
y= y + 1;
}
cout << endl << "Entre coordenadas na forma \"y x\"." << endl;
cout << "Use valores negativos para sair do programa." << endl;
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;
}
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.
#include <iostream>
#include <iomanip>
#define LIN 10
#define COL 10
int main()
{
int x; // numero da coluna
int y; // numero da linha
int tabela[LIN] [COL]; // tabela de taboada
// preenche a tabela
y = 0;
while (y < LIN)
{
x = 0;
while (x < COL)
{
66
tabela[y][x] = y*x;
x = x + 1;
}
y = y + 1;
}
y = 0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x = 0;
while (x < COL)
{
cout << setw(3) << tabela[y][x];
x = x + 1;
}
cout << endl;
y = y + 1;
}
}
A sada do programa :
Tabela de Multiplicacao
67
0 1 2 3 4 5 6 7 8 9
------------------------------
0| 0 0 0 0 0 0 0 0 0 0
1| 0 1 2 3 4 5 6 7 8 9
2| 0 2 4 6 8 10 12 14 16 18
3| 0 3 6 9 12 15 18 21 24 27
4| 0 4 8 12 16 20 24 28 32 36
5| 0 5 10 15 20 25 30 35 40 45
6| 0 6 12 18 24 30 36 42 48 54
7| 0 7 14 21 28 35 42 49 56 63
8| 0 8 16 24 32 40 48 56 64 72
9| 0 9 18 27 36 45 54 63 72 81
14.1 Inicializao
Arrays multidimensionais podem ser inicializados usando listas aninhadas de elementos entre chaves. Por
exemplo, um array bidimensional tabela com trs linhas e duas colunas pode ser inicializado da seguinte
forma:
Quando o array inicializado, o tamanho da primeira dimenso pode ser omitido. A definio de array
abaixo equivalente a dada anteriormente.
int tabela[2][3];
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:
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.
#include <iostream>
#include <iomanip>
using namespace std;
#define LIN 10
#define COL 10
// preenche o array
y=0;
while (y < LIN)
{
x=0;
while(x < COL)
{
69
arr[y][x] = y*x;
x = x + 1;
}
y = y + 1;
}
}
y = 0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x = 0;
while (x < COL)
{
cout << setw(3) << arr[y][x];
x = x + 1;
}
70
cout << endl;
y = y + 1;
}
}
int main()
{
int tabela[LIN] [COL];
inicializa_arr(tabela);
imprime_arr(tabela);
}
#include <iostream>
using namespace std;
#define ALTURA 7
#define LARGURA 7
y = 0;
while (y < ALTURA)
{
x = 0;
while (x < LARGURA)
{
cout << matriz[y][x] << " ";
x = x + 1;
}
71
// funcao que preenche uma matriz ALTURA X LARGURA com pontos
void pontos( char matriz[][LARGURA])
{
int x,y;
y = 0;
while (y < ALTURA)
{
x = 0;
while (x<LARGURA)
{
matriz[y][x] = .;
x = x + 1;
}
y = y + 1;
}
}
cout << endl << "Entre com as coordenadas na forma \"y x\"." << endl;
cout << "Use numeros negativos para terminar." << endl;
y = 0;
72
while (y < ALTURA)
{
x = 0;
while (x <= y)
{
matriz[y][x] = @;
x = x + 1;
}
y = y + 1;
}
}
// funcao que espera ate que uma tecla qualquer seja digitada
void pausar() {
char c;
cin.get(c);
}
pontos(matriz);
seleciona_elem(matriz);
73
pausar();
flip(matriz);
imprime_matriz(matriz);
pausar();
marca_triang( matriz);
imprime_matriz( matriz);
pausar();
flip( matriz);
imprime_matriz(matriz);
pausar();
}
74
Parte II
Tpicos Avanados
As sees seguintes apresentam temas mais avanados da linguagem C++ , no abordadas em sala de aula.
Elas podem ser estudadas pelo aluno como atividade complementar, pois apresentam mecanismos bastantes
teis em programas mais complexos (tratamento de arquivos e textos, manipulao dinmica de memria,
etc.).
75
15 Operadores e Expresses Especiais
15.1 Operao de Atribuio Aritmtica
freqente em programas C++ expresses do tipo:
x = x * (y + 1);
j = j - 1;
C++ fornece operadores adicionais que podem ser usados para tornar estes tipos de atribuies mais
curtos.
H um operador de atribuio para cada operao aritmtica listada anteriormente:
Cada uma dessas operaes podem ser usadas para tornar as expresses anteriores mais curtas:
tudo += parte;
tamanho *= 2.5;
x *= y + 1;
j -= 1;
H alguns operadores em C++ que so equivalentes as seguintes expresses (que so bastante comuns
em programas):
k = k + 1;
j = j - 1;
Estes operadores adicionais, que so ++ e --, podem ser usados para encurtar as operaes acima:
k++;
j--;
--j;
O fato do operador de incremento ser colocado antes ou depois da varivel no altera o efeito da operao
o valor da varivel incrementada ou decrementada de um. A diferena entre os dois casos QUANDO
a varivel incrementada. Na expresso k++, o valor de k primeiro usado e ento incrementada isto
chamado ps-incremento. Na expresso ++k, k incrementado primeiro, e ento o valor (o novo valor) de
k usado isso chamado pr-incremento.
A diferena ilustrada nos seguintes exemplos:
int main()
{
int k = 5;
Para o programa:
int main()
{
int k = 5;
Os operadores de atribuio no podem ser usados com expresses aritmticas. Por exemplo, as expres-
ses
(ack + 2)++;
(nope + 3) += 5;
resultaro em erros de compilao.
Finalmente, quando usar o operador de incremento em um cout, tome cuidado para no fazer o se-
guinte:
77
cout << ++uhoh << uhoh * 2 << endl;
Embora isso seja perfeitamente legal em C++ , os resultados no so garantidados que sejam consis-
tentes. A razo para isso que no h garantia que os argumentos do cout sejam avaliados em uma
determinada ordem. O resultado do cout ser diferente dependendo se ++uhoh avaliado primeiro ou
depois de uhoh * 2.
A soluo para este problema escrever o seguinte:
++uhoh;
cout << uhoh << uhoh * 2 << endl;
78
#include <iostream>
using namespace std;
int main() {
int n1, n2, n3;
Operador Associatividade
79
16 Mais sobre tipos: converso implcita e explcita
Expresses no tem somente um valor, mas tambm tem um tipo associado.
Se ambos os operandos de uma operao aritmtica binria so do mesmo tipo, o resultado ter o mesmo
tipo. Por exemplo:
3 + 5 8, e o tipo int
3.5 + 2.25 5.75, e o tipo double
30 / 5 6
31 / 5 6
29 / 5 5
3 / 5 0
Lembre-se de evitar escrever algo como 1 / 2 * x significando 21 x. Voc sempre obter o valor 0
porque 1 / 2 * x (1 / 2) * x que 0 * x que 0. Para obter o resultado desejado, voc poderia
escrever 1.0 / 2.0 * x.
O sinal de < significa que o tipo da esquerda promovido para o tipo da direita, e o resultado ser do
tipo mais a direita. Por exemplo:
3.5 + 1 4.5
4 * 2.5 10.0
Esta regra estende-se para expresses envolvendo mltiplos operadores, mas voc deve se lembrar que
a precedncia e associatividade dos operadores pode influenciar no resultado. Vejamos o exemplo abaixo:
int main()
{
int a, b;
cout << "A fracao em decimal e " << 1.0 * a / b << endl;
}
80
Multiplicando por 1.0 assegura que o resultado da multiplicao de 1.0 por a ser do tipo real, e
portanto, a regra de converso automtica evitar que o resultado da diviso seja truncado. Note que se ti-
vssemos primeiro feito a diviso a/b e depois multiplicado por 1.0, embora o tipo da expresso a/b*1.0
seja do tipo double, o valor da expresso seria diferente do valor de 1.0 * a/b. Por que ?
Em atribuies, o valor da expresso do lado direito convertido para o tipo da varivel do lado esquerdo
da atribuio. Isto pode causar promoo ou rebaixamento de tipo. O rebaixamento pode causar perda
de preciso ou mesmo resultar em valores errados.
Em operaes de atribuio, atribuir um int em um float causar a converso apropriada, e atribuir
um float em um int causar truncamento. Por exemplo:
Basicamente, se o valor da expresso do lado direito da atribuio de um tipo que no cabe no tamanho
do tipo da varivel do lado esquerdo, resultados errados e no esperados podem ocorrer.
(nome-do-tipo)expressao
81
O parnteses NO opcional na expresso acima.
Podemos usar o cast de tipos da seguinte forma:
int fahr = 5;
float cels;
Agora que conhecemos o operador de cast de tipo podemos reescrever o programa que faz a converso
de frao para decimal.
int main()
{
int a, b;
cout << "A fracao em decimal e " << (float) a / b << endl;
}
O cast de tipo tem a maior precedncia possvel, portanto podemos fazer o cast de a ou de b para ser do
tipo float, e no h necessidade de parnteses extra. No exemplo acima, o cast causa o valor da varivel
a ser convertido para float, mas no causa mudana no tipo da varivel a. O tipo das variveis definido
uma vez na declarao e no pode ser alterado.
82
17 A sentena switch
A sentena switch outra maneira de fazer decises mltiplas. Ele pode ser usado para testar se uma dada
expresso igual a um valor constante e, dependendo do valor, tomar determinadas aes.
O formato da sentena switch :
switch (expressao) {
case expressao-constante 1:
sentencas 1
case expressao-constante 2:
sentencas 2
..
.
default:
sentencas n
}
A sentena switch primeiro avalia a expresso. Se o valor da expresso for igual a uma das expresses
constantes, as sentenas que seguem o case so executados. Se o valor da expresso no for igual a
nenhuma das constantes, as sentenas que seguem default so executadas.
As sentenas que seguem o case so simplesmente uma lista de sentenas. Esta lista pode conter mais
de uma sentena e no necessrio coloc-las entre chaves ({ e }). A lista de sentenas tambm pode ser
vazia, isto , voc pode no colocar nenhuma sentena seguindo o case.
Tambm no obrigatrio colocar o default. S o use quando for necessrio.
Note no diagrama acima que TODAS as sentenas que seguem a constante com o valor igual ao da
expresso sero executados. Para que se execute APENAS as sentenas que seguem o case que seja igual
ao valor da expresso precisamos usar a sentena break, que veremos em seguida.
18 A sentena break
O break faz com que todas as sentenas que o seguem dentro da mesma sentena switch sejam ignora-
dos. Ou seja, colocando a sentena break no final de uma sentena case faz com que as sentenas que
seguem os cases subsequentes no sejam executadas. Em geral, este o comportamento desejado quando
se usa o switch, e cases sem o break no final so de pouca utilidade. Portanto, o uso de sentenas
case sem o break devem ser evitados e quando utilizados devem ser comentados ao lado com algo como
/* continua proxima sentenca - sem break */.
Com a sentena break o diagrama de fluxo fica:
83
Note a similaridade com o diagrama da sentena else-if e a diferena com o diagrama da sentena
switch acima.
O prximo programa tem a mesma funo de calculadora do programa anterior, porm utilizando a
sentena switch.
Exemplo 11:
#include <iostream>
using namespace std;
int main( ){
switch (op) {
case +:
cout << " = " << setprecision(2) << num1 + num2;
break;
case -:
cout << " = " << setprecision(2) << num1 - num2;
break;
case *:
cout << " = " << setprecision(2) << num1 * num2;
break;
case /:
cout << " = " << setprecision(2) << num1 / num2;
break;
default:
cout << " Operador invalido.";
break;
84
}
cout << endl;
}
Como mencionado anteriormente, possvel no colocar nenhuma sentena seguindo um case. Isso
til quando diversas sentenas case (diversas constantes) tm a mesma ao.
Por exemplo, podemos modificar o programa acima para aceitar x e X para multiplicao e \ para
diviso. O programa fica ento:
#include <iostream>
using namespace std;
int main( ){
switch (op) {
case +:
cout << " = " << setprecision(2) << num1 + num2;
break;
case -:
cout << " = " << setprecision(2) << num1 - num2;
break;
case *:
case x:
case X:
cout << " = " << setprecision(2) << num1 * num2;
break;
case /:
case \\:
cout << " = " << setprecision(2) << num1 / num2;
break;
default:
cout << " Operador invalido.";
break;
}
cout << endl;
}
Exerccio 2: Ler mes e ano e imprimir o numero de dias do mes no ano digitado.
85
19 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues. Estas estruturas de repeti-
o, tambm conhecidas como laos (do ingls loops). A primeira construo (while) foi vista na Seo 10.
Agora veremos for e de do ... while.
int i;
Este lao pode ser expresso de forma diferente utilizando a estrutura de repetio for. A estrutura acima
pode ser expressa de forma equivlente com um for da seguinte forma:
int i;
Como pode-se observar, h 4 partes no lao for: inicializao, expresso de teste, expresso de incre-
mento e o corpo do lao. O formato do lao for :
for (inicializao ; expresso de teste ; incremento ){
corpo da repetio
}
A inicializao executada uma nica vez no incio do lao. A expresso teste ento avaliada para
verificar se o lao deve terminar. Caso a expresso seja verdadeira (isto , diferente de Zero), o corpo da
repetio executado. Depois desta execuo, a expresso de incremento executada e o processo repetido
a partir da expresso teste. O corpo da repetio, por sua vez, pode ser uma sentena simples ou composta.
86
Veja abaixo um exemplo simples do lao for:
int contador;
Sada do programa:
contador = 0
contador = 1
contador = 2
contador = 3
contador = 4
ACABOU !!!!
Se voc examinar cuidadosamente este exemplo, poder ver precisamente o que est acontecendo. Pri-
meiro, a inicializao executada, que a sentena contador = 0. Isso modifica o valor da varivel con-
tador para 0. Ento, o teste executado. como 0 < 5 verdadeiro, o lao continua. Assim, o corpo da
repetio executado, imprimindo a primeira linha da sada, contador = 0. Depois disso, o incremento
executado, que a sentena contador++, que altera o valor da varivel contador para 1.
Esta a 1a iterao do lao. Ento, o teste executado novamente (como 1 < 5 verdadeiro, o lao
continua), o corpo da repetio mostra contador = 1, e contador incrementado novamente.
Este processo continua at que contador seja 4 e contador = 4 seja impresso. Depois disso, conta-
dor incrementado para 5 e o teste executado. Mas desta vez, 5 < 5 falso, ento o lao no continua.
A execuo do programa continua na sentena que segue o lao (no caso, imprimir a frase ACABOU !!!).
Aps a execuo do lao, a varivel contador tem valor 5.
Ao invs de usar o teste contador < 5, voc poderia tambm ter usado a expresso contador <= 4.
O resultado seria o mesmo. Use a expresso que voc preferir. Outra expresso que tambm poderia ter
sido usada contador != 5. Porm esta expresso torna o programa menos legvel (no to evidente
87
que o valor de contador est sendo incrementado at atingir o valor 5). Alm disso, isso poderia causar
problemas se mudssemos a inicializao para um valor maior que 5. Por exemplo, se a inicializao for
contador = 25 e a expresso teste for contador != 5 o lao nunca terminaria, pois o contador comea com
25 e a cada iterao o valor incrementado, o que nunca tornaria o teste falso.
Tambm poderamos ao invs de usar contador += 1 como a expresso de incremento, usar ++contador,
contador++ e contador = contador + 1. O resultado seria o mesmo (neste caso, o uso de ps- e pr-
incremento no faz diferena).
Se voc quisesse incrementos de dois, voc poderia escrever contador += 2 (ou contador = contador + 2).
Exemplo 1:
#include <iostream>
using namespace std;
int main( ){
Sada:
contador = 0, total = 0
contador = 1, total = 1
contador = 2, total = 3
contador = 3, total = 6
contador = 4, total = 10
contador = 5, total = 15
contador = 6, total = 21
contador = 7, total = 28
contador = 8, total = 36
contador = 9, total = 45
Exemplo 2: Um programa que imprime todos os nmeros entre 30 e 5 (nesta ordem) divisveis por 3, e
no final imprime sua soma.
88
#include <iostream>
#include <iomanip> // Necessrio para uso da funo setw() em cout
int main( ){
int i, soma;
soma = 0;
for( i = 30; i >= 5; i -= 1 ){
if( (i % 3) == 0 ){
cout << "\t" << setw(2) << i << endl;
soma += i;
}
}
cout << "\t soma = " << soma << endl;
}
Sada do programa:
30
27
24
21
18
15
12
9
6
soma = 162
equivalente a:
inicializacao;
while( teste ) {
sentenca;
incremento;
};
int contador = 0;
do {
cout << "contador = " << contador << endl;
contador += 1;
} while( contador < 5 );
A execuo deste programa idntico ao primeiro exemplo mostrado para o comando while, com a
expresso de teste mudada para o final.
Sada:
contador = 0
contador = 1
contador = 2
contador = 3
contador = 4
ACABOU !!!!
O do...while usado quando o corpo da repetio deve ser executado pelo menos uma vez. Um exemplo
comum disto o processamento da entrada de um programa.
Exemplo 3: Neste exemplo, o teste do lao baseado no valor digitado pelo usurio. O lao deve ser
executado pelo uma vez antes que o teste sobre o valor seja executado.
#include <iostream>
using namespace std;
90
int main( ){
int num;
do{
cin >> num;
} while( num % 2 != 0 );
int main( ){
num = 1;
while( num % 2 != 0 ){
cin >> num;
}
cout << "Obrigado.\n";
}
O problema com este programa que a varivel num deve ser inicializada com um valor que torne
o teste do lao verdadeiro. Neste exemplo, simples encontrar tal valor. Para uma expresso teste mais
complicada, isso pode no ser to fcil.
20 A sentena break
Em uma estrutura de repetio, o break faz com que todas as sentenas que o seguem dentro sejam igno-
rados. Alm disso, o break tambm TERMINA a repetio, fazendo com que o programa continue sua
execuo APS o bloco da repetio. A expresso da repetio e a reinicializao (no caso do for) no
so avaliadas aps a execuo de um break.
91
21 A sentena continue
Em uma estrutura de repetio, o continue faz com que todas as sentenas que o seguem sejam ignorados.
Alm disso, esta sentena faz com que a reinicializao e a expresso da repetio sejam avaliadas e a
execuo do bloco de repetio iniciado novamente.
Essencialmente, o continue significa ignore o restante do bloco de repetio e parta para a prxima
interao.
92
22 Tipo Enumerado
Em muitos programas, variveis do tipo int so utilizadas no por suas propriedades numricas, mas para
representar uma escolha dentre um pequeno nmero de alternativas. Por exemplo:
A utilizao de cdigos para representar os valores que uma varivel poder assumir, certamente com-
promete a clareza da estrutura de dados do programa, tornando sua lgica obscura e inconsistente. Por
exemplo:
cor = 3;
if( sexo == 2 ) ...
cor = cor + sexo;
for( cor = 1; cor < 10; cor ++ )...
Um tipo enumerado permite definir uma lista de valores que uma varivel deste tipo poder assumir. A
definio de um tipo enumerado feita da seguinte forma:
#include <iostream>
using namespace std;
int main(){
int diaPgto, mesPgto, anoPgto;
int diaSem;
Este programa ficaria mais legvel se ao invs de codificar os dias da semana como inteiros e colocar a
codificao como comentrio, utilizar tipos enumerados. O programa ficaria ento
#include <iostream>
using namespace std;
int main(){
int diaPgto, mesPgto, anoPgto;
int diaSem;
Note que a funo diaDaSemana agora retorna apenas um dos valores da lista SEG, TER, QUA,
QUI, SEX, SAB, DOM e portanto, no programa principal ao invs de testar se o diaSem == 5 pode-
mos escrever diaSem == SAB, o que torna o programa muito mais legvel.
94
23 Mais sobre funes
A nfase aqui ser em como funes funcionam. O que acontece quando uma funo chamada ? A que
varivel um nome est se referenciando?
O tratamento em tempo de execuo de um nome de varivel em C++ simples: um nome de varivel
ou uma varivel local (a funo) ou uma varivel global (definida fora de qualquer funo).
Em C++ , todas as funes tem que ser definidas. Para cada funo deve ser definido um prottipo. O
prottipo escrito fora de qualquer funo. Desta forma, nomes de funes so visveis para todas as outras
funes que podem ento invoc-las. A funo main() especial: onde a execuo do programa comea,
e o prottipo de main() pode ser omitido.
Uma definio de funo consiste de quatro partes:
1. o nome da funo;
2. a lista de parmetros formais (argumentos) com seus nomes e tipos. Se no houver argumentos, a
palavra void escrita entre os parnteses.
3. o tipo do resultado que a funo retorna atravs da sentena return ou void se a funo no retorna
nenhum valor. Lembre-se que somente um valor pode ser retornado por uma sentena return.
4. o corpo da funo, que uma sentena composta (comea e termina com chaves ({ }) contendo
definio de variveis e outras sentenas. Em C++ , no se pode definir uma funo dentro de outra.
Para funes com argumentos: uma funo chamada dando o seu nome e uma lista de argumentos
(expresses que so avaliadas e cujos valores so atribudos para os correspondentes parmetros formais da
funo).
Por exemplo, suponha que triang area() e circ area() sejam funes que calculam a rea de
tringulos e crculos, respectivamente. Seus prottipos so:
Estas funes podem chamadas de dentro de outras funes. Os argumentos reais com os quais elas so
chamadas podem ser expresses constantes, or variveis locais, ou qualquer expresso cuja avaliao resulte
em valores do tipo float (inteiros so convertidos para float da mesma forma que ocorre com atribuio
de inteiros para variveis do tipo float). Alguns exemplos de chamadas:
A ltima sentena do exemplo acima atribui a varivel area5 a rea de um tringulo cuja base igual
ao valor da varivel raio e a altura igual a area de um crculo de raio igual ao valor da varivel raio.
Quando um programa executado, somente uma nica funo tem o controle em determinado momento.
Falaremos mais sobre o que acontece quando uma funo chamada mais tarde nestas notas de aula.
95
Variveis Locais Variveis que so definidas dentro de uma funo so variveis locais desta funo.
Parmetros formais de uma funo so variveis locais da funo. Variveis locais so privativas a
funo na qual so definidas. Somente esta funo pode enxerg-las (ela conhece o endereo das variveis e
pode usar e modificar o seu contedo). Nenhuma outra funo pode acessar variveis locais de outra funo
sem permisso (uma funo pode acessar variveis locais de outra se esta passar o endereo da varivel
local como argumento este assunto ser tratado em notas de aula futuras). O fato de cada funo manter
variveis locais escondidas do resto do mundo torna mais fcil a tarefa de escrever programas estruturados
e modulares. Quando voc est escrevendo uma funo, voc pode dar as suas variveis locais o nome que
quiser. Voc tambm no precisa se preocupar se outra pessoa escrevendo outra funo ter acesso ou altera
variveis locais a sua funo.
Variveis locais que so definidas dentro da funo devem ser inicializadas com algum valor antes
de serem usadas. Caso contrrio, o seu valor indefinido.
J que parmetros formais (argumentos) so variveis locais da funo, eles podem ser usados no corpo
da funo. Eles no devem ser definidos dentro da funo (sua definio j est no cabealho da funo). Os
parmetros formais no precisam ser inicializados. Seus valores so fornecidos pelo chamador da funo
atravs dos argumentos reais.
Considere o seguinte exemplo:
/*****************************************************************
* Um programa que calcula a area de triangulos e circulos.
* A base, altura e raio sao fornecidos pelo usuario.
* A saida do programa e a area do triangulo e circulo.
*****************************************************************/
#include <iostream>
using namespace std;
#define PI 3.1415
/*******************
prototipos
*******************/
float triang_area(float, float);
float circ_area(float);
/*******************
definicao de funcoes
*******************/
main()
{
/* definicao das variaveis locais */
float base, altura, raio;
/* dialogo de entrada */
cout << "\nEntre com a base e altura do triangulo: ";
cin >> base >> altura;
cout << "\nEntre com o raio do circulo: ";
cin >> raio;
/*****************************************************************
* funcao: triang_area
* calcula a area de um triangulo dada a base e altura
* Entrada: base e altura do triangulo
* Saida: area do triangulo
*****************************************************************/
float triang_area(float base, float alt)
{
return 0.5*base*alt;
}
/*****************************************************************
* funcao: circ_area
* calcula a area de um circulo dado o raio
* Entrada: raio do circulo
* Saida: area do circulo
*****************************************************************/
float circ_area(float r)
{
return PI*r*r;
}
Este programa C++ consiste de trs funes, main(), triang_area(), e circ_area(). main()
tem variveis locais chamadas base, altura e raio; triang_area() tem como variveis locai seus
parmetros formais, base e alt; circ_area() tem como varivel local seu parmetro formal r.
Em geral, uma varivel local s existe durante a execuo da funo na qual ela est definida. Portanto,
variveis locais existem desde o momento que a funo chamada at o momento em que a funo
completada. Tais variveis so chamadas de automatic. Em C++ , uma varivel pode ser definida como
sendo static. Neste caso, uma varivel local no visvel de fora do corpo da funo, mas ela no
destruda no final da funo como variveis automticas so. Cada vez que a funo chamada, o valor das
variveis static o valor final da varivel da chamada anterior.
Variveis Globais
At este momento, todas as variveis que vimos so definidas dentro de funes (no corpo da funo
ou como parmetros formais). possvel tambm definir variveis fora das funes. Tais variveis so
chamadas de variveis globais ou externas. O formato da definio de variveis globais o mesmo da
definio de variveis locais. A nica diferena onde a varivel definida: variveis globais so definidas
fora de qualquer funo. Ao contrrio das variveis locais, variveis globais podem ser vistas por todas as
funes definidas aps a definio das variveis globais.
Ns temos usado declaraes globais este tempo todo por exemplo, as declaraes de prottipos de
funes. Elas so declaradas fora de qualquer funo e podem ser vistas por qualquer funo que esto aps
sua declarao.
No exemplo seguinte, uma varivel saldo que atualizada por trs funes diferentes definida como
uma varivel global. As trs funes que a atualizam no chamam uma a outra.
97
/*****************************************************************
* Caixa eletronico simples
* o saldo e o valor a ser alterado e entrado pelo usuario
* a saida do programa e o saldo atualizado, incluindo juros
*****************************************************************/
#include <iostream>
using namespace std;
/*******************
prototipos
*******************/
void credito(float);
void debito(float);
void juros(void);
/*******************
globais
*******************/
float saldo; /* saldo atual;
* Alterada em: credito(), debito(), juros(), main()
* Lida em:
*/
/***********************
definicao de funcoes
***********************/
main()
{
float valor; // valor a ser depositado/retirado
/*****************************************************************
* Deposita um valor; atualiza a variavel global saldo
98
* Entrada: valor a ser depositado
* Saida: nenhum
*****************************************************************/
void credito(float val)
{
saldo += val;
}
/*****************************************************************
* Debita um valor; atualiza a variavel global saldo
* Entrada: valor a ser debitado
* Saida: nenhum
*****************************************************************/
void debito(float val)
{
saldo -= val;
}
/*****************************************************************
* Acumula juros; atualiza a variavel global saldo; juros: RATE
* Entrada: nenhuma
* Saida: nenhuma
*****************************************************************/
void juros(void)
{
saldo += (saldo * JUROS);
}
Variveis globais devem ser usadas SOMENTE quando muitas funes usam muito as mesmas vari-
veis. No entanto, o uso de variveis globais perigoso (e no recomendado) porque a modularidade do
programa pode ser afetada. Uma varivel global pode ser alterada de dentro de uma funo, e esta alterao
pode influir no resultado de uma outra funo, tornando-a incorreta (em um exemplo dado posteriormente
nestas notas, duas chamadas a funo soma_y() com o mesmo argumento (zero) produz resultados dife-
rentes, 100 e 300).
Quando variveis globais so utilizadas, deve ser dado a elas nomes descritivos e um breve comentrio
qual a finalidade da varivel e quais funes a acessam.
Neste curso, voc utilizar variveis globais SOMENTE QUANDO FOR DADO PERMISSO PARA
FAZ-LO. Caso contrrio, no permitido utiliz-las (ou seja, sero descontados pontos).
Escopo de Variveis
99
Como j discutimos anteriormente, uma varivel uma abstrao de dados que ns usamos em um
programa. A varivel representa um endereo de memria onde os valores so armazenados. Durante a
execuo do programa, valores diferentes poder ser armazenados neste endereo. Quando uma varivel
definida, o nome da varivel atrelada a um endereo especfico na memria. At este momento, j
discutimos o que o nome de uma varivel, seu endereo, tipo e valor. Outra caracterstica que apresenta-
resmo agora o escopo. O escopo de uma varivel refere-se a parte do programa onde podemos utilizar a
varivel. Em outras, palavras, uma varivel visvel dentro do seu escopo.
O escopo de uma varivel local a funo na qual ela definida. Os parmetros formais de uma funo
tambm so tratados como variveis locais.
O escopo de uma varivel global a poro do programa depois da definio da varivel global (a partir
do ponto onde ela definida at o final do programa).
Se o nome de uma varivel global idntico a uma varivel local de uma funo, ento dentro desta
funo em particular, o nome refere-se a varivel local. (Embora tais conflitos devem ser evitados para
evitar confuso).
Por exemplo, considere o seguinte programa:
int valor = 3; /* definicao da variavel global */
int main()
{
/* definicao local de valor */
int valor = 4;
cout << valor << endl;
}
A sada do programa acima ser 4 j que valor refere-se a definio local.
Considere outro exemplo:
#include <iostream>
using namespace std;
int soma_y(int);
int soma_yy(int);
main()
{
int z = 0; // variavel local
int soma_y(int x)
{
return x + y; // x e variavel local, y e global
}
int soma_yy(int x)
{
100
y = 300; // y e variavel global
return x + y; // x e variavel local
}
Vamos seguir a execuo deste programa. Primeiro, a varivel global y criada e inicializada com 100.
Ento, a execuo da funo main() comeca: alocado espao na memria para a varivel local z. Esta
varivel inicializada com 0. Considere a primeira sentena cout :
Esta uma chamada para cout . Os parmetros reais desta chamada a expresso soma_y(z).
Ela consiste da chamada da funo soma_y(). O valor desta expresso o resultado retornado por
soma_y(). Qual o resultado? A funo soma_y chamada com o parmetro real z. Como z = 0,
este o valor que ser passado para a funo soma_y; o 0 copiado para o parmetro formal x da funo
soma_y(). Portanto, durante a excuo da primeira chamada a funo soma_y(), o valor da expresso x
+ y ser 0 + 100, que 100. Portanto, o valor da primeira chamada soma_ y(z) 100, e este nmero
ser impresso com o primeiro cout em main(). Agora considere a segunda sentena:
Quando a funo soma_y(z) chamada, o valor de z ainda 0, portanto, 0 copiada para o parmetro
formal int x da funo soma_y(). Quando soma_ y() executada pela segunda vez, a varivel
global y foi modificada para 300, portanto o valor de x + y 0 + 300. Portanto, o valor da chamada
soma_yy(z) 300, e este nmero ser impresso pelo terceiro cout em main().
Portanto, a sada da execuo deste programa ser
100
300
300
101
(
1 se n = 0
an = x
an1
+an1 para todo n N
2 caso contrrio
Os valores de an convergem para x a medida que n cresce.
Por exemplo, para achar a raiz quadrada inteira de 42 (usando diviso inteira que trunca a parte fracional
do nmero)
a0 = 1, a1 = (42/1 + 1)/2 = 21, a2 = (42/21 + 21)/2 = 11, a3 = (42/11 + 11)/2 = 7, a4 =
(42/7 + 7)/2 = 6.
Uma vez que a24 = 62 = 36 42 < (a4 + 1)2 = 72 = 49, o processo termina e a resposta 6.
(No necessrio voc entender por que este algoritmo funciona portanto no se preocupe se no
conseguir entend-lo)
102
int raizInteira(int); /* prototipo */
/**************************************************************
* function: raizInteira(x)
* acao: dado x, retorna a raiz quadrada inteira de x
* in: inteiro positivo x
* out: raiz quadrada inteira de x
* suposicoes: x >= 0
* algoritmo: metodo de dividr e calcular media: comecando com
* um palpite de 1, o proximo palpite e calculado como
* (x/palpite_ant + palpite_ant)/2. Isso e repetido
* ate que palpite^2 <= x < (palpite+1)^2
***************************************************************/
int raizInteira(int x)
{
int palpite = 1;
Note que usando a lei de DeMorgan, podemos re-escrever a expresso teste do while em uma forma
equivalente:
Deve estar claro neste ponto a diferenca entre ao e algoritmo. Uma pessoa que quer usar esta funo
precisa saber somente a ao, no o algoritmo. tambm importante especificar os dados que so esperados
pela funo e retornados por ela para outras pessoas poderem us-la. As suposies devem esclarecer as
restries da funo sobre quando a funo pode falhar ou produzir resultados errados. Neste caso, um
nmero negativo produziria um erro, j que nmeros negativos no possuem raiz quadrada.
No h necessidade de ir em muitos detalhes em qualquer parte da documentao da funo. Embora ela
deva conter informao suficiente para que algum (que no possa ver o cdigo) saber utiliz-la. Detalhes
sobre implementao e detalhes menores sobre o algoritmo devem ser colocados como comentrios no
prprio cdigo.
24 Ativao de funo
Uma funo comea sua execuo assim que for chamada. Cada execuo da funo chamada de ativao
da funo. Como j mencionamos em notas de aula anteriores, variveis locais so locais a ativao da
funo: cada ativao possui suas prprias variveis locais. No comeo da ativao, memria alocada para
as variveis locais e no final da execuo, elas so dealocadas.
Definies de funes em C++ no podem ser aninhadas, mas ativaes de funo podem: uma funo,
digamos A, pode chamar uma outra funo, digamos B (dizemos que A chama B). Nos referimos a A como
o chamador e B como a funo chamada.
103
O que acontece quando uma funo chama outra (quando A chama B)? Um registro especial, chamado
registro de ativao criado. A informao neste registro necessria para a ativao da funo chamada e
para a reativao do chamador depois que a execuo da funo chamada termina.
1. C++ usa chamada-por-valor, ou seja, o chamador avalia as expresses que so os parmetros reais e
passa seus valores para a funo chamada.
5. O valor retornado para a funo chamadora atravs de um return colocado em um lugar especial
para que a funo chamadora possa encontr-lo. O controle retorna a funo chamadora.
104
25 Array de Caracteres
Nas notas de aula anteriores, enfatizamos arrays de nmeros. Em geral, podemos ter arrays com elementos
de qualquer um dos tipos vistos at agora (incluindo arrays visto nas notas de aula 9). Nesta seo,
apresentaremos arrays com elementos do tipo char, usados para representar textos em programas.
Abaixo, apresentamos um exemplo de programa que define e inicializa um array de caracteres, e depois
imprime o array em ordem reversa.
#include <iostream>
using namespace std;
int main()
{
char arr1[] = {c,i,2,0,8};
int i;
for (i = 4; i >= 0; i -= 1)
cout << arr1[i];
}
Arrays de caracteres so usados para armazenar texto, mas muito inconveniente se tivermos que colocar
cada caractere entre apstrofes. A alternativa dada pela linguagem C++
Neste caso, ci208 um string de caracteres ou uma constante do tipo string. Ns j usamos strings
antes, com as funes cout (constantes do tipo string esto sempre entre aspas - "):
// a maneira tediosa
char name1[] = { j,o,s,e, ,s,i,l,v,a,\0 };
// e a maneira facil
char name2[] = "jose silva";
105
Embora o primeiro exemplo seja um string, o segundo exemplo mostra como strings so geralmente
escritos (como constantes). Note que se voc usar aspas quando escreve uma constante, voc no precisa
colocar \0, porque o compilador faz isso para voc.
Quando voc for criar um array de caracteres de um tamanho especfico, lembre-se de adicionar 1 para o
tamanho mximo de caracteres esperado para armazenar o caractere NULO. Por exemplo, para armazenar o
string programar eh divertido, voc precisa de um array de tamanho 22 (21 caracteres + 1 para
o NULO).
int main()
{
char mensagem[] = "tchau";
ola
tchau
#include <iostream>
using namespace std;
int main()
{
char nome[100];
Exemplo de execuo
Passando um nome de array para a funo cin.getline(), como ilustrado no programa acima,
coloca a linha inteira digitada pelo usurio no array nome (tudo ou mximo de 99 caracteres at que seja
teclado enter). Note que se o usurio digitar caracteres demais (neste caso, mais de 99 caracteres), apenas
os primeiros 99 caracteres digitados sero copiados para o array indicado no primeiro argumento da funo.
A funo cin pode ser usada de maneira similar. A nica diferena que cin l somente a primeira
palavra (tudo at que se digite um separador um espao em branco, tabulao, ou enter).
106
#include <iostream>
using namespace std;
int main()
{
char nome[100];
Exemplo de execuo
Note que somente o primeiro nome lido pelo cin porque a funo pra no primeiro espao em branco
que encontra (enquanto cin.getline() pra quando encontra um enter).
#include <iostream>
using namespace std;
int main()
{
char nomes[NUM_NOMES][TAM] = {"Jose Silva",
"Maria Silva",
"Antonio dos Santos",
"Pedro dos Santos",
"Joao da Silva"};
int i;
Jose Silva
Maria Silva
Antonio dos Santos
Pedro dos Santos
Joao da Silva
107
26.4 Funes de String
H funes para manipulao de string j definidas na biblioteca padro C++ chamada cstring. Todas as
funes que apresentaremos nesta seo so parte desta biblioteca. Portanto, se seu programa utilizar uma
destas funes voc deve incluir a linha #include <cstring> no incio do seu programa.
O objetivo desta seo mostrar como estas funes poderiam ser implementadas como exemplos de
programas de manipulao de strings.
A funo strlen() tem como argumento um string. Ela retorna um inteiro que o comprimento do
string (o nmero de caracteres do string, no contando o caractere NULL). Por exemplo, o comprimento do
string alo 3.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char nome[100];
int comprimento;
cout << "Seu nome tem " << comprimento << " caracteres." << endl;
}
Um exemplo de execuo:
A ordem relativa do trs conjuntos (dgitos, letras maisculas e letras minsculas) depende do computador
utilizado.
Se s1 e s2 so strings, o resultado da chamada de funo strcmp(s1, s2) :
se s1 =s s2, strcmp() retorna 0
se s1 <s s2, strcmp() retorna um nmero negativo (< 0)
se s1 >s s2, strcmp() retorna um inteiro positivo (> 0)
(onde =s , <s e >s so =, < e > para strings)
s1 <s s2 significa s1 vem antes de s2 no dicionrio. Exemplos: tudo menor que xadrez,
calor menor que calorao, frio menor que quente, e claro o string vazio , NULL,
menor que qualquer string.
Considere o exemplo abaixo que usa strcmp():
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char palavra1[100], palavra2[100];
int resultado;
if (resultado == 0)
cout << "igual" << endl;
else if (resultado > 0)
cout << "o primeiro e maior" << endl;
else
cout << "o segundo e maior" << endl;
}
while (1)
{
109
if (s1[i] == NULL && s2[i] == NULL)
return 0;
else if (s1[i] == NULL)
return -1;
else if (s2[i] == NULL)
return 1;
else if (s1[i] < s2[i])
return -1;
else if (s1[i] > s2[i])
return 1;
else
++i;
}
}
Na biblioteca padro, a funo strcmp() faz distino entre letras maisculas e minsculas. Se voc
no quer que a funo faa esta distino, voc pode modificar o seu string para ter apenas letras minsculas
(ou maisculas) antes de pass-lo como argumento para a funo strcmp(). Para fazer isso, voc pode
usar a funo da biblioteca padro tolower(), que tem como argumento um caractere. Se o caractere
passado uma letra maiscula, ele retorna esta letra minscula; caso contrrio, retorna o mesmo caractere.
Por exemplo: tolower(A) a, tolower(1) 1, tolower(a) a.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char pal[100], palCopia[100];
cout << "voce entrou primeiro: " << palCopia << endl;
}
Embora este programa pudesse ter sido escrito sem usar strcpy(), o objetivo mostrar que se pode
usar strcpy() para fazer atribuio de strings.
A funo strcpy() poderia ter sido implementada da seguinte forma:
110
void strcpy( char s1[], char s2[] )
{
int i = 0;
27 O tipo String
Em C++ possvel uma forma alternativa de lidar com textos, usando a classe String.
111
28 Estruturas
A estrutura de dados array usada para conter dados do mesmo tipo junto. Dados de tipos diferentes
tambm podem ser agregados em tipos chamados de estruturas ou registros (tipo struct em linguagem
C). Primeiro, o tipo estrutura declarado (precisamos especificar que tipos de variveis sero combinados
na estrutura), e ento variveis deste novo tipo podem ser definidas (de maneira similar que usamos para
definir variveis do tipo int ou char).
struct facil {
int num;
char ch;
};
Esta declaracao cria um novo tipo chamado struct facil que contm um inteiro chamado num e
um caracter chamado ch.
Tal definio est associada com a alocao de memria: memria suficiente ser alocada para guardar
um int e um char (nesta ordem). Como qualquer outra varivel, fac1 tem um nome, um tipo, e um
endereo associados.
Variveis de estruturas possuem tambm valores, e como outras variveis locais, se elas no tem atribu-
das um valor especfico, seu valor indefinido.
possvel definir variveis durente a declarao do tipo estrutura:
struct facil {
int num;
char ch;
} fac1;
112
Note-se que sem conflito, nomes de membros (tais como num e ch) podem ser usados como nomes de
outras variveis independentes (fora do tipo estrutura definido) or como nomes de membros em outros tipos
estrutura. No entanto, deve-se evitar situaes que criem confuso.
28.3 Acesso a membros de uma estrutura: ponto (.), o operador membro de estrutura
Dada uma varivel de estrutura, um membro especfico referenciado usando o nome da varivel seguida de
. (ponto) e pelo nome do membro da estrutura. Assim, as seguintes referncias a membros de uma estrutura
so vlidas:
fac1.num se refere ao membro com nome num na estrutura fac1;
fac1.ch se refere ao membro com nome ch na estrutura fac1.
Membros de estrutura (como fac1.num) so variveis, e podem ser usadas como valores (no lado
direito de uma atribuio, em expresses como argumentos para funes), ou como lvalues (no lado esquerdo
de atribuies, com operadores de incremento/decremento ou com o operador de endereo (&)). O exemplo
abaixo mostra alguns exemplos do uso de membros de estrutura:
fac1.ch = G;
fac1.num = 42;
fac1.num++;
if (fac1.ch == H) {
cout << fac1.num << endl;
}
struct facil {
int num;
char ch;
};
void main(void)
{
113
struct facil fac1, fac2;
fac1.num = 3;
fac1.ch = C;
Lembre-se que este tipo de atribuio ilegal com arrays. Tentar fazer isto com dois arrays causa um
erro de compilao (uma vez que nomes de arrays so apontadores constantes).
struct facil {
int num;
char ch;
};
void main(void)
{
struct facil fac1 = { 3, C }, fac2;
fac2 = fac1;
}
Uma lista de valores separados por vrgula fica entre chaves ({ e }). Os valores de inicializao devem
estar na mesma ordem dos membros na declarao da estrutura.
No exemplo acima, a estrutura struct endereco contm dois arrays de tamanho 50. Dentro da
funo obtem_endereco(), a varivel ender declarada como sendo do tipo struct endereco.
Aps usar cin.getline() para o fornecimento da informao, o valor de ender retornado para
main(), de onde a funo obtem_endereco() foi chamada. Este valor ento passado para a funo
imprime_endereco(), onde o valor de cada membro da estrutura exibido na tela.
Este programa pode ser comparado ao programa abaixo, que usa valores do tipo int no lugar de valores
do tipo struct endereco (claro que a informao lida e exibida um simples valor numrico, e no
um nome de rua, etc.):
114
int obtem_int(void);
void imprime_int(int);
int obtem_int(void)
{
int i;
return i;
}
void imprime_int(int i)
{
cout << i << endl;
}
void main(void)
{
int valor;
valor = obtem_int();
#define LEN 50
#define NUM 10
struct endereco {
char rua[LEN];
char cidade_estado_cep[LEN];
};
void main(void)
{
struct endereco residencias[NUM];
int i;
Neste programa, o array residencias passado para obtem_endereco(), juntamente com o in-
dice onde deve ser guardado o novo endereo. Depois, cada elemento do array passado para imprime_endereco()
um por vez.
Observe-se ainda na funo obtem_endereco() como os membros de cada elemento do array po-
dem ser acessados. elements da estrutura em can be accessed as well. Por exemplo, para acessar a rua do
elemento residencias[0] usa-se:
#define LEN 50
struct endereco {
char rua[LEN];
char cidade_estado_cep[LEN];
};
struct student {
char id[10];
int idade;
struct endereco casa;
struct endereco escola;
116
};
Dadas estas definies, pode-se potencialmente acessar os seguintes campos de pessoa, uma varivel
do tipo struct student:
pessoa.id
pessoa.casa.rua
pessoa.casa.cidade_estado_cep
pessoa.escola.rua
pessoa.escola.cidade_estado_cep
117
29 Entrada e Sada Padro
A forma com que um programa em C++ se comunica com o mundo externo atravs de entrada e sada de
dados: o usurio fornece dados via teclado e o programa imprime mensagens na tela. Todos os programas
vistos at agora lem suas entradas do teclado e produzem suas sadas na tela.
Em C++ toda entrada e sada feita com fluxos (streams) de caracteres organizados em linhas. Cada
linha consiste de zero ou mais caracteres e termina com o caracter de final de linha. Pode haver at 254
caracteres em uma linha (incluindo o caracter de final de linha). Quando um programa inicia, o sistema
operacional automaticamente define quem a entrada padro (geralmente o teclado) e quem a sada
padro (geralmente a tela).
As facilidades de entrada e sada no fazem parte da linguagem C++ . O que existe uma biblioteca
padro de classes e funes (mtodos) para manipular a transferncia de dados entre programa e os dis-
positivos (devices) de sada e entrada padro: cin, cout, cin.get(), cin.put(), puts(),
gets(). Estas classes e funes so declaradas no arquivo <iostream>. Existem funes teis para
converso e teste de caracteres declaradas no arquivo <ctype.h>.
As funes de entrada e sada operam sobre streams (fluxos) de caracteres. Toda vez que uma funo
se entrada chamada (por exemplo, cin, cin.get()) ela verifica pela prxima entrada disponvel na
entrada padro (por exemplo, texto digitado no teclado). Cada vez que uma funo de sada chamada, ela
entrega o dado para a sada padro (por exemplo, a tela).
As funes para leitura da entrada padro e para escrita na sada padro que tm sido usadas at agora
so:
#include <iostream>
using namespace std;
118
int main()
{
char ch;
cin.get(ch);
A funo cin.put() aceita um argumento de entrada, cujo valor ser impresso como caracter:
#include <iostream>
using namespace std;
int main()
{
char ch;
cin.get(ch);
cin.put(ch);
#include <iostream>
using namespace std;
int main(){
char ch;
119
cin.get(ch);
}
cin.get() obtm sua entrada do teclado. Portanto, quando o programa acima executado, o programa
espera que o usurio digite alguma coisa. Cada caractere digitado mostrado no monitor. O usurio pode
digitar diversos caracteres na mesma linha, inclusive backspace para corrigir caracteres j digitados. No
momento que ele teclar RETURN , o primeiro caractere da sequncia digitada o resultado da funo
cin.get(). Portanto, na instruo do programa acima o caractere (ou melhor, o seu cdigo ASCII) atribudo
a varivel ch. Note que o usurio pode ter digitado diversos caracteres antes de teclar RETURN , mas a
funo cin.get() s comear a ler o que foi digitado depois que for teclado RETURN . Alm disso, com
uma chamada da funo cin.get() s o primeiro caractere da sequncia digitada lida.
Voc deve saber que o caractere de nova linha, \n, que tem o cdigo ASCII 10, automaticamente
adicionado na sequncia de caracteres de entrada quando o RETURN teclado. Isso no tem importncia
quando a funo cin.get() chamada uma nica vez, mas isto pode causar problemas quando ele usado
dentro de um lao.
No iniccio de qualquer programa que usa cin.get(), voc deve incluir
#include <iostream>
using namespace std;
Esta diretiva do pr-processador diz ao compilador para incluir informaes sobre cin, cin.get() e EOF
(mais sobre EOF adiante.).
Considere o seguinte programa:
#include <iostream>
using namespace std;
int main(){
char ch;
120
Neste caso o usurio digitou quatro caracteres e depois teclou RETURN . Embora quatro caracteres
tenham sido digitados, somente uma chamada a funo cin.get() foi feita pelo programa, portanto s um
caractere foi lido. O valor atribudo ao argumento da funo o cdigo ASCII do primeiro caractere lido.
O tipo do resultado da funo cin.get() int e no char. O valor retornado pela funo o cdigo
ASCII do caractere lido.
int main()
{
int total = 0;
char ch;
S para esclarecer: voc deve teclar RETURN depois de entrar com o comando ^D (ou ^Z no MS-
Windows).
Note que isso no necessrio aps todas as chamadas a cin.get() ou cin . S depois daquelas chamadas
que precedem cin.get() (ou cin ), especialmente em um lao.
Exemplo 1:
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstring>
void cleanInput()
{
char cc;
if (cin.fail())
{
cin.clear();
while (cin.get(cc) && cc != \n);
}
}
void printStatInput()
{
cout << "\tGood: " << cin.good()
<< " Fail: " << cin.fail()
<< " Bad: " << cin.bad()
<< " EOF: " << cin.eof() << endl << endl;
}
122
int main ()
{
int b=1111, c=2222, d=3333;
float x=1.111, y=2.222;
void * cinerr;
cout << "b c d = " << b << " " << c << " " << d << endl;
cout << "x y = " << x << " " << y << endl;
if (!cinerr)
{
/* Limpar condio de erro em cin, se houver. */
cout << "Limpando condies de erro de CIN" << endl;
cin.clear();
printStatInput();
}
return 0;
123
cin ... retorna um valor especial4 . Se nulo, a entrada no foi aceita e o valor da varivel em que houve
erro fica inalterado. As variveis posteriores na leitura em que houve erro tambm mantm seus valores
inalterados. Execues subsequentes de cin somente podem ser feitas aps a execuo de cin.clear(), para
eliminar a condio de erro. Caso isto no seja feito, aps o primeiro erro de leitura, todos os cin ...
subsequentes daro erro.
Tambm podem ocorrer problemas de converso de tipos em cin. Observe o exemplo abaixo:
int b;
float x;
cin >> b;
cin >> x;
Neste caso, se usurio digita um float (por exemplo, 3.7) no 1o cin, o 2o.o cin no solicitar dado:
b recebe 3, deixando os chars .4 no buffer de leitura. o 2o cin, ento, armazena direto 0.4 em x, no
aguardando digitao do usurio. Note que neste caso, cin ... no acusar erro (isto , no retorna valor
nulo).
Exemplo 2:
#include <iostream>
#include <iomanip> // Necessrio para usar os manipuladores setw()
int main() {
int n1, n2, n3;
int soma;
124
ios::right
ios::left
*/
Exemplo 3:
#include <iostream>
#include <iomanip> // Necessrio para usar os manipuladores setw()
#define LIN 10
#define COL 10
int main()
{
int x; // numero da coluna
int y; // numero da linha
int taboada[LIN][COL]; // tabela de taboada
// preenche a taboada
y=0;
while(y < LIN)
{
x=0;
while(x < COL)
{
taboada[y][x] = y*x;
x = x+1;
}
y = y+1;
}
cout << "\n Taboada de Multiplicacao\n";
125
// Imprime o numero das colunas
cout << setw(6) << 0;
x=1;
while(x < COL)
{
cout << setw(3) << x;
x = x+1;
}
cout << endl;
y=0;
while (y < LIN)
{
cout << setw(2) << y << "|";
x=0;
while(x < COL)
{
cout << setw(3) << taboada[y][x];
x = x+1;
}
126
Referncias
[1] H. M. Deitel and P. J. Deitel. C++: Como Programar. Prentice-Hall, Inc., 5a edition, 2006.
[2] Stanley B. Lippman. C++ Primer. Addison-Wesley Publishing Company, 1991. ISBN: 0-201-54848-8.
Livro bastante didtico sobre C++.
[3] Victorine Viviane Mizrahi. Treinamento em Linguagem C++. Prentice-Hall, Inc., 2a edition, 2005.
[4] Walter Savitch. C++ Absoluto. Addison-Wesley Publishing Company, 2004. ISBN: 85-88639-09-2.
Livro bastante didtico sobre C++.
127