Escolar Documentos
Profissional Documentos
Cultura Documentos
SUMRIO
1 INTRODUO AO C++............................................................................................. 11 1.1. Aspectos gerais da linguagem C++ ........................................................................... 11 1.1.1. Comentrios........................................................................................................ 12 1.1.2. Identificadores .................................................................................................... 12 1.1.3. Case Sensitive..................................................................................................... 13 1.1.4. Palavras-Chave ................................................................................................... 13 1.1.5. Pontuao ........................................................................................................... 13 1.1.6. Separadores......................................................................................................... 13 1.1.7. Arquivos de cabealho........................................................................................ 14 1.2. Variveis.................................................................................................................... 15 1.2.1. Inicializando variveis com definies............................................................... 15 1.2.2. Escopo de uma varivel...................................................................................... 16 1.2.3. Inicializando variveis globais e locais .............................................................. 17 1.3. Entrada e sada de dados............................................................................................ 18 1.3.1. Fluxos de sada de dados .................................................................................... 18 1.3.2. Sada de dados no estilo C.................................................................................. 19 1.3.3. Sada de dados formatada ................................................................................... 19 1.3.4. Fluxos de entrada de dados................................................................................. 20 1.4. Constantes.................................................................................................................. 21 1.4.1. Constantes literais............................................................................................... 22 1.4.2. Constantes definidas ........................................................................................... 24 1.4.3. Constantes declaradas......................................................................................... 25 1.4.4. Constantes enumeradas ...................................................................................... 27 1.4.5. Atribuio de valores a elementos enumerados ................................................. 29 1.5. Operadores................................................................................................................. 29 1.5.1. Operadores e precedncia................................................................................... 30 1.5.2. Operadores de incremento e decremento............................................................ 30 1.5.3. Expresses .......................................................................................................... 32 1.6. Exerccios do captulo ............................................................................................... 34 2 INSTRUES E OPERADORES AVANADOS ................................................... 36 2.1. Operadores avanados ............................................................................................... 36 2.1.1. Entendendo os operadores relacionais................................................................ 36 2.1.2. O comando If, Else If e Else ............................................................................... 38 2.1.3. Entendendo os operadores lgicos ..................................................................... 39 2.1.4. Avaliando o resultado de operadores.................................................................. 41 2.1.5. Entendendo o operador condicional ternrio...................................................... 42 2.2. Operadores de Bits .................................................................................................... 43 2.2.1. O operador binrio E .......................................................................................... 43 2.2.2. O operador binrio OU ....................................................................................... 45 2.2.3. O operador binrio OU exclusivo ....................................................................... 47
Verso 1.1
2005
2.2.4. Aplicaes dos operadores binrios ................................................................... 48 2.2.5. Operadores de deslocamento de bits .................................................................. 49 2.2.6. O operador binrio NOT ..................................................................................... 51 2.2.7. Atribuies combinadas ..................................................................................... 52 2.3. Instrues de fluxo de programa ............................................................................... 53 2.3.1. O comando EXIT ................................................................................................ 53 2.3.2. O comando WHILE ............................................................................................ 55 2.3.3. O comando SWITCH .......................................................................................... 55 2.3.4. O comando DO/WHILE...................................................................................... 58 2.3.5. O comando FOR................................................................................................. 59 2.3.6. Elementos de um loop FOR mltiplo ................................................................. 60 2.3.7. Loop eterno usando o comando FOR ................................................................. 61 2.3.8. O comando BREAK ............................................................................................ 61 2.3.9. O comando CONTINUE..................................................................................... 62 2.9. Exerccios do captulo ............................................................................................... 63 3 ESTRUTURAS DE DADOS........................................................................................ 64 3.1. Estruturas confiveis para o armazenamento de dados ............................................. 64 3.2. Estruturas aninhadas .................................................................................................. 70 3.3. As unies ................................................................................................................... 71 3.4. Vetores....................................................................................................................... 73 3.4.1. Inicializando vetores........................................................................................... 77 3.5. Matrizes ..................................................................................................................... 78 3.6. Strings........................................................................................................................ 81 3.6.1. Inicializando vetores de caracteres ..................................................................... 82 3.7. Vetores e ponteiros .................................................................................................... 82 3.8. Campos de bits .......................................................................................................... 83 3.9. O operador SIZEOF .................................................................................................. 86 3.10. Exerccios do captulo ............................................................................................. 87 4 FUNES: PROGRAMANDO POR PARTES........................................................ 88 4.1. Chamando uma funo .............................................................................................. 88 4.2. Funes simples......................................................................................................... 89 4.3. Prottipo de funes .................................................................................................. 90 4.3.1. Prottipo externo e local..................................................................................... 90 4.3.2. Eliminando o prottipo de funes..................................................................... 91 4.4. Tipos de funes........................................................................................................ 92 4.4.1. O comando RETURN ......................................................................................... 92 4.4.2. Limitaes do comando RETURN...................................................................... 93 4.5. Definio de funes ................................................................................................. 93 4.5.1. Parmetros da funo.......................................................................................... 93 4.5.2. Passagem de argumentos por valor .................................................................... 93 4.5.3. Funes do tipo VOID ........................................................................................ 94 4.5.4. Funes que no recebem nada e no retornam nada......................................... 95 4.5.5. Passagem de vrios argumentos ......................................................................... 96
Verso 1.1
2005
4.5.6. Escrevendo vrias funes em um mesmo programa......................................... 96 4.5.7. Funes usadas como argumento de outras funes .......................................... 97 4.6. O operador unrio de referncia & ............................................................................ 97 4.6.1. Passagem de argumentos por referncia............................................................. 98 4.6.2. Referncias constantes...................................................................................... 100 4.6.3. Consideraes sobre referncias....................................................................... 101 4.7. Valores default para os argumentos de uma funo ................................................ 101 4.8. Sobrecarga de funes ............................................................................................. 103 4.9. Funes inline.......................................................................................................... 105 4.10 Funes recursivas.................................................................................................. 106 4.10.1. Como trabalha uma funo recursiva? ........................................................... 107 4.10.2. O jogo das torres de Hani ............................................................................. 108 4.11. Classes de armazenamento .................................................................................... 110 4.11.1. A classe de armazenamento auto.................................................................... 110 4.11.2. A classe de armazenamento extern................................................................. 111 4.11.3. A classe de armazenamento static .................................................................. 115 4.11.4. A classe de armazenamento static extern ...................................................... 121 4.11.5. A classe de armazenamento register ............................................................. 122 4.12. O pr-processador C++.......................................................................................... 124 4.12.1. A diretiva #define ........................................................................................... 125 4.12.2. A diretiva #undef ............................................................................................ 130 4.12.3. A diretiva #include ......................................................................................... 131 4.12.4. As diretivas #if, #ifdef, #ifndef, #elif, #else e #endif ...................................... 131 4.12.5. A diretiva #error............................................................................................. 134 4.13. Exerccios do captulo ........................................................................................... 135 5 MANIPULAO DE ARQUIVOS EM DISCO ..................................................... 138 6 PONTEIROS............................................................................................................... 139 APNDICES ..................................................................................................................... 140 A.1. BASES NUMRICAS ........................................................................................... 140 A.1.1. A BASE BINRIA ......................................................................................... 140 A.1.2. A BASE OCTAL............................................................................................. 141 A.1.3. A BASE HEXADECIMAL............................................................................. 141
Verso 1.1
2005
NDICE DE FIGURAS
Figura 1.1 - Exemplo do escopo de uma varivel. .............................................................. 17 Figura 3.1 - Os bytes de cada campo de uma varivel struct so armazenados na memria consecutivamente.......................................................................................................... 66 Figura 3.2 - Os bytes de cada campo de uma varivel union so armazenados na mesma posio da memria. ..................................................................................................... 72 Figura 3.3 - Representao esquemtica de um vetor de 100 nmeros inteiros................... 74 Figura 3.4 - Um vetor bidimensional um vetor de vetores, mas tambm pode-se encar-lo como sendo uma matriz................................................................................................ 78 Figura 4.1 - Esquema de funcionamento do jogo das torres de Hani............................... 109
Verso 1.1
2005
NDICE DE TABELAS
Tabela 1.1 - Tipos usuais de dados em C++......................................................................... 15 Tabela 1.2 - Cdigos de escape utilizados em C++............................................................. 23 Tabela 1.3 - Operadores usados em C++ e sua respectiva precedncia. ............................. 30 Tabela 2.1 - Operadores relacionais em C++. ...................................................................... 37 Tabela 2.2 - Modo de avaliao de operandos e resultados produzidos por operadores aritmticos, relacionais e lgicos.................................................................................. 42 Tabela 2.3 - Operadores de Bits. .......................................................................................... 43 Tabela 2.4 - Possveis resultados para o operador E binrio. ............................................... 43 Tabela 2.5 - Possveis resultados para o operador OU binrio............................................. 45 Tabela 2.6 - Possveis resultados para o operador OU exclusivo binrio............................. 47 Tabela 4.1 - Analogia entre as diretivas de compilao condicional e operador if. ........... 132
Verso 1.1
2005
NDICE DE CDIGOS
Cdigo 1.1 - Um programa tpico em C++........................................................................... 11 Cdigo 1.2 - Exemplo de cabealho..................................................................................... 12 Cdigo 1.3 - Outra forma de se escrever um programa....................................................... 14 Cdigo 1.4 - Exemplos de usos de arquivos de cabealho................................................... 14 Cdigo 1.5 - Inicializao de variveis no momento de sua declarao. ............................. 16 Cdigo 1.6 - Programa que retorna a data e a hora atual...................................................... 18 Cdigo 1.7 - O comando PRINTF. ....................................................................................... 19 Cdigo 1.8 - Exemplo de converso de formato de dados. .................................................. 19 Cdigo 1.9 - Programa para clculo da mdia de trs nmeros. .......................................... 20 Cdigo 1.10 - Mtodo para evitar uma entrada incorreta do tipo de dado. .......................... 20 Cdigo 1.11 - Uso de #define para a declarao de constantes....................................... 24 Cdigo 1.12 - Uso do comando const para a declarao constantes................................. 25 Cdigo 1.13 - Uso dos comandos #define e #undef..................................................... 26 Cdigo 1.14 - Uso de constantes enumeradas. ..................................................................... 28 Cdigo 1.15 - Uso de operadores de incremento e decremento. .......................................... 31 Cdigo 1.16 - Programa para clculo do imposto incidente sobre mercadorias. ................ 32 Cdigo 2.1 - Programa para a converso de milhas para quilmetros. ................................ 37 Cdigo 2.2 - A estrutura if / else if / else........................................................ 38 Cdigo 2.3 - Programa para averiguao do desempenho de automveis. .......................... 40 Cdigo 2.4 - Uso do operador condicional ternrio. ............................................................ 42 Cdigo 2.5 - Uso do operador E binrio............................................................................... 44 Cdigo 2.6 - Uso do operador OU binrio. .......................................................................... 46 Cdigo 2.7 - Uso do operador OU exclusivo binrio........................................................... 47 Cdigo 2.8 - Uso dos operadores de deslocamento de bits. ................................................. 49 Cdigo 2.9 - Uso do operador NOT binrio. ........................................................................ 51 Cdigo 2.10 - Uso do comando EXIT................................................................................... 54 Cdigo 2.11 - Uso do camando EXIT (verso simplificada)................................................ 54 Cdigo 2.12 - Uso do comando WHILE e do comando SWITCH........................................ 57 Cdigo 2.13 - Uso do comando DO/WHILE........................................................................ 58 Cdigo 2.14 - Uso do comando FOR. .................................................................................. 59 Cdigo 2.15 - Programa para exibio dos caracteres da Tabela ASCII. ............................ 60 Cdigo 2.16 - Uso do comando BREAK............................................................................... 61 Cdigo 2.17 - Uso do comando CONTINUE. ...................................................................... 62 Cdigo 3.1 - Uso do comando STRUCT para os principais tipos de dados em C++. .......... 65 Cdigo 3.2 - Arquivo de cabealho (.h) tpico de um banco de dados................................. 67 Cdigo 3.3 - Uso do comando STRUCT em banco de dados. .............................................. 68 Cdigo 3.4 - Declarao e inicilaizao conjunta de uma varivel STRUCT. ..................... 69 Cdigo 3.5 - Uso do comando UNION. ............................................................................... 72 Cdigo 3.6 - Uso de VETORES em C++.............................................................................. 74 Cdigo 3.7 - Programa para clculo da mdia de 18 nmeros utilizando vetores. .............. 76 Cdigo 3.8 - Programa para teste da inicializao de vetores. ............................................. 77 Cdigo 3.9 - Exemplo do uso de matrizes em C++.............................................................. 79
Verso 1.1
2005
Cdigo 3.10 - Exemplo do uso de um CAMPO DE BITS. ................................................... 84 Cdigo 3.11 - Uso do operador SIZEOF. ............................................................................. 86 Cdigo 4.1 - Exemplo do uso de uma FUNO simples. ................................................... 89 Cdigo 4.2 - Uso de funes de prottipo local. .................................................................. 90 Cdigo 4.3 - Uso de funes sem prottipo. ........................................................................ 91 Cdigo 4.4 - Uso de passagem de argumentos por valor em funes. ................................. 94 Cdigo 4.5 - Uso de funes do tipo VOID.......................................................................... 94 Cdigo 4.6 - Uso de funes que no recebem e nem retornam nada.................................. 95 Cdigo 4.7 - Uso de funes com mais de um argumento. .................................................. 96 Cdigo 4.8 - Uso de funes como argumento de outras funes. ...................................... 97 Cdigo 4.9 - Uso de passagem de argumentos por referncia em funes. ......................... 98 Cdigo 4.10 - Uso de passagem de argumentos por referncia para ordenar um vetor. ...... 99 Cdigo 4.11 - Uso de passagem de argumentos por referncias constantes. ..................... 101 Cdigo 4.12 - Uso de valores default para argumentos de funes. .................................. 102 Cdigo 4.13 - Uso de sobrecarga (overload) de funes. .................................................. 103 Cdigo 4.14 - Cdigo 4.12 modificado para o uso de sobrecarga de funes. .................. 104 Cdigo 4.15 - Uso de funes INLINE............................................................................... 105 Cdigo 4.16 - Uso de funes recursivas. .......................................................................... 106 Cdigo 4.17 - Programa que imprime uma frase digitada pelo usurio ao contrrio......... 108 Cdigo 4.18 - Resoluo do problema das torres de Hani. .............................................. 109 Cdigo 4.19 - O operador de escopo de variveis ::. ................................................... 113 Cdigo 4.20 Exemplo de uma funo que retorna mais de um valor usando referncias. .................................................................................................................................... 114 Cdigo 4.21 - Exemplo de uma funo que retorna um valor uma varivel por referncia. .................................................................................................................................... 115 Cdigo 4.22 - Uso de variveis da classe static. ................................................................ 116 Cdigo 4.23 - Uso da funo RAND para a simulao de um lanamento de um dado ou de uma moeda.................................................................................................................. 117 Cdigo 4.24 - Gerador de nmeros pseudoaleatrios......................................................... 119 Cdigo 4.25 - Gerador de nmeros aleatrios que usa a funo _dos_gettime(). .............. 120 Cdigo 4.26 - Gerador de nmeros aleatrios que utiliza uma varivel da classe static extern como semente. ................................................................................................. 121 Cdigo 4.27 - Uso de variveis da classe register.............................................................. 123 Cdigo 4.28 - Uso de macros. ............................................................................................ 125 Cdigo 4.29 - Uso de uma macro na definio de outra macro. ........................................ 127 Cdigo 4.30 - Problemas no uso de macros. ...................................................................... 128 Cdigo 4.31 - Uso de funes inline no lugar de macros................................................... 128 Cdigo 4.32 - Outro exemplo do uso incorreto de uma macro. ......................................... 129 Cdigo 4.33 - Outro exemplo do uso de funes inline no lugar de macros. .................... 129
Verso 1.1
2005
PREFCIO
A cada dia que se passa a informtica se torna mais e mais parte do nosso dia a dia. Seja como ferramental para a resoluo de problemas matemticos ou como um poderoso e polivalente laboratrio de simulaes a informtica tem revolucionado a forma como os engenheiros resolvem seus problemas. Nesta apostila o aluno ter contato com a linguagem de programao mais difundida entre os programadores de todo o mundo, o C e seu sucessor o C++. Tpicos mais avanados, tais como programao orientada a objetos, arvores, grafos, etc so deixados para os cursos posteriores a este. Neste curso espera-se que o aluno adquira conhecimento para criar os seus primeiros programas, computacionalmente simples, mas que na prtica j resolvem alguns problemas do dia a dia. Esta apostila destina-se aos alunos do segundo semestre do curso de Engenharia de Produo da Faculdade Santa Rita (FASAR), os quais tenho o prazer de ter como meus alunos. Por fim, estou a disposio de todos que lerem esta apostila para tirar dvidas, assim como para receber crticas.
Verso 1.1
10
2005
1 INTRODUO AO C++
//Programa welcome to C++ #include <stream.h> main () { cout << "Bem Vindo ao mundo do C++!\n"; } O exemplo acima mostra como o aspecto geral de um programa escrito em C++. O leitor no deve se ater, por enquanto, sintaxe dos comandos, mas sim morfologia do corpo do programa. Note que algumas linhas terminam em ponto-e-vrgula (;) e que outras no. A primeira linha comea com o caractere #. Aos poucos abordaremos todos os conceitos que esto envolvidos neste pequeno programa e que tem por finalidade apenas mostrar na tela a mensagem: Bem Vindo ao mundo do C++!. Assim sendo, comecemos com o comando cout (do ingls character out) que tem por finalidade imprimir na tela uma seqncia de caracteres, aqui representada pela frase: Bem Vindo ao mundo do C++! O comando cout usado juntamente com o sinal de duplo menor-que (<<), que tem por finalidade mostrar como o fluxo do comando (neste caso a instruo da direita ser passada ao comando da esquerda). O sinal \n (do ingls to a new-line) indica que naquele ponto dever ser inserida uma quebra de linha pelo compilador. Uma propriedade interessante da linguagem C++ que se pode escrever instrues simples em uma ou mais linhas sem problema algum. Assim sendo, o bloco de instrues abaixo tratado pelo compilador como se fosse uma linha apenas. cout << "Esta apenas" << "uma instruo" << "dividida em trs linhas...\n"; Que na tela ser exibida a mensagem: Esta apenas uma instruo dividida em trs linhas...
Verso 1.1
11
2005
1.1.1. Comentrios
H duas formas de se inserir um comentrio em C++. Uma delas uma herana direta da linguagem C e a outra nativa do C++. As duas formas so: /* Comentrio no estilo C */ // Comentrio no estilo C++ H uma pequena, porm sutil diferena nas duas formas de se escrever um comentrio, e esta se deve ao fato de que um comentrio no estilo C++ torna toda a linha aps as duas barras (//) uma linha de comentrio, assim sendo tudo o que se encontra direita das duas barras at o incio da prxima linha ignorado pelo compilador. J o comentrio escrito em linguagem C tem um smbolo de incio (/*) e um de fim (*/), o que permite que sejam escritos comentrios desta forma no meio de linhas de comando1. A maioria dos programadores costuma fazer uma moldura inicial em seus programas, tal moldura til a nvel de comparao entre verses, direitos autorais, etc. Um exemplo de moldura pode ser visto no Cdigo 1.2.
Cdigo 1.2 - Exemplo de cabealho.
/*********************************************************/ /* PROGRAMA Exemplo de Cabealho */ /* */ /* ESCRITO por Andr Carlos Silva VERSO 1.00.00 */ /* DATA: 08/09/01 TODOS OS DIREITOS RESERVADOS */ /*********************************************************/
1.1.2. Identificadores
Identificadores so smbolos singulares (ou nicos) utilizados nos programas. O nome da funo main no Cdigo 1.1 um identificador, porque identifica o incio do programa principal (ou o programa propriamente dito). Os identificadores podem conter apenas letras (maisculas e/ou minsculas), algarismos e traos de sublinha (em ingls underscore, o caractere _), e se comporem de at 127 caracteres. Os identificadores devem comear com letras de A a Z (como fn1 ou Catch21). O identificador 123abc no vlido, pois comea com um caractere numrico, j o identificador abc123 vlido. Identificadores do sistema freqentemente comeam com trao de sublinha, o que torna o seu uso como caractere inicial no muito recomendvel. Alm do trao de sublinha, outros sinais de pontuao, tais como ponto final (.), aspas ( ), etc., so usados pelo compilador
1
Linha de comando toda instruo dada ao compilador. Pode ser uma declarao ou um comando propriamente dito, apesar de alguns autores no pensarem assim.
Verso 1.1
12
2005
e no devem ser incorporados em identificadores para que no causem nenhum efeito inesperado ao funcionamento do programa.
1.1.4. Palavras-Chave
Palavras-Chave (ou keywords) so identificadores que o compilador reserva para o seu uso prprio. As palavras auto, float, signed, void e while so exemplos de palavras chave, uma vez que tais palavras tm um significado prprio previamente definido para o compilador, significado este que no pode ser mudado.
1.1.5. Pontuao
Uma linha de instruo dever ser terminada por ponto-e-vrgula (;), os parentes (( )) aps o identificador main no Cdigo 1.1 delimitam a passagem de parmetros entre o programa e outras funes e as chaves ({}) logo aps o identificador main delimitam um bloco de instrues2, sendo anlogas aos comandos BEGIN e END do Pascal. Estes so exemplos de sinais de pontuao que j foram usados previamente e que sero, sem dvida alguma, usados novamente. O conjunto completo de sinais de pontuao usados pelo compilador pode ser visto abaixo. # ( ) [ ] { } , : ; . ...
medida que novos sinais forem sendo apresentados os seus significados sero explicados.
1.1.6. Separadores
Diferem dos sinais de pontuao por serem invisveis. So descritos pelo termo espao em branco (ou blank space). Os separadores em C++ incluem espaos, tabulaes, carriage return e line feeds includas no texto. Usualmente o C++ ignora os espaos em branco que no so utilizados para separar identificadores, nmeros e outras construes que devam permanecer unidas. Assim sendo,
Quando temos instrues que so executadas em dentro de um mesmo nvel de um programa o seu conjunto recebe o nome de bloco de instrues e diz-se que as instrues esto aninhadas.
Verso 1.1
13
2005
o Cdigo 1.1 pode ser reescrito como no Cdigo 1.3, sem que o contedo do programa seja afetado3.
Cdigo 1.3 - Outra forma de se escrever um programa.
#include <stream.h> // Esta declarao inclui todo o contedo do arquivo // stream.h neste programa. #include "stdio.h" // Esta declarao inclui todo o contedo do arquivo // stdio.h neste programa. altamente recomendvel que sempre se use os sinais de < > para inserir um arquivo de cabealho fornecido junto com o compilador e para inserir um arquivo de cabealho que no venha incluso neste. O ponto mais importante que se deve ressaltar sobre os arquivos de cabealho que so estes arquivos que possuem todos os comandos passados ao compilador. O compilador C, bem como o C++, no reconhecem quase comando algum (ao contrrio de compiladores tais como o PASCAL, o FORTRAN, o DELPHI, etc.). Um programador em C++ deve conhecer os arquivos de cabealho, tanto a sua estrutura quanto os seus comandos.
3
O cdigo descrito em 1.3 no de uso aconselhvel, pois torna o algoritmo do programa extremamente complexo para a leitura.
Verso 1.1
14
2005
1.2. Variveis
Em C++ uma varivel uma posio da memria que recebeu um nome. Assim sendo, as variveis podem armazenar todo o tipo de informao, ou de dados. Dentro de um programa podemos usar o nome de uma varivel livremente como se fosse o seu valor. Todas as variveis apresentam, alm de um nome, um tipo declarado, que a informao que o compilador requer para distinguir qual o tipo de dado que ser armazenado pela varivel. A Tabela 1.1 apresenta os principais tipos de variveis existentes no C++ e os seus limites de aplicabilidade.
Tabela 0.1 - Tipos usuais de dados em C++.
* Valores aproximados.
Tamanho (bytes) 1 2 2 4 4 8 8
Para criar uma varivel em um programa deve-se comear com uma declarao de seu tipo e terminar com o seu identificador (ou nome da varivel), seguido de ponto-e-vrgula. Abaixo segue o exemplo da declarao de uma varivel do tipo caractere chamada sim_ou_nao. char sim_ou_nao; Tal comando denominado definio, porque define o espao na memria para o armazenamento de uma varivel. Pode-se inserir definies de variveis em qualquer lugar do programa, porm o local da definio de uma varivel muda o seu escopo, o que pode afetar o modo como o programa ser executado. Voltaremos a falar em escopo de variveis no item 1.2.2.
Existem duas formas de se inicializar4 uma varivel, isto , de atribuir-lhe um valor inicial. O primeiro, e provavelmente o melhor, visto no Cdigo 1.5. Desta forma a varivel inicializada logo aps ter sido declarada.
A necessidade de se inicializar uma varivel se deve ao fato do compilador C, e tambm o C++, guardarem lixo, que o fato de uma varivel no inicializada comear com um valor esdrxulo, oriundo de dados
Verso 1.1
15
2005
char sim_ou_no = S; int contador = 1; float peso = 155.5; A outra forma inicializar a varivel no decorrer do programa. Isso feito mediante um simples comando de atribuio, da seguinte forma: int contador; ... contador = 1; Um programa pode mudar o valor de uma varivel quantas vezes forem necessrias e toda vez que o programa atribui um novo valor para uma varivel, este substitui o valor antigo, sendo este ltimo perdido.
previamente armazenados na memria do computador, o que pode causar srios transtornos na vida do programador.
Verso 1.1
16
2005
Definies que so realizadas dentro das chaves abertas logo aps main so locais funo main. Tal aspecto deve ficar bem claro desde j, uma vez que logo sero apresentados os conceitos de funes similares funo main.
Verso 1.1
17
2005
//Programa para ler a data e a hora do sistema #include <stream.h> #include <dos.h> main () { struct dosdate_t hoje; struct dostime_t agora; _dos_getdate(&hoje); cout << "A data de hoje e: " << (int)hoje.day << "/" << (int)hoje.month << "/" << (int)hoje.year << "\n"; _dos_gettime(&agora); cout << "A hora atual e: " << (int)agora.hour << ":"; if (agora.minute < 10) cout << '0'; cout << (int)agora.minute << ":"; if (agora.second < 10) cout << '0'; cout << (int)agora.second << "\n"; } Existem alguns itens ainda no estudados no Cdigo 1.6, como nas linhas 8 e 9, onde so definidas duas variveis do tipo struct, denominadas hoje e agora. J as linhas 11 e 16 usam funes para ler e armazenar a data e a hora atual do sistema nestas variveis. Basta, por enquanto, saber que o comando struct um tipo de definio. O comando (int)agora.second denominado de molde de tipo (do ingls type cast). Neste caso, a varivel agora.second foi definida previamente no arquivo de cabealho dos.h como um char de um nico byte, que normalmente armazena pequenos valores ou caracteres ASCII5. O programa usa uma varivel char para armazenar pequenos nmeros
5
Vide captulo 1.4.1.1. Constantes literais do tipo caractere para mais informaes.
Verso 1.1
18
2005
inteiros, e no caracteres. Assim sendo, para que sejam exibidos na tela nmeros inteiros deve-se utilizar o comando (int), que molda a varivel char em um tipo inteiro (int).
printf("Entre com o seu nome"); printf("Seu saldo $ %d\n", saldo); A funo printf6, freqentemente encontrada em programas escritos em C, transfere argumentos encontrados entre os parnteses para a sada de vdeo padro, que normalmente o monitor de vdeo. A primeira instruo do Cdigo 1.7 imprime no vdeo uma string simples. A segunda instruo tambm imprime uma string na tela, mas usa notao especial (%d) que usada para acrescentar elementos aos caracteres entre aspas. Nesse caso desejase acrescentar uma varivel, denominada saldo, a qual printf converte seu contedo em caracteres e os insere na posio indicada na string de sada. A execuo do Cdigo 1.7 traz como resultado no vdeo algo como: Entre com o seu nome Seu saldo $ 75.68
cout <<"A conta em octal :" << oct << conta; cout <<"A conta em hexadecimal :" << hex << conta; cout <<"A conta em decimal :" << dec << conta; Uma outra razo para se usar funes de formatao de dados para alinhar ou justificar colunas de nmeros. Para faz-lo basta que se acrescente um nmero inteiro aps a varivel que se deseja exibir o contedo, nmero este que indica o mnimo de caracteres que a varivel ir ocupar, por exemplo: cout <<"A conta :" << setw(10) << conta;
6
Para usar o comando printf em programas escritos em C++ deve-se usar o cabealho stdio.h.
Verso 1.1
19
2005
O comando acima exibe na tela o valor da varivel conta, acrescentando espaos sua esquerda para completar um mnimo de 10 colunas de caracteres. Se o nmero de colunas reservado for menor que o necessrio para a correta exibio da varivel, esta ser exibida corretamente, porm no estar alinhada como o esperado.
//Programa para calcular a media de trs nmeros reais #include <stream.h> main () { float a, b, c; cout << "Digite trs nmeros.\n"; cin >> a >> b >> c; cout << "A media dos trs nmeros e: '\n'; }
Fluxos de entrada de dados partem do pressuposto que a informao que lhes ser passada ser condizente com o tipo da varivel que lhe receber. Muitas vezes isso no ocorre, seja por um erro de digitao do usurio ou outro motivo qualquer, o que ocorre comumente quando os dados a serem lidos so de tipos numricos e, ao invs disso, o dado lido um dado no-numrico. Quando erros como o do exemplo como o anterior ocorre, quase sempre ocorrem erros internos no programa, o que pode causar a sua falha geral. Uma boa forma de lidar com estes tipos de erros ler todas as entradas de dados armazenando-as em strings de caracteres e converte-las, posteriormente, para o tipo de dado desejado. O Cdigo 1.10 apresenta o mesmo programa do Cdigo 1.9, porm caso o dado lido no seja numrico o programa continua sua execuo normalmente.
Cdigo 1.10 - Mtodo para evitar uma entrada incorreta do tipo de dado.
Programas em C utilizam tipicamente a funo scanf para a entrada de dados. O C++ tambm reconhece esta funo exatamente como faz com a funo printf.
Verso 1.1
20
2005
#include <stdlib.h> main () { float a, b, c; char d[20], e[20], f[20]; cout << "Digite trs nmeros.\n"; cin >> d >> e >> f; a = atof(d); cout <<"O primeiro valor digitado foi: " << a << '\n'; b = atof(e); cout <<"O segundo valor digitado foi: " << b << '\n'; c = atof(f); cout <<"O terceiro valor digitado foi: " << c << '\n'; cout << "A media dos trs nmeros e: " << (a+b+c)/3 << '\n'; } No programa apresentado no Cdigo 1.9, caso o usurio digite um caractere no-numrico o programa automaticamente pararia de ler as demais variveis e saltaria para linha de comando posterior. O mesmo j no acontece com programa apresentando no Cdigo 1.10, pois os dados lidos so armazenados em variveis do tipo char, podendo ter cada uma vinte posies8. A funo atof (ASCII to Float Point) se encarrega de converter a string lida para um valor real e caso o contedo da string seja um caractere no-numrico, o programa simplesmente atribuir o valor zero para a varivel, evitando assim maiores problemas. As funes atol (ASCII to Long) e atoi (ASCII to Ingeter) so anlogas funo atof, porm a primeira converte a string para um valor do tipo inteiro longo, a segunda para um valor do tipo inteiro e a terceira para um valor do tipo real.
1.4. Constantes
Constantes9 so valores que no se alteram durante a execuo de um programa, como por exemplo o valor de , ou se alteram raramente, como no caso de um programa que armazena as notas de exames de alunos. Pode-se criar uma constante chamada NOTA_MAXIMA e associar a esta o valor 10. Se a nota mxima mais tarde for alterada para 100 bastar revisar o valor da constante e recompilar o programa, no havendo a necessidade de se revisar todo o programa alterando todo 10 por 100. Em programas escritos em C++ existem quatro tipos de constantes, que so:
8 9
O nmero de posies de uma string definido pelo nmero entre colchetes aps o nome da varivel. Constantes em C e C++ so tipicamente escritas com letras maisculas, ainda que isso no seja obrigatrio.
Verso 1.1
21
2005
10
As faixas de valores signed e unsigned possuem os mesmos comprimentos, porm representam diferentes faixas de valores. Apenas tipos de dados signed podem representar valores negativos.
Verso 1.1
22
2005
Programao I Prof. Andr Carlos Silva Tabela 0.2 - Cdigos de escape utilizados em C++.
Cdigo de escape '\a' '\b' '\f' '\n' '\r' '\t' '\v' '\\' '\'' '\"' '\?' '\000' '\x00'
Significado Campainha Backspace Form feed New-line Carriage return Tab horizontal Tab vertical Barra reversa Apstrofo Aspas Ponto de interrogao Octal em ASCII Hexadecimal em ASCII
Valores em ASCII Hexadecimal Smbolo(s) 07 BEL 08 BS 0C FF 0D0A CRLF 0D CR 09 HT 0B VT 5C \ 27 22 3F ? todos todos todos todos
Verso 1.1
23
2005
#include <stream.h> #define #define #define #define #define #define #define #define NUMERO 51 CARACTERE '@' STRING "Aprendendo C++." OCTAL 0233 DECIMAL 155 HEXADECIMAL 0x9b REAL 3.14159 NOVALINHA '\n'
main () { cout << STRING << NOVALINHA << CARACTERE << NOVALINHA << NUMERO << NOVALINHA << DECIMAL << NOVALINHA << OCTAL << NOVALINHA
Verso 1.1
24
2005
<< HEXADECIMAL << NOVALINHA << REAL << NOVALINHA; } O C++ substitui o NUMERO e NOVALINHA com o texto associado a estes smbolos, 51 e '\n', respectivamente. Nota-se que um espao simples suficiente para se separar um identificador de seu valor. O C++ ignora os espaos extras que por ventura existam.
#include <stream.h> const const const const const const const const int char char int int int float char NUMERO = 51; CARACTERE = '@'; STRING[] = "Aprendendo C++."; OCTAL = 0233; DECIMAL = 155; HEXADECIMAL = 0x9b; REAL = 3.14159; NOVALINHA = '\n';
main () { cout << STRING << NOVALINHA << CARACTERE << NOVALINHA << NUMERO << NOVALINHA << DECIMAL << NOVALINHA << OCTAL << NOVALINHA << HEXADECIMAL << NOVALINHA << REAL << NOVALINHA; }
Verso 1.1
25
2005
Exceto para a constante STRING na linha 5, os identificadores so declarados da mesma maneira nos Cdigos 1.11 e 1.12. Na linha 5 do Cdigo 1.12 a constante STRING termina com um par de colchetes ([ ]). Os colchetes aps STRING dizem ao C++ para criar um vetor de caracteres, em outras palavras, uma string de mais de um caractere. Sem os colchetes o compilador iria considerar a linha 5 como definindo um nico char, e no um vetor deles. Uma outra diferena significativa entre constantes #definidas e constantes criadas com o comando const quando o compilador avalia um valor. Por exemplo, suponhamos que um programa contivesse o cdigo abaixo: #define X 5 #define Y X + 10 Como era de se esperar, X est associado ao valor 5 e Y est associado ao valor X + 10. Todavia deve-se ter muito cuidado com ais tipos de definies, pois estas podem conduzir a bugs no programa. Apenas o texto X + 10 est associado constante Y, e no o resultado numrico dessa expresso. Isso pode causar resultados surpreendentes em instrues como a abaixo: cout << "X = " << X << "Y = " << Y; Quando o C++ compila essa instruo, ele insere o texto 5 e o texto X + 10 no lugar das constantes X e Y. A expresso X + 10 ento avaliada quando esta instruo for compilada e no antes quando a constante Y foi definida. Por isso, se o programa mencionado acima executar as linhas a seguir antes da instruo de fluxo de sada de dados, X ter um valor diferente quando a instruo for compilada e, portanto, a expresso X + 10 tambm ter. #undef X #define X 10 O comando de controle #undef desfaz a definio de um smbolo previamente criado com o comando #define. Quando usamos o comando #undef destrumos a constante da memria e, atravs de um novo #define podemos definir uma nova constante com o mesmo nome da anterior, porm com um contedo diferente. O Cdigo 1.13 apresenta um programa exemplo de como se pode usar os comandos #define e #undef e as conseqncias de tais usos.
Cdigo 1.13 - Uso dos comandos #define e #undef.
Verso 1.1
26
2005
cout << "X = " << X << " Y = " << Y << '\n'; #undef X #define X 10 cout << "X = " << X << " Y = " << Y << '\n'; #undef X #define X 100 cout << "X = " << X << " Y = " << Y << '\n'; } O que acontece no Cdigo 1.13 no acontece com constantes do tipo const, pois estas nunca podem ser alteradas de forma semelhante e portanto so mais seguras, ou pelo menos mais constantes. Existem duas outras vantagens de se usar constantes do tipo const em um programa ao invs de usar constantes do tipo #define. A primeira que o compilador, na maioria das vezes, pode criar um cdigo mais eficiente com constantes do tipo const. Em segundo lugar, como as definies especificam tipos de dados, o compilador pode verificar na compilao se as constantes do tipo const esto no formato correto. Com #define o compilador no pode fazer isso at que uma instruo utilize o identificador da constante, tornando quaisquer erros na constante mais difceis de serem identificados.
Verso 1.1
27
2005
cores corFavorita = AZUL; O cdigo acima cria uma varivel chamada corFavorita do tipo cores e atribui a esta varivel o valor inicial AZUL11. Como corFavorita uma varivel, uma instruo de atribuio pode lhe dar um novo valor, como por exemplo: corFavorita = LARANJA; Pode-se definir uma constante to tipo cores usando o comando const. De qualquer forma que se utilize constante enumeradas, como os exemplos acima mostram, o seu uso aumenta enormemente a legibilidade de um programa. Se uma pessoa ao ler um programa se depara com uma instruo no comentada semelhante a: cor = 4; ter que buscar o significado de 4 em uma lista de referncias para descobrir qual a cor atribuda pelo programa varivel cor. J a atribuio: cor = AZUL; clara por si s. O Cdigo 1.14 mostra alguns outros exemplos de constantes enumeradas e ilustra alguns dos modos dos quais os programas podem utiliza-las.
Cdigo 1.14 - Uso de constantes enumeradas.
#include <stream.h> enum LINGUAGENS {ASSEMBY, BASIC, C, CPP, FORTRAN, PASCAL} linguagens; enum escala {DO, RE, MI, FA, SOL, LA, SI}; enum {FALSE, TRUE}; main () { int nota_da_escala = LA; int operacao = TRUE; linguagens = CPP; cout << "Linguagem = " << '\n' << "Nota musical (int)nota_da_escala << '\n'
11
Na realidade o compilador inicializa a varivel corFavorita com o valor numrico da varivel AZUL, que igual a 4.
Verso 1.1
28
2005
<< "Resultado da operacao = " << (int)operacao << '\n'; } A linha 3 do Cdigo 1.14 declara o tipo enumerado LINGUAGENS, usando letras maisculas para o nome do tipo dos dados. No final da mesma linha de comando existe a declarao de uma varivel chamada linguagens, usando letras minsculas. A varivel linguagens uma varivel do tipo enumerado LINGUAGENS e a linha 13 atribui um dos elementos listados entre chaves de LINGUAGENS para esta varivel. A linha 6 demonstra como criar um tipo de dado enumerado sem dar-lhe um nome, o que ocasionalmente til. O C++ permite isso para simplificar o trabalho de se dar nomes a listas enumeradas que sero criadas apenas para se usar os itens contidos nas listas ao invs de seus valores do tipo int.
1.5. Operadores
O C++ repleto de operadores, que so smbolos que executam vrios tipos de operaes sobre os seus argumentos. O sinal de mais (+) um operador. Em uma expresso, como era de se esperar, este operador soma dois valores, como por exemplo: a = b + c; As variveis a, b e c poderiam ser de quaisquer tipos numricos de dados e o efeito do exemplo acima a atribuio varivel a o valor da soma da varivel b com a varivel c.
Verso 1.1
29
2005
O sinal de igual neste exemplo tambm um operador, com a funo de atribuir o valor da sua direita para a posio da memria representada pela varivel esquerda.
Nvel de precedncia 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Operador12 ( ) . [ ] -> :: ->* this & * & nem delete ! ~ ++ -- - sizeof * / % + << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= <<= >>= &= ^= |= '
//Soma 1 varivel do tipo int i //Soma 1 varivel do tipo int i //Subtrai 1 da varivel do tipo int j
O smbolo * no nvel 2 o operador de referenciamento de ponteiros. O mesmo smbolo no nvel 3 o operador matemtico de multiplicao.
Verso 1.1
30
2005
j--;
Normalmente, quando no se faz nada com o valor de uma expresso, este valor perdido. Mas as expresses i++ e j-- so especiais. Elas executam uma ao sobre os seus argumentos (incrementam i e decrementam j) e possuem valor prprio. O Cdigo 1.15 mostra um exemplo do uso dos operadores ++ e --.
Cdigo 1.15 - Uso de operadores de incremento e decremento.
#include <stream.h> main () { int i = 100, j = 100; cout << "i++ = " << i++ << '\n'; cout << "i = " << i << '\n'; cout << "j-- = " << j-- << '\n'; cout << "j = " << j; } Quando se executa o Cdigo 1.15, o vdeo mostrar o seguinte resultado: i++ i j-j = = = = 100 101 100 99
Isso pode parecer estranho primeira vista, mas no o . Deve-se entender que quando se usa o operador ++, bem como --, este possui um valor prprio (que o valor do seu argumento antes da operao) e passa ao seu argumento o valor relativo ao seu incremento, ou decremento. Assim sendo, para i = 100, a expresso: j = i++; Atribuir j o valor de 100 e no o valor de i + 1 como pode-se ser levado a pensar. A expresso anterior equivalente expresso: j = i; i = i + 1; Pensando-se apenas na expresso expandida nunca se esquece que o valor de i++ igual ao valor de i antes do incremento. Porm, se os operadores ++ e -- aparecerem frente de seus argumentos, eles passam a ter efeito antes que o valor da expresso seja formado. Uma vez mais assumindo que i = 100, a expresso abaixo incrementa a varivel i em uma unidade: j = ++i;
Verso 1.1
31
2005
Entretanto, como o operador ++ aparece antes de i, o operador ++ incrementa a varivel i antes do resultado ser atribudo varivel j. Assim sendo, a expresso anterior atribui o valor 101 tanto para j quanto para i. A expresso anterior equivalente expresso: i = i + 1; j = i; Quando no se deseja atribuir o resultado do incremento ou decremento de uma varivel a uma outra varivel no h diferena em se colocar o operador antes ou depois do seu argumento. Assumindo que as variveis do exemplo a seguir so do tipo int, as instrues abaixo incrementam cada uma destas variveis de 1: peso++; //peso = peso + 1 saldo++; //saldo = saldo + 1 nota++; //nota = nota + 1 Posicionando os operadores em primeiro lugar tm-se os mesmos resultados: ++peso; //peso = peso + 1 ++saldo; //saldo = saldo + 1 ++nota; //nota = nota + 1
1.5.3. Expresses
Expresses so os processadores numricos de uma linguagem de programao, so um modo de se passar instrues a um programa sobre o que ele deve fazer com vrios valores. O Cdigo 1.16 apresenta um programa muito simples de lgebra. Este consiste em, dado o preo de custo de uma mercadoria em dlares e uma taxa de impostos, qual o deveria ser o preo de venda desta mercadoria e quanto seria o imposto pago, ambos em dlares?
Cdigo 1.16 - Programa para clculo do imposto incidente sobre mercadorias.
#include <stream.h> #include <stdlib.h> char resposta[80]; float preco_custo, taxa, preco_venda, impostos; main () { cout << "Digite o preco de custo da mercadoria (em US$): "; cin >> resposta; preco_custo = atof(resposta); cout << "Digite a taxa de impostos sobre a mercadoria (em %): "; cin >> resposta; taxa = atof(resposta);
Verso 1.1
32
2005
taxa = taxa / 100; preco_venda = preco_custo * ( 1 + taxa); impostos = preco_venda - preco_custo; cout << "\nO preco de venda da mercadoria devera ser de: US$ " << preco_venda ; cout << "\nO valor dos impostos sobre a mercadoria e de: US$ " << impostos; } O Cdigo 1.16 no possui nenhum comando ainda no visto e, alm de muito simples, mostra como possvel a elaborao de programas teis com recursos simples e de fcil aplicao.
Verso 1.1
33
2005
Verso 1.1
34
2005
"Its raining "dogs and cats" in here!" 1.13. Escreva um programa que atribua um apstrofo () a uma varivel do tipo char e, ento, exiba essa varivel na tela. 1.14. Escreva um programa que declare duas constantes denominadas MIN, com valor igual a 1 e MAX com valor igual a 999. Exiba as constantes na tela. Faa o exerccio utilizando constantes declaradas e definidas. 1.15. Crie um tipo enumerado de dados denominado flores com os elementos ROSA, CARMELIA, ORQUIDEA e GARDENIA. 1.16. Se i = 98, qual o resultado de cada uma das operaes que se seguem, executadas na ordem que se segue: i++, ++i, i-- e --i? Qual o valor final de i? Faa um programa para ajudar nas respostas.
Verso 1.1
35
2005
Programas de computador operam de forma bastante semelhante a motores de combusto interna. Queimam combustvel (usam dados) e executam trabalho (instrues). Sem combustvel o motor no funciona e, sem motor, o combustvel no teria que ser retirado do subsolo. A maior parte dos programas precisa tanto de combustvel quanto de um motor que funcione, isto , de dados e de instrues, para desempenhar tarefas teis. Como seria de se esperar, o C++ possui uma ampla variedade de tipos de estruturas de dados para o armazenamento de informaes na memria. Tambm possui alguns tipos de instrues que, entre outras funes, podem tomar decises, repetir aes e selecionar elementos de algum padro de um conjunto de valores. Aprender os tipos fundamentais de estruturas de dados e instrues da linguagem C++ no difcil. De fato, quando algum se depara com tais estruturas e instrues pela primeira vez estas talvez lhe paream at mesmo simples demais para qualquer uso prtico. Isso natural e ilustra uma das razes pelas quais nunca avanam alm de um conhecimento simples de programao em uma linguagem de propsito genrico como o C++, ou C ou mesmo o Pascal. Elas memorizam o bsico da linguagem, do modo como elas talvez o fizessem com uma lista de peas em uma loja de equipamentos, mas deixam de aprender como combinar estas peas para criarem programas que fazem os computadores renderem o mximo possvel. Por essa razo em vez de documentar cada estrutura de dados e tipos de instruo uma a uma, como o manual de um compilador talvez o faa, neste captulo sero introduzidos os fundamentos sobre as instrues e tipos de dados do C++ em situaes prticas, pelo menos na maioria dos casos. Aprenderemos no apenas o que uma estrutura, mas tambm como aplic-la na resoluo de problemas.
Verso 1.1
36
2005
argumentos para produzir um resultado, que pode ser verdadeiro ou falso. De posse desse resultado o programa pode ento decidir o que fazer a seguir13. Pode-se usar qualquer operador da Tabela 2.1 em expresses para se comparar dois valores, numricos ou no. Comparar duas strings requer mais trabalho e uma abordagem vetorial, o que ser abordado em captulos mais frente.
Tabela 0.1 - Operadores relacionais em C++.
Descrio Menor que Menor ou igual a Maior que Maior ou igual a Igual a Diferente de
A expresso (a == b) avaliada como verdadeira se, e somente se, a e b possurem o mesmo valor. J a expresso (a = b) atribui o valor de b a. O primeiro programa deste captulo, apresentado no Cdigo 2.1 usa operadores relacionais de um modo tpico, possibilitar ao usurio escolher entre vrias opes de um menu exibido no vdeo. As opes apresentadas neste programa so a converso de milhas em quilmetros, quilmetros em milhas ou abandonar o programa sem executar nenhum clculo.
Cdigo 2.1 - Programa para a converso de milhas para quilmetros.
#include <stream.h> const float mil_por_km = 0.6214, km_por_mil = 1.6093; const char linha[] = "\n_______________________________\n"; main () { int escolha; float km, mil; cout << linha; cout << "Conversao de MILHAS para QUILOMETROS" << linha; cout << "Digite:\n"; cout << "1 : Milhas para Quilometros\n"; cout << "2 : Quilometros para Milhas\n"; cout << "3 : Quit\n"; cout << "RESPOSTA: "; cin >> escolha; if (escolha == 1)
13
Internamente o compilador C++ reduz uma expresso relacional em um valor inteiro 0, para falso, ou 1 para verdadeiro. Tais nmeros so conhecidos como variveis lgicas ou Booleanas.
Verso 1.1
37
2005
{ cout << linha; cout << "Digite o valor em milhas: "; cin >> mil; km = mil * km_por_mil; cout << mil << " milhas = " << km << " km" << linha; } else if (escolha == 2) { cout << linha; cout << "Digite o valor em quilometros: "; cin >> km; mil = km * mil_por_km; cout << km << " km = " << mil << " milhas" << linha; } else cout << linha << "Fim do programa" << linha; }
executados
caso
expresso
else if (expresso relacional 2) {Bloco de comandos a serem executados relacional 2 seja verdadeira} else if (expresso relacional n) {Bloco de comandos a serem executados expresso relacional seja verdadeira}
caso
expresso
caso
n-sima
Verso 1.1
38
2005
else {Bloco de comandos a serem executados caso nenhuma expresso relacional seja verdadeira} Seja ento o exemplo em que se deseja exibir o valor de uma varivel chamada conta, apenas se este for maior que 100, pode-se proceder da seguinte maneira: if (conta > 100) cout << "Conta = " << conta; Quando se deseja que uma instruo if execute um bloco de comandos e no apenas uma linha de comando deve-se delimitar tal bloco por chaves.
Verso 1.1
39
2005
bloco de comandos se a primeira operao relacional ou a segunda forem verdadeiras. Por exemplo: if ((1 == conta) || (conta == 100)) cout << "Conta igual a 1 ou a 100."; O efeito deste exemplo a execuo da instruo de fluxo de sada apenas se conta for igual ou 1 a 100. Quaisquer outros valores fazem com que a expresso relacional inteira seja avaliada como falsa, o que ocasiona a no execuo da instruo de sada. Pode-se criar expresses ainda mais complexas, usando criteriosamente parnteses para combinar && e ||, como por exemplo: if (((1 <= conta) && (conta <= 100)) || (conta == -1)) cout << "Conta igual a -1 ou esta entre 1 e 100."; Neste caso a instruo de fluxo de sada executada apenas se conta for um valor entre 1 e 100 ou se for igual a 1. O Cdigo 2.3 apresenta um programa que utiliza os conceitos de operadores lgicos para calcular o consumo de gasolina de veculo e relatar se o seu desempenho insatisfatrio, bom ou excelente.
Cdigo 2.3 - Programa para averiguao do desempenho de automveis.
#include <stream.h> #include <stdlib.h> const char linha[] = "\n_______________________________\n"; float inicio, fim, litros, km, consumo; main () { cout << linha; cout << setw(30) << "Programa para a averiguacao do desempenho de automoveis." << linha; cout << "\nDigite a leitura inicial do odometro:"; cin >> inicio; cout << "Digite a leitura final do odometro:"; cin >> fim; cout << "Digite o consumo de combustivel (em L):"; cin >> litros; if (litros == 0) { cout << "\aO consumo deve diferente de zero!"; exit(1); } km = fim - inicio; consumo = km/litros; cout << "O automovel apresenta um consumo de " << setprecision(3) << consumo << " km/L."; cout << linha << "O que indica um desempenho ";
Verso 1.1
40
2005
if (consumo < 8.503 cout << "INSATISFATORIO!!!" << linha; else if ((consumo >= 8.503) && (consumo < 10.629)) cout << "BOM!!!" << linha; else cout << "EXCELENTE!!!" << linha; } Aps solicitar as leituras iniciais e finais do odmetro, o programa apresentado no Cdigo 2.3 usa uma instruo if para verificar se o consumo de combustvel informado pelo usurio igual a zero, o que ocasionaria um erro fatal na linha 22 (ocasionaria uma diviso por zero, o que representa um erro na execuo do programa). Caso o usurio informe um consumo de combustvel igual a zero a instruo if ser executada e aps uma mensagem ao usurio o programa tem sua execuo interrompida pelo comando exit(1)14. O uso do comando exit para interromper um programa faz com que este envie para o DOS o valor dentro dos parnteses, neste caso 1.
Verso 1.1
41
2005
Tabela 0.2 - Modo de avaliao de operandos e resultados produzidos por operadores aritmticos, relacionais e lgicos.
#include <stream.h> main () { int a, b, max; cout << "Digite o valor de a: "; cin >> a; cout << "Digite o valor de b: "; cin >> b; max = (a > b) ? a : b; cout << "O maior valor digitado foi: " << max; }
15
Em C++ no existe o tipo Booleano de variveis. Assim sendo, o C++ adota como sendo uma expresso verdadeira se o seu resultado numrico for igual a 1 e falsa se este for igual a 0.
Verso 1.1
42
2005
Descrio E binrio OU binrio OU EXCLUSIVO binrio Desloca bits para a esquerda Desloca bits para a direita Calcula o complemento dos bits
Em expresses, os trs primeiros operadores de bits da Tabela 2.3 combinam dois valores conforme as regras para os seus operadores lgicos equivalentes.
Verso 1.1
43
2005
O Cdigo 2.5 apresenta um programa que combina dois valores unsigned long v1 e v2 utilizando o operador E binrio e atribui o resultado dessa operao varivel v3, de mesmo tipo das anteriores.
Cdigo 2.5 - Uso do operador E binrio.
#include <stream.h> unsigned long v1, v2, v3; long double inttobin (unsigned long v); void main () { cout << setw(55) << "Programa exemplo do uso do operador E binario"; cout << "\n\nDigite dois valores inteiros\nv1: "; cin >> v1; cout << "v2: "; cin >> v2; v3 = v1 & v2; cout << setw(20) << dec << v1 << setw(6) << hex << v1 << setprecision(20) << setw(20) << inttobin(v1) << '\n'; cout << 'E' << setw(19) << dec << v2 << setw(6) << hex << v2 << setprecision(20) << setw(20) << inttobin(v2) << '\n'; cout << "============================================\n"; cout << "Igual a:" << setw(12) << dec << v3 << setw(6) << hex << v3 << setprecision(20) << setw(20) << inttobin(v3) << '\n'; } long double inttobin(unsigned long x) { unsigned long resto; long double y, i; y = 0; if (x == 0) y = 0; else if (x == 1) y = 1; else { i = 1; while (x > 1) { resto = x%2; x = (x - resto)/2; y = y + (i * resto); i = i * 10; if (x == 1) y = y + i;
Verso 1.1
44
2005
} } return y; } A declarao na linha 3 do Cdigo 2.5 apresenta a declarao de uma funo em C++. Os conceitos sobre o uso de funes sero vistos mais frente mas, por enquanto, note que uma funo em C++ tem que ser declarada e a sua declarao muito semelhante declarao de uma varivel. O resultado da execuo do programa apresentado no Cdigo 2.5 um programa que solicita ao usurio a entrada de dois valores numricos inteiros, por exemplo 1021 e 15. O resultado do programa ser: 1021 3fd 1111111101 E ............................................................................................................................................... .............................................................................................................. 15 f 1111 ======================================= Igual a: 13 d 1101 Assim, o resultado da operao 1021 & 15 igual a 13. Pode parecer estranho primeira vista tal operao, mas se lembramos que o operador & um operador binrio fica mais fcil entender qual operao realizada por este. Note que no resultado apresentado acima o operador & comparou bit a bit os nmeros 1021 e 15, e gerou o resultado 13 de acordo com as regras da Tabela 2.4, assim sendo o resultado da combinao de dois valores A e B com o operador E binrio 1 apenas se os dois bits comparados forem iguais a 1. Um uso tpico para o operador E binrio mascarar uma parte de um valor, permitindo apenas que alguns bits do valor original sejam passados para o resultado. Em qualquer posio que aparece um bit 1 na mscara, o resultado conter o mesmo bit do valor original. Em qualquer posio que aparece um bit 0 na mscara, o resultado conter o bit 0. O 0 na mscara bloqueia o bit do valor original, impedindo que ele passe adiante.
Verso 1.1
45
2005
O Cdigo 2.6 apresenta o mesmo programa do Cdigo 2.5 modificado apenas para utilizar o operador OU binrio16.
Cdigo 2.6 - Uso do operador OU binrio.
#include <stream.h> unsigned long v1, v2, v3; void main () { cout << setw(55) << "Programa exemplo do uso do operador OU binario"; cout << "\n\nDigite dois valores inteiros\nv1: "; cin >> v1; cout << "v2: "; cin >> v2; v3 = v1 | v2; cout << setw(20) << dec << v1 << setw(6) << hex << v1 << setprecision(20) << setw(20) << inttobin(v1) << '\n'; cout << "OU" << setw(18) << dec << v2 << setw(6) << hex << v2 << setprecision(20) << setw(20) << inttobin(v2) << '\n'; cout << "============================================\n"; cout << "Igual a:" << setw(12) << dec << v3 << setw(6) << hex << v3 << setprecision(20) << setw(20) << inttobin(v3) << '\n'; } O resultado da execuo do programa apresentado no Cdigo 2.6 um programa que solicita ao usurio a entrada de dois valores numricos inteiros, por exemplo 1021 e 15. O resultado do programa ser: 1021 3fd 1111111101 OU ............................................................................................................................................ .............................................................................................................. 15 f 1111 ======================================= Igual a: 1023 3ff 1111111111 Assim, o resultado da operao 1021 | 15 igual a 1023. O operador OU binrio usado freqentemente para inserir bits dentro de valores. Suponha que uma varivel contenha o valor 152, ou 10011000 em binrio. Para mudar o primeiro e o terceiro bit mais direita para 1, basta usarmos uma mscara de valor 5, ou 101 em binrio. Se entrarmos com tais valores no programa apresentado no Cdigo 2.6, o resultado ser:
16
Apesar dos programas apresentados nos Cdigos 2.6 e 2.7 usarem a mesma funo apresentada no Cdigo 2.5, esta foi suprimida nos dois ltimos apenas por uma questo de inteligibilidade dos cdigos.
Verso 1.1
46
2005
152 98 10011000 OU ............................................................................................................................................ ............................................................................................................... 5 5 101 ======================================= Igual a: 157 9d 10011101 O resultado acima contm todos os bits do valor original acrescidos dos bits da mscara inseridos onde zeros apareciam anteriormente. Essa tcnica til para ligar bits em registradores e em outras variveis sem perturbar outros bits existentes.
O terceiro operador da Tabela 2.3 o operador binrio OU exclusivo17. Tal operador retorna 1 apenas se os bits originais comparados forem diferentes entre si. Em todos os outros casos o resultado sempre zero. A Tabela 2.6 mostra os possveis resultados para o uso do operador OU exclusivo binrio.
Tabela 0.6 - Possveis resultados para o operador OU exclusivo binrio.
A^B=C 0^0=0 0^1=1 1^0=1 1^1=0 O Cdigo 2.7 apresenta o mesmo programa do Cdigo 2.5 e do Cdigo 2.6, modificado apenas para utilizar o operador OU exclusivo binrio.
Cdigo 2.7 - Uso do operador OU exclusivo binrio.
#include <stream.h> unsigned long v1, v2, v3; void main () { cout << setw(55) << "Programa exemplo do uso do operador OU binario"; cout << "\n\nDigite dois valores inteiros\nv1: "; cin >> v1; cout << "v2: "; cin >> v2; v3 = v1 ^ v2; cout << setw(20) << dec << v1 << setw(6) << hex << v1 << setprecision(20) << setw(20) << inttobin(v1) << '\n'; cout << "XOR" << setw(17) << dec << v2 << setw(6) << hex
17
O operador binrio E usualmente tratado por AND binrio, o operador binrio OU por OR binrio e o operador binrio OU exclusivo por XOR.
Verso 1.1
47
2005
v2 << setprecision(20) << setw(20) inttobin(v2) << '\n'; "============================================\n"; "Igual a:" << setw(12) << dec << v3 << setw(6) hex << v3 << setprecision(20) << setw(20) inttobin(v3) << '\n';
O resultado da execuo do programa apresentado no Cdigo 2.7 um programa que solicita ao usurio a entrada de dois valores numricos inteiros, por exemplo 1021 e 15. O resultado do programa ser: 1021 3fd 1111111101 XOR ......................................................................................................................................... .............................................................................................................. 15 f 1111 ======================================= Igual a: 1010 3f2 1111110010 Assim, o resultado da operao 1021 ^ 15 igual a 1010.
Verso 1.1
48
2005
exemplo de aplicarmos o operador XOR aos nmeros 45001 e 15, obtendo o seguinte resultado: 45001 afc9 1010111111001001 XOR ......................................................................................................................................... ............................................................................................................ 15 f 1111 ======================================== Igual a: 44998 afc6 1010111111000110 Seja agora aplicarmos o operador XOR aos nmeros 44998 e 15, obtendo o seguinte resultado: 44998 afc6 1010111111000110 XOR ......................................................................................................................................... ............................................................................................................ 15 f 1111 ======================================== Igual a: 45001 afc9 1010111111001001 Programas grficos freqentemente fazem uso dessa propriedade do operador XOR para fazer formas se moverem no vdeo sem perturbar as imagens de fundo. Um outro uso para XOR a criptografia, em que uma mscara serve de argumento para XOR, que opera sobre todos os bits de um arquivo, e, assim, disfara o seu contedo. Para restaurar o contedo original do arquivo basta aplicar a mesma operao.
#include <stream.h>
Verso 1.1
49
2005
unsigned long v1, v2, v3; void main () { cout << setw(55) << "Programa exemplo do uso dos operadores de deslocamento de bits\n(V1 >> V2 e V1 << V2)"; cout << "\n\nDigite dois valores inteiros\nv1: "; cin >> v1; cout << "v2: "; cin >> v2; v3 = v1 << v2; cout << "\n\nV1 e igual a:"; cout << setw(8) << "INT" << setw(6) << "HEX" << setw (20) << "BIN\n"; cout << setw(20) << dec << v1 << setw(6) << hex << v1 << setprecision(20) << setw(20) << inttobin(v1) << '\n'; cout << "Deslocado de " << v2 << " bits a esquerda resulta em:\n"; cout << setw(20) << dec << v3 << setw(6) << hex << v3 << setprecision(20) << setw(20) << inttobin(v3) << '\n'; v3 = v1 >> v2; cout << "Deslocado de " << v2 << " bits a direita resulta em:\n"; cout << setw(20) << dec << v3 << setw(6) << hex << v3 << setprecision(20) << setw(20) << inttobin(v3) << '\n'; } O resultado do Cdigo 2.8 para, por exemplo, 4 e 1 : INT HEX 4 4 Deslocado de 1 bit esquerda resulta em: 8 8 1000 Deslocado de 1 bit direita resulta em: 2 2 10 V1 igual a: BIN 100
Note que o resultado para o deslocamento esquerda de 1 bit do nmero 4 8, e o resultado para o deslocamento direita de 1 bit do nmero 4 2. Ou seja, quando se desloca um nmero x de y bits esquerda e atribui-se este resultado a uma varivel z, o compilador faz a seguinte conta: z = x * 2y J quando se desloca um nmero x de y bits direita e atribui-se este resultado a uma varivel z, o compilador faz a seguinte conta: z = x / 2y
Verso 1.1
50
2005
O resultado do Cdigo 2.8 para, por exemplo, 10 e 4 : INT HEX 10 a Deslocado de 1 bit esquerda resulta em: 160 a0 10100000 Deslocado de 1 bit direita resulta em: 0 0 0 V1 igual a: BIN 1010
Note que apesar de 10 / 24 no ser igual a zero este foi o resultado retornado pelo computador. O que acontece que o compilador desloca quatro bits do nmero 10, comeando do bit mais direta para o bit mais esquerda, como o nmero 10 s possui quatro bits o resultado dever ser 0. Como os computadores podem deslocar bits muito mais rapidamente do que podem realizar uma multiplicao, o que verdade mesmo com a presena de um co-processador matemtico, quando se deseja multiplicar um valor por potncias de 2, normalmente mais eficiente empregar os deslocamentos de bits do que multiplicaes.
#include <stream.h> unsigned long v1, v2; void main () { cout << setw(55) << "Programa exemplo do uso do operador NOT binario"; cout << "\n\nDigite um valor inteiro\nv1: "; cin >> v1; v2 = ~v1; cout << "\n\nV1 e igual a:";
Verso 1.1
51
2005
cout << << cout << << << cout << cout << << << }
setw(8) << "INT" << setw(6) << "HEX" << setw (20) "BIN\n"; setw(20) << dec << v1 << setw(6) << hex << v1 setprecision(20) << setw(20) << inttobin(v1) '\n'; "~V1 e igual a:\n"; setw(20) << dec << v2 << setw(6) << hex << v2 setprecision(20) << setw(20) << inttobin(v2) '\n';
Combinar o operador de complemento com outros operadores, com freqncia o &, pode ser, algumas vezes, til. Por exemplo, para desligar o primeiro bit (torn-lo igual a zero) em uma varivel conta, podemos escrever: conta = conta & ~1;
Verso 1.1
52
2005
Algumas vezes o compilador ser capaz de gerar um cdigo mais eficiente para um operador de atribuio combinada do que para uma expresso equivalente no abreviada. Esta , talvez, a maior vantagem de se usar um operador de atribuio combinada.
18
Loop uma expresso em ingls, sem boas tradues, mas que significa uma estrutura de repetio na qual, aps uma srie de comandos serem executados, o fluxo do programa volta ao ponto onde este comeou, como se estivesse se movendo sobre um crculo.
Verso 1.1
53
2005
Programao I Prof. Andr Carlos Silva Cdigo 2.10 - Uso do comando EXIT.
#include <stream.h> #include <stdlib.h> #include <ctype.h> main () { char resposta; cout << "Digite S para sim ou N para no\nRESPOSTA: "; cin >> resposta; resposta = toupper(resposta); if (resposta == 'S') exit(1); else exit(0); cout << "Esta linha do programa NUNCA executada..."; } O Cdigo 2.10 apresenta uma funo ainda no vista, a funo toupper, que tecnicamente uma macro, mas que destina a converter um caractere minsculo em maisculo. Outros smbolos passados a toupper, tais como nmeros, sinais de pontuao ou mesmo letras j em maisculas, permanecem inalterados. Para usar a funo toupper um programa dever incluir dever incluir o arquivo cabealho ctype.h. Existe uma outra maneira de se escrever o Cdigo 2.10 que no requer o uso da instruo if e que reduz o tamanho do texto do programa. A expresso exit((toupper(resposta) == 'S')) compara o resultado de toupper(resposta) com o caractere 'S', retornando o valor 0 se a expresso for falsa e 1 se esta for verdadeira, valor este que passado imediatamente instruo exit. O Cdigo 2.11 apresenta o mesmo programa do Cdigo 2.10, porm agora em sua verso mais curta.
Cdigo 2.11 - Uso do camando EXIT (verso simplificada).
#include <stream.h> #include <stdlib.h> #include <ctype.h> main () { char resposta; cout << "Digite S para sim ou N para nao\nRESPOSTA: "; cin >> resposta; exit(toupper(resposta) == 'S'); }
Verso 1.1
54
2005
Verso 1.1
55
2005
executadas se o seletor (neste exemplo a varivel resposta) for igual a um dos valores indicados aps os cases. switch (resposta) { case 'A': { // Instrues a serem executadas se resposta == A; break; } case 'B': { // Instrues a serem executadas se resposta == B; break; } case 'C': { // Instrues a serem executadas se resposta == C; break; } default: { //Instrues a serem executadas quando resposta //possuir outro valor que no A, B ou C; } } A instruo comea com a palavra-chave switch e uma expresso entre parnteses, expresso esta que dever retornar um valor inteiro ou um caractere. Os seletores case devem ser constantes ou expresses constantes. O resultado da expresso do switch comparado com todas as constantes dos seletores case subseqentes, cada um dos quais devendo terminar com dois-pontos (:). Os valores apresentados nos seletores case devem ser nicos, podendo estar dispostos em qualquer ordem. Somente as instrues abaixo do primeiro case cuja constante seletora for igual ao resultado da expresso que sero executadas. As vrias instrues break marcam o fim das instrues de cada case. Sem um break o programa comearia a executar as instrues a partir do primeiro case aceito e continuaria at o final da instruo switch. se nenhum dos valores case for igual ao resultado da expresso, as instrues aps o case default sero executadas, sendo que o uso deste de carter opcional. De modo diferente de outras instrues em C++, instrues mltiplas em cases dentro de instrues switch no precisam ser obrigatoriamente cercadas por chaves. Uma instruo switch torna-se prtica sempre que um programa necessita selecionar uma ao dentre as diversas possveis tendo como base o resultado de uma expresso ou o valor de uma varivel, equivalentes a um valor inteiro ou a um caractere. Um exemplo tpico onde uma instruo switch funciona bem a criao de menus de opes em programas, onde o usurio digita uma letra (ou nmero) para escolher uma dentre vrias opes. O Cdigo 2.12 apresenta um programa que exibe um menu de cinco opes ao usurio, A de adicionar, S de subtrair, M de multiplicar, D de dividir e Q de quit (do ingls sair do programa). Apesar deste exemplo no fazer nenhum clculo, ele demonstra a utilizao do
Verso 1.1
56
2005
comando switch para fazer a seleo das opes do menu e do comando while para forar o programa a s terminar a sua execuo quando o usurio solicitar.
Cdigo 2.12 - Uso do comando WHILE e do comando SWITCH.
#include <stream.h> #include <stdlib.h> #include <ctype.h> const char linha[40] = "\n*****************************\n"; char resposta; main () { while ((toupper(resposta)) != 'Q') { cout << linha << "* << "* Calculadora de 4 operacoes feita em C++ << "* << "*Digite: << "* A para adicao << "* S para subtracao << "* M para multiplicacao << "* D para divisao << "* Q para sair do programa << "* << "*RESPOSTA: "; cin >> resposta; cout << linha; switch (toupper(resposta)) { case 'A': cout << "*Voce selecionou o modulo de adicao break; case 'S': cout << "*Voce selecionou o modulo de subtracao break;
*\n" *\n" *\n" *\n" *\n" *\n" *\n" *\n" *\n" *\n"
*";
*";
case 'M': cout << "*Voce selecionou o modulo de multiplicao*"; break; case 'D': cout << "*Voce selecionou o modulo de divisao break; *";
Verso 1.1
57
2005
case 'Q': cout << "*Voce selecionou sair do programa!!! break; default: cout << "*Opcao invalida. Tente de novo!!! } cout << linha; }
*";
*";
executadas
enquanto
expresso
for
A grande diferena entre um loop while e um loop do/while que o primeiro pode nunca ser executado, caso a expresso de controle seja falsa, ao passo que o ltimo sempre executado pelo menos uma vez, pois o programa no avalia a sua expresso de controle at que o loop tenha sido executado uma vez. Seja o exemplo em que desejase contar at 10, poderia-se usar um loop do/while da seguinte maneira: int conta = 0; do { cout << conta++ << '\n'; } while (conta <= 10); Mas se a varivel conta fosse inicializada com o valor conta = 12, e no conta = 0, o programa apresentado acima imprimiria na tela o valor 12 na tela, ou seja, o programa seria executado uma vez, o que no aconteceria se o loop fosse feito usando o comando while. Na prtica os loops while tendem a ser mais comuns que os loops do/while, apesar de ambos possurem usos distintos. Uma boa maneira de decidir qual dos dois loops usar
Verso 1.1
58
2005
respondendo seguinte pergunta: Existe alguma condio passvel de ocorrer, na qual este loop no devesse ser executado nem mesmo uma nica vez?. Se a resposta for sim, o uso de um loop while mais apropriado. Se a resposta for no, utilize um loop do/while.
for (instruo1; expresso; instruo2) { //Instrues a serem executadas; } Dentro dos parnteses aps a palavra-chave for existem trs elementos que controlam a execuo do loop for. Em primeiro lugar h uma instruo (instruo1), que executada uma nica vez, antes do incio do loop. Normalmente esta instruo inicializa uma varivel que ser utilizada pelos prximos dois elementos. O prximo elemento, a expresso, uma expresso relacional que o comando for testa sempre que o fluxo do programa se encontrar no incio do loop. O ltimo elemento, a instruo2, executada no final do loop, aps a execuo do bloco de instrues internas do loop e antes que o fluxo do programa retorne ao incio do loop. A descrio precedente faz mais sentido quando comparada a um loop while que executa as mesmas instrues do loop for mostrado no Cdigo 2.14. instruo1; while (expresso) { //Instrues a serem executadas; instruo2; } Para criar um programa que usasse o comando for para exibir uma contagem de 0 a 10 bastaria poucas linhas. Por exemplo: int conta; for (conta = 0; conta <= 10; conta++)
Verso 1.1
59
2005
cout << conta << '\n'; O que equivale exatamente ao loop while abaixo: int conta = 0; while (conta <= 10) { cout << conta << '\n'; conta++; } Apesar do efeito dos dois loops apresentados acima serem idnticos, o loop for mais conciso e aps ter aprendido como constru-lo o leitor provavelmente o achar mais legvel e inteligvel que os loops while equivalentes. Um programa exemplo do uso do comando for apresentado no Cdigo 2.15, que exibe na tela uma tabela dos caracteres ASCII.
Cdigo 2.15 - Programa para exibio dos caracteres da Tabela ASCII.
#include <stream.h> unsigned char caractere; int i; main () { for (caractere = 0; caractere <= 254; caractere++) { cout << setw(6) << i << " = " << caractere; i++; if ((caractere%7) == 0) cout << '\n'; } }
Verso 1.1
60
2005
#include <stream.h> int i; main () { cout << "Loop for:\n"; for (i = 1;i <= 10;i++) { if (i > 5) break; cout << i << '\n'; } ................................................................................................... cout << "\nLoop while:\n"; i = 1; while (i <= 10) { if (i > 5) break; cout << i << '\n'; i++; } cout << "\nLoop do/while:\n"; i = 1;
19
Evidentemente que o loop ser finalizado se o usurio desligar o PC, mas este no o caso, quando digo que o loop no ter fim me refiro a um fim causado pelo prprio programa.
Verso 1.1
61
2005
do { if (i > 5) break; cout << i << '\n'; i++; } while (i <= 10); } O Cdigo 2.16 contm um loop for, um loop while e um loop do/while, todos os quais tem a mesma finalidade, contar de 1 at 10 usando uma varivel do tipo inteiro i. Entretanto, em cada caso, o comando break interrompe o loop assim que a varivel atinge o valor 5. Uma instruo break til para o tratamento de erros dentro de loops complexos e para fornecer uma sada de um loop em execuo, seja ele eterno ou no.
#include <stream.h> int i; main () { cout << "Incio do loop usando continue...\n"; for (i = 1;i <= 10;i++) { if (i > 5) continue; cout << i << '\n'; } cout << "\nAps o loop o contador ser igual a: " << i << "\n\nIncio do loop usando break...\n"; for (i = 1;i <= 10;i++) { if (i > 5) break; cout << i << '\n'; } cout <<"\nAps o loop o contador ser igual a: " << i; } O resultado do Cdigo 2.17 que ao final do primeiro loop a varivel i ser igual a 11 e ao final do segundo loop esta ser igual a 6.
Verso 1.1
62
2005
Verso 1.1
63
2005
3 ESTRUTURAS DE DADOS
Os chips de memria do computador so feitos de silcio, isto , de areia, literalmente. Como partculas de areia, a memria apenas um monte de pequenos pedaos sem forma... TOM SWAN Para dar forma memria o C++ possui diversas caractersticas que impem estruturas na memria do mesmo modo que os castelos de areia impem uma estrutura a esta. Alm disso as estruturas de dados so compostas de pedaos (bits) de memria, assim como os castelos de areia so compostos de partculas de areia. Nesta seo voc conhecer as estruturas de dados do C++, as quais lhe permitem reunir campos de variveis, armazenar informaes em vetores e manipular bits com a utilizao de tcnicas normalmente mais convenientes que os operadores de bits descritos no incio deste captulo.
Verso 1.1
64
2005
Digitar separadamente cada nome, peso e nmero telefnico montono e entope o programa com variveis confusas. Pior ainda, se houver a necessidade de se inserir ou apagar um nome, voc ter que escrever novas instrues que trataro cada varivel, o que no nada prtico. Um mtodo mais indicado criar um novo tipo de dados que possa armazenar nomes, pesos e nmeros telefnicos conjuntamente. Voc poder, ento, escrever instrues que operem sobre este tipo de estrutura e, portanto, sobre as informaes de qualquer membro do seu clube. Para faz-lo comece declarando um novo tipo de dados com a palavra-chave struct, conforme mostrado a seguir: struct membro { char nome[30]; float peso; char telefone[15]; }; Esta construo declara um novo tipo de dado chamado membro, com a capacidade de armazenar trs campos, que so o nome (uma string de 30 caracteres), o peso (um nmero real) e o telefone (uma string de 15 caracteres). No se pode esquecer do ponto-evrgula necessrio no final da declarao aps o fecha-chaves21. Um tipo de dados struct no reserva nenhuma parte da memria para o armazenamento de informaes, o comando struct apenas cria um molde que diz ao compilador a natureza da estrutura. Os campos podem at parecer definir variveis, mas como as declaraes esto dentro da estrutura de um struct no o fazem. Aps definir um tipo struct, pode-se criar variveis desse tipo do mesmo modo como se faz para outros tipos de dados, ou seja: membro membro1; A declarao precedente cria uma varivel chamada membro1 do tipo membro. Tal declarao reserva espao na memria para todos campos declarados dentro da struct, neste caso uma string de 30 caracteres, um valor real e uma string de 15 caracteres. O Cdigo 2.18 apresenta um exemplo onde os principais tipos de dados do C++ so declarados dentro de uma mesma struct.
Cdigo 3.1 - Uso do comando STRUCT para os principais tipos de dados em C++.
Ele fcil de ser esquecido porque blocos de instrues com aparncia similar s declaraes do tipo struct no terminam com ponto-e-vrgula.
Verso 1.1
65
2005
Em alguns casos o tamanho de uma varivel struct pode ser maior que a soma dos campos declarados. Isso ocorre porque o C++ recheia os campos que contenham um nmero mpar de bytes de modo que todos os campos principiem num endereo de nmero par (veja o byte rotulado de enchimento na Figura 2.1). A razo para tal manter maior rapidez na execuo de programas em sistemas que possuam processadores 80x86 de 16 bits, que podem ler dados mais rapidamente em endereos pares do que em endereos mpares.
Figura 3.1 - Os bytes de cada campo de uma varivel struct so armazenados na memria consecutivamente.
Para criar uma varivel chamada Exe, do tipo ExemploDeStruct (vide Cdigo 2.18) e atribuir valores a cada um dos seus campos, pode-se proceder da seguinte maneira: //Declara a varivel Exe. //Atribui um valor ao campo //UmFloat. Exe.UmInt = 2001; //Atribui um valor ao campo UmInt Exe.UmaString = "Abc"; //Atribui uma string ao campo //UmaString. Exe.UmChar = 'M'; //Atribui um caractere ao campo //UmChar. Exe.UmLong = 2147483640; //Atribui um valor longo ao campo //UmLong. Assim sendo, a varivel Exe uma varivel do tipo ExemploDeStruct e possui cinco campos declarados em ExemploDeStruct, cada um dos quais acessado escrevendo-se o nome da varivel seguido de um ponto final e do nome do campo. Esta forma de referncia algumas vezes chamada de tipo de notao de ponto.
Verso 1.1
66
2005
As expresses Exe.UmLong, Exe.UmChar e Exe.UmFloat, por exemplo, so inteiramente qualificadas, significando que elas contm informaes suficientes para que o compilador possa trat-las como se fossem de um tipo simples. No se pode escrever algo como Exe = 15 porque Exe do tipo ExemploDeStruct. Como pode ser feito com outras variveis, pode-se declarar e inicializar uma struct com uma instruo nica. Para faz-lo basta que se insira os valores dos campos entre chaves e separados por vrgulas, aps a definio da varivel. Note que os valores devero estar ordenados da mesma maneira que os campos. Por exemplo, para se criar uma varivel chamada exemplo, do tipo ExemploDeStruct e inicializ-la, pode-se proceder da seguinte maneira: ExemploDeStruct exemplo = {4.3541, 2001, "Abc", 'M', 2147}; Cada campo dever ser separado do prximo por uma vrgula e, ao final da declarao da varivel, deve-se terminar com um ponto-e-vrgula. Alm disso, no se pode pular nenhum campo, apesar de se poder parar a inicializao antes de se atribuir valores a todos os campos. Por exemplo, para se atribuir apenas UmFloat e UmInt, deixando de lado os outros campos de uma varivel do tipo ExemploDeStruct, poder-se-ia escrever ExemploDeStruct exemplo2 = {4.3541, 2001}; Aps declarar um tipo de dados struct e definir uma ou mais variveis desse tipo, podese atribuir valores para essas variveis, exibir os seus valores no vdeo, utiliz-las em expresses, etc. Para demonstrar algumas dessas possibilidades, suponha que voc precise pesquisar os modelos, as velocidades, a capacidade do HD e outros detalhes dos computadores da sua empresa. Voc decide ento armazenar essas informaes em uma struct chamada inventario. Os Cdigos 2.19 e 2.20 mostram algumas das instrues necessrias para se escrever um programa de banco de dados. Compile apenas o Cdigo 2.20, que contm o cdigo anterior. Estes dois cdigos so os primeiros de muitos exemplos de programas armazenados em mais de um arquivo. O Cdigo 2.19 o arquivo de cabealho22 que declara alguns elementos que sero usados no programa do Cdigo 2.20, inclusive a struct que ir armazenar a descrio dos computadores da sua empresa. Outros programas que precisarem criar variveis do tipo pc podem simplesmente incluir o arquivo de cabealho pcdb.h, ou seja, no precisam declarar novamente o mesmo tipo de dados. Isso economiza tempo de digitao e mantm as declaraes comuns a vrios programas em um nico lugar, de modo que apenas um nico arquivo precise ser editado se for necessrio modificar os campos de inventario.
Cdigo 3.2 - Arquivo de cabealho (.h) tpico de um banco de dados.
//Arquivo de cabecalho tipico para um banco de dados const char linha[80] = "______________________________\n"; enum boolean {FALSE, TRUE}; struct inventario
22
Verso 1.1
67
2005
{ char *modelo; char *cpu; char *monitor; int velocidade; int numfloppy; int capacidadehd; int ram; boolean modem; char *modelomodem boolean cdrom; int velcdrom; boolean cdrw; char *velcdrw; boolean placa3d; char *modelo3d; boolean dvd; char *veldvd; };
Cdigo 3.3 - Uso do comando STRUCT em banco de dados.
//Nome do modelo do PC //Tipo da CPU do PC //Tipo do Monitor do PC //Velocidade do PC em MHz //Numero de floppy drives //Capacidade do HD em GB //Quantidade de RAM instalada //PC possui Modem instalado? //Modelo do Modem //PC possui drive de CDROM? //Velocidade da cdrom em x //PC possui drive CDRW? //Velocidade da cdrw //PC possui placa 3D? //Modelo da placa de video 3D //PC possui drive de DVD? //Velocidade do DVD
#include <stream.h> #include "pcdb.h" main () { inventario pc; pc.modelo pc.cpu pc.monitor pc.velocidade pc.numfloppy pc.capacidadehd pc.ram pc.modem pc.modelomodem pc.cdrom pc.velcdrom pc.cdrw pc.velcdrw pc.placa3d pc.modelo3d pc.dvd "AMD K6II 3D NOW"; "80686"; "Sansung SyncMaster 450b"; 450; 1; 6; 128; TRUE; "US ROBOTICS 56K WinModem"; TRUE; 56; TRUE; = "6x4x32"; = TRUE; = "Diammond Viper RIVA 128 de 4 MB"; = FALSE; = = = = = = = = = = = =
cout << linha << setw(53) << "Meu computador atualmente e:\n\n";
Verso 1.1
68
2005
cout << setfill('.') << "Modelo" << setw(63) << pc.modelo << "\nCPU" << setw(66) << pc.cpu << "\nMonitor" << setw(62) << pc.monitor << "\nVelocidade" << setw(50) << pc.velocidade << "\nNumero de floppy drives" << setw(46) << pc.numfloppy << "\nCapacidade do HD (em GB)" << setw(45) << pc.capacidadehd << "\nMemoria RAM (em MB)" << setw(50) << pc.ram; if (pc.modem) cout << "\nModelo do modem" << setw(54) << pc.modelomodem; if (pc.cdrom) cout << "\nVelocidade do CDROM" << setw(50) << pc.velcdrom; if (pc.cdrw) cout << "\nVelocidade do CDRW" << setw(51) << pc.velcdrw; if (pc.placa3d) cout << "\nModelo da Placa 3D" << setw(51) << pc.modelo3d; if (pc.dvd) cout << "\nVelocidade do DVD" << setw(52) << pc.veldvd; } O Cdigo 3.2 utiliza a declarao char *modelo e declaraes similares. Estas so declaraes de ponteiros, tpico que ser abordado no Captulo 4 desta apostila. Por enquanto, entenda-os como sendo uma outra forma de se criar variveis do tipo string, por exemplo modelo. Adiante, ainda neste captulo ser explicado mais sobre esse formato. A linha 6 do Cdigo 3.3 define uma varivel chamada pc do tipo inventario. Isso pode ser feito porque a declarao da struct inventario foi includa previamente na linha 2, na forma do arquivo de cabealho pcdb.h. As linhas 8 a 23 atribuem valores aos campos da varivel pc, fazendo isso individualmente. O Cdigo 3.4 semelhante ao Cdigo 3.3, mas usa uma nica instruo para declarar e inicializar a varivel pc do tipo inventario. Esse um mtodo conveniente para a inicializao de estruturas e o leitor deve-se familiar com tal formato. O resto do Cdigo 3.4 idntico ao Cdigo 3.3.
Cdigo 3.4 - Declarao e inicilaizao conjunta de uma varivel STRUCT.
Verso 1.1
69
2005
{ inventario pc = { "AMD K6II 3D NOW", "80686", "Sansung SyncMaster 450b", 450, 1, 6, 128, TRUE, "US ROBOTICS 56K WinModem", TRUE, 56, TRUE, "6x4x32", TRUE, "Diammond Viper RIVA 128 de 4 MB", FALSE}; cout << linha << setw(53) << "Meu computador atualmente e:\n\n"; cout << setfill('.') << "Modelo" << setw(63) << pc.modelo << "\nCPU" << setw(66) << pc.cpu << "\nMonitor" << setw(62) << pc.monitor << "\nVelocidade" << setw(50) << pc.velocidade << "\nNumero de floppy drives" << setw(46) << pc.numfloppy << "\nCapacidade do HD (em GB)" << setw(45) << pc.capacidadehd << "\nMemoria RAM (em MB)" << setw(50) << pc.ram; if (pc.modem) cout << "\nModelo do modem" << setw(54) << pc.modelomodem; if (pc.cdrom) cout << "\nVelocidade do CDROM" << setw(50) << pc.velcdrom; if (pc.cdrw) cout << "\nVelocidade do CDRW" << setw(51) << pc.velcdrw; if (pc.placa3d) cout << "\nModelo da Placa 3D" << setw(51) << pc.modelo3d; if (pc.dvd) cout << "\nVelocidade do DVD" << setw(52) << pc.veldvd; }
Verso 1.1
70
2005
struct cliente { char *nome; char *endereco; int idade; inventario pc; } Declarado dessa forma, um cliente uma estrutura com quatro campos: nome, endereo, idade e pc da pessoa. Os primeiros trs campos so idnticos, no formato, queles j estudados. O ltimo campo, no entanto, do tipo inventario, a struct declarada no cabealho pcdb.h. Para criar uma varivel chamada cliente1 e atribuir a esta varivel um nome, endereo e idade, pode-se proceder da seguinte maneira: cliente cliente1; cliente1.nome = "Arthur of Pendragon"; cliente1.endereco = "Camelot"; cliente1.idade = 32; Entretanto, atribuir valores ao campo pc requer um pouco mais de trabalho. Como esse campo uma estrutura do tipo inventario, introduzida dentro de outra estrutura do tipo cliente, deve-se utilizar a notao de ponto, juntamente com ambos os nomes dos tipos de dados referentes aos campos da estrutura inventario e da estrutura cliente. cliente1.pc.modelo = "PENTIUM IV"; cliente1.pc.cpu = "80886"; cliente1.pc.monitor = "Sansung SyncMaster 550b";
3.3. As unies
As unies so quase idnticas s estruturas, e, de fato, se no for tomado o devido cuidado, pode-se facilmente confundir as duas, ocasionando em resultados desastrosos. Apesar de estruturas e unies possurem formatos gmeos, estas devem ser encaradas mais como primas que como gmeas idnticas. Como j visto, as estruturas renem vrios campos em um pacote conveniente, ou seja, uma struct permite armazenar variveis relacionadas conjuntamente, o que conveniente quando se precisa manter registros de bancos de dados. J as unies, declaradas com a palavra-chave union, tambm podem armazenar campos mltiplos em um nico pacote. Porm, em vez de encontramos esses campos uns aps os outros na memria, como acontece com uma struct, em uma union todos os campos se sobrepem na mesma localidade da memria. O uso mais comum das unies na criao de um tipo de dados que pode ser usado como dois ou mais tipos de dados diferentes. Por exemplo, podemos criar uma unio de um tipo long com um tipo float, mas trata-lo, tambm, como se fosse um tipo char. Isso no
Verso 1.1
71
2005
significa que as unies do C++ convertem campos de um tipo para outro. O que acontece que os bits na memria, que armazenam as informaes para cada campo, so apenas interpretados como sendo de um determinado tipo de dados para algumas instrues e como um outro tipo de dados para outras instrues. Considere uma unio declarada como: union ExemploDeUnion { float UmFloat; long UmLong; } Em uma varivel do tipo ExemploDeUnion, os campos UmFloat e UmLong ficam armazenados no mesmo endereo da memria do computador (vide Figura 2.2). Isso significa que se um programa atribui um valor ao campo UmFloat, ele mudar tambm o valor do campo UmLong, o que no significa que existem duas variveis na unio. Existe apenas um valor representado de dois modos. O tamanho da union igual ao tamanho do maior elemento nesta declarado.
Figura 3.2 - Os bytes de cada campo de uma varivel union so armazenados na mesma posio da memria.
Um exemplo prtico ajuda, e muito, a entender melhor o funcionamento das unies em C++. O Cdigo 3.5 apresenta um programa que declara uma unio com dois campos, um campo do tipo char e outro do tipo int. Quando se compila e executa o Cdigo 3.5 o resultado a exibio do alfabeto na tela do computador.
Cdigo 3.5 - Uso do comando UNION.
#include <stream.h> union charint { char c; int i; }; charint ci; main () { int i; for (i = 65; i < 91; i++) { ci.i = i;
Verso 1.1
72
2005
cout << ci.c; } } Para entender como o Cdigo 3.5 exibe o alfabeto, observe atentamente as linhas 2 a 7. Elas declaram uma union chamada charint que contm dois campos, um do tipo char chamado c e outro do tipo int chamado i. Exceto pela palavra-chave union, esse formato idntico ao formato utilizado pelas declaraes de estruturas, ou seja, de uma struct. A linha 7 declara uma varivel ci do tipo charint. As linhas 12 a 16 executam um loop for que a cada iterao incrementa uma varivel do tipo int chamada i, sendo que a nica finalidade desta varivel atribuir o seu valor ao campo i da varivel, ou seja, o campo ci.i. A linha 15 exibe ento o outro campo da unio, o campo ci.c. Apesar de nenhuma instruo ter atribudo qualquer valor ao campo c da varivel ci.c, o programa ainda assim exibe o alfabeto. Obviamente alguma coisa alterou o valor do campo c. Tal coisa trata-se da atribuio na linha 14. Como todos os campos em uma unio se sobrepem, atribuir valores a um campo afeta todos os outros campos da varivel. Neste exemplo, atribuir os valores 65 at 90 ao campo i tambm atribui os mesmos valores ao campo c, que so os cdigos ASCII para as letras A at Z.
3.4. Vetores
Da mesma forma que estruturas e unies, os vetores tambm renem vrios pedaos de informao. Todos os vetores possuem duas caractersticas principais. Em primeiro lugar, so declarados para armazenar uma ou mais variveis do mesmo tipo de dados. Por exemplo, um vetor pode armazenar variveis do tipo int ou uma struct declarada anteriormente no programa, mas no pode armazenar uma struct e uma varivel do tipo int. A segunda caracterstica tpica dos vetores o seu tamanho. Quando se defini um vetor, deve-se planejar antecipadamente quantos elementos sero armazenados neste vetor, alm do tipo dos dados que sero armazenados neste vetor, conforme j mencionado. Esse um passo importante porque o compilador s pode reservar memria suficiente para o vetor se lhe for dito quantos elementos o comporo. Dito de maneira simples, o compilador multiplica o nmero de itens pelo tamanho de cada um e reserva o montante de bytes para o vetor23. Uma demonstrao do uso de vetores e de como cri-los e us-los mostrada no Cdigo 3.6, onde um programa declara, preenche e exibe o valor de um vetor de cem posies de nmeros inteiros, ou seja, do tipo int e de tamanho igual a 100. A linha 3 do Cdigo 3.6 mostra como feita a definio de um vetor em C++. A definio similar definio de uma varivel de um tipo qualquer, porm, acrescida de colchetes ao
23
possvel escrever programas que calculem o tamanho de vetores e reservem espao para eles em tempo de execuo com o uso de ponteiros. Assim, pode-se criar programas que criem vetores cujos tamanhos variem dependendo da necessidade. Tal assunto ser abordado no Captulo 5.
Verso 1.1
73
2005
redor de uma constante literal aps o nome da varivel que se deseja declarar. O par de colchetes o smbolo de vetor em C++. A declarao da linha 3 cria um vetor de 100 posies, todas elas do tipo inteiro, armazenadas em posies consecutivas da memria do computador. Cada um dos inteiros no vetor uma varivel distinta, com seu prprio espao na memria (vide figura 3.3).
Cdigo 3.6 - Uso de VETORES em C++.
#include <stream.h> int vetor[100]; int i; main () { //Preenche o vetor com valores de 0 a 99 for (i = 0; i <= 99; i++) vetor[i] = i; //Exibe o conteudo do vetor crescente e decrescentemente cout << "Valores do vetor de [0] a [99]:\n"; for (i = 0; i <= 99; i++) cout << setw(5) << vetor[i]; cout << "\n\nValores do vetor de [99] a [0]:\n"; for (i = 99; i >= 0; i--) cout << setw(5) << vetor[i]; }
Para acessar um dos elementos do vetor (por exemplo para exibir o seu valor) basta que se especifique o elemento que desejado com o seu respectivo ndice dentro de colchetes, logo aps o nome do vetor, conforme foi feito nas linhas 14 e 17 do Cdigo 3.6.
Verso 1.1
74
2005
Uma importante considerao a respeito de vetores em C++ o fato de que o primeiro elemento de todos os vetores em C++ corresponde ao ndice de nmero zero (0), e no ao ndice de nmero um (1). Em outras palavras, para exibir os cinco primeiros valores do tipo inteiro do vetor declarado no Cdigo 3.6 poder-se-ia escrever: cout cout cout cout cout << << << << << vetor[0] vetor[1] vetor[2] vetor[3] vetor[4] << << << << << '\n'; '\n'; '\n'; '\n'; '\n';
Obviamente, para exibir os cinco primeiros valores do tipo inteiro do vetor declarado no Cdigo 3.6 muito mais fcil (e mais eficiente) usar um loop for, com por exemplo: for (i = 0; i <= 4; i++) cout << vetor[i] << '\n'; Vetores, em C++, podem tambm ser indexados com expresses, desde que estas expresses gerem um resultado inteiro, positivo e compatvel com os ndices dos vetores. Assim sendo, qualquer expresso, varivel ou constante que representa, ou quando avaliada gera um valor inteiro, serve como um ndice de vetor vlido. Uma boa utilizao de vetores o armazenamento de variveis struct mltiplas. Por exemplo, para criar um vetor de 50 registros do tipo inventario, usando as declaraes do arquivo de cabealho pcdb.h apresentado no Cdigo 3.1, bastaria escrever: inventario sistemas[50]; A declarao acima define um vetor chamado sistemas, capaz de armazenar 50 variveis struct do tipo inventario, que uma estrutura mais conveniente do que 50 variveis do tipo inventario individuais. Para mudar o nome do sexto registro da varivel sistemas, basta escrever: sistemas[5].nome = "PS/2"; Assim como com os vetores simples de variveis do tipo int, o nome do vetor (sistemas) seguido de um valor de ndice entre colchetes ([5]). O C++ reconhece que essa parte da expresso refere-se a um elemento do vetor, neste caso um registro do tipo inventario. Como esse registro uma struct, para chegar at os campos, a instruo qualifica a referncia com o uso da notao de ponto seguido do nome do campo (nome). Um outro programa exemplo que mostra como os vetores podem ser teis para guardar informaes que o prprio programa pode usar mais tarde apresentado no Cdigo 3.7, que permite que o usurio entre com 18 notas de alunos, de uma avaliao qualquer. De posse das notas o programa calcula a mdia das notas.
Verso 1.1
75
2005
Programao I Prof. Andr Carlos Silva Cdigo 3.7 - Programa para clculo da mdia de 18 nmeros utilizando vetores.
#include <stream.h> #include <stdlib.h> const int max_notas = 18; float notas[max_notas]; int i, numero_notas; float soma, media; main () { //Solicita ao usario as notas e as armazena em no vetor for (numero_notas = 0; numero_notas < max_notas; numero_notas++) { cout << "Digite o valor da nota " << (numero_notas + 1) << " (-1) para sair: "; cin >> notas[numero_notas]; if (notas[numero_notas] < 0) break; } if (numero_notas <= 0) exit (0); //Nenhuma nota foi digitada //Exibe as notas digitadas armazenadas no vetor e calcula a soma das notas cout << "\nAs notas digitadas foram:"; for (i = 0; i < numero_notas; i++) { cout << setw(5) << "\nNota " << (i + 1) << " = " << notas[i]; soma += notas[i]; } //Calcula e exibe o valor da media das notas media = soma / numero_notas; cout << "\nForam digitadas " << numero_notas << " notas" << "\nA soma das notas digitadas foi igual a: " << setw(15) << soma << "\nA media das notas digitadas foi igual a: " << setw(14) << media; } Combinar tipos de dados dessa maneira (vetores de structs que contm outros campos ou at mesmo outros vetores de algum outro tipo) um conceito poderoso. Em geral, podemos combinar tipos de dados simples, tais como int e float, com structs, unions e vetores para se construir os mais variados tipos de castelos de areia em nossos programas.
Verso 1.1
76
2005
main () { int vetor2[10]; for (i = 0; i < 10; i++) cout << "vetor global[" << (i + 1) << "] = " << vetor1[i] << setw(15) << "vetor local[" << (i + 1) << "] = " << vetor2[i] << '\n'; } O resultado da execuo do programa apresentado no Cdigo 3.8 a exibio de zero (0) para todos os elementos do vetor1, que um vetor global, e a exibio de uma srie de nmeros aparentemente escolhidos ao acaso para os elementos do vetor2, que um vetor local. Isso acontece porque os vetores se comportam como todas as variveis em C++. Variveis globais so inicializadas com 0, mas variveis locais no so inicializadas com quaisquer valores especficos. Uma maneira de inicializar os elementos de um vetor atribuindo valores para todos os seus elementos usando um loop for, o qual pode ser semelhante a: for (i = 0; i < 10; i++) vetor[i] = 0; Um outro meio de inicializar os elementos de um vetor listando valores constantes, dentro de chaves, aps a definio do vetor. O C++ l cada valor listado e o atribui para posies sucessivas dentro do vetor. Por exemplo, para inicializar um vetor de 10 inteiros com valores de 10 at 1 e, ento, exibir estes valores em ordem reversa, basta escrever: int vetor[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
24
Para maiores informaes sobre variveis, globais e locais, e a sua inicializao automtica pelo compilador vide os Captulos 1.2.2. e 1.2.3.
Verso 1.1
77
2005
for (int i = 9; i >= 0; i--) cout << "vetor[" << i << "] = " << vetor[i] << '\n';
3.5. Matrizes
Todos os vetores j mostrados at aqui so vetores ditos lineares, pois possuem apenas uma dimenso. Algumas vezes, entretanto, os vetores precisam ter mais de uma dimenso. Um vetor no linear chamado de matriz. As matrizes podem ter duas ou mais dimenses. Um exemplo do uso de um vetor que necessita ter mais de uma dimenso, ou seja, um exemplo do uso de uma matriz, a tela do monitor do computador. As linhas e as colunas na tela so facilmente representadas por uma estrutura de dados bidimensionais, contendo 25 linhas e 80 colunas, normalmente. Em C++, podemos definir uma matriz deste tamanho (25 x 80) da seguinte maneira: int monitor[25][80]; Definida com dois pares de colchetes e tamanhos, a matriz monitor tecnicamente um vetor de vetores, capaz de armazenar 25 vetores do tipo int, sendo cada um destes vetores um vetor capaz de armazenar 80 posies tambm do tipo int. mais fcil, no entanto, visualizar este tipo de vetor como sendo um conjunto de linhas e colunas (um matriz). Um outro exemplo de matriz : int multi[7][7]; O vetor multi composto por sete vetores de sete inteiros, mas a maioria das pessoas a v como sendo uma matriz de sete linhas e sete colunas de valores inteiros (vide Figura 3.4).
Figura 3.4 - Um vetor bidimensional um vetor de vetores, mas tambm pode-se encar-lo como sendo uma matriz.
Verso 1.1
78
2005
Como mencionado anteriormente, todos os vetores so indexados a partir de zero (0) em C++, uma regra que tambm se estende s matrizes. Para se exibir todos os elementos da matriz multi pode-se usar um loop for inserido dentro de outro da seguinte maneira: for (int linha = 0; linha <= 6; linha++) { for (int coluna = 0; coluna <= 6; coluna++) cout << setw(10) << multi[linha][coluna]; cout << '\n'; } As matrizes so feitas sob medida para o armazenamento de sries de fatos cobrindo categorias. Um exemplo demonstra bem esta idia e, com um pouco de trabalho extra, o programa que ser discutido a seguir pode se transformar em uma ferramenta bastante til. Suponha que o leitor seja gerente de um escritrio de pessoas muito ocupadas, e deseja saber que horrios elas tm disponveis para as reunies do grupo. Um modo de se fazer isso perguntar a todos os funcionrios quando eles prefeririam se reunir. Se isso no funcionar, o leitor poderia escrever um programa para procurar, em um vetor de horas para as reunies, os horrios que os funcionrios tm disponveis. O Cdigo 3.9 mostra como resolver este problema utilizando uma matriz. Execute o programa e entre com o nmero entre 0 e 3, inclusive, referente a um funcionrio.Ento entre com as horas, de 8 at 17, em que essa pessoa j assumiu algum compromisso. Entre com 1 quando findar a digitao das horas. Depois disso tecle um novo nmero de funcionrio e fornea as horas ocupadas deste. Proceda desta maneira para um mximo de quatro funcionrios e, ao final, entre com 1 para encerrar essa fase. O programa ir exibir uma tabela com a agenda de compromissos de cada funcionrio e uma lista com os possveis horrios de reunies, isto , quando todos os funcionrios esto com os seus horrios vagos.
Cdigo 3.9 - Exemplo do uso de matrizes em C++.
#include <stream.h> #include <conio.h> const int ftotal = 4; const int htotal = 10; const int hzero = 8; enum funcionarios {JOSE, SAMUEL, PAULA, MARIA}; int agenda[htotal][ftotal]; main () { int fn, hora; cout << linha <<"| CALCULO DE HORARIO DE REUNIOES <<"|FUNCIONARIOS: <<"| 0 Jose da Silva
Verso 1.1
79
<<"| 1 Samuel Coelho |\n" <<"| 2 Paula Cristina dos Santos |\n" <<"| 3 Maria Aparecida Ribeiro |\n"; //Leitura dos compromissos dos funcionarios for (;;) { cout << "|Digite o numero do funcionario (-1 para sair): "; cin >> fn; if (fn < 0) break; if (fn > ftotal) { cout <<"|O numero do funcionario esta fora dos limites estipulados|\n"; continue; } for (;;) { cout <<"Hora do compromisso?(8-17,-1 para sair):"; cin >> hora; if (hora < 0) break; if ((hzero <= hora) && (hora < hzero + htotal)) agenda[hora - hzero][fn] = 1; else cout << "| Hora fora dos limites... |\n"; } } cout << "| AGENDA DE COMPROMISSOS |\n" << setw(80) << "| JOSE | SAMUEL | PAULA | MARIA |\n" for (hora = 0; hora < htotal; hora++) { cout << '|'<< setw(6) << (hora + hzero) << ":00" << setw(7) << '|'; for (fn = 0; fn < ftotal; fn++) { if (agenda[hora][fn] != 0) cout << setw(7)<< 'X'<< setw(6) << '|'; else cout << setw(13) << '|'; } cout << '\n' << linha; } cout << "|Prescione qualquer tecla para continuar\n"; getch()25;
25
A funo getch()l um nico caractere diretamente do teclado, sem que este seja mostrado na tela do vdeo. Para usar a funo getch() deve-se incluir o cabealho conio.h.
Verso 1.1
80
2005
clrscr(); cout << "| POSSIVEIS HORARIOS PARA UMA REUNIAO |\n"; for (hora = 0; hora < htotal; hora++) { int k = 0; for (fn = JOSE; fn < ftotal; fn++) k += agenda[hora][fn]; if (k == 0) cout << (hora + hzero) << ":00 "; } } Quando voc for examinar o Cdigo 3.9, preste muita ateno no modo como as constantes hzero (representando a hora inicial) e htotal (representando o total de horas do expediente) so usadas para o clculo de ndices da matriz. Como todos os vetores em C++ usam ndices que comeam em 0, usar vetores indexados por valores entre 8 e 17 requer cuidadosa programao. Obviamente, voc poderia simplesmente declarar um vetor de 24 posies, cada posio representando uma hora do dia, e aproveitar apenas as posies entre 8 e 17.
3.6. Strings
Agora que o leitor tem conhecimento do que so vetores, voc est pronto para considerar a verdadeira natureza das strings e responder pergunta: O que, afinal de contas, uma string?. Se voc respondeu um vetor de caracteres, acertou em cheio. Como temos visto em vrios cdigos-fonte nesta apostila, para declarar uma string de 80 caracteres basta escrever: char string[80]; Esta , obviamente, apenas uma definio de um vetor que cria uma varivel chamada string com espao para 80 elementos do tipo char. Em C++, uma string um vetor de caracteres, e no um tipo de dados string, como acontece em outras linguagens de programao, tais como PASCAL e BASIC. Em uma instruo do tipo: char string[15] = "Luis Felipe"; O compilador C++ no copia os caracteres da string "Luis Felipe" para as posies da memria reservadas para o vetor do tipo char string. O C++ no copia caracteres dentro de uma instruo ou definio que atribua uma string literal a um vetor do tipo char. Em vez disso ele atribui o endereo do primeiro caractere da string varivel do tipo vetor. necessria muito menos energia para fazer uma varivel apontar para uma string j armazenada na memria do que para copiar os caracteres da string de uma posio para outra, fato esse que o C++ utiliza para manter os programas se executando mais rapidamente.
Verso 1.1
81
2005
82
2005
tipo de definio com colchetes para criar vetores em seus prprios programas. Declaraes dentro de estruturas (struct), no entanto, tem-se necessariamente que usar a forma de declarao com ponteiro (asterisco) para criar campos de strings de comprimentos variveis, como ilustrado no Cdigo 3.1.
So necessrios seis bytes, dois para cada campo int da estrutura anterior. Infelizmente, h muito espao desperdiado nesta estrutura. Por exemplo, o campo sexo requer apenas um nico bit para representar o seu valor, e os outros 15 bits deste inteiro nunca sero usados. Se a estrutura pudesse empacotar a informao dentro de um espao menor, com apenas tantos bits quanto os necessrios para representar cada campo, ela deixaria de desperdia-los. A maneira de se fazer isso com o uso de um campo de bits, que se assemelha a uma struct, porm especifica o nmero de bits que cada campo da estrutura dever ocupar, dentro do tamanho de um inteiro (int). Vejamos a seguir como a estrutura anterior se parece quando convertida para um campo de bits: struct pessoa { unsigned idade unsigned sexo unsigned filhos unsigned };
Colocar aps cada nome de campo dois-pontos e um valor literal unsigned faz com que esse campo fique empacotado de acordo com o nmero especificado de bits na estrutura, que pode totalizar at 16 bits para todos os seus campos. No exemplo acima, 7 bits so reservados para o campo idade, 1 bit para o campo sexo e 4 bits para o campo filhos.
Verso 1.1
83
2005
A grande maioria dos compiladores C++ permitem que estruturas de campos de bits sejam maiores que 16 bits. Entretanto, o limite oficial para o tamanho de um campo de bits o mesmo que para uma varivel do tipo int, ou seja, 16 bits. No h nenhuma regra estabelecida se o tamanho mximo de um campo de bits pode, ou no, ser maior que o tamanho de um inteiro, e provavelmente cada compilador construir os seus campos de bits de modo diferente. O ltimo campo de bits que aparece na estrutura pessoa no recebeu nenhum nome. Ele apenas reserva uma quantidade de espao e sua finalidade fazer com que o nmero total de bits do campo de bits seja igual a 16. Esse campo opcional, mas usualmente includo para podermos responder por todos os bits da estrutura. Pode-se tambm utilizar mais de um campo desse tipo para forar os outros campos a comearem em determinados bits. Por exemplo, uma porta de entrada pode definir certos bits com vrios significados: se um byte esta disponvel, qual o status da porta, se ela est pronta para enviar outro byte, etc. Poderamos usar uma estrutura de campos de bits para ler essa informao para dentro de um programa, mas devemos usar campos para reservar espao para fazer com que alguns campos coincidam com posies de valores especficos. Use campos de bits como se faz com campos de outras estruturas. Por exemplo, para exibir na tela a idade e o nmero de filhos de um campo de bits pessoa poderamos escrever: pessoa p; ... cout << "\nIdade:
De maneira diferente que em outras linguagens de programao, em C++ no preciso extrair os bits da estrutura e no tem-se que usar operadores de bits para isolar valores dos campos de seus vizinhos. Em vez disso, apenas utilize os campos como se fossem do tipo int. O C++ cuida dos detalhes confusos de extrair e inserir os campos de bits empacotados na estrutura sem alterar os outros bits l presentes. Obviamente, deve-se ser cuidadoso para no atribuir valores maiores do que aqueles que um campo pode representar. Exceto por esse detalhe, pode-se usar campos de bits como se fossem variveis unsigned int individuais. Lembrando que os campos de bits devem sempre ser declarados em structs, e o seu uso no permitido em unions. O Cdigo 3.10 mostra como usar campos de bits para extrair informaes sobre o hardware de um computador. Tais informaes se encontram empacotadas na BIOS do computador. O programa usa uma estrutura de campos de bits para interpretar uma informao retornada pela funo _bios_equiplist, declarada no arquivo de cabealho bios.h. Quando o programa executado ele detecta quantas unidades de disco, portas seriais e portas de impressoras esto instaladas, se um adaptador de jogos est disponvel e a configurao inicial do vdeo do PC.
Cdigo 3.10 - Exemplo do uso de um CAMPO DE BITS.
Verso 1.1
84
2005
struct equipamentos { unsigned diskette : 1; unsigned : 1; unsigned planar : 2; unsigned videomode : 2; unsigned numfloppy : 2; unsigned : 1; unsigned numserial : 3; unsigned gameadaptador : 1; unsigned : 1; unsigned numprinters: 2; }; union doistipos { equipamentos eq; int k; }; doistipos dt; main () { dt.k = _bios_equiplist(); cout << "Numero de impressoras" << setw(48) << dt.eq.numprinters << "\nAdaptador de jogos instalado (1)" << setw(37) << dt.eq.gameadaptador << "\nNumero de portas seriais" << setw(45) << dt.eq.numserial << "\nNumero de drives de diskette"; if (dt.eq.diskette) cout << setw(41) << dt.eq.numfloppy; else cout << setw(41) << '0'; cout << "\nResolucao de video (2)" << setw(46) << dt.eq.videomode << "\nMemoria RAM plana (3)" << setw(46) << dt.eq.planar << "\n\n\nObservacoes:" << "\n(1) 0 = FALSO e 1 = VERDADEIRO;" << "\n(2) 1 = 40 * 25 color; 2 = 80 * 25 color; 3 = monocromatico" << "\n(3) 1 = 128 MB"; }
Verso 1.1
85
2005
Os campos de bits restringem, normalmente, a utilizao de programas a hardwares especficos. Executar o programa apresentado no Cdigo 3.10 em qualquer mquina que no um legtimo IBM, PC, AT, PS/2 ou clone poder fazer com que o programa no funcione corretamente. Alem disso, como cdigo-fonte se baseia nas declaraes do arquivo de cabealho bios.h, o programa pode tambm no funcionar corretamente em outros compiladores C++, j que este um arquivo de cabealho que distribudo juntamente com o compilador.
#include <stream.h> main () { char a = 'A'; short b = -7; int c = 156; long d = 2147483640; float e = 10.5; double f = 0.00045; long double g = 1e-6; cout << setfill('.') << "Tamanho de um << sizeof(a) << " << "Tamanho de um << sizeof(b) << "
Verso 1.1
char: " << setw(40) byte(s)\n" short: " << setw(39) byte(s)\n" 86
2005
<< << << << << << << << << << }
"Tamanho de um sizeof(c) << " "Tamanho de um sizeof(d) << " "Tamanho de um sizeof(e) << " "Tamanho de um sizeof(f) << " "Tamanho de um sizeof(g) << "
int: " << byte(s)\n" long: " << byte(s)\n" float: " << byte(s)\n" double: " << byte(s)\n" long double: byte(s)\n";
Programadores cuidadosos utilizam o operador sizeof para escrever programas que sejam independentes do sistema em que estes iro ser executados. Ao invs de assumir que uma varivel do tipo int ocupa dois bytes, uma instruo pode usar a expresso sizeof(int). Compilar tal instruo em sistemas diferentes d ao programa meios de determinar quantos bytes um inteiro ocupa. O programa apresentado no Cdigo 3.11 pode ser modificado para calcular o tamanho da estrutura inventario, apresentada no Cdigo 3.1, incluindo-se neste apenas as seguintes linhas. #include "pcdb.h" inventario pc; cout << "Tamanho da struct inventario: " << setw(30) << sizeof(pc) << " byte(s)\n"; Usar sizeof para determinar o tamanho de um vetor ou de uma estrutura prefervel a assumir o tamanho destes como sendo igual soma do tamanho de cada campo, ou elemento, que compe a estrutura ou o vetor, respectivamente. O operador sizeof o nico meio confivel de se determinar o verdadeiro tamanho de uma estrutura. A aplicao do operador sizeof a uma unio retorna o tamanho do maior elemento da unio.
Verso 1.1
87
2005
At este ponto j examinamos a maioria dos operadores e das estruturas de dados da linguagem C++. Com esses elementos, e com a ajuda das instrues de fluxo de controle podemos escrever programas mais sofisticados, que repetem aes e que tomam decises. Infelizmente, na medida em que seus programas crescem, voc perceber que main() tende a se expandir, como um balo de ar quente com sua vlvula de entrada aberta. A menos que se faca algo para aliviar a presso interna, cedo ou tarde o balo explodir. Assim sendo, a menos que se faa algo para impedir o abarrotamento de main() com instrues aps instrues, seus programas talvez entrem em pane medida que se tornem mais difceis de serem criados e mantidos. Uma funo main() que se estenda por pginas de cdigo-fonte , alm de deselegante, susceptvel a bugs. Bons programadores evitam escrever cdigos-fonte desta maneira. Em vez disso, eles dividem os seus programas em pequenas partes, que so mais fceis de se administrar. Tal como main(), estas pequenas partes so denominadas de funes, e chegada a hora de se explicar o que so funes e como podemos usa-las para escrever at mesmo os mais complexos programas em C++, sem nunca trabalhar com pedaos de cdigo-fonte que no sejam pequenos e de fcil entendimento26. Uma funo um tipo de mini-programa dentro de um programa. Elas renem varias instrues sob um nico nome que, desta forma, pode ser chamado uma ou mais vezes pelo programa, para a execuo dessas instrues. Funes economizam espao, reduzindo as repeties, e tornam a programao mais fcil, fornecendo-nos um meio de dividir um grande projeto em pequenos mdulos, de fcil concepo e administrao.
26
Se voc j programou em BASIC ou em linguagem Assembler, reconhecer as funes em C++ como elementos muito similares s sub-rotinas. Se voc conhece Pascal, perceber que as funes em C++ so equivalentes aos procedimentos e s funes do Pascal. Mesmo se voc j possuir experincia em C, voc deve, ainda assim, ler este Captulo, pois as funes em C++ podem parecer iguais s funes em C, mas existem muitas diferenas entre as funes destas duas linguagens.
Verso 1.1
88
2005
Voc j escreveu, mesmo sem saber ao certo, programas que chamam funes. Como por exemplo o programa apresentado no Cdigo 2.28, que utiliza a funo sizeof(), a funo setw(), etc. Vrias funes, tais como sizeof(), so fornecidas em arquivos de cabealho distribudos junto com o compilador e agregadas aos programas que as chamam durante a compilao do programa. Outras funes podem ser escritas pelo prprio programador. A sintaxe para a chamada de uma funo a mesma tanto para funes escritas pelo programador quanto para funes do sistema.
#include <stream.h> float celsius (float fahr); main () { float c, f; cout << "Digite a temperatura em graus Fahrenheit: "; cin >> f; c = celsius(f); //Chamada a funcao cout << setw(5) << f << " graus Fahrenheit = " << setw(5) << c << " graus Celsius"; } float celsius (float fahr) { float c; c = (fahr - 32) * 5 / 9; return c; } //Definicao da funcao //Prototipo da funcao Celsius
Os componentes necessrios para se adicionar uma funo a um programa so: o prottipo de uma funo, a chamada funo e a definio da funo.
Verso 1.1
89
2005
O prottipo acima informa ao compilador que a funo de nome celsius() do tipo real e recebe como argumento um valor tambm real, que ser armazenado na varivel fahr. A informao do nome da varivel que receber o argumento facultativa, mas a informao do seu tipo obrigatria. Poderamos escrever o mesmo prottipo da seguinte forma: float celsius (float); //Prototipo da funcao Celsius
Verso 1.1
90
2005
cout << "Digite a temperatura em graus Fahrenheit: "; cin >> f; c = celsius(f); //Chamada a funcao cout << setw(5) << f << " graus Fahrenheit = " << setw(5) << c << " graus Celsius"; } float celsius (float fahr) { float c; c = (fahr - 32) * 5 / 9; return c; } //Definicao da funcao
#include <stream.h> float celsius (float fahr) { float c; c = (fahr - 32) * 5 / 9; return c; } main () { float c, f; cout << "Digite a temperatura em graus Fahrenheit: "; cin >> f; c = celsius(f); //Chamada a funcao cout << setw(5) << f << " graus Fahrenheit = " << setw(5) << c << " graus Celsius"; } Bons programadores sempre escrevem o prottipo de todas as suas funes, mesmo os prottipos das funes definidas antes de sua chamada. //Definicao da funcao
Verso 1.1
91
2005
Podemos eliminar a varivel desnecessria declarada no corpo da funo celsius() e colocar a expresso de clculo diretamente junto ao comando return, conforme mostrado abaixo: float celsius (float fahr) //Definicao da funcao { return (fahr - 32) * 5 / 9; } O uso do comando return no obrigatrio e uma funo que no possui o comando return se encerra quando o fluxo de controle do programa encontra a chave ('}') que indica o fim da funo. Tais funes que no utilizam o comando return so funes do tipo void. O valor de retorno de uma funo acessado, na instruo de chamada, por meio do nome da funo seguido de parnteses, parnteses estes que podem conter, ou no, os argumentos necessrios execuo da funo. O valor de retorno de uma funo pode ser atribudo a uma varivel ou mesmo fazer parte de uma expresso. Uma mesma funo pode conter vrios comandos return, mas apenas um ser executado cada vez que a funo for executada.
Verso 1.1
92
2005
93
2005
um nmero e retorna o seu mdulo, que definido como sendo o valor do nmero desconsiderando-se o seu sinal. A passagem de parmetros da funo do tipo passagem por valor.
Cdigo 4.4 - Uso de passagem de argumentos por valor em funes.
#include <stream.h> float abs (float x); main () { float x; cout << "Digite um numero real: "; cin >> x; cout << "O modulo do valor digitado e: " << abs(x); } float abs (float x) { return (x >= 0)? x : -x; }
#include <stream.h> void linha (int i); main () { linha(21); cout << "\n* FELIZ ANIVERSARIO *\n"; linha(21); } void linha (int i) { for (int j = 0; j < i; j++) cout << '*'; }
Verso 1.1
94
2005
O resultado da execuo do programa acima algo como: ********************* * FELIZ ANIVERSARIO * *********************
#include <stream.h> void beep (void); main () { int dig; cout << "Digite um numero entre 0 e 9: "; cin >> dig; if (!(dig >= 0 && dig <= 9)) { cout << "ERRO!!!"; beep(); } } void beep (void) { cout << '\a'; for (int i = 0; i < 30000; i++); cout << '\a'; }
Verso 1.1
95
2005
#include <stream.h> void retangulo (int largura, int altura); main () { int alt, larg; cout << "Digite um valor para a largura do retangulo: "; cin >> larg; cout << "Digite um valor para a altura do retangulo: "; cin >> alt; retangulo(larg,alt); } void retangulo (int largura, int altura) { for (int i = 1; i < altura; i++) { cout << "\t\t"; for (int j = 1; j < largura; j++) cout << char(1); cout << '\n'; } }
Verso 1.1
96
2005
#include <stream.h> float somasqr (float m, float n); float sqr (float x); float soma (float m, float n); main () { float a, b; cout << "Digite dois numeros: "; cin >> a >> b; cout << "A soma de seu quadrados e: " << somasqr(a, b); } float somasqr (float m, float n) { return soma(sqr(m), sqr(n)); } float sqr (float x) { return x*x; } float soma (float m, float n) { return m + n; }
Verso 1.1
97
2005
int& n1 = n; Uma referncia no uma cpia da uma varivel a qual se refere, sim a mesma varivel sob nomes diferentes. As instrues abaixo imprimem na tela 5 e 8 respectivamente. int n; int& n1 = n; n = 5; cout << n1; n1 = 8; cout << n; Quando se usa o operador unrio & na criao de referncias, este se torna parte do tipo de dados. Toda referncia deve ser, obrigatoriamente, inicializada.
#include <stream.h> void juros (float& p, float& r, float i); main () { float preco, taxa, val_reaj;
Verso 1.1
98
2005
cout << "Digite o preco atual (em R$): "; cin >> preco; cout << "Digite a taxa de juros (em %): "; cin >> taxa; juros(preco, val_reaj, taxa); cout << "O novo preco sera: " << setw(10) << "R$ " << preco << "\nO aumento foi de: " << setw(11) << "R$ " <<val_reaj; } void juros (float& p, float& r, float i) { r = p * i / 100; p = p * (1 + (i / 100)); } A funo juros() apresentada no Cdigo 4.9 poderia encontrar o valor do novo preo e do reajuste sem a utilizao de referncias, mas como estas informaes seriam passadas para a funo main()? Por meio do comando return possvel retornar apenas um dos dois valores calculados, mas no os dois. Uma das respostas a esta pergunta o uso de referncias, mas existem outras, que sero faladas ainda neste captulo. Funes que recebem argumentos por referncia utilizam o operador & somente nas definies dos tipos dos argumentos da funo. Observe no exemplo anterior que a chamada a uma funo que recebe uma referncia idntica chamada s funes em que os argumentos so passados por valores. A declarao abaixo indica que os argumentos p e r da funo juros() so outros nomes para as variveis passadas como argumento pela funo que chamar a funo juros(). Em outras palavras, quando usamos as variveis p e r, estamos utilizando, na realidade, as variveis preco e val_reaj da funo main(). void juros (float& p, float& r, float i) As referncias no existem na linguagem C, so exclusividades da linguagem C++, e no h um meio de se criar um outro nome para uma mesma varivel em tal linguagem. O prximo exemplo, apresentado no Cdigo 4.10, cria uma funo que troca o contedo de duas variveis. Utilizaremos a funo troca() para ordenar um vetor de 10 nmeros reais digitados pelo usurio.
Cdigo 4.10 - Uso de passagem de argumentos por referncia para ordenar um vetor.
Verso 1.1
99
2005
main () { float valores[10], ordenados[10]; cout << "Digite 10 valores em qualquer ordem\n"; for (int i = 0; i < 10; i++) { cout << "Valor " << (i + 1) << " : "; cin >> valores[i]; ordenados[i] = valores[i]; } for (int j = 0; j < 10; j++) for (i = 0; i < 10; i++) troca(ordenados[i], ordenados[i+1]); cout << "\n\nVetor digitado Vetor ordenado\n"; for (i = 0; i < 10; i++) cout << setw(15) << valores[i] << setw(31) << ordenados[i] << '\n'; } void troca (float& x, float& y) { float bolha; if (x > y) { bolha = x; x = y; y = bolha; } }
Verso 1.1
100
2005
argumentos. Se estes argumentos forem passados por valor, a funo criar uma cpia das variveis a ela passadas, mas como so muitos os argumentos, pode-se ter problemas com falta de memria e o programa no rodar. O exemplo apresentado no Cdigo 4.11 solicita do usurio dois nmeros reais e, de posse destes, calcula o quadrado de cada um deles e imprime o resultado, usando passagem de argumentos por referncia constante.
Cdigo 4.11 - Uso de passagem de argumentos por referncias constantes.
#include <stream.h> void imprime (const double& x, const double& y); main () { double n1, n2; cout << "Digite 2 numeros:"; cin >> n1 >> n2; imprime(n1, n2); } void imprime (const double& x, const double& y) { cout << "O quadrado de " << x << " e " << x*x << '\n' << "O quadrado de " << y << " e " << y*y; }
Verso 1.1
101
2005
Programao I Prof. Andr Carlos Silva Cdigo 4.12 - Uso de valores default para argumentos de funes.
#include <stream.h> void linha (int i = 20, char ch = '*'); main () { linha(); cout << '\n'; linha(34); cout << '\n'; linha(45, '='); }
void linha (int i, char ch) { for (int j = 0; j < i; j++) cout << ch; } A sada do programa acima : ******************** ********************************** ======================================== No programa apresentado no Cdigo 4.12 a funo linha() chamada trs vezes. Na primeira vez todos os argumentos da funo so omitidos, e estes assumiro os valores 20 e '*', respectivamente. Na segunda vez, os argumentos assumiro os valores de 34 e '*', respectivamente. E, na terceira vez, sero respeitados os argumentos passados funo, e estes assumiro os valores de 45 e '='. Se o primeiro argumento de uma funo, com mais de um argumento, for omitido, todos os argumentos subseqentes tambm devero ser omitidos. Se o segundo argumento for omitido, todos os argumentos subseqentes tambm devero ser omitidos. Assim sendo, a seguinte instruo ilegal. linha( , '+'); //ERRADO!!!!
Pode-se escrever funes que tenham argumentos inicializados com valores default e argumentos no inicializados, mas aps a primeira inicializao todos os argumentos seguintes devero ser inicializados tambm, como no exemplo abaixo. void linha(int n = 20, char ch); void linha(int n = 20, char ch = '+'); //ERRADO!!!! //CORRETO
Verso 1.1
102
2005
#include <stream.h> int cubo (int i); float cubo (float i); double cubo (double i); main () { cout << cubo(876) << '\n'; cout << cubo(12.34) << '\n'; cout << cubo(4567.35) << '\n'; } int cubo (int i) { return i * i * i; } float cubo (float i) { return i * i * i; } double cubo (double i) { return i * i * i; } Observe que a sistema considera somente a lista de argumentos da famlia de funes para escolher qual das funes ser executada, e no o valor de retorno da funo. Assim sendo, o exemplo abaixo considerado erro pelo compilador. int cubo (int i);
Verso 1.1
103
2005
float cubo (int i); //ERRADO!!! Pois ambas funes tem o mesmo nmero e tipo de //argumento O programa apresentado no Cdigo 4.12 no permite definir o caractere que ser usado para desenhar a linha sem tambm definir o nmero de caracteres que devero ser desenhados. Suponhamos que voc queira que a funo possa ser chamada com qualquer um dos dois argumentos, com os dois argumentos em qualquer ordem, ou mesmo sem nenhum dos dois argumentos. Para isso, podemos definir uma famlia de funes, como mostra o Cdigo 4.14.
Cdigo 4.14 - Cdigo 4.12 modificado para o uso de sobrecarga de funes.
#include <stream.h> void void void void void linha linha linha linha linha (void); (int i); (char ch); (int i, char ch); (char ch, int i);
main () { linha(); cout << '\n'; linha(34); cout << '\n'; linha(45, '='); cout << '\n'; linha('+'); }
//Imprime 20 caracteres '*' //Imprime 34 caracteres '*' //Imprime 45 caracteres '=' //Imprime 20 caracteres '+'
void linha (void) { for (int j = 0; j < 20; j++) cout << '*'; } void linha (int i) { for (int j = 0; j < i; j++) cout << '*'; } void linha (char ch) { for (int j = 0; j < 20; j++) cout << ch; } void linha (int i, char ch)
Verso 1.1
104
2005
{ for (int j = 0; j < i; j++) cout << ch; } void linha (char ch, int i) { for (int j = 0; j < i; j++) cout << ch; }
#include <stream.h> #include <conio.h> inline char minusculo (char ch) { return ((ch >= 'A' && ch <= 'Z')? (ch - 'A' + 'a'): ch); } main () { const char ctrlz = 26; char ch; while ((ch = minusculo(getch())) != ctrlz) cout << ch; } O programa apresentado no Cdigo 4.15 muito simples em sua concepo, e sua finalidade semelhante a um editor de textos, porm no h como o usurio digitar uma letra maiscula pois, caso ele tente, a funo minsculo() converter a letra maiscula digitada para a sua correspondente minscula. Como se pode observar no Cdigo 4.15, uma funo inline escrita exatamente igual a uma funo comum, exceto pela incluso do qualificador inline no incio da definio da funo.
Verso 1.1
105
2005
Uma outra diferena nas funes inline que estas so escritas antes da funo main(). Ou seja, a definio de uma funo inline deve preceder a sua primeira chamada. Isto se deve ao fato de que o compilador deve conhecer de antemo o cdigo da funo para poder inseri-lo dentro do programa. Como a funo minsculo() foi definida antes de ser chamada, no necessrio escrever o seu prottipo. Conforme j mencionado, uma funo um cdigo-fonte presente uma nica vez no corpo do programa, mas que pode ser executado vrias vezes. Assim, um dos motivos de se utilizar funes o de poupar memria. A chamada de uma funo provoca o desvio do fluxo do programa para o cdigo-fonte da funo e, ao trmino desta, um novo desvio do fluxo do programa, afim de que este retorne instruo seguinte chamada da funo. Se por um lado o uso de funes poupa espao na memria, por outro lado, o uso de funes requer mais tempo de execuo. Quando escrevemos funes pequenas, podemos poupar tempo de execuo do programa colocando o cdigo-fonte da funo diretamente no programa. Quando uma funo muito pequena (constituda por uma ou duas instrues apenas), as instrues necessrias sua chamada podem ocupar mais espao na memria que as instrues do seu prprio cdigo-fonte. Assim sendo, em casos semelhantes, extremamente aconselhvel o uso de funes inline.
#include <stream.h> long double fatorial (int n); main () { int n; for (;;) { cout << cin >> if (n < cout << << } }
"Digite um numero (-1 para sair): "; n; 0) break; n << "! = " << setprecision(5) << fatorial(n) '\n';
Verso 1.1
106
2005
long double fatorial (int n) { return ( (n == 0)? 1: n * fatorial(n - 1)); } O cdigo-fonte gerado por uma funo recursiva exige a utilizao de mais memria do computador, o que torna a sua execuo mais lenta. No difcil criar funes recursivas, o difcil conhecer as situaes nas quais a recurso apropriada. Assim sendo, trs pontos devem ser lembrados ao se escrever funes recursivas: i. Antes de criar a funo deve-se escrever o problema em termos de recurso. No exemplo do Cdigo 4.16, o fatorial de um nmero n qualquer pode ser definido por meio da seguinte expresso: n! = n * (n 1)! Toda funo recursiva deve ter uma condio de trmino, chamada de condio bsica. A funo fatorial(), quando chamada, verifica se n zero. Se esta condio for verdadeira, a funo fatorial() deixa de ser recursiva, encerrando a sua execuo. Cada vez que uma funo chamada recursivamente, esta deve estar mais prxima de satisfazer a sua condio bsica. Isto garante que o programa converge para a sua condio bsica. Em caso contrrio o programa entraria em uma espcie de loop infinito, no encerrando nunca a sua execuo. A cada chamada da funo fatorial(), o valor de n estar sempre mais prximo de zero, e conseqentemente, da condio bsica da funo.
ii.
iii.
107
2005
{ return ( (n == 0)? 1: 1 * f3(0)); //Chama outra funo } long double f3 (int n) { return 1; }
//Condio bsica
O que ocorre na memria do computador quase a mesma coisa , exceto pelo fato de que no h repetio do cdigo-fonte a funo recursiva. Vrias chamadas a uma funo recursiva podem estar ativas ao mesmo tempo e, enquanto a ltima chamada no encerrar a sua execuo a penltima chamada no encerra a sua, e assim por diante. Isto faz com que variveis de cada chamada funo sejam todas mantidas na memria, o que requer mais memria do computador. O exemplo do Cdigo 4.17 mostra um programa que solicita que usurio digite uma frase inteira, terminada quando a tecla [ENTER] pressionada. Ao trmino da frase, o programa imprime a frase digitada pelo usurio de traz para frente.
Cdigo 4.17 - Programa que imprime uma frase digitada pelo usurio ao contrrio.
#include <stream.h> #include <conio.h> void inverte (void); main () { inverte(); } void inverte (void) { char ch; if ((ch = getche()) != '\r') inverte(); cout << ch; } Quando o programa acima compilado e o usurio digita uma frase, como por exemplo BOM DIA!, o programa imprime na tela, assim que o usurio pressiona a tecla [ENTER] a frase !AID MOB.
108
2005
Origem, conforme ilustrado na Figura 4.1. Os discos so dispostos em ordem decrescente de tamanho, de forma que o maior disco fica embaixo e o menor disco em cima dos demais. O objetivo do jogo movimentar, um a um, todos os discos da haste Origem para a haste Destino, utilizando, quando necessrio, a haste Temporria como uma haste auxiliar.
Porm, nenhum disco pode ser colocado sobre um disco menor que ele prprio.
Figura 4.1 - Esquema de funcionamento do jogo das torres de Hani.
A funo que iremos escrever recebe o nmero de discos e o nome das hastes como argumento e imprime a soluo para o problema do deslocamento dos discos.Para isso, vamos considerar os seguintes passos como uma soluo do problema das torres: i. ii. iii. Mover (n 1) discos da haste Origem para a haste Temporria; Mover o n-simo disco da haste Origem para a haste Destino; Mover (n 1) discos da haste Temporria para a haste Destino.
Assim sendo, pode-se escrever uma funo recursiva chamada mover(), conforme mostra o Cdigo 4.18.
Cdigo 4.18 - Resoluo do problema das torres de Hani.
#include <stream.h> void mover (int n, char orig, char temp, char dest); main () { mover(3, 'O', 'T', 'D'); } void mover (int n, char orig, char temp, char dest) { if (n == 1) cout << "\nMova o disco 1 da haste " << orig << " para a haste " << dest; else
Verso 1.1
109
2005
{ mover(n - 1, orig, dest, temp); cout << "\nMova o disco " << n << " da haste " << orig << " para a haste " << dest; mover(n - 1, temp, orig, dest); } } A execuo do programa acima gera a seguinte sada no vdeo: Mova o disco 1 da haste O para a haste D Mova o disco 2 da haste O para a haste T Mova o disco 1 da haste D para a haste T Mova o disco 3 da haste O para a haste D Mova o disco 1 da haste T para a haste O Mova o disco 2 da haste T para a haste D Mova o disco 1 da haste O para a haste D
As duas primeiras classes de armazenamento (auto e extern) j foram, indiretamente, abordadas nesta apostila. Elas so, na verdade, as variveis de escopo local e global, respectivamente. No entanto, as classes de armazenamento vo alm do conceito de escopo de uma varivel. Assim sendo, os conceitos sobre ambas as classes sero reapresentados ao leitor de forma que este, alm de relembrar o j aprendido, possa ampliar seus conceitos sobre variveis.
Verso 1.1
110
2005
esto declaradas. Tais variveis assim definidas so da classe auto. As variveis automticas foram, at ento, tratadas apenas por variveis de escopo local. A palavra-chave auto pode ser usada para especificar uma varivel automtica, mas no necessria, visto que a classe auto a classe default das variveis em C++. As variveis do tipo auto so criadas em tempo de execuo do programa, especificamente quando o programa encontra a instruo de sua declarao, e so destrudas ao trmino do bloco ao qual pertencem. Variveis automticas podem ser acessadas somente pelas instrues do bloco que as define e utilizadas somente aps a sua declarao. Por meio de referncia a elas, algumas funes podero tambm acessa-las. Quando uma varivel automtica criada, o programa no as inicializa com nenhum valor especfico. Variveis automticas podem ento conter um valor inicial aleatrio, j definido por ns por lixo.
main () { int i = 5, j = 10; //Declaracao de variaveis automaticas cout << "i = " << i << "\nj = " << j; }
Verso 1.1
111
2005
O que o programa acima imprime? Quais variveis sero usadas em main()? Em C++, as variveis automticas tm precedncia sobre as variveis externas. Assim sendo, o cdigo anterior imprimir: i = 5 j = 10 s vezes pode-se ser necessrio solicitar ao compilador que utilize uma varivel externa em vez da varivel automtica. Para isso basta que se utilize o operador de escopo :: antes do nome da varivel. Assim sendo, o exemplo anterior pode ser alterado, para que este imprima o valor das variveis externas ao invs das variveis automticas da seguinte maneira:
Verso 1.1
112
2005
#include <stream.h> int i; int j = 234; main () { int i = cout << << cout << << } //Variavel inicializada com zero //Variavel inicializada com 234
= " = = =
10; //Declaracao de variaveis automaticas << ::i //Imprime as variaveis esternas " << ::j; " << i //Imprime as variaveis esternas " << j;
Se uma varivel externa, criada em outro programa, for usada em um cdigo-fonte de sua autoria, o compilador apresentar um erro ao compilar o programa, devido ao fato de que a palavra-chave extern s deve ser usada para indicar que a varivel est armazenada em um mdulo de definies27, externo ao programa.
27
Os conceitos sobre mdulos de definies de variveis sero apresentados mais frente nesta apostila. Por hora basta apenas saber que mdulos de definies so como arquivos de cabealhos contendo apenas definies de variveis.
Verso 1.1
113
2005
Devido ao fato do uso do adjetivo externa para designar uma varivel criar uma certa ambigidade quanto a sua natureza, se esta externa no sentido do seu escopo ser global ou se esta externa no sentido de ser externa ao programa, utilizarei a seguinte nomenclatura: varivel global uma varivel externa, ou seja, declarada antes de main(), mas no mesmo programa que a utiliza; uma varivel externa uma varivel que tem a palavra-chave extern anteposta sua declarao.
#include <stream.h> int a, b, c; void retorna (int& d, int& e, int& f); main () { cout << "Digite tres valores: "; cin >> a >> b >> c; retorna(a, b, c); cout << "a = " << a << "\nb = " << b << "\nc = " << c; } void retorna { d = e + e = 5 * f = f / } (int& d, int& e, int& f) f; f; 12;
Alm de poder retornar mais de um valor, uma funo pode usar o conceito de referncia para que ela mesma seja avaliada como uma referncia a uma varivel, ou seja, o valor retornado por uma funo pode ser uma referncia a uma varivel. O Cdigo 4.21 mostra uma funo que, ao receber um valor, altera a valor da varivel a qual esta se referencia.
Verso 1.1
114
2005
Programao I Prof. Andr Carlos Silva Cdigo 4.21 - Exemplo de uma funo que retorna um valor uma varivel por referncia.
#include <stream.h> int x; int& intx (void); main () { intx() = 567; cout << "x = " } int& intx (void) { return x; } Quando se executa o Cdigo 4.21 o valor retornado pela funo intx() uma referncia varivel x. Como resultado, a expresso intx() um outro nome para a varivel x e a chamada funo pode aparecer do lado esquerdo do sinal de atribuio. Para entender a utilidade prtica desta tcnica necessrio que se aprenda um pouco mais sobre C++. Mais adiante nesta apostila sero mostrados alguns exemplos prticos que ajudaram o leitor a compreender o porque de se utilizar tal tcnica.
Verso 1.1
115
2005
Programao I Prof. Andr Carlos Silva Cdigo 4.22 - Uso de variveis da classe static.
#include <stream.h> void soma (void); main () { soma(); soma(); soma(); } void soma (void) { static int x; cout << "x = " }
116
2005
os resultados possveis so dois, ou ser cara ou coroa. Assim sendo, se a funo rand() for usada da seguinte maneira: int a = rand() % 2 Os valores atribudos varivel a sero sempre 0 ou 1, que corresponde cara ou coroa, respectivamente. Um procedimento anlogo adotado quanto ao lanamento de um dado simulado pelo programa.
Cdigo 4.23 - Uso da funo RAND para a simulao de um lanamento de um dado ou de uma moeda.
void simula (int eventos); main () { int eventos; char resp; for (;;) { clrscr(); cout << "Programa para simulacao de eventos aleatorios.\n\n\n" << "Digite o numero de faces de um dado, ou 2 para uma moeda.\n" << "RESPOSTA: "; cin >> eventos; if (eventos < 2) { cout << "O numero de eventos deve ser maior que dois..."; continue; } simula(eventos); clrscr(); cout << "Repetir o programa? (S/N): "; cin >> resp; if (toupper(resp) == 'N') exit(0); } } void simula (int eventos) {
Verso 1.1
117
2005
char resp; for (;;) { if (eventos == 2) { if ((rand() % eventos) == 0) { cout << "\nO lancamento da moeda deu cara.\n" << "Jogar a moeda novamente? (S/N): "; cin >> resp; if (toupper(resp) == 'N') break; } else { cout << "\nO lancamento da moeda deu coroa.\n" << "Jogar a moeda novamente? (S/N): "; cin >> resp; if (toupper(resp) == 'N') break; } } else { cout << "\nO lancamento do dado deu a face " << (rand() % eventos) + 1 << "\nJogar o dado novamente? (S/N): "; cin >> resp; if (toupper(resp) == 'N') break; } } }
Verso 1.1
118
2005
Programao I Prof. Andr Carlos Silva Cdigo 4.24 - Gerador de nmeros pseudoaleatrios.
#include <stream.h> unsigned ale (void); main () { for (int i = 0; i < 5; i++) cout << ale() << '\n'; } unsigned ale (void) { static unsigned semente = 1; semente = (semente * 25173 + 13849)%65536; return semente; } A varivel semente comea com o valor 1 e este alterado pela frmula a cada chamada funo ale(). Ao executar o Cdigo 4.24 obteremos a seguinte sada: 39022 61087 20196 45005 3882 Se o programa for executado novamente, a sada novamente ser: 39022 61087 20196 45005 3882 Observe que a sada do programa exatamente a mesma nas duas execues do programa. O problema da funo ale() que,a cada execuo do programa, a varivel semente comea sempre com o seu valor igual a 1. Para resolver este problema devemos inicializar a varivel semente com um valor novo a cada execuo do programa. Podemos fazer isso de duas maneiras, a primeira poderia ser criar uma chamada ao relgio do sistema e este seria o valor da semente. Uma outra maneira seria solicitar ao usurio a entrada do valor da semente. Para se utilizar a primeira soluo acima ns precisamos conhecer a funo que retorna o valor da hora do sistema, sendo esta em horas, minutos e segundos. Ns j utilizamos tal funo no Cdigo 1.6, onde a funo _dos_gettime() era utilizada com tal finalidade. O Cdigo 4.25 apresenta o mesmo programa mostrado no Cdigo 4.24, apenas com a modificao que a varivel semente inicializada com o relgio do sistema.
Verso 1.1
119
2005
#include <stream.h> #include <dos.h> unsigned ale (void); main () { for (int i = 0; i < 5; i++) cout << ale() << '\n'; } unsigned ale (void) { struct dostime_t agora; _dos_gettime(&agora); static unsigned semente = agora.second + 60 * agora.minute; semente = (semente * 25173 + 13849)%65536; return semente; } Anteriormente, quando a funo _dos_gettime() foi utilizada pela primeira vez, intencionalmente, algumas consideraes importantes foram omitidas sobre ela. A primeira considerao a se fazer que a funo _dos_gettime() utiliza passagem de parmetros por referncia, para que esta possa retornar trs valores, as horas, os minutos e os segundos atuais do sistema. A segunda considerao que, como a funo deseja apenas retornar trs valores utilizando passagem de argumentos por referncia, no h muito sentido em se criar trs argumentos para a funo, e sim criar uma struct que possui os trs campos necessrios, que so hour, minute e second. Ao executar o Cdigo 4.25 obteremos, por exemplo, a seguinte sada: 56310 27335 55340 54453 8242 Se o programa for executado novamente obteremos, por exemplo, a seguinte sada: 53164 565 15282 11315 26888
Verso 1.1
120
2005
Nota-se que as sadas do programa sero diferentes. Na verdade o Cdigo 4.25 no resolve o problema da escolha da semente dos nmeros pseudoaleatrios, mas sim o mitiga. Uma vez que a semente ser sempre a soma, em segundos, dos minutos e dos segundos atuais do relgio do sistema, a cada hora completa, a mesma seqncia de nmeros pseudoaleatrios ser gerada, uma vez que a semente ser novamente a mesma. Assim sendo, o perodo da semente de uma hora.
#include <stream.h> unsigned ale (void); void ini_s (int n); main () { int s; cout << "Digite um numero inteiro para ser usado como semente: ";
Verso 1.1
121
2005
cin >> s; ini_s(s); for (int i = 0; i < 5; i++) cout << ale() << '\n'; } static int semente; unsigned ale (void) //Funcao que gera numeros pseudoaleatorios { semente = (semente * 25173 + 13849)%65536; //Formula magica... return semente; } void ini_s (int n) { semente = n; } Ao executar o Cdigo 4.26 obteremos, por exemplo, a seguinte sada: Digite um numero inteiro para ser usado como semente: 1 39022 61087 20196 45005 3882 Se o programa for executado novamente obteremos, por exemplo, a seguinte sada: Digite um numero inteiro para ser usado como semente: 2 64195 7896 9169 7294 59375
Verso 1.1
122
2005
Cada mquina oferece um certo nmero de registradores que podem ser manuseados pelos usurios. Por exemplo, o computador IBM-PC oferece somente dois registradores para esse uso, portanto s podemos ter duas variveis em registradores de cada vez. Mas isto no nos impede de declarar quantas variveis da classe register que quisermos. Se os registradores estiverem ocupados, o computador simplesmente ignora a palavra-chave register das declaraes das variveis. Basicamente, variveis da classe register so usadas para aumentar a velocidade de processamento do computador. Assim, o programador deve escolher as variveis que so mais freqentemente acessadas pelo programa e declara-las como variveis da classe register. As variveis que so as candidatas mais fortes a receberem tal tratamento so as variveis de laos e os argumentos de funes. O Cdigo 4.27 apresenta um exemplo que mostra a diferena da velocidade de processamento de variveis de memria e variveis de registradores. O programa executa um teste muito simples em sua concepo, ele executa dois loops for aninhados, primeiramente utilizando variveis do tipo register e posteriormente utilizando variveis no register.
Cdigo 4.27 - Uso de variveis da classe register.
#include <stream.h> #include <time.h> main () { register int a, b; int c, d; long t; t = time(0); for (a = 0; a < 30000; a++) for (b = 0; b < 30000; b++) ; cout << "A duracao dos loops com variaveis REGISTER foi: " << (time(0) - t) << " s."; t = time(0); for (c = 0; c < 30000; c++) for (d = 0; d < 30000; d++) ; cout << "\nO duracao dos loops com REGISTER foi: " << (time(0) - t) << " s."; variaveis NAO
Verso 1.1
123
2005
} Ao executar o Cdigo 4.27 obtive, no meu computador, a seguinte sada: A duracao dos loops com variaveis REGISTER foi de 4 s. A duracao dos loops com variaveis NAO REGISTER foi de 7 s. Conforme mostrado acima, a durao dos loops for utilizando variveis register cerca de metade do tempo dos mesmos loops utilizando-se variveis comuns. O Cdigo 4.27 utiliza uma funo ainda no estuda, chamada time(), declarada no arquivo de cabealho time.h. Quando se passa o valor 0 como argumento da funo time(), esta retorna um nmero longo, que a hora corrente do sistema, em segundos, desde 1 de Janeiro de 1970, 00:00:00 GMT. Assim sendo, a funo time() uso perfeito quando se precisa criar um cronmetro cuja precisa pode ser de segundos.
Verso 1.1
124
2005
Algumas das diretivas acima no so estranhas para ns, outras ainda so novidade. Assim sendo, abordaremos a seguir as diretivas mais importantes e as mais usuais.
#include <stream.h> #define PRN(n) cout << n << '\n' main () { int a = 1416, b = 708; PRN(a); PRN(b); } Ao executar o Cdigo 4.28 obtm-se a seguinte sada: 1416 708 Toda ocorrncia da macro PRN(n) apresentada no Cdigo 4.28 ser substituda, pelo prprocessador, pelo comando cout << n << '\n' de forma que no lugar do argumento n usado o argumento usado na chamada macro. Na definio de uma macro nunca deve haver espao em branco entre o identificador da macro e o seu argumento. Por exemplo, a macro: #define PRN (n) cout << n << '\n'
28
//ERRADO
Para maiores informaes sobre o uso da diretiva #define para a criao de constantes definidas vide Captulo 1.4.2.
Verso 1.1
125
2005
no funcionar, porque o espao em branco colocado entre PRN e (n) interpretado pelo pr-processador como sendo o fim do identificador PRN.
Verso 1.1
126
2005
z = (2 + 3 * 4); e o valor atribudo varivel z ser 14, e no 20. A soluo para o problema anterior envolver cada argumento da macro por parnteses. Logicamente tal procedimento dever ser executado de maneira que a precedncia29 desejada dos operadores seja alcanada. Assim sendo o exemplo anterior ser resolvido da seguinte maneira: #define PROD(x,y) ((x) * (y))
#include <stream.h> #define PI 3.14159265358979323846 #define SQR(x) ((x) * (x)) #define AREA(x) ((4) * (PI) * SQR(x)) main () { float raio; cout << "Digite o valor do raio da esfera: "; cin >> raio; cout << "\nA area superficial da esfera e: " << AREA(raio); } Comumente uma macro pode conter instrues que no caibam todas em uma mesma linha. Para se escrever uma macro em mais de uma linha basta que se acrescente uma barra invertida (\) no final da linha, como mostrado no exemplo abaixo: #define MAIUSC(ch) ((ch) >= 'a' && (ch) <= 'z')?\ ((ch) - 'a' + 'A') : (ch)
29
Verso 1.1
127
2005
#include <stream.h> #include <conio.h> #define MAIUSC(ch) ((ch) >= 'a' && (ch) <= 'z')?\ ((ch) - 'a' + 'A') : (ch) main () { char ch; cout << "Digite uma letra minuscula: "; ch = MAIUSC(getche()); }
Cdigo 4.31 - Uso de funes inline no lugar de macros.
//Problemas...
Verso 1.1
128
2005
{ return (ch >= 'a' && ch <= 'z')? (ch - 'a' + 'A') : ch; } main () { char ch; cout << "Digite uma letra minuscula: "; ch = maiusc(getche()); } Executando os dois programas acima percebe-se, e muito bem, que no programa do Cdigo 4.30 tem-se que digitar a letra trs vezes para que esta seja convertida para maiscula, o que no acontece no Cdigo 4.31. A seguir so mostrados mais dois exemplos onde o uso de uma funo inline supera o uso ineficiente de uma macro. Os Cdigos 4.32 e 4.33 apresentam um programa que retorna o menor de dois valores, sendo que o primeiro utiliza uma macro e o segundo utiliza uma funo inline para executar esta tarefa.
Cdigo 4.32 - Outro exemplo do uso incorreto de uma macro.
//Sem Problemas!!!
#include <stream.h> #define MIN(x,y) (x < y)?(x) : (y) main () { int n1 = 1, n2 = 2, n; n = MIN(n1++, n2++); cout << "n1 = " << n1 << " << " n = " << n; }
Cdigo 4.33 - Outro exemplo do uso de funes inline no lugar de macros.
#include <stream.h> inline char min (int x, int y) { return (x < y)? x : y; } main ()
Verso 1.1
129
2005
{ int n1 = 1, n2 = 2, n; n = min(n1++, n2++); problemas!!! cout << "n1 = " << n1 << " << " n = " << n; } Por mais incrvel que possa parecer, o resultado da execuo do Cdigo 4.32 a seguinte tela: n1 = 3 n2 = 3 n = 2 n2 = " << n2 //Sem
A resposta acima , logicamente, um absurdo. Inicialmente a varivel inteira n1 tem valor 1 e a varivel n2 tem valor 2. Aps o incremento de ambas, estas deveriam ter os valor 2 e 3, respectivamente, e no 3 e 3 conforme mostrado acima. Assim sendo, a varivel n deveria ser igual a 1, pois 1 < 2, que so os valores das variveis n1 e n2 antes de serem incrementadas. O resultado da execuo do Cdigo 4.33 a seguinte tela: n1 = 2 n2 = 3 n = 1
O que prova claramente que a macro do Cdigo 4.32 no se mostrou eficiente, mais uma vez, na execuo de uma tarefa simples. De uma maneira geral, no se deve usar uma macro que chama uma funo. Nos Cdigos 4.30 e 4.32 as macros problemticas eram macros que tinham funes como seus argumentos. Criar uma macro desta maneira representa, na maioria dos casos, problemas. Pode-se adotar ento, como via de regra, que sempre que um argumento a ser usado for uma funo, utilizaremos tambm uma funo para operar sobre este argumento. Caso contrrio pode-se pensar em se utilizar uma macro.
130
2005
... ... #undef GRANDE #define ENORME 10 ... ... #undef ENORME ... ... #undef ENORME ... ... #undef SOMA ...
//Remove a definicao da constante //declarada GRANDE //A constante declarada ENORME //agora vale 10 //A constante declarada ENORME //volta a valer 8 //Remove a definicao da constante //declarada ENORME //Remove a definicao da macro SOMA
Verso 1.1
131
2005
Cada diretiva #if deve sempre terminar pela diretiva #endif, que como o prprio nome diz, marca o fim da diretiva #if. Entre a diretiva #if e a diretiva #endif podem ser utilizadas quantas diretivas #elif forem necessrias, mas s pode ser utilizada uma nica diretiva #else. Tanto a diretiva #elif quanto a diretiva #else so opcionais e, caso sejam utilizadas, a diretiva #else deve ser a ltima diretiva condicional antes da diretiva #endif. Obviamente que o leitor j deve ter estabelecido a correlao lgica entre as diretivas condicionais e a estrutura tomadora de deciso if/else if/else. Apenas no sentido de elucidao, a Tabela 4.1 mostra a correlao direta entre as duas estruturas.
Tabela 4.1 - Analogia entre as diretivas de compilao condicional e operador if.
O exemplo abaixo um fragmento de cdigo-fonte, que compara uma constante definida chamada DEBUG, executando trs instrues diferentes, de acordo com o valor da constante. #define DEBUG 1 ... ... #if DEBUG == 1 cout << "ERRO = " << erro1; #elif DEBUG == 2 cout << "ERRO = " << erro2; #else cout << "ERRO nao documentado"; #endif Seja agora um outro exemplo, onde de acordo com o valor de uma constante definida chamada CORES so includos diferentes arquivos de cabealho ao programa. #if CORES > 5 #define SOMBRA 1 #if COR_FUNDO 1 #include "corfundo.h" #else #include "semfundo.h" #endif #else #define SOMBRA 0
Verso 1.1
132
2005
#if CGA == 1 #include "cga.h" #else #include "mono.h" #endif #endif Para testar uma determinada constante foi definida pode-se utilizar as diretivas #ifdef e #ifndef. O exemplo abaixo mostra como um mesmo cdigo-fonte pode gerar dois executveis diferentes entre si. Se a diretiva que define a constante VERSAO_DEMO for inserida no cdigo-fonte, o executvel s poder manipular 20 registros, e estar criada assim a verso de demonstrao do seu programa. Caso esta diretiva no esteja presente no cdigo-fonte, o programa poder manipular o nmero mximo de registros. #define VERSAO_DEMO ... ... #ifdef VERSAO_DEMO #define NUM_REC 20 #else #define NUM_REC MAXINT #endif Veja outro exemplo: #ifdef REDE #define PASSWORD #include "redes.h" #else #include "monouso.h" #endif A diretiva #ifdef vem do ingls if defined, ou seja, se definida, e a diretiva #ifndef significa if not defined, ou seja, se no definida. Assim sendo, a diretiva #ifndef verifica a no definio de uma constante definida. Por exemplo: #ifndef WINDOWS #define VERSAO "VERSAO DOS" #else #define VERSAO "VERSAO WINDOWS" #endif Uma alternativa para o uso das diretivas #ifdef e #ifndef o operador defined. O exemplo abaixo mostra o mesmo exemplo anterior, porm utilizando o operador defined ao invs da diretiva #ifndef. #if !defined(WINDOWS) #define VERSAO "VERSAO DOS"
Verso 1.1
133
2005
#else #define VERSAO "VERSAO WINDOWS" #endif O exemplo acima pode ainda ser escrito como: #if defined(WINDOWS) #define VERSAO "VERSAO WINDOWS" #else #define VERSAO "VERSAO DOS" #endif
Verso 1.1
134
2005
Verso 1.1
135
2005
c. chamadas a outras funes; d. expresses; e. prottipos de funes. 4.9. Quando argumentos so passados por valor: a. a funo cria novas variveis para receb-los; b. a funo acessa as prprias variveis da funo que a chama; c. a funo pode alterar as variveis da funo que a chama; d. a funo no pode alterar as variveis da funo que a chama. 4.10. a. b. c. d. 4.11. a. b. c. d. 4.12. a. b. c. d. 4.13. a. b. c. d. Uma funo que no recebe nenhum argumento do tipo: int; void; float; Nenhuma das alternativas acima. Uma funo que no retorna nenhum valor do tipo: int; void; float; Nenhuma das alternativas acima. A instruo int& x = y; cria a varivel x com o valor da varivel y; cria uma cpia da varivel y; x a mesma varivel que y; y uma referncia varivel x. Quando os argumentos so passados por referncia: a funo cria novas variveis para receb-los; a funo acessa as prprias variveis da funo que a chama; a funo pode alterar as variveis da funo que a chama; a funo no pode alterar as variveis da funo que a chama.
4.14. O que so referncias constantes e para que servem? 4.15. a. b. c. d. 4.16. a. b. c. Funes sobregarregadas: so um grupo de funes, todas de mesmo nome; simplificam a vida do programador; todas tm o mesmo tipo e o mesmo nmero de argumentos; sobrecarregam o programador. Funes inline: poupam memria; poupam tempo de execuo; aumentam a legibilidade do programa;
Verso 1.1
136
2005
d. usam mais memria. 4.17. a. b. c. d. 4.18. a. b. c. d. 4.19. a. b. c. d. Uma funo inline: deve ser escrita em uma nica linha; pode ser escrita em qualquer parte do programa; deve ser escrita antes da primeira chamada a ela; haver tantas cpias de seu cdigo no programa quantas forem as chamadas a ela. Uma funo recursiva: definida dentro de outra funo; contm grandes recursos; contm uma chamada a ela mesma; solicita recursos de outros programas. As funes recursivas: poupam memria; poupam tempo de execuo; aumentam a legibilidade do programa; usam mais memria.
Verso 1.1
137
2005
Verso 1.1
138
2005
6 PONTEIROS
Verso 1.1
139
2005
APNDICES
Verso 1.1
140
2005
11 1011 e assim por diante. Para converter um nmero da base decimal para a base binria basta dividir o nmero que se deseja converter por dois sucessivamente at que o resto seja 0. Uma vez realizada esta operao monta-se o binrio utilizando os restos da diviso ordenados da ltima para a primeira diviso. Este o modo como se procede para converter manualmente um nmero da base decimal para a base binria. Observe o exemplo abaixo, o qual consiste na converso do decimal 23 no seu respectivo binrio: 23 / 2 = 11 e resto 1 11 / 2 = 5 e resto 1 5 / 2 = 2 e resto 1 2 / 2 = 1 e resto 0 1 / 2 = 0 e resto 1 Portanto o decimal 23 igual ao binrio 10111. Para a realizao da operao inversa, ou seja, para a converso da base 2 para a base 10, devemos proceder exatamente ao contrrio. Para isso utiliza-se um polinmio de potncias onde os coeficientes do polinmio so os algarismos do binrio. O exemplo abaixo mostra a converso do binrio 1011 para o decimal 23. 1.24 + 0.23 + 1.22 + 1.21 + 1.20 = 16 + 0 + 4 + 2 + 1 = 23 Assim sendo, o polinmio para a converso de binrio para decimal dado por:
a n .2 n + ... + a 3 .2 3 + a 2 .2 2 + a1 .2 + a 0 =
n i =0
a i .2 i
Onde: an o n-simo dgito do binrio, ou seja, o dgito de ordem n do binrio; n a ordem do n-simo dgito do binrio.
Verso 1.1
141
2005