Você está na página 1de 17

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

Estes operadores adicionais, que so ++ and - -, podem ser usados para encurtar as operaes acima: Next: Bibliografia Up: Linguagem C++ - Notas Previous: 1 Programao Bsica em
k++; j--;

2 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.).

Estes operadores tambm podem ser colocados depois do nome da varivel:


++k; --j;

17 Operadores e Expresses Especiais


17.1 Operao de Atribuio Aritmtica
freqente em programas C++ expresses do tipo:
tudo = tudo + parte;

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; cout << "k = " << k << endl; cout << "k = " << k++ << endl; cout << "k = " << k << endl; }

tamanho = tamanho * 2.5; x = x * (y + 1); j = j - 1;

C++ fornece operadores adicionais que podem ser usados para tornar estes tipos de atribuies mais curtos. H um operador de atribuio para cada operao aritmtica listada anteriormente: += operao de atribuio de adio -= operao de atribuio de subtrao *= operao de atribuio de multiplicao /= operao de atribuio de diviso %= operao de atribuio de resto Cada uma dessas operaes podem ser usadas para tornar as expresses anteriores mais curtas:

O programa acima (que usa ps-incremento) imprimir o seguinte:


k = 5 k = 5 k = 6

A segunda linha impressa com o valor de k 5 porque o valor de k++ era 5, e k 6 depois da impresso. Para o programa:
int main() { int k = 5; cout << "k = " << k << endl; cout << "k = " << ++k << endl; cout << "k = " << k << endl; }

tudo += parte; tamanho *= 2.5; x *= y + 1; j -= 1;

O programa, que usa pr-incremento, ter a seguinte sada:


k = 5 k = 6 k = 6

17.2 Operadores de Incremento e Decremento


H alguns operadores em C++ que so equivalentes as seguintes expresses (que so bastante comuns em programas):
k = k + 1;

A segunda linha impressa 6 porque o valor de ++k 6. Os operadores de atribuio no podem ser usados com expresses aritmticas. Por exemplo, as expresses
(ack + 2)++; (nope + 3) += 5;

j = j - 1;

1 de 33

24/08/2011 10:39

2 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

resultaro em erros de compilao. Finalmente, quando usar o operador de incremento em um cout, tome cuidado para no fazer o seguinte:
cout << ++uhoh << uhoh * 2 << endl;

O nico comportamento no bvio a da diviso de inteiros:


30 / 5 6 31 / 5 6 29 / 5 5 3 / 5

Embora isso seja perfeitamente legal em C++ , os resultados no so garantidados que sejam consistentes. 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;

0 . Voc sempre obter o valor 0 porque

Lembre-se de evitar escrever algo como 1 / 2 * x significando


1 / 2 * x (1 / 2) * x que 1.0 / 2.0 * x.

0 * x que 0. Para obter o resultado desejado, voc poderia escrever

17.3 Expresses como Valor com Operadores de incremento e decremento


J que incremento e decremento so formas de atribuio, o operando deve ser um lvalue. O valor de uma expresso de incremento ou decremento depende se o operador usado na notao PR ou PS fixada (x++, ++x, x--, --x). Se for pr-fixada, o valor da expresso o novo valor aps o incremento ou decremento. Se for ps-fixada, o valor da expresso o valor antigo (antes do incremento ou decremento). Por exemplo no caso de incremento, a expresso:
x++ ++x

18.1 Converso de tipos


Valores podem ser convertidos de um tipo para outro implicitamente, da forma j comentada anteriormente. Em expresses envolvendo operadores binrios com operandos de tipos diferentes, os valores dos operandos so convertidos para o mesmo tipo antes da operao ser executada: tipos mais simples so ``promovidos'' para tipos mais complexos. Portanto, o resultado da avaliao de uma expresso com operandos de tipos diferentes ser o tipo do operando mais complexo. Os tipos em C++ so (do mais simples para o mais complexo):
char < int < long < float < double

tem o valor de x tem o valor de x + 1

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

Note que no importando a notao usada, o valor de x (o contedo do endereo de memria associada a x) ser x + 1. A diferena est no valor das expresses x++ e ++x, no no valor de x (em ambos os casos o valor de x ser incrementada de um).

17.4 Ambiguidade em certas expresses


s vezes, problemas podem acontecer devido o fato que C++ no especifica a ordem de avaliao dos operadores em uma operao binria. Em outras palavras, em expresses como a + b ou a < b, no h maneira de saber se o valor de a ser avaliado antes ou depois de b (pense em a e b como sendo qualquer expresso, no somente variveis.) Qual deles ser avaliado primeiro particular de cada compilador, e diferentes compiladores em mquinas diferentes podem ter resultados diferentes. Portanto, se a avaliao de um dos operadores pode alterar o valor do outro, o resultado pode ser diferente dependendo da ordem de avaliao. Portanto, em expresses do tipo x + x++, o valor pode diferir dependendo do compilador utilizado. Isto porque no sabemos quando exatamente o incremento de x ocorre. Outros maus exemplos: y = x + x-- e x = x++. De forma geral, para evitar este problema, no utilize senteas como estas.

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 << "Entre uma fracao (numerador e denominador): "; cin >> a >> b; cout << "A fracao em decimal e } " << 1.0 * a / b << endl;

18 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

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 tivssemos primeiro feito a diviso a/b e depois multiplicado por 1.0, embora o tipo da expresso a/b*1.0 seja do tipo double, o valor da expresso seria diferente do valor de 1.0 * a/b. Por que ? Em atribuies, o valor da expresso do lado direito convertido para o tipo da varivel do lado esquerdo da atribuio. Isto pode causar promoo ou ``rebaixamento'' de tipo. O ``rebaixamento'' pode causar perda de preciso ou mesmo resultar em valores errados. Em operaes de atribuio, atribuir um int em um float causar a converso apropriada, e atribuir um float em um int causar truncamento. Por exemplo:
float a = 3;

8, e o tipo int e o tipo double

3.5 + 2.25 5.75,

equivalente a a = 3.0

3 de 33

24/08/2011 10:39

4 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

int a = 3.1415;

equivalente a a = 3 (truncado)

float cels; cout << "Valor = " << (float) fahr << endl; cels = (float)5 / 9 * (fahr - 32); cout << "celsius = " << (int) cels << endl;

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.

18.2 Modificadores de tipos


Os tipos de dados bsicos em C++ podem estar acompanhados por modificadores na declarao de variveis. Tais modificadores so: long, short, signed e unsigned. Os dois primeiros tm impacto no tamanho (nmero de bits) usados para representar um valor e os dois ltimos indicam se o tipo ser usado para representar valores negativos e positivos (signed) ou sem este modificador) ou apenas positivos (unsigned). A Tabela 4 mostra uma lista completa de todos os tipos de dados em C++ , com e sem modificadores:

Agora que conhecemos o operador de cast de tipo podemos reescrever o programa que faz a converso de frao para decimal.
int main() { int a, b; cout << "Entre com uma fracao (numerador e denominador): "; cin >> a >> b; cout << "A fracao em decimal e } " << (float) a / b << endl;

Tabela 4: Modificadores de Tipos de Dados

Modificador

Tamanho em bits Faixa de valores

O cast de tipo tem a maior precedncia possvel, portanto podemos fazer o cast de a ou de b para ser do tipo 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.
float,

char unsigned char int unsigned int short int unsigned short int long int unsigned long int float double long double

8 8 16 16 16 16 32 32 32 64 80

-127 a 127 0 a 255 -32767 a 32767 0 a 65535 -32767 a 32767 0 a 65535 -2147483647 a 2147483647 0 a 4294967295 Mantissa de 6 dgitos Mantissa de 10 dgitos Mantissa de 10 dgitos

19 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

18.3 Cast de tipos


C++ tem um operador para alterar o tipo de um valor explicitamente. Este operador chamado de cast. Executando um cast de tipos, o valor da expresso forado a ser de um tipo particular, no importando a regra de converso de tipos. O formato do cast de tipos :
(

default:

sentencas n
}

O parnteses NO opcional na expresso acima. Podemos usar o cast de tipos da seguinte forma:
int fahr = 5;

5 de 33

24/08/2011 10:39

6 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

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.

Note a similaridade com o diagrama da sentena else-if e a diferena com o diagrama da sentena switch acima. O prximo programa tem a mesma funo de calculadora do programa anterior, porm utilizando a sentena switch. Exemplo 11:
#include <iostream> using namespace std; int main( ){ float num1, num2; char op; // obtem uma expressao do usuario cout << "Entre com numero operador numero\n"; cin >> num1 >> op >> num2; switch (op) { case '+': cout << " = " << setprecision(2) break; case '-': cout << " = " << setprecision(2) break; case '*': cout << " = " << setprecision(2) break; case '/': cout << " = " << setprecision(2) break; default: cout << " Operador invalido."; break; } cout << endl; }

20 A sentena break
O break faz com que todas as sentenas que o seguem dentro da mesma sentena switch sejam ignorados. 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:

<< num1 + num2;

<< num1 - num2;

<< num1 * num2;

<< num1 / num2;

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:

7 de 33

24/08/2011 10:39

8 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

#include <iostream> using namespace std; } int main( ){ float num1, num2; char op; // obtem uma expressao do usuario cout << "Entre com numero operador numero\n"; cin >> num1 >> op >> num2; switch (op) { case '+': cout << " = " << setprecision(2) break; case '-': cout << " = " << setprecision(2) break; case '*': case 'x': case 'X': cout << " = " << setprecision(2) break; case '/': case '\\': cout << " = " << setprecision(2) break; default: cout << " Operador invalido."; break; } cout << endl; } }

cout << mes << "/" << ano << " tem " << numDias << " dias\n"; }

21 Estruturas de Repetio
A linguagem C++ possui comandos para repetir uma sequncia de instrues. Estas estruturas de repetio, tambm conhecidas como laos (do ingls loops). A primeira construo que veremos o while, seguida de for e de do ... while.

<< num1 + num2;

<< num1 - num2;

21.1 A Estrutura de Repetio for


<< num1 * num2;

Considere o lao while abaixo:


int i;

<< num1 / num2;

i = 0; /* valor inicial da varivel de controle da repetio */ while (i <= 10) /* Testa varivel de controle para saber se haver repetio ou no do corpo do "while" */ { .... .... i += 1; /* expresso de incremento da varivel de controle da repetio */

Exerccio 2: Ler mes e ano e imprimir o numero de dias do mes no ano digitado.
#include <iostream> using namespace std; int main() { int mes, ano, numDias; cout << "Entre com mes e ano (mm aa): "; cin >> mes >> ano; if( mes < 1 || mes > 12 || ano < 0 || ano > 99 ) cout << "mes ou ano invalido\n"; else { switch( mes ){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: numDias = 31; break; case 2: if( ano % 4 == 0 ) numDias = 29; else numDias = 28; break; default: numDias = 30; }

Este lao pode ser expresso de forma diferente utilizando a estrutura de repetio for. A estrutura acima pode ser expressa de forma equivlente com um for da seguinte forma:
int i; for (i = 0; i <= 10; i += 1) { .... .... }

Como pode-se observar, h 4 partes no lao for: inicializao, expresso de teste, expresso de incremento e o corpo do lao. O formato do lao for : 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.

9 de 33

24/08/2011 10:39

10 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

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

21.1.1 Diversas sentenas dentro de um lao


Como no comando while, o corpo da repetio pode ser definido por uma sentena simples ou composta. No caso de uma sentena composta (bloco), no se deve esquecer de usar as chaves ( { e }) para delimitar o bloco da sentena composta. Em um for tambm podemos ter mais de uma expresso de inicializao ou incremento. Nestes caso, elas devem ser separadas por vrgula ( ,) o que ilustrado no exemplo abaixo: Exemplo 1:
#include <iostream> using namespace std; int main( ){ int contador, total; for( contador = 0, total = 0; contador < 10; contador += 1 ){ total += contador; cout << "contador = " << contador << ", total = " << total << endl; } }

Veja abaixo um exemplo simples do lao for:


int contador; for( contador = 0; contador < 5; contador += 1 ) cout << "contador = " << contador << endl; cout << "ACABOU !!!!\n";

Sada do programa:
contador = 0 contador = 1 contador = 2 contador = 3 contador = 4 ACABOU !!!!

Sada:
contador contador contador contador contador contador contador contador contador contador = = = = = = = = = = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, total total total total total total total total total total = = = = = = = = = = 0 1 3 6 10 15 21 28 36 45

Se voc examinar cuidadosamente este exemplo, poder ver precisamente o que est acontecendo. Primeiro, a inicializao executada, que a sentena contador = 0. Isso modifica o valor da varivel contador para 0. Ento, o teste executado. como 0 < 5 verdadeiro, o lao continua. Assim, o corpo da repetio executado, imprimindo a primeira linha da sada, contador = 0. Depois disso, o incremento executado, que a sentena contador++, que altera o valor da varivel contador para 1. Esta a 1 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, contador 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 que o valor de

No exemplo acima, contador = 0, total = 0 a inicializao, contador < 10 a expresso teste, e contador += 1 a expresso de incremento. Exemplo 2: Um programa que imprime todos os nmeros entre 30 e 5 (nesta ordem) divisveis por 3, e no final imprime sua soma.
#include <iostream> #include <iomanip> using namespace std; int main( ){

11 de 33

24/08/2011 10:39

12 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

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

O exemplo abaixo usa o do...while:


int contador = 0; do { cout << "contador = " << contador << endl; contador += 1; } while( contador < 5 ); cout << "ACABOU !!!!\n";

21.2 Usando while e for


Embora qualquer lao possa ser escrito usando while ou for, a escolha baseada principalmente no estilo. Por exemplo, se o lao precisa de uma inicializao e um incremento, ento o for geralmente usado. No caso em que o nmero de repeties no pr-determinado em geral usa-se o while. Como o comando for:
for( inicializacao; teste; incremento ) sentenca;

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

equivalente a:
inicializacao; while( teste ) { sentenca; incremento; };

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; int main( ){ int num; cout << "Entre com um numero par:\n"; do{ cin >> num; } while( num % 2 != 0 ); cout << "Obrigado.\n";

voc pode escolher o que preferir, a princpio.

21.3 A Estrutura de Repetio do...while


H outro comando de repetio em linguagem C++ . O do...while bastante parecido com while, com a diferena que a expresso de teste avaliada DEPOIS que o corpo da repetio executado. O formato do do...while : do corpo da repetio while (expresso teste )

Exemplo de execuo:

13 de 33

24/08/2011 10:39

14 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

Entre com um numero par: 3 1 5 4 Obrigado.

enum TpCores var1, var2; enum TpDias var3;

Agora, possvel dar valores a estas variveis, por exemplo:


var1 = AMARELO; var3 = QUI;

Neste caso, o valor da varivel num digitado pelo usurio. Depois disso, o teste executado para verificar se o nmero par (o teste num % 2 != 0 falso se num par j que o resto da diviso de qualquer nmero par por 2 zero). possvel escrever o programa acima usando while:
#include <iostream> using namespace std; int main( ){ int num; // Atribui um numero impar a num

um erro usar valores no definidos na declarao do tipo. A expresso var2 = AZUL; causa erro de compilao. Internamente, o compilador trata variveis enumeradas como inteiros. Cada valor na lista de valores possveis corresponde a um inteiro, comeando com 0 (zero). Portanto, no exemplo enum TpCores, VERMELHO armazenado como 0, AMARELO armazenado como 1, e VERDE armazenado como 2. Utilizao de tipos enumerados Variveis de tipos enumerados so geralmente usados para clarificar a operao do programa. Considere o seguinte trecho de programa que codifica dias da semana como inteiros (sendo sabado = 5 e domingo = 6) para verificar se o dia do pagamento cai no final de semana e altera a dia para a segunda-feira seguinte.
#include <iostream> using namespace std; // prototipo da funcao que dada a data, retorna o dia da semana. // seg=0, ter=1, qua=2, qui=3, sex=4, sab=5, dom=6 int diaDaSemana( int dia, int mes, int ano ); int main(){ int diaPgto, mesPgto, anoPgto; int diaSem; cout << "Entre com a data de pagamento (dd mm aa): "; cin >> diaPgto >> mesPgto >> anoPgto; diaSem = diaDaSemana( diaPgto, mesPgto, anoPgto ); if( diaSem == 5 ) diaPgto = diaPgto + 2; else if( diaSem == 6 ) diaPgto++; cout << "Data do pagamento: " << diaPgto << "/" << mesPgto << "/" << anoPgto << endl; }

cout << "Entre com um numero par:\n"; num = 1; while( num % 2 != 0 ){ cin >> num; } cout << "Obrigado.\n"; }

O problema com este programa que a varivel num deve ser inicializada com um valor que torne o teste do lao verdadeiro. Neste exemplo, simples encontrar tal valor. Para uma expresso teste mais complicada, isso pode no ser to fcil.

22 Tipo Enumerado
Em muitos programas, variveis do tipo int so utilizadas no por suas propriedades numricas, mas para representar uma escolha dentre um pequeno nmero de alternativas. Por exemplo:
int sexo; int cor; // masculino = 1 , feminino = 2 // vermelho = 1 , amarelo = 2 , verde = 3

A utilizao de cdigos para representar os valores que uma varivel poder assumir, certamente compromete 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 ++ )...

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; enum TpSemana {SEG, TER, QUA, QUI, SEX, SAB, DOM};

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:
enum

// prototipo da funcao que dada a data, retorna o dia da semana enum TpSemana diaDaSemana( int dia, int mes, int ano ); int main(){ int diaPgto, mesPgto, anoPgto; int diaSem; cout << "Entre com a data de pagamento (dd mm aa): "; cin >> diaPgto >> mesPgto >> anoPgto; diaSem = diaDaSemana( diaPgto, mesPgto, anoPgto ); if( diaSem == SAB ) diaPgto = diaPgto + 2; else if( diaSem == DOM ) diaPgto++;

};

Exemplos de definio de tipos enumerados:


enum TpCores {VERMELHO, AMARELO, VERDE}; enum TpDias {SEG, TER, QUA, QUI, SEX, SAB, DOM}; enum TpSexos {MASCULINO, FEMININO};

Variveis destes tipos so definidas da seguinte forma:

15 de 33

24/08/2011 10:39

16 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

cout << "Data do pagamento: " << diaPgto << "/" << mesPgto << "/" << anoPgto << endl; }

especfico (o que feito por cin). Isso pode ser feito usando a funo cin.get(). A funo cin.get() l o caracter do teclado e mostra o que foi digitado na tela.
#include <iostream> using namespace std; int main() { char ch; cout << "Digite algum caracter: ";

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 podemos escrever diaSem == SAB, o que torna o programa muito mais legvel.

23 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 funes para manipular a transferncia de dados entre programa e os dispositivos (devices) de sada e entrada padro. Algumas destas funes so: cin, cout, cin.get(), cin.put(), puts(), gets(). Estas 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: 1. Entrada e sada de caracteres:
int cin.get( void ); int cin.put( int );

cin.get(ch); cout << "\n A tecla pressionada eh " << ch << endl; }

O Resultado deste programa na tela :


Digite algum caracter: A A tecla pressionada eh A.

A funo cin.put() aceita um argumento de entrada, cujo valor ser impresso como caracter:
#include <iostream> using namespace std; int main() { char ch; cout << "Digite algum caracter: "; cin.get(ch); cin.put(ch); }

23.2 Consideraes sobre Leitura de Dados pelo Teclado


23.2.1 Lendo o teclado usando cin.get()

2. Entrada e sada de strings:


char *gets(char *); int puts( char *);

cin.get() uma funo vinculada primitiva principal de entrada cin. Cada vez que chamada, esta funo l um caractere teclado; cin.get comea a ler depois que a tecla digitada no final de uma sequncia de caracteres (dizemos que a entrada para a funo cin.get() est no fluxo de entrada). A funo cin.get() retorna um valor, o caractere lido (mais precisamente, o cdigo inteiro ASCII correspondente ao caractere). Vejamos o que acontece quando um programa trivial executado.
#include <iostream> using namespace std; int main(){ char ch; cin.get(ch); }

3. Entrada e sada formatada:


int cin >> arg1 >> arg2 >> ...; int cout << arg1 << arg2 << ...;

23.1 Comandos de entrada e sada: cin.get() e cin.put()


Vamos discutir algumas funes de entrada de dados (diferente do cin). A entrada de texto considerada como um fluxo de caratecteres. Um fluxo texto uma sequncia de caracteres dividida em linhas; cada linha consiste de zero ou mais caracteres seguido do caractere de nova linha ( \n). Como programador, voc no quer se preocupar em como as linhas so representadas fora do programa. Quem faz isso por voc so funes de uma biblioteca padro. Suponha que voc queira ler um nico caractere, sem fazer qualquer tipo de converso para um tipo de dados

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

17 de 33

24/08/2011 10:39

18 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

caracteres na mesma linha, inclusive backspace para corrigir caracteres j digitados. No momento que ele teclar , 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 , mas a funo cin.get() s comear a ler o que

Frequentemente quando voc est digitando a entrada para o programa, voc quer dizer ao programa que voc terminou de digitar o que queria. Em ambiente Unix, digitando ^D (segure a tecla de Ctrl e pressione D) voc diz ao programa que terminou a entrada do programa. Em ambiente MS-Windows, voc faz isto digitando ^Z (segure a tecla de Ctrl e pressione Z). Isto envia uma indicao para a funo cin.get(). Quando isso ocorre, o valor de ch depois de executar cin.get(ch); ser um valor especial do tipo inteiro chamado EOF (que significa end of file - final do arquivo). Considere o seguinte programa exemplo que conta o nmero de caracteres digitados (incluindo o caractere de ``prxima linha''):
#include <iostream> using namespace std; int main() { int total = 0; char ch; // Le o proximo caractere em ch e para quando encontrar // final do arquivo cin.get(ch); while( ! cin.eof() ) { total++; cin.get(ch); } cout << endl << total << " caracteres digitados" << endl; }

foi digitado depois que for teclado . 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 teclado. Isso no tem importncia quando a funo cin.get() chamada uma nica vez, mas isto pode causar problemas quando ele usado dentro de um lao. No iniccio de qualquer programa que usa cin.get(), voc deve incluir #include <iostream> using namespace std; Esta diretiva do pr-processador diz ao compilador para incluir informaes sobre cin, cin.get() e EOF (mais sobre EOF adiante.). Considere o seguinte programa:
#include <iostream> using namespace std; int main(){ char ch; cout << "Entre com uma letra: "; cin.get(ch); if( ch < 'A' || ch > 'z' ) cout << "Voce nao teclou uma letra!"; else cout << "Voce teclou " << ch << ", e seu codigo ASCII eh " << (int) ch << endl; }

S para esclarecer: voc deve teclar

depois de entrar com o comando ^D (ou ^Z no MS-Windows).

23.2.3 Para evitar problemas com a entrada...


(Observao: nesta seo, espaos em branco so relevantes e so mostrados como ) Quando voc executa um programa, cada caractere que voc digita lido e considerado como parte do fluxo de entrada. Por exemplo, quando voc usa cin.get(), voc deve teclar no final. Como mencionado anteriormente, o primeiro caractere digitado lido pelo cin.get(). Mas, o caractere de nova linha continua no fluxo de entrada (porque voc teclou ).

Um exemplo da execuo do programa:


Entre com uma letra: A Voce teclou A, e seu codigo ASCII eh 65.

De qualquer forma, se voc executar um cin.get() depois de um cin ou de um cin.get() voc ler o caractere de nova linha deixado no fluxo de entrada. . Da mesma forma, quando voc usa cin para ler informaes, ele somente l o que necessrio. Se voce usar cin para ler um nmero inteiro e digitar 42 (seguido de ), o cin l 42, mas deixa (e o caractere de

No exemplo de execuo acima o usurio teclou A e depois Outro exemplo de execuo do programa:
Entre com uma letra: AbcD Voce teclou A, e seu codigo ASCII eh 65.

nova linha do

) no fluxo de entrada.

Neste caso o usurio digitou quatro caracteres e depois teclou . 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.

Outro caso ``problemtico'' quando o cin usado num lao. Se voc digitar um valor do tipo errado, o cin ler o valor errado e a execuo do lao continuar na sentena aps o cin . Na prxima iterao do lao o cin vai tentar ler novamente, mas o ``lixo'' deixado da iterao anterior ainda estar l, e portanto a chamada corrente do cin tambm no dar certo. Este comportamento resultar num lao infinito (um lao que nunca termina), ou terminar e ter um resultado errado. H uma maneira simples de resolver este problema; toda vez que voc usar cin.get() (para ler um caracter s) ou cin , voc deve ler todo o ``lixo'' restante at o caractere de nova linha. Colocando as seguinte linhas aps chamadas a cin.get() ou cin o problema eliminado:

23.2.2 Marcando o final da entrada


19 de 33 24/08/2011 10:39 20 de 33 24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

// Pula o restante da linha while( cin.get(c) != '\n' );

Note que isso no necessrio aps todas as chamadas a cin.get() ou cin . S depois daquelas chamadas que precedem cin.get() (ou cin ), especialmente em um lao. A funo cin na realidade retorna um inteiro que o nmero de itens (valores) lidos com sucesso. Voc pode verificar se o cin funcionou testando se o valor retornado igual ao nmero de especificadores de formato no primeiro argumento da funo.
int main(){ int total = 0, num; while( total < 20 ){ cout << "Total = " << total << endl; cout << "Entre com um numero: "; if( (cin >> num) < 1 ) // Ignora o resto da linha while( cin.get() != '\n' ); else total += num; } cout << } "Final total = " << total << endl;

Strings so arrays de caracteres (arrays com elementos do tipo char) que DEVEM terminar com '\0' (o caracter NULL). Se voc usa o nome NULL em seu programa, ento necessria a definio #define NULL '\0'. No exemplo acima, embora no tenhamos escrito explicitamente o caracter NULL, o compilador automaticamente o colocou como o ltimo elemento do array arr2[]. Portanto, o tamanho de arr2[] 6: 5 para os caracteres que digitamos (ci208) e 1 para o caractere NULL que o compilador introduziu automaticamente. As definies abaixo so equivalentes.
char arr2[] = char arr2[] = {'c','i',' ', '2','0','8','\0'}; {'c','i',' ', '2','0','8', NULL};

O caractere NULL marca o fim de um string. Outros exemplos:


// a maneira tediosa char name1[] = { 'j','o','s','e',' ','s','i','l','v','a','\0' }; // e a maneira facil char name2[] = "jose silva";

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 NULL. Por exemplo, para armazenar o string ``programar e divertido'', voc precisa de um array de tamanho 22 (21 caracteres + 1 para o NULL).

24 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. 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]; }

25.1 Imprimindo strings com cout


Strings podem ser impressos usando cout . Por exemplo:
int main() { char mensagem[] = "tchau"; cout << "ola" << endl << mensagem << endl; }

A sada deste programa :


ola tchau

25.2 Lendo strings do teclado com cin.getline() e cin


A funo cin.getline() l uma linha de texto digitado no teclado e a armazena em um vetor indicado como primeiro argumento. O segundo argumento da funo indica o nmero mximo de caracteres que ser lido. Veja o exemplo abaixo:
#include <iostream> using namespace std; int main() { char nome[100]; cout << "Entre seu nome: "; cin.getline (nome, 100); cout << "Oi, " << nome << "." << endl ;

Arrays de caracteres so usados para armazenar texto, mas muito inconveniente se tivermos que colocar cada caractere entre apstrofes. A alternativa dada pela linguagem C++
char arr2[] = "ci208" ;

Neste caso, ``ci208'' um string de caracteres ou uma constante do tipo string. Ns j usamos strings antes, com as funes cout e cin (constantes do tipo string esto sempre entre aspas - "):
cout << "Entre com a nota para o estudante 2: "; cin >> gr2;

25 Strings
21 de 33 24/08/2011 10:39 22 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

Exemplo de execuo
Entre seu nome: Jose Silva Oi, Jose Silva.

Antonio dos Santos Pedro dos Santos Joao da Silva

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

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).
#include <iostream> using namespace std; int main() { char nome[100]; cout << "Entre seu nome: "; cin >> nome; cout << "Oi, " << nome << "." << endl; }

25.4.1 A funo strlen()


A funo strlen() tem como argumento um string. Ela retorna um inteiro que o comprimento do string (o nmero de caracteres do string, no contando o caractere NULL). Por exemplo, o comprimento do string ``alo'' 3.
#include <iostream> #include <cstring> using namespace std; int main() { char nome[100]; int comprimento; cout << "Entre seu nome: "; cin.getline(nome, 100); comprimento = strlen(nome); cout << "Seu nome tem } " << comprimento << " caracteres." << endl;

Exemplo de execuo
Entre seu nome: Jose Silva Oi, Jose.

Note que somente o primeiro nome lido pelo cin porque a funo pra no primeiro espao em branco que encontra (enquanto cin.getline() pra quando encontra um enter).

25.3 Array de Strings


Em notas de aula anteriores, vimos alguns exemplos de arrays de arrays (matrizes ou tabelas). Como strings so tambm arrays, podemos definir arrays de strings. O programa abaixo inicializa um array de strings com nomes e os imprime.
#include <iostream> using namespace std; #define NUM_NOMES 5 #define TAM 20 // define a quantidade de nomes no array // define o tamanho maximo do nome

Um exemplo de execuo:
Entre seu nome: Dostoevsky Seu nome tem 10 caracteres.

Abaixo, mostramos como a funo strlen() poderia ser implementada.


int strlen( char str[] ) { int comprimento = 0;

int main() { char nomes[NUM_NOMES][TAM] = {"Jose Silva", "Maria Silva", "Antonio dos Santos", "Pedro dos Santos", "Joao da Silva"}; int i; for(i = 0; i < 5; i++) cout << nomes[i] << endl; }

while ( str[comprimento] != NULL ) ++comprimento; return comprimento; }

25.4.2 A funo strcmp()


A funo strcmp() usada para comparar dois strings. Lembre que no podemos usar ==, como em str1 == para comparar dois strings, uma vez que strings so arrays. Strings devem ser comparados caractere por caractere. A funo strcmp() tem como argumento dois strings e retorna um inteiro.
str2,

A sada deste programa :


Jose Silva Maria Silva

Strings so ordenados de forma similar a maneira como palavras so ordenadas em um dicionrio. Ordenamos palavras em um dicionrio alfabeticamente, e ordenamos strings respeitando a ordem dos caracteres no conjunto de caracteres da mquina. A ordenao abaixo vlida em qualquer computador:

23 de 33

24/08/2011 10:39

24 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

'0' < '1' < ... < '8' < '9' 'A' < 'B' < ... < 'Y' < 'Z' 'a' < 'b' < ... < 'y' < 'z'

A ordem relativa do trs conjuntos (dgitos, letras maisculas e letras minsculas) depende do computador utilizado. Se s1 e s2 so strings, o resultado da chamada de funo strcmp(s1, s2) : se s1 se s1 se s1 (onde ,
s2, strcmp()

return -1; else if (s1[i] > s2[i]) return 1; else ++i; } }

retorna 0 retorna um nmero negativo (< 0) retorna um inteiro positivo (> 0) , e para strings) no dicionrio''. Exemplos: ``tudo'' menor que ``xadrez'',

s2, strcmp()

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

s2, strcmp()

25.4.3 A funo strcpy()


A funo strcpy() usada para copiar o contedo de um string para outro. Ela tem dois argumentos: strcpy(s1, s2) copia o contedo do string s2 para o string s1. A funo strcpy() que apresentamos abaixo no retorna um valor. Seu prottipo
void strcmp(char [], char []);

so

significa ``

vem antes de

``calor'' menor que ``calorao'', ``frio'' menor que ``quente'', e claro o string vazio , NULL, menor que qualquer string.

O exemplo abaixo mostra a utilizao do strcpy().


#include <iostream> #include <cstring> using namespace std; int main() { char pal[100], palCopia[100]; cout << "entre com uma palavra: "; cin >> pal; strcpy(palCopia, pal); cout << "entre outra palavra: "; cin >> pal; cout << "voce entrou primeiro: " << palCopia << endl; }

Considere o exemplo abaixo que usa strcmp():


#include <iostream> #include <cstring> using namespace std; int main() { char palavra1[100], palavra2[100]; int resultado; cout << "entre com uma palavra: "; cin >> palavra1; cout << "entre outra palavra: "; cin >> palavra2; resultado = strcmp(palavra1, palavra2); if (resultado == 0) cout << "igual" << endl; else if (resultado > 0) cout << "o primeiro e' maior" << endl; else cout << "o segundo e' maior" << endl; }

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:
void strcpy( char s1[], char s2[] ) { int i = 0; while ( s2[i] != NULL ) { s1[i] = s2[i]; ++i; } s1[i] = s2[i]; }

Aqui est um exemplo de como a funo strcmp() poderia ser implementada.


int strcmp( char s1[], char s2[] ) { int i = 0; while (1) { 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])

26 Estruturas
A estrutura de dados array usada para conter dados do mesmo tipo junto. Dados de tipos diferentes tambm

25 de 33

24/08/2011 10:39

26 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

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

char ch; } fac1;

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.

26.1 Declarao de Estruturas


Uma declarao de estrutura declara um tipo struct. Cada tipo struct recebe um nome (ou tag). Refere-se quele tipo pelo nome precedido pela palavra struct. Cada unidade de dados na estrutura chamada membro e possui um nome de membro. Os membros de uma estrutura podem ser de qualquer tipo. Declaraes de estrutura no so definies. No alocada memria, simplesmente introduzida um novo tipo de estrutura. Geralmente declaraes de estruturas so globais. Elas so colocadas prximas ao topo do arquivo com o cdigo fonte do programa, assim elas so visveis por todas as funes (embora isto dependa de como a estrutura est sendo usada). A forma padro de declarao de uma estrutura :

26.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 fac1.ch

refere ao membro com nome num na estrutura fac1;

se refere ao membro com nome ch na estrutura fac1.

struct nome-estrutura {

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

declarao dos membros


}

definio de variveis (optional);

Abaixo se apresenta um exemplo de um tipo estrutura que contm um membro do tipo int e um outro membro do tipo char.
struct facil { int num; char ch; };

Tentar acessar um nome de membro que no existe causa um erro de compilao.

26.4 Operadores usados com variveis de estrutura: valores e lvalues


Uma varivel de estrutura pode ser tratada como um objeto simples no todo, com um valor especfico associado a ela (a estrutura fac1 tem um valor que agrega valores de todos os seus membros). Note a diferena com arrays: se arr[] um array de tamanho 2 definedo como int arr[2] = {0,1};, o nome arr2 no se refere ao valor coletivo de todos os elementos do array. Na verdade, arr2 um apontador constante e se refere ao endereo de memria onde o array se inicia. Alm disso arr2 no um lvalue e no pode ser mudado. Variveis de estrutura so diferentes. Elas podem ser usadas como valores e lvalues, mas com certas limitaes. Os nicos usos vlidos de uma varivel de estrutura so dos dois lados de um operador de atribuio (=), como operando do operador de endereo & (obtendo o endereo da estrutura), e referenciando seus membros. De todas as variaes de atribuio (incluindo o incremento e decremento) atribuio de estruturas pode ser usada APENAS com =. O uso de outros operadores de atribuio ou de incremento causar um erro de compilao A atribuio de um valor de estrutura para outro copia todos os membros de uma estrutura para outra. Mesmo que um dos membros seja um array ou outra estrutura, ela copiada integralmente. As duas estruturas envolvidas na atribuio devem ser do mesto tipo struct. Considere o seguinte exemplo:
struct facil { int num; char ch; };

Esta declaracao cria um novo tipo chamado struct facil que contm um inteiro chamado num e um caracter chamado ch.

26.2 Definio de variveis de um tipo estrutura declarado


Como acontece com qualquer outro tipo de dados, variveis de tipos de estruturas so definidas fornecendo o nome do tipo e o nome da varivel. Considere a definio abaixo relativa a uma varivel com o nome fac1 que do tipo struct facil:
struct facil fac1;

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 atribudas um valor especfico, seu valor indefinido. possvel definir variveis durente a declarao do tipo estrutura:
struct facil { int num;

27 de 33

24/08/2011 10:39

28 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

void main(void) { struct facil fac1, fac2; } fac1.num = 3; fac1.ch = 'C'; /* Atribuindo fac1 a fac2 */ fac2 = fac1; }

cin.getline(ender.cidade_estado_cep, LEN); return ender;

void imprime_endereco(struct endereco ender) { cout << "\t " << ender.rua << endl; cout << "\t " << ender.cidade_estado_cep << endl; } main() { struct endereco residencia; cout << "Entre seu endereco residencial:\n"; residencia = obtem_endereco(); cout << "\nSeu endereco eh:\n"; imprime_endereco(residencia); }

Lembre-se que este tipo de atribuio ilegal com arrays. Tentar fazer isto com dois arrays causa um erro de compilao (uma vez que nomes de arrays so apontadores constantes).
int a[5], b[5]; /* Est errado -- No ir compilar */ a = b;

26.5 Inicializao de estruturas


Variveis de estruturas no-inicializadas contm valores indefinidos em cada um de seus membros. Como em outras variveis, variveis de estruturas podem ser inicializadas ao serem declaradas. Esta inicializao anloga ao que feito no caso de arrays. O exemplo abaixo ilustra a inicializao de estruturas:
struct facil { int num; char ch; }; void main(void) { struct facil fac1 = { 3, 'C' }, fac2; fac2 = fac1; }

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.):
int obtem_int(void); void imprime_int(int); int obtem_int(void) { int i; cout << "Entre valor: "; cin >> i; return i; } void imprime_int(int i) { cout << i << endl; } void main(void) { int valor; valor = obtem_int(); cout << "\nSeu valor:\n"; imprime_int(valor); }

Uma lista de valores separados por vrgula fica entre chaves ({ and }). Os valores de inicializao devem estar na mesma ordem dos membros na declarao da estrutura.

26.6 Estruturas como argumentos de funo e valores de retorno


Como qualquer outro valor do tipo int ou float, valores de estruturas podem ser passados como argumentos para funes, e podem ser retornados de funes. O exemplo abaixo ilustra tal prorpiedade:
#include <iostream> using namespace std; #define LEN 50 struct endereco { char rua[LEN]; char cidade_estado_cep[LEN]; }; struct endereco obtem_endereco(void); void imprime_endereco(struct endereco); struct endereco obtem_endereco(void) { struct endereco ender; cout << "\t Entre rua: "; cin.getline(ender.rua, LEN); cout << "\t Entre cidade/estado/cep: ";

26.7 Arrays de estruturas


Arrays de estruturas so como arrays de qualquer outro tipo. Eles so referenciados e definidos da mesma forma. O exemplo abaixo anlogo ao exemplo de endereo apresentado anteriormente, exceto que uma quantidade de NUM endereos armazenada ao invs de apenas um.

29 de 33

24/08/2011 10:39

30 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

#define LEN 50 #define NUM 10 struct endereco { char rua[LEN]; char cidade_estado_cep[LEN]; }; void obtem_endereco(struct endereco [], int); void imprime_endereco(struct endereco); void obtem_endereco(struct endereco aender [], int index) { cout << "Entre rua: "; cin.getline(aender[index].rua, LEN); cout << "Entre cidade/estado/cep: "; cin.getline(aender[index].cidade_estado_cep, LEN); } void imprime_endereco(struct endereco ender) { cout << ender.rua << endl; cout << ender.cidade_estado_cep << endl;; } void main(void) { struct endereco residencias[NUM]; int i; for (i = 0; i < NUM; i++) { cout << "Entre o endereco da pessoa " << i << ":\n"; obtem_endereco(residencias,i); } for (i = 0; i < NUM; i++) { cout << "endereco da pessoa " << i << ":\n"; imprime_endereco(residencias[i]); } }

struct endereco escola; }; struct student pessoa;

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

Note o uso repetido de . quando se acessa membros dentro de membros.

Subseces 17 Operadores e Expresses Especiais 17.1 Operao de Atribuio Aritmtica 17.2 Operadores de Incremento e Decremento 17.3 Expresses como Valor com Operadores de incremento e decremento 17.4 Ambiguidade em certas expresses 18 Mais sobre tipos: converso implcita e explcita 18.1 Converso de tipos 18.2 Modificadores de tipos 18.3 Cast de tipos 19 A sentena switch 20 A sentena break 21 Estruturas de Repetio 21.1 A Estrutura de Repetio for 21.1.1 Diversas sentenas dentro de um lao 21.2 Usando while e for 21.3 A Estrutura de Repetio do...while 22 Tipo Enumerado 23 Entrada e Sada Padro 23.1 Comandos de entrada e sada: cin.get() e cin.put() 23.2 Consideraes sobre Leitura de Dados pelo Teclado 23.2.1 Lendo o teclado usando cin.get() 23.2.2 Marcando o final da entrada 23.2.3 Para evitar problemas com a entrada... 24 Array de Caracteres 25 Strings 25.1 Imprimindo strings com cout 25.2 Lendo strings do teclado com cin.getline() e cin 25.3 Array de Strings 25.4 Funes de String 25.4.1 A funo strlen() 25.4.2 A funo strcmp() 25.4.3 A funo strcpy() 26 Estruturas 26.1 Declarao de Estruturas 26.2 Definio de variveis de um tipo estrutura declarado 26.3 Acesso a membros de uma estrutura: ponto (.), o operador membro de estrutura

Neste programa, o array residencias passado para obtem_endereco(), juntamente com o indice 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 podem ser acessados. elements da estrutura em can be accessed as well. Por exemplo, para acessar a rua do elemento residencias[0] usa-se:
cout << residencias[0].rua << endl; cout << residencias[0].cidade_estado_cep << endl;

26.8 Estruturas aninhadas


Como definido anteriormente, membros de estruturas podem ser de qualquer tipo. Isto inclui outras estruturas. Abaixo define-se duas estruturas, a segunda tendo membros que so tambm estruturas:
#define LEN 50 struct endereco { char rua[LEN]; char cidade_estado_cep[LEN]; }; struct student { char id[10]; int idade; struct endereco casa;

31 de 33

24/08/2011 10:39

32 de 33

24/08/2011 10:39

2 Tpicos Avanados

http://www.inf.ufpr.br/ci208/NotasAula/notas-2_Topicos_Avan_c_cad...

26.4 Operadores usados com variveis de estrutura: valores e lvalues 26.5 Inicializao de estruturas 26.6 Estruturas como argumentos de funo e valores de retorno 26.7 Arrays de estruturas 26.8 Estruturas aninhadas

Next: Bibliografia Up: Linguagem C++ - Notas Previous: 1 Programao Bsica em Armando Luiz Nicolini Delgado 2011-02-03

33 de 33

24/08/2011 10:39

Você também pode gostar