Académique Documents
Professionnel Documents
Culture Documents
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.).
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; }
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:
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; }
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;
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;
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).
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;
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;
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.
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;
Modificador
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
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:
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.
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).
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
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";
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...
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++;
};
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.
cin.get(ch); cout << "\n A tecla pressionada eh " << ch << endl; }
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); }
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); }
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; }
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:
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...
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};
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]; }
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.
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; }
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).
Um exemplo de execuo:
Entre seu nome: Dostoevsky Seu nome tem 10 caracteres.
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; }
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()
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()
so
significa ``
vem antes de
``calor'' menor que ``calorao'', ``frio'' menor que ``quente'', e claro o string vazio , NULL, menor que qualquer string.
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]; }
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).
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.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
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; }
Abaixo se apresenta um exemplo de um tipo estrutura que contm um membro do tipo int e um outro membro do tipo char.
struct facil { int num; char ch; };
Esta declaracao cria um novo tipo chamado struct facil que contm um inteiro chamado num e um caracter chamado ch.
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; }
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;
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.
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]); } }
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
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;
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