Você está na página 1de 140

APOSTILA DE PROGRAMAO I

PARA ENGENHARIA DE PRODUO

Prof. ANDR CARLOS SILVA

FASAR 2005 Verso 1.1

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

1 INTRODUO AO C++

1.1. Aspectos gerais da linguagem C++


Cdigo 1.1 - Um programa tpico em 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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

e no devem ser incorporados em identificadores para que no causem nenhum efeito inesperado ao funcionamento do programa.

1.1.3. Case Sensitive


Tanto a linguagem C quanto a linguagem C++ so case sensitive, que quer dizer que o compilador diferencia identificadores escritos em maisculas e em minsculas, ou seja, para o compilador o identificador x1 diferente do identificador X1. Essa propriedade vale para qualquer letra em qualquer posio de um identificador e no apenas para a primeira letra do identificador. Mediante isso altamente recomendvel que um padro para a criao e utilizao de identificadores seja adotado pelo programador.

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

Programao I Prof. Andr Carlos Silva

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> main () {cout << "Bem Vindo ao mundo do C++!\n";}

1.1.7. Arquivos de cabealho


Arquivos de cabealho so arquivos includos no programa atravs do comando #include, localizado sempre no comeo do programa. O resultado de se incluir um arquivo de cabealho o mesmo que de se incluir o contedo de todo o arquivo na mesma posio em que se incluiu a chamada ao arquivo. O que significa que uma alterao no arquivo de cabealho acarretar em mudanas em todos os programas que fazem meno a este. Os arquivos de cabealho tm a terminao .h ou .hpp, ao passo que o cdigo-fonte escrito em C++ tem a terminao .cpp. Os smbolos < > delimitam o nome do arquivo a ser includo e indicam que o arquivo est armazenado em um diretrio default chamado include, dentro da pasta onde o compilador foi instalado. Se desejarmos adicionar um arquivo de cabealho que no se encontra no diretrio include, podemos utilizar aspas ( ) para indicar que o arquivo se encontra no mesmo diretrio onde o cdigo-fonte do programa se encontra. O Cdigo 1.4 apresenta um exemplo onde o arquivo de cabealho stream.h se encontra no diretrio include e o arquivo stdio.h se encontra no mesmo diretrio do cdigo-fonte.
Cdigo 1.4 - Exemplos de usos de arquivos de cabealho.

#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

Programao I Prof. Andr Carlos Silva

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

Tipo Char Short Int Long Float Double Long double

Exemplo C -7 1024 262144 10,5 0,00045 1e-8

* Valores aproximados.

Tamanho (bytes) 1 2 2 4 4 8 8

Mnimo - 128 - 32768 - 32768 - 2147483648 1,5e-45 5,0e-324 5,0e-324

Range ... ... ... ... ... ... ...

Mximo 127 32767 32767 2147483647 3,4e38* 1,7e308* 1,7e308*

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.

1.2.1. Inicializando variveis com definies

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

Programao I Prof. Andr Carlos Silva

Cdigo 1.5 - Inicializao de variveis no momento de sua declarao.

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.

1.2.2. Escopo de uma varivel


Instrues podem se referir a variveis apenas quando estas variveis se encontram dentro do mesmo escopo, ou nvel, das instrues. O escopo de uma varivel se estende at as fronteiras do bloco que lhe define. A Figura 1.1 apresenta um cdigo-fonte escrito em C++ de carter didtico onde as variveis vo sendo declaradas em diferentes nveis do programa. A cada nvel uma nova varivel declarada e sua cor corresponde cor do quadro que delimita o escopo desta varivel. Note que a varivel Q de escopo global, ou seja sua declarao valida para todo o programa, j as demais variveis so locais.

previamente armazenados na memria do computador, o que pode causar srios transtornos na vida do programador.
Verso 1.1

16

2005

Programao I Prof. Andr Carlos Silva

Figura 1.1 - Exemplo do escopo de uma varivel.

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.

1.2.3. Inicializando variveis globais e locais


Ainda que estas se apresentem de maneira muito semelhante nos programas, variveis globais e locais so armazenadas na memria de maneiras muito diferentes. O compilador reserva um espao fixo na memria para cada varivel global, denominado segmento de dados. Ao fazer isso o compilador inicializa todas as variveis globais com o valor zero (no caso das variveis do tipo char o seu contedo nulo, do ingls void). J para as variveis locais o compilador cria um espao temporrio denominado de pilha (do ingls stack). Conforme j mencionado, todas as variveis globais so inicializadas automaticamente com o valor nulo quando o programa executado, mas o mesmo no ocorre com as variveis locais, que podem ser inicializadas com algum lixo da memria.

Verso 1.1

17

2005

Programao I Prof. Andr Carlos Silva

1.3. Entrada e sada de dados


As instrues de entrada e sada de dados (I/O, do ingls Input/Output) de um programa se responsabilizam por todas as trocas de dados entre o computador e meio externo, como por exemplo a apresentao de textos em vdeo, a impresso de relatrios, o recebimento de um dado emitido diretamente pelo usurio via teclado ou mesmo a comunicao com sistemas remotos atravs de uma linha telefnica ou porta serial.

1.3.1. Fluxos de sada de dados


Cdigos-fonte j mostrados usaram instrues de fluxo de sada para apresentar strings e valores de variveis na tela. O cdigo 1.6 mostra um exemplo mais prtico desta tarefa, exibindo na tela do computador a data e a hora atual, fornecida pelo relgio do sistema.
Cdigo 1.6 - Programa que retorna a data e a hora atual.

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

Programao I Prof. Andr Carlos Silva

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

1.3.2. Sada de dados no estilo C


Cdigo 1.7 - O comando PRINTF.

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

1.3.3. Sada de dados formatada


A formatao de dados muito usada quando se tm variveis de um determinado tipo e se deseja imprimir o seu contedo como outro tipo, ou com um determinado nmero de casas decimais. Suponha o caso em que um programa realiza determinadas contas com nmeros inteiros e, em seu final, deseja-se que o resultado seja impresso nas bases octal, hexadecimal e decimal. Neste caso pode-se utilizar uma funo de formatao de dados para que a sada dos dados seja como a desejada. O Cdigo 1.8 mostra um exemplo da formatao de dados para a impresso.
Cdigo 1.8 - Exemplo de converso de formato de dados.

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

Programao I Prof. Andr Carlos Silva

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.

1.3.4. Fluxos de entrada de dados


Para que um dado flua para fora do computador usamos a instruo cout, j agora para que um dado flua para dentro do computador usaremos a instruo cin7 (do ingls character input). O comando cin um comando de atribuio no qual atribudo a uma varivel um dado. O Cdigo 1.9 apresenta um programa que solicita ao usurio que digite trs nmeros reais e retorna o valor da mdia destes trs valores.
Cdigo 1.9 - Programa para clculo da mdia de trs nmeros.

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

" << (a+b+c)/3 <<

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.

//Programa para calcular a media de trs nmeros reais #include <stream.h>


7

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

Programao I Prof. Andr Carlos Silva

#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

Constantes literais Constantes definidas

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

Programao I Prof. Andr Carlos Silva

Constantes declaradas Constantes enumeradas

1.4.1. Constantes literais


So a forma mais comum de constantes e se compem de valores numricos ou alfanumricos digitados diretamente no cdigo-fonte do programa. A forma de uma constante literal determina o seu tipo de dados, que pode ser qualquer um dos tipos listados na Tabela 1.1 referentes a variveis, uma vez que uma constante uma varivel na qual o programa no pode alterar o seu valor durante a sua execuo.

1.4.1.1. Constantes literais do tipo caractere (char)


Usualmente uma constante do tipo char representa smbolos constantes no conjunto de caracteres ASCII e que so envolvidos por apstrofos ( ). Exemplos de constantes do tipo char so $, U, z, ?. Como esses smbolos so representados internamente por nmeros inteiros de 0 a 255 (que so a tabela ASCII propriamente dita), constantes do tipo char tambm podem ser usadas para armazenar nmeros dentro dessa mesma faixa. Isso torna o tipo char conveniente para o armazenamento de pequenos valores ocupando apenas um byte. Deve-se tomar ateno quanto ao fato da constante char estar ou no declarada como uma constante dotada de sinal (signed). Constantes, e/ou variveis, signed representam grandezas positivas e negativas, mas constantes, e/ou variveis, unsigned representam apenas valores positivos10. Assim sendo, apesar de constantes unsigned char representares valores entre 0 e 255, constantes signed char representam valores entre 128 e 127. O mesmo vlido para os outros tipos de constantes/variveis, uma constante unsigned int pode variar entre 0 e 65535, j constantes signed int podem variar entre 32768 e 32767. Os quatro tipos de inteiros (char, short, int e long) so signed por default. Para imprimir na tela caracteres que no podem ser digitados diretamente via teclado podese usar comandos, tal como '\n' para representar um caractere de new-line, que so caracteres denominados de cdigos de escape. A Tabela 1.2 lista outros cdigos de escape que o compilador C++ reconhece. Pode-se usar os cdigos de escape como constantes do tipo char individuais, ou seja, dentro de apstrofes, ou como de strings, ou seja, dentro de aspas.

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

Decimal 7 8 12 1310 13 9 11 92 39 34 63 Todos Todos

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

1.4.1.2. Constantes do tipo string


Em C++ uma string pode ter qualquer tamanho e pode conter quaisquer caracteres que se possa digitar entre duas aspas, bem como quaisquer dos cdigos de escape da Tabela 1.2. Na memria do computador, as strings so representadas por uma srie de valores de caracteres ASCII alm do 0 ou NULL. O caractere NULL marca o fim de uma string e inserido automaticamente pelo C++ ao final das constantes do tipo string. Como strings terminam com NULL, no se deve utilizar aspas para representar caracteres simples. Se isso for feito, pode-se estar desperdiando espao da memria. Por exemplo, "J" uma string composta por dois caracteres (um caractere para representar a letra J e outro para o NULL, sendo este invisvel ao final da string), j 'J' um caractere simples, ocupando apenas um byte de espao na memria e no demandando um valor NULL para marcar o seu fim.

1.4.1.3. Constantes do tipo inteiro (int)


Quando se trabalha com constantes do tipo inteiro deve-se tomar os seguintes cuidados: a. Nunca use virgula ou outra pontuao em nmeros inteiros. Entre com 123456 e no com 123,456 ou 123.456. b. Para forar que o valor seja do tipo long, coloque em seu final a letra L maiscula. Por exemplo, 1024 do tipo int, mas 1024L do tipo long. c. Para forar que o valor seja do tipo unsigned, coloque em seu final um U maisculo.

Verso 1.1

23

2005

Programao I Prof. Andr Carlos Silva

1.4.1.4. Constantes do tipo real (float)


Valores do tipo real so sempre do tipo signed. Pode-se entrar com valores reais de maneira usual (como por exemplo 1.2 ou 555.9), ou ento usando notao cientfica, colocando-se aps o nmero um E seguido de um expoente, positivo ou negativo. Assim, o nmero 10.589,25 pode ser representado por 1.058E4 (sendo que aqui a preciso escolhida foi de trs casas decimais).

1.4.2. Constantes definidas


As constantes literais so comuns e teis, mas lhes falta clareza. Por exemplo, o que significa a constante literal 51? Trata-se da idade de algum? Do nmero de batatas em ma lata? De um nmero sorteado na loteria? 51 pode ser quaisquer destes valores ou um infinito de outros. Como constantes literais podem confundir a pessoa que est lendo o programa, deve-se dar nomes s constantes. Um modo de se dar nome a uma constante usar o comando #define. Como exemplo tem-se: #define NUMERO 51 #define NOVALINHA '\n' As linhas acima no so instrues, por isso no terminam em ponto-e-vrgula. Elas so linhas de controle e no ocupam qualquer espao no cdigo compilado. No corpo de um programa o compilador substitui um smbolo definido por #define com o texto associado. O programa apresentado no Cdigo 1.11 define duas constantes e imprime o valor de cada uma delas na tela.
Cdigo 1.11 - Uso de #define para a declarao de constantes.

#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

Programao I Prof. Andr Carlos Silva

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

1.4.3. Constantes declaradas


Um segundo modo, freqentemente preferido, de se criar uma constante em programas anteceder uma definio normal de varivel com a palavra-chave const. Uma vez feito isso, o compilador rejeita quaisquer instrues que tentem alterar os valores definidos desta forma. O programa apresentado no Cdigo 1.12 o mesmo programa do Cdigo 1.11, mas com a diferena deste declarar todas as suas constantes com o comando const e no com o comando #define. Observe que as definies com const especificam tipos de dados, terminam com ponto-e-vrgula e so inicializadas como variveis comuns. O comando #define no especifica tipo de dados, no uso o smbolo de atribuio (=) e no termina com ponto-e-vrgula.
Cdigo 1.12 - Uso do comando const para a declarao constantes.

#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

Programao I Prof. Andr Carlos Silva

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.

#include <stream.h> #define X 5 #define Y X+5 main () {

Verso 1.1

26

2005

Programao I Prof. Andr Carlos Silva

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.

1.4.4. Constantes enumeradas


Pode-se usar constantes enumeradas para criar listas de categorizadas. O exemplo clssico de constantes enumeradas o de uma lista de cores, onde cada cor recebe um valor inteiro, comeando em zero. Tal lista til devido ao fato de podermos trabalhar com o nome da cor ao invs de seu respectivo cdigo. Em C++ pode-se gerar uma lista enumerada da seguinte maneira: enum cores {VERMELHO, LARANJA, AMARELO, VERDE, AZUL, INDIGO, VIOLETA}; O comando acima associa os elementos constantes listados entre chaves (VERMELHO, LARANJA, ... , VIOLETA) ao identificador cores, que um nome atribudo a este novo tipo de dados. O comando enum diz ao compilador que os itens entre chaves so constantes e devem ser enumeradas, isto , a estes itens devem ser associados nmeros inteiros seqenciais. Quando o compilador processa esse comando ele atribui valores, comeando de 0, para cada elemento enumerado de forma que VERMELHO seja igual a 0, LARANJA igual a 1 e VIOLETA igual a 6. Aps um novo tipo enumerado de dados ser declarado pode-se criar variveis desse mesmo tipo, assim como se faz com variveis de outros tipos de dados. Por exemplo, pode-se definir uma varivel do tipo cores e faze-se isso da seguinte maneira:

Verso 1.1

27

2005

Programao I Prof. Andr Carlos Silva

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

<< (int)linguagens = " <<

Na realidade o compilador inicializa a varivel corFavorita com o valor numrico da varivel AZUL, que igual a 4.

Verso 1.1

28

2005

Programao I Prof. Andr Carlos Silva

<< "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.4.5. Atribuio de valores a elementos enumerados


Normalmente melhor deixar o compilador atribuir os valores seqenciais aos elementos de tipos enumerados de dados. Porm, em caso de necessidade, pode-s alterar os valores que o compilador associa a cada elemento. Para atribuir um valor especfico a um elemento enumerado basta que se coloque aps o elemento o sinal de igual e o valor desejado. Por exemplo: enum semforo {VERDE, AMARELO = 10, VERMELHO}; No exemplo acima o elemento VERDE igual a 0, o elemento AMARELO igual a 10 e o elemento VERMELHO igual a 11. Elementos enumerados que por ventura viessem aps o elemento VERMELHO teriam valores crescentes a partir do nmero 12. Pode-se atribuir valores explcitos para mais de um elemento enumerado. Quando precisamos criar tipos enumerados de dados com elementos cujos valores coincidam com outras constantes (tais como nmeros de referentes a erros no sistema operacional, portas de I/O e outras grandezas constantes), a possibilidade de iniciar novas seqncias dentro da declarao de tipo enum extremamente til.

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

Programao I Prof. Andr Carlos Silva

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.

1.5.1. Operadores e precedncia


O C++ possui mais operadores que os operadores matemticos bsicos (+, , *, /). Existem operadores que criam funes, operadores para vetores, operadores que incrementam e decrementam valores e operadores complexos que executam mais de uma tarefa de uma s vez. A Tabela 1.3 apresenta os operadores da linguagem C++ e tambm mostra os seus nveis de precedncia. Em sua utilizao normal, operadores de menor precedncia executam as suas operaes em expresses antes de operadores de maior precedncia.

Tabela 0.3 - Operadores usados em C++ e sua respectiva precedncia.

Nvel de precedncia 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Operador12 ( ) . [ ] -> :: ->* this & * & nem delete ! ~ ++ -- - sizeof * / % + << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= <<= >>= &= ^= |= '

1.5.2. Operadores de incremento e decremento


Dois dos mais usados operadores da linguagem C e C++ so os operadores de incremento (++) e decremento (--). O operador ++ incrementa o seu argumento em uma unidade, ao passo que o operador decrementa o seu argumento em uma unidade. Os exemplos abaixo mostram a grande utilidade que os operadores de incremento e decremento podem ter: i = i + 1; i++; j = j 1;
12

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

Programao I Prof. Andr Carlos Silva

j--;

//Subtrai 1 da varivel do tipo int 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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

1.6. Exerccios do captulo


1.1. Escreva um programa que solicite o seu primeiro nome e imprima uma mensagem na tela incluindo o nome fornecido. 1.2. Explique o significado dos smbolos //, /* e */ nas linhas abaixo: /*Prompt para a entrada de dados*/ cout << "Entre com o valor: "; //Prompt para um valor cin >> valor; //L o valor 1.3. Escreva o menor programa em C++ possvel de ser compilado e executado. 1.4. Quais destes identificadores so vlidos: myMoney, 2por1, _max, _max_Value, $Balance, A_L_F_A_B_E_T_O_? Prove a sua resposta. 1.5. Escreva um programa que exiba os sinais de pontuao da linguagem C++. 1.6. Explique o que so espaos em branco e para que so usados. 1.7. Que tipo ou tipos de dados podem armazenar os valores 145540, 145.543 e 10? Qual o menor tipo que pode armazenar estes valores? 1.8. Com uma nica linha de cdigo, defina uma varivel de denominada alfa do tipo char e atribua o caractere A varivel. 1.9. Quais so as duas principais diferenas entre uma varivel local e um global? 1.10. Escreva um programa que exiba na tela a seguinte linha: Idade = 70, Aniversrio = 01/10/1931, Saldo = $1300.76 Onde os valores 70, 01, 10, 1931 e 1300.76 fiquem armazenados em variveis do tipo int denominadas idade, dia, ms e ano em uma varivel real denominada saldo, respectivamente. 1.11. Escreva dois programas, sendo que ambos devem apenas ler um valor real digitado pelo usurio, armazena-lo em uma constante real e imprimi-lo na tela. No primeiro programa use uma instruo de fluxo de entrada de dados para armazenar o valor digitado diretamente em uma varivel real. No segundo armazene o valor primeiramente em uma string e depois o atribua para uma varivel real. Por que o segundo mtodo mais seguro? 1.12. Escreva um programa que exiba na tela a seguinte frase, incluindo todas as aspas e o apstrofo:

Verso 1.1

34

2005

Programao I Prof. Andr Carlos Silva

"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

Programao I Prof. Andr Carlos Silva

2 INSTRUES E OPERADORES AVANADOS

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.

2.1. Operadores avanados


No Captulo 1 aprendemos sobre os operadores da linguagem C++, que so smbolos que executam aes sobre seus argumentos. Por exemplo, o sinal de mais (+) um operador com um propsito bvio, somar dois valores. Nesta seo, porm, encontraremos alguns dos operadores do C++ menos bvios. Operadores que podem comparar valores, avaliar expresses e manipular bits na memria. Iremos tambm aprender como usar abreviaes prticas para escrever expresses.

2.1.1. Entendendo os operadores relacionais


Os operadores relacionais do C++ permitem que se escrevam instrues para comparar valores. Quando um programa executa uma expresso relacional ele avalia seus

Verso 1.1

36

2005

Programao I Prof. Andr Carlos Silva

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

Operador < <= > >= == !=

Descrio Menor que Menor ou igual a Maior que Maior ou igual a Igual a Diferente de

Exemplo (a < b) (a <= b) (a > b) (a >= b) (a == b) (a != b)

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

Programao I Prof. Andr Carlos Silva

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

2.1.2. O comando If, Else If e Else


O uso de expresses relacionais e instrues if/else permite que o programa mude o seu curso tendo como base a sua entrada de dados. O Cdigo 2.1 utiliza um tipo de instruo denominada if/else, que a principal estrutura tomadora de decises no C++. Sua utilizao bastante simples, basta apenas acrescentar uma expresso relacional entre parnteses aps a palavra-chave if e ento o bloco de instrues que se deseja realizar se (do ingls if) a expresso relacional seja avaliada como verdadeira. A estrutura else if funciona da mesma maneira que o if e equivale pergunta ou se. O uso da estrutura else, como o da estrutura else if, sempre opcional e este no precisa de expresso relacional, uma vez que a sua finalidade abranger todos os casos que no foram tratados pelas estruturas if/else if anteriores. Basicamente um bloco if/else if/else funciona com mostrado no cdigo 2.2.
Cdigo 2.2 - A estrutura if / else if / else.

if (expresso relacional 1) {Bloco de comandos a serem relacional 1 seja verdadeira}

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

Programao I Prof. Andr Carlos Silva

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.

2.1.3. Entendendo os operadores lgicos


Como j foi visto na seo anterior, os operadores relacionais nos capacitam a escrever expresses que executam aes baseadas na veracidade ou falsidade de vrias condies. Os operadores lgicos expandem essa idia, fornecendo-nos os meios para avaliar expresses relacionais mltiplas (ou interdependentes) de modo a se obter um nico resultado, verdadeiro ou falso. Por exemplo, suponha o caso em que se deseja exibir o valor de uma varivel chamada conta, apenas se este se encontrar entre 1 e 100.

2.1.3.1. O operador lgico E


Uma forma de se fazer isso usando o operador lgico E, representado em C++ por && (ou and, de acordo com o ingls) que combina o resultado de duas expresses relacionais. O operador lgico && retorna um valor verdadeiro se ambas as expresses relacionais as quais este est associado forem verdadeiras, ou seja, se a primeira e a segunda expresso relacional forem verdadeiras. Para este caso pode-se proceder da seguinte maneira: if ((conta >= 1) && (conta <= 100)) cout << "Conta = " << conta; Poderamos tambm escrever a expresso acima de forma a parecer com a expresso matemtica 1 < conta < 100 da seguinte forma: if ((1 <= conta) && (conta <= 100)) cout << "Conta = " << conta; Desta forma, um programa que contivesse o cdigo acima s exibiria a mensagem acima caso o valor da varivel conta estivesse compreendido entre 1 e 100, inclusive.

2.1.3.2. O operador lgico OU


Um outro operador lgico o OU, representado em C++ por ||. Assim como com &&, pode-se usar o operador || para criar expresses relacionais complexas que executem um

Verso 1.1

39

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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.

2.1.3.3. O operador lgico NOT


Alm dos operadores lgicos que funcionam com dois argumentos (ditos binrios), o C++ tambm possui um operador lgico unrio denominado NOT e representado por um ponto de exclamao (!). O operador ! reverte o resultado de uma expresso relacional, mudandoa de verdadeira para falsa, ou vice-versa. Para executar uma instruo se uma condio no for verdadeira, pode-se escrever algo do tipo: if (!(conta < 100)) cout << "A conta >= 100"; A expresso if (!(conta < 100)) consiste na verdade de duas expresses. A primeira a expresso relacional mais interna (conta < 100), que gera um resultado verdadeiro ou falso dependendo do valor da varivel conta. A segunda expresso a aplicao do operador ! sobre o resultado da primeira expresso, mudando o seu valor. O efeito final a execuo da instruo de sada apenas se conta no for menor que 100.

2.1.4. Avaliando o resultado de operadores


Todo operador opera sobre um, ou mais, operandos e a operao por eles executada gera um resultado. Os operandos so avaliados como operandos numricos ou como operandos lgicos, dependendo do operador em questo. Da mesma forma, o resultado de uma operao pode ser um valor numrico ou um valor lgico. O modo de avaliao dos operandos e o resultado produzido pelos operadores aritmticos, relacionais e lgicos esto resumidos na Tabela 2..
14

A funo exit est declarada no arquivo de cabealho stdlib.h.

Verso 1.1

41

2005

Programao I Prof. Andr Carlos Silva

Tabela 0.2 - Modo de avaliao de operandos e resultados produzidos por operadores aritmticos, relacionais e lgicos.

Operadores Aritmticos Relacionais Lgicos

Operandos Numricos Numricos Lgicos

Resultado Numrico Lgico Lgico

2.1.5. Entendendo o operador condicional ternrio


O operador condicional ternrio o nico operador em C++ que opera sobre trs expresses. Sua sintaxe geral possui a seguinte construo: exp1 ? exp2 : exp3; A primeira expresso, ou exp1, sempre avaliada primeiro. Se o seu valor for diferente de zero esta considerada verdadeira15 e a segunda expresso, a exp2, avaliada. O resultado da segunda expresso ser ento o resultado da expresso condicional como um todo. Se a primeira expresso for igual a zero a terceira expresso, a exp3, avaliada e o seu resultado ser o resultado da expresso condicional como um todo. O Cdigo 2.4 apresenta um programa que solicita ao usurio dois nmeros inteiros e, de posse destes, utiliza o operador condicional ternrio para verificar qual dos dois o maior. Esta uma aplicao dentre muitas deste operador que, apesar de simples, uma poderosa ferramenta de programao.
Cdigo 2.4 - Uso do operador condicional ternrio.

#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

Programao I Prof. Andr Carlos Silva

2.2. Operadores de Bits


Em muitas linguagens computacionais difcil manipular bits na memria do computador, mas isso no se aplica ao C++. O C++ uma linguagem de alto nvel, mas que no impede que o programador escreva cdigos que operem no nvel do sistema operacional. Uma razo para se trabalhar diretamente com bits na memria o armazenamento de informaes no menor espao possvel. Por exemplo, um certo bit em um registro de banco de dados poderia representar o status corrente de um fato, sendo 1 para sim e 0 para no, ou 0 para masculino e 1 para feminino. Uma srie de bits tambm poderia representar um conjunto de valores: se o bit 1 estiver ligado, o valor de A considerado como pertencendo ao conjunto, se o bit 2 estiver ligado, o valor B pertence ao conjunto e assim por diante. Muitos programadores preferem utilizar a linguagem assembler (ou assembly) para programao em baixo nvel, uma vez que esta manipula tanto memria quanto hardware bit a bit. Porm, provavelmente mais fcil usar os operadores de bits do C++ listados na Tabela 2.3. Com estes operadores pode-se manipular bits como se estes fossem valores inteiros, com resultados comparveis em velocidade e eficincia aos resultados da linguagem assembler.
Tabela 0.3 - Operadores de Bits.

Operador & | ^ << >> ~

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.

2.2.1. O operador binrio E


O primeiro operador da Tabela 2.3 o operador binrio E. Tal operador s retorna 1 se os dois bits originais comparados forem iguais a 1. Em todos os outros casos o resultado sempre zero. A Tabela 2.4 mostra os possveis resultados para o uso do operador E binrio.
Tabela 0.4 - Possveis resultados para o operador E binrio.

A&B=C 0&0=0 0&1=0 1&0=0 1&1=1

Verso 1.1

43

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

2.2.2. O operador binrio OU


O segundo operador da Tabela 2.3 o operador binrio OU. Tal operador retorna 1 se um, ou ambos, bits originais comparados forem iguais a 1. Em todos os outros casos o resultado sempre zero. A Tabela 2.5 mostra os possveis resultados para o uso do operador OU binrio.
Tabela 0.5 - Possveis resultados para o operador OU binrio.

A|B=C 0|0=0 0|1=1 1|0=1 1|1=1

Verso 1.1

45

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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.

2.2.3. O operador binrio OU exclusivo

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

Programao I Prof. Andr Carlos Silva

<< << cout << cout << << << }

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.

2.2.4. Aplicaes dos operadores binrios


Saber como, quando e por que usar os operadores &, | e ^ exige prtica. Como j mencionado, & freqentemente usado para mascarar ou para desligar (ou zerar) determinados bits permitindo que outros bits sigam inalterados. Seja o exemplo de aplicarmos o operador E aos nmeros 45001 e 15, obtendo o seguinte resultado: 45001 afc9 1010111111001001 E ............................................................................................................................................... ............................................................................................................ 15 f 1111 ======================================== Igual a: 9 9 1001 O operador | usado tipicamente para o propsito oposto do operador &, ou seja, para ligar (ou mudar o valor para 1) de determinados bits permitindo que outros bits sigam inalterados. Seja o exemplo de aplicarmos o operador OU aos nmeros 45001 e 15, obtendo o seguinte resultado: 45001 afc9 1010111111001001 OU ............................................................................................................................................ ............................................................................................................ 15 f 1111 ======================================== Igual a: 45007 afcf 1010111111001111 O operador ^ freqentemente utilizado como uma chave para tornar bits 1 em 0 e 0 em 1. Uma caracterstica do comando XOR o fato de, ao se aplicar este operador a um argumento e a uma mscara, obtm-se um resultado tal que, se aplicado novamente o mesmo operador e a mesma mscara ao resultado obtido restaura-se o valor original. Seja o

Verso 1.1

48

2005

Programao I Prof. Andr Carlos Silva

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.

2.2.5. Operadores de deslocamento de bits


At agora examinamos apenas trs dos seis operadores de bits da linguagem C++ apresentados na Tabela 2.3. Os outros trs operadores permitem que expresses desloquem bits para a esquerda e para a direita e faam o complemento de todos os bits de valores inteiros, mudando os zeros para uns e vice-versa. Os operadores de deslocamento de bits se dividem em: i. Operador de deslocamento de bits para a esquerda (<<), utilizado em dois argumentos, como por exemplo V1 << 2, faz com que o valor de V1 seja deslocado para a esquerda em dois bits. ii. Operador de deslocamento de bits para a direita (>>), utilizado em dois argumentos, como por exemplo V1 >> 2, faz com que o valor de V1 seja deslocado para a direita em dois bits. O Cdigo 2.8 apresenta um programa exemplo da utilizao dos operadores de deslocamento de bits, tanto direita quanto esquerda. O programa solicita ao usurio que este lhe informe dois nmeros inteiros, de posse destes o programa desloca o primeiro valor de acordo com o segundo valor, para a esquerda e para a direita.
Cdigo 2.8 - Uso dos operadores de deslocamento de bits.

#include <stream.h>

Verso 1.1

49

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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.

2.2.6. O operador binrio NOT


O operador de bits restante em C++ o operador NOT binrio, representado pelo smbolo ~. Este operador funciona um pouco diferentemente do que os outros operadores de bits, em vez de utilizar dois argumentos, o operador NOT binrio um operador unrio que se aplica ao valor localizado sua esquerda (semelhantemente ao operador NOT lgico (!)). Por exemplo, a expresso ~conta complementa o valor de conta, chaveando todos os bits 1 para 0 e os bits 0 para 1. Como acontece com outros operadores (exceto ++ e --) o uso do operador NOT binrio no altera diretamente o valor da varivel, no exemplo conta, e deve-se atribuir o resultado desta operao a uma varivel quando se deseja armazen-lo. O Cdigo 2.9 mostra um programa exemplo do uso do operador NOT binrio.
Cdigo 2.9 - Uso do operador NOT binrio.

#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

Programao I Prof. Andr Carlos Silva

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;

2.2.7. Atribuies combinadas


Examine a instruo: conta = conta & ~1; Tal instruo pega o valor da varivel conta, aplica-lhe o operador & sobre o complemento do nmero 1 e, ento, atribui o resultado varivel conta. Para esse, e outros casos similares, em que um operador age sobre uma varivel e, ento, o resultado da operao atribudo de volta varivel original, o C++ possui um operador especial que abrevia a expresso, realizando o que conhecido como atribuio combinada. Para utilizar um operador de atribuio combinada basta que se acrescente um sinal de igual a qualquer um dos operadores: +, -, *, /, %, <<, >>, &, ^ ou |. Por exemplo, em vez de se escrever conta = conta & ~1, pode-se escrever: conta &= ~1; O C++ interpreta o operador combinado como uma instruo para executar uma operao com o valor inicial (a varivel conta neste caso) e, ento, atribuir o resultado de volta a essa mesma varivel. A seguir so listados alguns outros exemplos que mostram usos de atribuies combinadas. conta conta conta conta conta += -= *= *= %= 10; 2; 5; conta; 16; //Equivale //Equivale //Equivale //Equivale //Equivale a: a: a: a: a: conta conta conta conta conta = = = = = conta conta conta conta conta + * * % 10; 2; 5; conta; 16;

Verso 1.1

52

2005

Programao I Prof. Andr Carlos Silva

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.

2.3. Instrues de fluxo de programa


Talvez voc j tenha notado uma deficincia em todos os cdigos-fonte mostrados nesta apostila. Em todos os casos (exceto nos cdigos onde foi utilizada a funo inttobin, criada por ns), os programas comeam no seu topo e correm em linha reta at o seu trmino. Obviamente, a maioria dos programas de computador no funcionam assim, pelo contrrio, eles percorrem loops18, saltam de uma seo para outra e no terminam at que o usurio lhe d um comando especfico. Nas prximas pginas desta apostila explicaremos como adicionar estas, e outras, caractersticas aos seus programas. Programas em C++ tm seu incio na primeira instruo dentro do bloco da funo main e continuam a executar uma instruo aps a outra at alcanarem as chaves que fecham tal bloco. Isso verdade a menos que uma instruo altere o fluxo normal de um programa. Chamo as instrues desta categoria de instrues de fluxo de programa, apesar desta no ser uma expresso oficial. Elas tambm so conhecidas por estruturas de controle. Uma instruo de fluxo de programa controla a ordem na qual outras instrues so executadas. Estas podem interromper os programas, tomar decises, escolher elementos de um conjunto de acordo com alguma condio e repetir uma ou mais instrues. Com instruo de fluxo de programa pode-se escrever programas que rodem at que um determinado evento planejado ocorra ou at que o usurio deseje que o programa pare.

2.3.1. O comando EXIT


Em condies normais os programas escritos em C++ se interrompem aps a execuo da ltima instruo de main, ou seja, quando se atinge as chaves que fecham o bloco de main. Depois disso, o sistema operacional recupera o controle de modo que se possa dar novos comandos ou executar outros programas. Uma maneira de interromper um programa atravs da execuo de uma instruo denominada exit. Conforme j mencionado, a instruo exit retorna um valor inteiro, sem sinal, de volta para o sistema operacional, valor este que um arquivo batch pode recuperar, examinando a varivel errorlevel. Antes de usar a instruo exit um programa dever incluir o arquivo cabealho stdlib.h. O Cdigo 2.10 mostra um programa em que, de acordo com a vontade do usurio, o programa se encerra e retorna um valor diferente para o sistema operacional.

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

Programao I Prof. Andr Carlos Silva

2.3.2. O comando WHILE


O comando while, tambm denominado de loop while, tem por finalidade a repetio de uma ou mais instrues enquanto uma determinada condio for verdadeira. Por exemplo, se conta for uma varivel inteira, o loop while que segue abaixo exibir na tela do computador uma contagem de 1 at 10. conta = 1; while (conta <= 10) cout << conta++ << '\n'; Pode-se tambm executar um bloco de instrues dentro de um loop while, para isso basta delimitar o bloco de instrues com chaves. Em geral, um loop while tem a seguinte forma: while (expresso) { //Instrues a serem executadas enquanto a expresso for //verdadeira } Sendo que a (expresso) pode ser qualquer expresso que gere um resultado verdadeiro ou falso, ou seja lgico.

2.3.3. O comando SWITCH


Quando se elabora um programa em que este precisa selecionar uma de vrias aes durante a sua execuo, pode-se usar uma srie de instrues if/else. Por exemplo, suponha que um programa dever executar determinadas aes, de acordo com uma varivel resposta do tipo caractere, quando esta for igual a 'A', 'B' ou 'C'. Para fazer isso poderia-se usar uma estrutura do tipo: if (resposta == 'A') { //Instrues a serem executadas se resposta == A;} else if (resposta == 'B') { //Instrues a serem executadas se resposta == B;} else if (resposta == 'C') { //Instrues a serem executadas se resposta == C;} else { //Instrues a serem executadas quando resposta possuir //outro valor que no A, B ou C;} No h nada de errado com a construo anterior, a no ser que esta muito longa e que pode facilmente levar a erros. Uma alternativa construo anterior o uso do comando switch, que permite que se atinja os mesmos objetivos da construo anterior, mas de uma forma mais inteligvel, se assemelhando a uma tabela. A seguir apresentada uma verso da construo anterior, porm usando o comando switch. Nesta construo, os cases (ou casos 'A', 'B' e 'C' neste exemplo) marcam as sees que devem ser

Verso 1.1

55

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

case 'Q': cout << "*Voce selecionou sair do programa!!! break; default: cout << "*Opcao invalida. Tente de novo!!! } cout << linha; }

*";

*";

2.3.4. O comando DO/WHILE


A instruo do/while executa uma, ou mais instrues enquanto uma expresso seja verdadeira. A diferena do comando do/while para o comando while que o teste da expresso relacional no feito no comeo do loop, mas sim em seu trmino. Em geral, o loop do/while se apresenta como mostrado no Cdigo 2.13.
Cdigo 2.13 - Uso do comando DO/WHILE.

do { //Instrues a serem //verdadeira; } while (expresso);

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

Programao I Prof. Andr Carlos Silva

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.

2.3.5. O comando FOR


Quando se sabe, ou quando o programa pode calcular previamente o nmero de vezes que um bloco de instrues deve ser executado, o uso do comando for normalmente a melhor escolha para a construo de um loop. Todo comando for em C++ apresentam os seguintes elementos: A palavra-chave for Trs expresses, delimitadas por parnteses e separadas por ponto-e-vrgulas Uma instruo, ou um bloco de instrues a serem executados Um loop for combina os trs elementos acima tendo como formato geral o Cdigo 2.14.
Cdigo 2.14 - Uso do comando FOR.

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

Programao I Prof. Andr Carlos Silva

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

2.3.6. Elementos de um loop FOR mltiplo


Pode-se separar elementos de um loop for mltiplo por vrgulas, para que sejam executadas mais de uma inicializao e expresses dentro do mesmo loop. Por exemplo, para contar uma varivel interia i de 0 a 9 e, ao mesmo tempo, contar uma outra varivel inteira j de 9 a 0, pode-se escrever: for (i = 0, j = 9;((i <= 9)&&(j >= 0));i++, j--) cout << "\ni = " << i << " j = " << j;

Verso 1.1

60

2005

Programao I Prof. Andr Carlos Silva

2.3.7. Loop eterno usando o comando FOR


Quando a expresso existente no comando for nunca seja falsa, o que ocasiona no fim do loop, dizemos que o loop um loop eterno, pois este nunca ter fim19, ou simplesmente que este um loop FOREVER. O exemplo mais simples de um loop for infinito o caso: for (;;) { //Instrues a serem realizadas "eternamente"; } O loop acima no inicializa nada, no testa nada e no incrementa nenhuma varivel de controle. Os dois ponto-e-vrgulas dentro dos parnteses so necessrios para marcar o lugar dos elementos que foram omitidos.

2.3.8. O comando BREAK


Algumas vezes til interromper o progresso de um loop while, do/while ou for. Para faze-lo basta que se insira uma instruo break no ponto onde se deseja parar o loop. O Cdigo 2.16 mostra um programa exemplo do comando break.
Cdigo 2.16 - Uso do comando BREAK.

#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

Programao I Prof. Andr Carlos Silva

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.

2.3.9. O comando CONTINUE


Enquanto um comando break encerra imediatamente um loop, uma instruo semelhante, mas oposta em sua concepo o comando continue, que fora um loop a comear a sua prxima iterao, voltando ao incio do bloco de instrues. O Cdigo 2.17 demonstra a diferena entre os dois comandos.
Cdigo 2.17 - Uso do comando CONTINUE.

#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

Programao I Prof. Andr Carlos Silva

2.9. Exerccios do captulo


2.1.Em expresses relacionais, quais valores so utilizados internamente pelo compilador C++ para representar verdadeiro e falso? 2.2. Explique a diferena entre == e =. 2.3. Escreva um programa em C++ utilizando um loop que solicite ao usurio um valor entre 1 e 100. Se o usurio digitar um valor fora dessa faixa o programa dever exibir uma mensagem de erro e solicitar o valor novamente, s encerrando o loop quando o usurio digitar um valor entre 1 e 100. 2.4. Escreva a instruo while equivalente ao loop for que se segue: for (int contador = 0; contador > -8; contador--) { cout << "\nValor do contador: " << contador; cout << "\n--"; } 2.5. Usando operadores de bits, escreva um programa que limite a faixa de valores de uma varivel inteira qualquer entre 0 e 31. 2.6. Escreva um programa que criptografe uma string aps a entrada de uma senha e, ento, recupere a mesma string. Use o operador XOR em sua resposta. 2.7. Escreva um programa que determine se um nmero inteiro digitado pelo usurio par ou mpar.

Verso 1.1

63

2005

Programao I Prof. Andr Carlos Silva

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.

3.1. Estruturas confiveis para o armazenamento de dados


Pode-se reunir variveis, at mesmo aquelas de tipos diferentes, com o uso da palavrachave struct20, a fim de criar um novo tipo de dados que reserve memria suficiente para guardar diversas variveis relacionadas de alguma maneira no mesmo lugar. Um exemplo tpico onde struct til em um programa de banco de dados voltado para o armazenamento de registros que contenham uma variedade de campos. Por exemplo, suponha que voc seja o presidente de um clube de emagrecimento e precise registrar os nomes, pesos e nmeros telefnicos dos membros do clube. Assim sendo, provavelmente voc precisar de uma srie de variveis, tais quais: char nome1[30] = "Marta"; float peso1 = 110.0; char telefone1[15] = "031-3561-1524"; char nome2[30] = "Jose"; float peso2 = 119.0; char telefone2[15] = "031-3561-1525"; char nome3[30] = "Pedro"; float peso3 = 130.0; char telefone3[15] = "031-3561-1526";
20

A palavra-chave struct j foi usada nesta apostila no Cdigo 1.6.

Verso 1.1

64

2005

Programao I Prof. Andr Carlos Silva

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

struct ExemploDeStruct { float UmFloat;


21

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

Programao I Prof. Andr Carlos Silva

int char char long }

UmInt; UmaString[8]; UmChar; UmLong;

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

ExemploDeStruct Exe; Exe.UmFloat = 4.3541;

66

2005

Programao I Prof. Andr Carlos Silva

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

Para maiores informaes sobre arquivos de cabealho consulte o Captulo 1.1.7.

Verso 1.1

67

2005

Programao I Prof. Andr Carlos Silva

{ 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

Programao I Prof. Andr Carlos Silva

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.

#include <stream.h> #include "pcdb.h" main ()

Verso 1.1

69

2005

Programao I Prof. Andr Carlos Silva

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

3.2. Estruturas aninhadas


Uma struct pode residir dentro de outra, criando um tipo de dados complexo, mas com inmeras possibilidades de utilizao para o armazenamento de todos os tipos de informaes. Por exemplo, em um banco de dados de nomes e endereos de clientes de uma seguradora, talvez se deseje incluir informaes sobre o computador pessoal de cada cliente da seguradora. Ao invs de declarar novamente todos os campos do Cdigo 3.1, poder-se-ia apenas introduzir a estrutura inventario dentro da nova estrutura criada, como por exemplo:

Verso 1.1

70

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Figura 3.3 - Representao esquemtica de um vetor de 100 nmeros inteiros.

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

3.4.1. Inicializando vetores


Quando definimos um vetor de qualquer tipo, assim como as outras variveis em C++, seus valores podem ou no ser inicializados automaticamente. Se um vetor global, todos os elementos que pertencem ao vetor recebem o valor zero (0), se o vetor for local, os seus elementos podem (e provavelmente contero) valores diferentes de zero, ou seja, lixo24. Pode-se provar as afirmaes acima executando um programa teste, conforme mostrado no Cdigo 3.8.
Cdigo 3.8 - Programa para teste da inicializao de vetores.

#include <stream.h> int i, vetor1[10];

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

|\n" |\n" |\n"


2005

79

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

3.6.1. Inicializando vetores de caracteres


Como acontece com outros vetores, pode-se inicializar vetores do tipo char alinhando os elementos individuais que comporo o vetor entre chaves, aps a definio do vetor. Normalmente, no entanto, o mais fcil simplesmente atribuir uma string como nos exemplos j vistos anteriormente (utilizando aspas para delimit-la). Todavia, se o leitor preferir, pode-se se inicializar um vetor de caracteres da seguinte maneira: char exemplo[20] = {'N','A','O',' ','U','S','U','A','L'}; A atribuio acima parece atribuir os caracteres individuais a posies sucessivas do vetor, porm, como com todos os vetores de caracteres, o que realmente acontece que o C++ armazena os caracteres, alm do demarcador NULL, na memria e atribui o endereo de 'Q' varivel exemplo. A declarao anterior idntica a declarao: char exemplo[20] = "NAO USUAL"; //Declarao mais legvel A declarao anterior usualmente mais fcil de se lidar do que listar caracteres individuais entre chaves.

3.7. Vetores e ponteiros


Uma outra maneira de se declarar uma string, conforme j visto em alguns cdigos anteriormente, usando o conceito de ponteiros (assunto que ser retomado no Captulo 5), por exemplo a varivel char *modelo definida no Cdigo 3.1. O asterisco frente do nome da varivel diz ao C++ que modelo um ponteiro para uma ou mais variveis do tipo char armazenadas em uma localidade na memria. Apesar da falta de colchetes na definio, o C++ permite que modelo seja utilizado como um vetor. A semelhana entre ponteiros como char *modelo e vetores como char modelo[20] mais que superficial. Todos os vetores em C++ so implementados como ponteiros. Suponha que definamos um vetor como este: int vetor[10]; Quando o compilador processa essa definio ele reserva espao para 10 nmeros inteiros e atribui o endereo do primeiro inteiro varivel vetor. Pode at parecer que a varivel vetor armazena os inteiros dentro dela mesma, mas, no cdigo compilado do programa, a varivel vetor implementada como um ponteiro para o primeiro elemento desse vetor. Variveis definidas como char *modelo e char modelo[20] so funcionalmente equivalentes, significando que se pode usar modelo de muitos modos semelhantes em instrues de programas. Ambas as definies criam ponteiros para a memria onde caracteres ficam armazenados, mas apenas a definio com colchetes reserva memria para esses caracteres. Por essa razo, at que voc aprenda a usar ponteiros no Captulo 5 use o
Verso 1.1

82

2005

Programao I Prof. Andr Carlos Silva

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.

3.8. Campos de bits


Freqentemente ocorre que campos em uma estrutura nunca excedem um certo valor, geralmente pequeno. Por exemplo, em um banco de dados de fatos sobre pais, um campo que representa o nmero de crianas muito raramente ser maior que 15 e, normalmente, ser igual a 2 ou 3. O campo que representa o sexo de uma pessoa necessitar de apenas um nico bit, 0 para masculino e 1 para feminino. Tal estrutura se parecia com a estrutura a seguir. struct pessoa { unsigned idade; unsigned sexo; unsigned filhos; };

//0...99 //0 = masculino, 1 = feminino //0...15

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

:7; :1; :4; :4;

//0...99 //0 = masculino, 1 = feminino //0...15 //No usado

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

Programao I Prof. Andr Carlos Silva

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:

" << p.idade << "\nFilhos: " << p.filhos;

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.

#include <stream.h> #include <bios.h>

Verso 1.1

84

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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.

3.9. O operador SIZEOF


Um operador de extrema importncia quando se fala em itens dependentes do sistema o operador sizeof, que utilizado para determinar o nmero de bytes ocupado por uma varivel ou por um tipo de dados. Por exemplo, para exibir quantos bytes um float ocupa pode-se escrever: cout << "Tamanho de um float" << sizeof(float); O C++ substitui a expresso sizeof(float) pelo nmero de bytes que uma varivel do tipo float ocupa na memria do computador. De modo similar, pode-se utilizar o operador sizeof para se determinar o tamanho de um vetor, de uma unio, de uma estrutura ou de um campo de bits. Para isso basta apenas colocar o nome da varivel, ou do tipo de dados, entre parnteses aps o operador sizeof. O Cdigo 3.11 demonstra como usar o operador sizeof para determinar o tamanho de todos os tipos de dados bsicos da linguagem C++. Este programa um teste til a ser executado em outros compiladores, ou mesmo em outros sistemas, para comparar os tamanhos de dados bsicos assumidos por compiladores e por sistemas diferentes.
Cdigo 3.11 - Uso do operador SIZEOF.

#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

Programao I Prof. Andr Carlos Silva

<< << << << << << << << << << }

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

setw(41) setw(40) setw(39) setw(38) " << setw(33)

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.

3.10. Exerccios do captulo


2.8.Escreva loops for, while e do/while que exibam o alfabeto. Insira os loops dentro de uma instruo switch que permita ao usurio selecionar qual loop dever ser executado. 2.9. Escreva um programa para exibir caracteres de uma string separados por espaos em branco. Por exemplo, se o usurio digitar ABCDEFG, o programa dever exibir A B C D E F G.

Verso 1.1

87

2005

Programao I Prof. Andr Carlos Silva

4 FUNES: PROGRAMANDO POR PARTES

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.

4.1. Chamando uma funo


Um programa pode conter uma ou mais funes, das quais uma delas deve ser a funo main(). A execuo do programa sempre comea na funo main() e, quando o controle do fluxo do programa encontra uma instruo que inclui o nome de uma funo, esta chamada. Chamar uma funo o meio pelo qual solicitamos que o programa desvie o seu fluxo de controle, passando execuo da funo e, ao termino desta, volte instruo imediatamente posterior chamada da funo.

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

Programao I Prof. Andr Carlos Silva

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.

4.2. Funes simples


O Cdigo 4.1 mostra uma funo simples, destinada converso de um valor de temperatura em graus Fahrenheit para graus Celsius. Como se pode ver, a estrutura de uma funo em C++ semelhante da funo main(). A nica diferena que a funo main() possui um nome reservado especial.
Cdigo 4.1 - Exemplo do uso de uma FUNO simples.

#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

Programao I Prof. Andr Carlos Silva

4.3. Prottipo de funes


Da mesma forma que com relao a uma varivel, no podemos tambm utilizar uma funo sem antes declar-la. A declarao de uma funo chamada de prottipo de uma funo e uma instruo colocada, geralmente, no incio do programa. Assim sendo, o prottipo de uma funo deve preceder a sua definio e a sua chamada. O prottipo de uma funo estabelece o tipo da funo e os argumentos que esta recebe. O prottipo de uma funo tem a mesma forma da definio da funo, anterior ao corpo da funo, exceto por terminar com ponto-e-vrgula. O corpo de uma funo, que a funo propriamente dita, so todas as instrues executadas quando a funo chamada. O principal propsito de se escrever prottipos de funes em C++ fornecer ao compilador as informaes necessrias sobre o tipo da funo e o nmero e tipo dos argumentos que esta usar. Sem o prottipo da funo, o compilador no teria como checar se h erros no uso da funo. No Cdigo 4.1, o prottipo da funo apresentado na linha: float celsius (float fahr); //Prototipo da funcao Celsius

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

4.3.1. Prottipo externo e local


Existem duas formas de se declarar funes em C++. A mais usada a chamada prottipo externo, e escrita antes de qualquer funo, como no exemplo apresentado no Cdigo 4.1. Esta declarao feita uma nica vez e visvel para todas as funes que a chamam. A outra forma de se declarar uma funo a chamada prottipo local, e escrita no corpo de todas as funes que a chamam, porm antes da sua chamada. O Cdigo 4.2 apresenta o mesmo programa do Cdigo 4.1, porm este agora utiliza a funo celsius() como sendo de prottipo local.
Cdigo 4.2 - Uso de funes de prottipo local.

#include <stream.h> main () { float celsius (float fahr); Celsius float c, f;

//Prototipo local da funcao

Verso 1.1

90

2005

Programao I Prof. Andr Carlos Silva

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

4.3.2. Eliminando o prottipo de funes


Se a definio da funo for feita antes da instruo de sua chamada, o seu prottipo no obrigatrio. Assim sendo, poderamos reescrever o Cdigo 4.1, omitindo-se o prottipo da funo celsius() como mostrado no Cdigo 4.3.
Cdigo 4.3 - Uso de funes sem prottipo.

#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

Programao I Prof. Andr Carlos Silva

4.4. Tipos de funes


O tipo de uma funo definido pelo tipo dos dados que ela retorna, e no pelo tipo dos argumentos que ela recebe, sendo este retornado por meio do comando return. Assim sendo, uma funo dita do tipo inteiro quando esta retorna um valor do tipo int. Os tipos de funes em C++ so os mesmos tipos das variveis bsicas. Uma funo em C++ pode, entretanto, no retornar valor algum. Neste caso a funo do tipo void.

4.4.1. O comando RETURN


O comando return termina a execuo de uma funo e retorna o controle para a instruo do cdigo-fonte seguinte chamada funo. O valor da instruo aps o comando return retornado como sendo o valor da prpria funo, devendo este valor ser condizente com o tipo da funo declarado em seu prottipo. Um comando return sem expresso alguma termina uma funo do tipo void. A sintaxe de uma instruo return tem uma das trs formas seguintes: return; return expresso; return (expresso); //Funo do tipo void

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

Programao I Prof. Andr Carlos Silva

4.4.2. Limitaes do comando RETURN


Enquanto vrios valores podem ser passados para uma funo na forma de argumentos, no permitido que uma funo retorne mais de um valor por meio do comando return. Existem ento formas de uma funo retornar mais de um valor, mas isso ser abordado mais frente nesta apostila, ainda neste captulo, para mais informaes vide Captulo 4.6.1.

4.5. Definio de funes


O cdigo-fonte em C++ que descreve o que a funo efetivamente faz chamado de definio da funo. A parte da definio da funo que vem antes abertura de chaves ('{') compreende o cabealho da funo, e tudo o estiver entre as chaves compreende o corpo da funo. A forma geral da definio de uma funo a que se segue: tipo_da_funo nome_da_funo (declarao dos parmetros) { instrues da funo; } A definio de qualquer funo em C++ comea com o tipo da funo, que dever ser o mesmo tipo do prottipo da funo.

4.5.1. Parmetros da funo


As informaes transmitidas para uma funo so chamadas de parmetros da funo. A funo dever declarar todos os seus argumentos entre os parnteses, tanto no seu cabealho quanto no seu prottipo. Os parmetros de uma funo podem ser utilizados livremente no corpo da funo que os declarou. Variveis que no fazem parte dos parmetros de uma funo no podem ser declaradas no cabealho da funo. A funo celsius(), por exemplo, necessita de uma varivel auxiliar c declarada aps a abertura de chaves. Esta varivel criada toda vez que a funo inicia sua execuo e destruda quando a funo termina a sua execuo. Tal varivel passvel de acesso somente por instrues internas ao corpo da funo, uma vez que o escopo desta varivel local funo celsius(). A varivel c declarada em main() outra varivel, no tendo nada a ver com a varivel c declarada em celsius().

4.5.2. Passagem de argumentos por valor


No Cdigo 4.1., a funo celsius() cria uma nova varivel para receber o valor passado a ela na forma de argumento. Sua declarao indica que o valor enviado ser armazenado na varivel fahr criada quando a funo inicia a sua execuo e destruda quando a funo termina a sua execuo, conforme explicado anteriormente. Receber parmetros desta forma, em que a funo cria novas cpias dos parmetros transmitidos, chama-se passagem por valor. O Cdigo 4.4 mostra um programa que recebe
Verso 1.1

93

2005

Programao I Prof. Andr Carlos Silva

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

4.5.3. Funes do tipo VOID


Uma funo que no retornam nada definida como sendo do tipo void. Como exemplo, consideremos uma funo que desenha uma linha de 21 asteriscos na tela do monitor, conforme apresentado no Cdigo 4.5.
Cdigo 4.5 - Uso de funes do tipo VOID.

#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

Programao I Prof. Andr Carlos Silva

O resultado da execuo do programa acima algo como: ********************* * FELIZ ANIVERSARIO * *********************

4.5.4. Funes que no recebem nada e no retornam nada


O fato de uma funo no retornar nenhum valor indicado no prottipo da funo pela palavra void antes do nome da funo. Uma funo que no recebe argumento algum tem em seu prottipo a palavra void escrita no lugar de seus argumentos. Mas uma funo que no recebe argumento algum e no retorna valor algum considerada de tipo void e de retorno tambm void. Uma funo deste tipo desempenha o papel de um procedimento da linguagem Pascal e de uma sub-rotina da linguagem FORTRAN. Como j mencionado, main() uma funo, assim sendo este deveria retornar algum valor e receber algum valor, o que no aconteceu em nenhum programa mostrado at aqui. O fato que, at o presente momento, todos os programas apresentados possuam a sua funo main() void, tanto para argumentos quanto para valores de retorno. A funo apresentada no Cdigo 4.6 usa o caractere , tambm chamado de BELL, para tocar o alto-falante do sistema. Observe que tal funo no recebe e no retorna nada.
Cdigo 4.6 - Uso de funes que no recebem e nem retornam nada.

#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

Programao I Prof. Andr Carlos Silva

4.5.5. Passagem de vrios argumentos


Se uma funo necessita de mais de um argumento, eles devem ser declarados na lista de argumentos, tanto da declarao quanto do prottipo da funo. O Cdigo 4.7 mostra o exemplo de um programa que passa dois argumentos a uma funo, chamada de retngulo(), cujo propsito desenhar retngulos de vrios tamanhos na tela do computador. Os dois argumentos passados funo so a largura e a altura do retngulo.
Cdigo 4.7 - Uso de funes com mais de um argumento.

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

4.5.6. Escrevendo vrias funes em um mesmo programa


Pode-se escrever quantas funes forem necessrias num mesmo programa, e qualquer uma das funes pode chamar qualquer uma outra. Em C++, no entanto, no permitido que se defina uma funo dentro de outra funo. As funes em C++ so mdulos independentes uns dos outros.

Verso 1.1

96

2005

Programao I Prof. Andr Carlos Silva

4.5.7. Funes usadas como argumento de outras funes


Conforme j mencionado, a chamada a uma funo pode ser utilizada numa expresso da mesma forma que se utiliza valores numricos. Pode-se tambm utilizar a chamada a uma funo como sendo o argumento de uma outra funo. O Cdigo 4.8 apresenta um programa simples que calcula a soma dos quadrados de dois nmeros fornecidos pelo usurio.
Cdigo 4.8 - Uso de funes como argumento de outras funes.

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

4.6. O operador unrio de referncia &


O operador unrio de referncia cria um outro nome para uma varivel previamente declarada. As instrues abaixo informam ao compilador que n1 um outro nome para a varivel n. Assim sendo, toda operao que for executada em qualquer um dos dois nomes tem o mesmo resultado. int n;

Verso 1.1

97

2005

Programao I Prof. Andr Carlos Silva

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.

4.6.1. Passagem de argumentos por referncia


O uso mais importante para referncias na passagem de argumentos para funes. Os exemplos de argumentos de funes vistos at o presente momento foram todos passados por valores. Quando argumentos so passados por valores, a funo chamada cria novas variveis do mesmo tipo dos argumentos e copia nelas o valor dos argumentos passados. Desta forma, a funo no tem acesso s variveis originais passadas funo e assim no as pode modificar. A principal vantagem da passagem por referncia a de que a funo pode acessar as variveis da funo que a chamou. Alm disso, tal mecanismo de passagem de parmetros possibilita que uma funo retorne mais de um valor para a funo que a chamou. Assim sendo, quando se deseja retornar mais de um valor, estes so colocados como referncias a variveis da funo de execuo mais externa. O programa apresentado no Cdigo 4.9 mostra um exemplo simples de passagem de argumentos por referncia. O programa solicita ao usurio o preo atual de uma mercadoria e uma taxa de juros. De posse destes o programa modifica o preo para um valor reajustado de acordo com a taxa de juros informada pelo usurio e calcula o aumento em termos de preo.
Cdigo 4.9 - Uso de passagem de argumentos por referncia em funes.

#include <stream.h> void juros (float& p, float& r, float i); main () { float preco, taxa, val_reaj;

Verso 1.1

98

2005

Programao I Prof. Andr Carlos Silva

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.

#include <stream.h> void troca (float& x, float& y);

Verso 1.1

99

2005

Programao I Prof. Andr Carlos Silva

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

4.6.2. Referncias constantes


Pode-se combinar a palavra-chave const com a declarao de referncia a uma varivel a fim de se criar uma referncia somente leitura (read-only) de uma varivel. Considere o exemplo abaixo. int n; const int& n1 = n; As declaraes anteriores fazem da varivel n1 um nome read-only para a varivel n. Assim sendo, no se pode mudar o valor da varivel n1 diretamente, para isso deve-se alterar o valor da varivel n. Utilizam-se referncias constantes quando a funo no necessita alterar as variveis enviadas como argumento. Imagine uma funo que recebe muitos dados como

Verso 1.1

100

2005

Programao I Prof. Andr Carlos Silva

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

4.6.3. Consideraes sobre referncias


O uso de referncias poder ser bastante confuso para algum que leia um programa que as utiliza. Sem que seja lido o prottipo da funo, impossvel saber se a funo recebe uma referncia da varivel ou um valor. Assim, no sabemos se a varivel passada como argumento alterada ou no. As referncias devem ser usadas com muito cuidado e sempre acompanhadas de linhas de comentrio.

4.7. Valores default para os argumentos de uma funo


O prottipo de uma funo pode incluir valores para um, alguns ou todos os argumentos de uma funo. Se forem omitidos, os argumentos correspondentes na chamada funo, os valores default sero automaticamente usados. Se os argumentos correspondentes forem enviados, estes sero respeitados. Como exemplo, vamos alterar a funo linha() apresentada no Cdigo 4.5 para que ela receba dois argumentos, sendo o primeiro o caractere para o desenho da linha e o segundo o nmero de caracteres a serem desenhados. A funo imprime uma linha de 20 asteriscos por default.

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, '='); }

//Imprime os argumentos default //Imprime os 34 asteriscos //Imprime os 45 caracteres '='

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

Programao I Prof. Andr Carlos Silva

4.8. Sobrecarga de funes


Sobrecarregar uma funo significa criar uma famlia de funes, todas com o mesmo nome, mas com a lista de parmetros diferentes. Funes sobrecarregadas devem ter a lista de parmetros diferentes, seja em nmero ou em tipo. Quando uma funo chamada, a lista de parmetros passada para ela que permite ao compilador identificar qual o cdigo-fonte dever ser executado. Por exemplo, suponhamos que voc queira criar uma funo que calcule o cubo de seu argumento e que o argumento possa ser um nmero inteiro, um float ou double. Para resolver este problema, pode-se criar uma famlia de funes chamadas cubo() com parmetros diferentes, conforme mostrado no Cdigo 4.13.
Cdigo 4.13 - Uso de sobrecarga (overload) de funes.

#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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

{ for (int j = 0; j < i; j++) cout << ch; } void linha (char ch, int i) { for (int j = 0; j < i; j++) cout << ch; }

4.9. Funes inline


A palavra-chave inline, quando colocada como primeiro elemento do cabealho da definio de uma funo, causa a insero de uma cpia da funo em todo lugar onde a funo chamada. Como exemplo consideremos o Cdigo 4.15, onde apresentado um programa que l caracteres do teclado e chama uma funo que analisa cada caractere. Caso o caractere seja uma letra maiscula, a funo converte-a para minscula, seno retorna o prprio caractere.
Cdigo 4.15 - Uso de funes INLINE.

#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

Programao I Prof. Andr Carlos Silva

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.

4.10 Funes recursivas


Uma funo dita recursiva se esta definida em termos dela mesma. Isto , uma funo dita recursiva se quando dentro dela est presente uma chamada a ela mesma. O Cdigo 4.16 mostra um programa que calcula o fatorial de um nmero n, representado matematicamente por n!, utilizando os conceitos de recursividade de funes.
Cdigo 4.16 - Uso de funes recursivas.

#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

Programao I Prof. Andr Carlos Silva

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.

4.10.1. Como trabalha uma funo recursiva?


primeira vista no fcil entender o funcionamento de uma funo recursiva. Para facilitar o seu entendimento, vamos imaginar que uma chamada recursiva uma chamada a uma outra funo, que tenha o mesmo cdigo-fonte da funo original. Assim sendo, a funo fatorial() pode ter a sua recursividade substituda por uma seqncia de funes, idnticas funo fatorial(). Por exemplo, para se calcular o fatorial de 3, a seqncia de funes poderia ser a seguinte: long double fatorial (int n) { return ( (n == 0)? 1: 3 * f1(2)); //Chama outra funo } long double f1 (int n) { return ( (n == 0)? 1: 2 * f2(1)); //Chama outra funo } long double f2 (int n)
Verso 1.1

107

2005

Programao I Prof. Andr Carlos Silva

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

4.10.2. O jogo das torres de Hani


Neste jogo existem trs hastes, que so chamadas de Origem, Destino e Temporria, e um nmero qualquer de discos, de diferentes tamanhos, posicionados inicialmente na haste
Verso 1.1

108

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

{ 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

4.11. Classes de armazenamento


Todas as variveis e funes em C++ tm um tipo e uma classe de armazenamento. Voc j sabe que o tipo de uma varivel diz respeito ao tamanho que ela ocupar na memria e forma como ela ser armazenada. A classe de armazenamento de uma varivel determina em que pontos do programa ela pode ser acessada, quando ela ser criada e quando ser destruda, em que lugar ela ser armazenada e qual ser seu valor inicial. So quatro as classes de armazenamento em C++: auto extern static register (automticas) (externas) (estticas) (em registradores)

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.

4.11.1. A classe de armazenamento auto


As maiorias das variveis que temos usado em nossos exemplos esto confinadas nas funes que as usam, isto , so visveis ou acessveis somente nas funes em que

Verso 1.1

110

2005

Programao I Prof. Andr Carlos Silva

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.

4.11.2. A classe de armazenamento extern


Ao contrrio das variveis automticas, declaradas dentro das funes que as utilizam, as variveis externas so declaradas fora de qualquer funo. A instruo de declarao de uma varivel externa idntica declarao de uma varivel automtica. A nica diferena que as variveis externas so declaradas externamente a qualquer funo, ou seja, so as variveis de escopo global. As variveis da classe extern so criadas em tempo de compilao, especificamente quando o programa estiver sendo compilado, e so inicializadas com zero quando no existir uma inicializao explicita.

4.11.2.1. O operador de escopo de variveis ::


Observe o programa mostrado a seguir. #include <stream.h> int i; int j = 234; //Variavel inicializada com zero //Variavel inicializada com 234

main () { int i = 5, j = 10; //Declaracao de variaveis automaticas cout << "i = " << i << "\nj = " << j; }

Verso 1.1

111

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

Cdigo 4.19 - O operador de escopo de variveis ::.

#include <stream.h> int i; int j = 234; main () { int i = cout << << cout << << } //Variavel inicializada com zero //Variavel inicializada com 234

5, j "i = "\nj "\ni "\nj

= " = = =

10; //Declaracao de variaveis automaticas << ::i //Imprime as variaveis esternas " << ::j; " << i //Imprime as variaveis esternas " << j;

O programa acima imprimir na tela: i j i j = = = = 0 234 5 10

4.11.2.2. A palavra-chave EXTERN


Um erro muito comum entre novos, e at mesmo antigos, programadores achar que a palavra-chave extern utilizada em C++ para criar variveis externas, o que no verdade. A palavra-chave extern usada apenas para informar ao compilador que a varivel em questo foi criada em outro programa, ou seja, esta externa ao programa em questo. Assim sendo, uma varivel que tem a palavra-chave extern precedendo-a foi compilada em outro programa e apenas ser criado um link com o novo programa. A sintaxe de uma varivel externa a um programa a seguinte: extern int i; //Link com a varivel

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

Programao I Prof. Andr Carlos Silva

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.

4.11.2.3. Retornando valores de uma funo por referncia


Alm de passar argumentos por referncia para uma funo, uma referncia a uma varivel global pode ser utiliza a fim de que uma funo possa retornar mais que um valor apenas. O Cdigo 4.20 mostra uma funo que recebe trs argumentos por referncia e, aps realizar algumas contas com cada um deles, encerra a sua execuo. Logo em seguida o programa imprime na tela o valor dos argumentos passados funo e, obviamente, os valores dos trs argumentos tero sido modificados. Assim sendo, pode-se considerar como se a funo tivesse retornado trs valores, mesmo esta sendo do tipo void.
Cdigo 4.20 Exemplo de uma funo que retorna mais de um valor usando referncias.

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

//Atribui um valor a variavel x << x;

4.11.3. A classe de armazenamento static


As variveis da classe static se assemelham, por um lado, s variveis automticas, pois estas s podem ser acessadas pelas funes que as declaram, mas, por outro lado, se assemelham s variveis globais, pois matem os seus valores na memria do computador mesmo quando a funo que as declarou termina a sua execuo. Assim sendo, variveis do tipo static so utilizadas quando se deseja chamar uma funo vrias vezes, mas se deseja que os valores das variveis locais a esta funo no se percam entre duas chamadas funo. As variveis da classe static so criadas em tempo de compilao, especificamente quando o programa est sendo compilado, e so inicializadas com zero na falta de inicializao explcita, tal qual as variveis globais. O Cdigo 4.22 apresenta a funo soma() que imprime uma varivel static e a incrementa de uma unidade. A funo soma() chamada trs vezes pelo programa principal, sendo que a varivel k da classe static no perde o seu valor em nenhuma das chamadas. Nota-se ainda que, apesar da varivel k ter sido inicializada aps a sua declarao, esta inicializada uma nica vez, no importando quantas vezes a funo seja chamada.

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 = " }

<< x++ << '\n';

O resultado do Cdigo 4.22 a seguinte impresso na tela: x = 0 x = 1 x = 2

4.11.3.1. Nmeros aleatrios e simulao


Quando se deseja simular um evento, por exemplo o lanamento de uma moeda ou mesmo de um dado, fatalmente se cai em um caso onde necessrio o uso de nmeros aleatrios que, teoricamente, so nmeros compreendidos em um determinado intervalo que possuem igual probabilidade de chance de serem escolhidos ao acaso. De outra forma, podemos dizer que x um nmero aleatrio pertencente ao intervalo (a, b) se todos os elementos do intervalo tem a mesma probabilidade do elemento x de serem sorteados. Em se tratando de nmeros aleatrios gerados computacionalmente, usual trata-los por nmeros pseudoaleatrios, uma vez que a maioria das rotinas computacionais que deveriam gerar nmeros aleatrios geram, na verdade, nmeros com uma certa tendncia. O compilador C++ possui uma funo geradora de nmeros pseudoaleatrios chamada rand(). A funo rand() usa um gerador aleatrio de congruncia multiplicativa, com perodo de segunda at trigsima segunda potncia, para retornar sucessivos nmeros pseudoaleatrios, estes variando em uma faixa de valores de 0 at RAND_MAX, sendo a constante simblica RAND_MAX definida no arquivo de cabealho stdlib.h. Por default, RAND_MAX igual a 32767 (ou 0x7FFF). Assim sendo, a funo rand() gera nmeros inteiros pseudoaleatrios compreendidos no intervalo [0, 32767]. O Cdigo 4.23 apresenta um pequeno programa sobre simulao. Apesar de muito simples, ele tem por finalidade mostrar ao leitor o que uma simulao, neste exemplo simula-se uma moeda ou um dado, de quantas faces o usurio desejar. Quando uma moeda a joga,
Verso 1.1

116

2005

Programao I Prof. Andr Carlos Silva

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.

#include #include #include #include

<stream.h> <ctype.h> <stdlib.h> <conio.h>

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

Programao I Prof. Andr Carlos Silva

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

4.11.3.2. Um gerador de nmeros pseudoaleatrios


Agora que o conceito de nmeros pseudoaleatrios j foi introduzido, podemos criar a nossa prpria funo geradora de nmeros pseudoaleatrios, utilizando o conceito de variveis da classe static. A funo geradora dever sempre ser inicializada com um nmero, usualmente chamado de semente, que ser utilizado para produzir um novo nmero, que se tornar a semente para a produo de um novo nmero, e assim por diante. Desta forma, a nossa funo geradora deve necessariamente lembrar-se da semente usada na sua ltima chamada, da a necessidade de se utilizar uma varivel da classe static. O mtodo utilizado baseado em congruncia linear, mtodo este que no ser explicado nesta apostila. O Cdigo 4.24 apresenta ento a nossa funo ale(), para a gerao de nmeros pseudoaleatrios.

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

Programao I Prof. Andr Carlos Silva

Cdigo 4.25 - Gerador de nmeros aleatrios que usa a funo _dos_gettime().

#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

Programao I Prof. Andr Carlos Silva

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.

4.11.4. A classe de armazenamento static extern


A outra maneira de se tentar solucionar o problema da inicializao da semente de gerao dos nmeros pseudoaleatrios solicitando ao usurio que digite o valor da semente. Assim sendo, a varivel semente dever ser acessvel tanto pela funo ale() como pela funo que a chama, no nosso caso a funo main(). Intuitivamente pode-se pensar em mudar a classe da varivel semente para global. Mas variveis globais podem ser acessadas por quaisquer funes do programa e no queremos que nenhuma outra funo, exceto a funo ale() e a funo que a chamou, tenha acesso varivel semente. A soluo est no uso de variveis globais estticas (usualmente chamadas de variveis static extern). Quando se utiliza uma varivel static extern cria-se uma varivel global vinculada a um mecanismo de privacidade. Para se declarar uma varivel static extern basta que se adicione a palavra-chave static anteposta declarao da varivel global. Uma varivel static extern tem as mesmas propriedades de uma varivel global, exceto pelo fato de que as variveis extern podem ser usadas em qualquer parte do programa, entanto que as variveis static extern s podem ser acessadas pelas funes do mesmo cdigo-fonte e definidas abaixo de suas declaraes. O Cdigo 4.26 apresenta o programa do Cdigo 2.24 utilizando uma varivel static extern como semente do gerador de nmeros pseudoaleatrios.
Cdigo 4.26 - Gerador de nmeros aleatrios que utiliza uma varivel da classe static extern como semente.

#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

Programao I Prof. Andr Carlos Silva

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

4.11.5. A classe de armazenamento register


A classe de armazenamento register indica que a varivel associada deve ser armazenada fisicamente numa memria de acesso muito mais rpido, chamada registrador. Um registrador da mquina um espao de 16 bits (no IBM-PC) onde podemos armazenar um int ou um char. Em outras palavras, as variveis da classe register so semelhantes s variveis automticas, mas se aplicam apenas s variveis do tipo int e char.

Verso 1.1

122

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

4.12. O pr-processador C++


O pr-processador C++ um programa que examina automaticamente o cdigo-fonte em C++ e executa certas modificaes no cdigo-fonte, antes de sua compilao, com base em instrues chamadas de diretivas. Assim sendo, as diretivas so instrues para o prprocessador. As diretivas devem fazer parte do cdigo-fonte que criamos, mas no faro parte do programa compilado, pois estas so retiradas do cdigo-fonte pelo pr-processador antes da compilao. As diretivas so utilizadas, geralmente, para tornar o cdigo-fonte de um programa mais claro e fcil de se criar e manusear. As diretivas mais comumente utilizadas em C++ so: #define #undef #include #if #ifdef #ifndef #else #elif #endif #error As diretivas podem ser colocadas em qualquer lugar do cdigo-fonte de um programa, ma estas so escritas, geralmente, nas primeiras linhas do cdigo-fonte, antes da funo main() ou mesmo antes do prottipo de qualquer funo. As diretivas se aplicam somente do ponto onde estas so escritas at o final do cdigo-fonte.

Verso 1.1

124

2005

Programao I Prof. Andr Carlos Silva

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.

4.12.1. A diretiva #define


Conforme visto anteriormente no Captulo 1.4.2 a diretiva #define, em sua forma mais simples, utilizada para definir constantes simblicas (usualmente tratadas por constantes definidas)28.

4.12.1.1. Uso de MACROS


At o presente momento, consideramos somente a diretiva #define em sua forma mais simples, ou seja, utilizada apenas na criao de constantes definidas. A seguir ser mostrado como escrever diretivas #define que aceitam argumentos, analogamente a uma funo, chamadas de macros. Uma macro como se fosse uma funo, porm todas as chamadas s macros so substitudas pelo pr-processador por suas definies. O Cdigo 4.28 apresenta um uso simples de uma macro chamada PRN(n).
Cdigo 4.28 - Uso de macros.

#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

//Chamada a macro PRN

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

Programao I Prof. Andr Carlos Silva

no funcionar, porque o espao em branco colocado entre PRN e (n) interpretado pelo pr-processador como sendo o fim do identificador PRN.

4.12.1.2. Uso de parnteses em macros


A falta de parnteses em macros pode provocar erros considerveis em um programa. Por exemplo, suponha que seu programa contenha as seguintes linhas em seu cdigo-fonte: #define SOMA(x,y) x + y ... ... z = 10 * SOMA(3,4); Qual ser o valor atribudo varivel z? Intuitivamente somos levados a pensar que 3 ser somado a 4, gerando o resultado 7 e este resultado, quando multiplicado por 10, resultar em 70, sendo este o valor atribudo varivel z. ERRADO! O pr-processador executa uma substituio literal, e em nada inteligente, da macro pela sua definio. Assim sendo, a instruo acima, aps a substituio executada pelo pr-processador ser: z = 10 * 3 + 4; e o valor atribudo varivel z ser 34, e no 70. A soluo para tais tipos de problemas no uso de macros o uso de parnteses que, devidamente colocados, indicam a correta ordem de precedncia a ser adotada durante a compilao do programa. O exemplo anterior deve ento ser corrigido da seguinte maneira: #define SOMA(x,y) (x + y) Aps a substituio executada pelo pr-processador, a instruo de atribuio ser: z = 10 * (3 + 4); e o valor atribudo varivel z ser 70. Entretanto, em alguns casos, envolver a definio da macro em parnteses pode no ser suficiente para resolver o problema de precedncia de operadores. Considere o seguinte trecho de um programa: #define PROD(x,y) (x * y) ... ... z = PROD(2 + 3, 4); Assim sendo, a instruo acima, aps a substituio executada pelo pr-processador ser:

Verso 1.1

126

2005

Programao I Prof. Andr Carlos Silva

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

4.12.1.3. Definindo macros usando outras macros


Uma macro pode ser definida utilizando outras macros. O Cdigo 4.29 apresenta um programa que calcula a rea superficial de uma esfera utilizando o conceito de macros que usam macros. Observe que a macro AREA utiliza, na sua definio, as macros PI e SQR.
Cdigo 4.29 - Uso de uma macro na definio de outra macro.

#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

Para maiores informaes sobre precedncia de operadores vide o Captulo 1.5.1.

Verso 1.1

127

2005

Programao I Prof. Andr Carlos Silva

4.12.1.4. Macros versus funes inline


As macros definidas utilizando o comando #define so similares a funes inline, entretanto, as funes inline so reconhecidas pelo compilador C++, ao passo que as macros sapo implementadas no programa por meio de uma simples substituio, muitas vezes burra, de texto. O tipo do argumento de uma macro no avaliado pelo compilador, o que em alguns casos pode ser uma vantagem. Por exemplo, a macro SOMA pode ser utilizada com qualquer tipo de valor, como se segue abaixo: a = SOMA(3.48,4.5); b = SOMA(3,4); c = SOMA(3.48e89,4.5e90); Se uma funo for escrita para calcular a soma de dois nmeros ser necessrio respeitar o tipo dos argumentos da funo, ou escrever uma famlia de funes utilizando os conceitos de sobrecarga de funes vistos no Captulo 4.8. Por outro lado, a falta da avaliao dos argumentos de uma macro pode provocar resultados inesperados, e muitas vezes indesejados. A seguir so mostrados dois exemplos, sendo que o Cdigo 4.30 utiliza uma macro e o Cdigo 4.31, que realiza a mesma tarefa, utiliza uma funo inline.
Cdigo 4.30 - Problemas no uso de macros.

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

cout << "\nA letra digitada, maiuscula, e: " << ch;

#include <conio.h> inline char maiusc (char ch)

Verso 1.1

128

2005

Programao I Prof. Andr Carlos Silva

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

cout << "\nA letra digitada, maiuscula, e: " << ch;

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

//Problemas... n2 = " << n2

#include <stream.h> inline char min (int x, int y) { return (x < y)? x : y; } main ()

Verso 1.1

129

2005

Programao I Prof. Andr Carlos Silva

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

4.12.2. A diretiva #undef


Se por um lado a diretiva #define define uma constante declarada, ou mesmo uma macro, por outro lado a diretiva #undef (do ingls undefine) remove a definio de uma constante definida, ou de uma macro. O exemplo abaixo parte de um cdigo fonte e tem por finalidade apenas demonstrar o uso da diretiva #undef. Observe que para se remover a definio de uma macro somente o nome da macro deve constar na diretiva #undef, ou seja, no se deve incluir a lista de argumentos da macro. #define GRANDE 3 #define ENORME 8 #define SOMA(x,y) (x) + (y)
Verso 1.1

130

2005

Programao I Prof. Andr Carlos Silva

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

4.12.3. A diretiva #include


Conforme j mencionado no Captulo 1.1.7, a diretiva #include causa a incluso de um arquivo em nosso cdigo-fonte. Na verdade o compilador substitui a diretiva #include pelo contedo do arquivo indicado, antes do programa ser compilado. Assim sendo, a linha #include <stream.h> solicita ao compilador que o arquivo stream.h, localizado no diretrio INCLUDE, seja incluso no cdigo-fonte antes que este seja compilado. Alm do uso dos sinais < >, a diretiva #include aceita ainda uma segunda sintaxe, onde se utilizam aspas (""). Assim sendo, a linha #include "bintoint.h" solicita ao compilador que o arquivo bintoint.h, localizado no diretrio atual, seja incluso no cdigo-fonte antes que este seja compilado.

4.12.4. As diretivas #if, #ifdef, #ifndef, #elif, #else e #endif


O pr-processador oferece diretivas que permitem que a compilao de um cdigo-fonte seja feita de maneira condicional, utilizando diretivas semelhantes, em sintaxe e em significado, estrutura if/else if/else. Tais diretivas facilitam tanto o desenvolvimento do programa quanto a escrita de cdigos com maior portabilidade de uma mquina para outra, ou mesmo de um sistema operacional para outro. So elas as diretivas #if, #ifdef, #ifndef, #elif, #else e #endif.

Verso 1.1

131

2005

Programao I Prof. Andr Carlos Silva

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.

Diretiva condicional #if #elif #else #endif

Tomador de deciso anlogo if else if else }

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

Programao I Prof. Andr Carlos Silva

#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

Programao I Prof. Andr Carlos Silva

#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

4.12.5. A diretiva #error


A diretiva #error provoca uma mensagem de erro do compilador em tempo de compilao, o que muito til quando se quer fazer um programa para ser distribudo em vrios sistemas operacionais. Considere o exemplo abaixo, ele usa uma diretiva de compilao condicional #if e, de acordo com o seu resultado, gera um erro. #if TAMANHO > TAMANHO_MAX #error "Tamanho incompativel" #endif

Verso 1.1

134

2005

Programao I Prof. Andr Carlos Silva

4.13. Exerccios do captulo


4.1. Quais das razes abaixo so vlidas em se tratando de escrever funes? a. economizar memria; b. rodar mais rpido; c. dar um nome a um bloco de cdigo; d. dividir uma tarefa em pequenas unidades; e. ajudar a organizar o programa; f. reduzir o tamanho do cdigo-fonte do programa. 4.2. Quais das instrues abaixo uma chamada funo sorte? a. sorte = 5; b. int sorte() {return rand();} c. x = sorte(); d. int y = sorte() % 10; 4.3. Qual a diferena entre definir e declarar uma funo? 4.4. Parmetros de uma funo so: a. a parametrizao das variveis recebidas; b. as variveis da funo que recebem os valores da funo que a chama; c. os valores retornados da funo; d. as variveis visveis somente pela funo que a chama. 4.5. correto afirmar sobre o prottipo de uma funo: a. pode ser escrito em qualquer lugar do programa; b. deve preceder a definio da funo e toda chama a esta; c. pode ser suprimido se a funo for definida antes de ser chamada; d. uma instruo que pertence ao corpo da funo. 4.6. correto afirmar sobre o tipo de uma funo: a. definido pelos argumentos que esta recebe; b. definido pelo valor retornado pelo comando return; c. sempre void; d. pode ser qualquer um, exceto void. 4.7. correto afirmar sobre o comando return: a. de uso obrigatrio em todas as funes; b. termina a execuo de uma funo; c. retorna o fluxo do programa para o incio da funo; d. s pode retornar um nico valor funo que o chama. 4.8. Os argumentos de uma funo podem ser: a. constantes; b. variveis;

Verso 1.1

135

2005

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

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

Programao I Prof. Andr Carlos Silva

5 MANIPULAO DE ARQUIVOS EM DISCO

Verso 1.1

138

2005

Programao I Prof. Andr Carlos Silva

6 PONTEIROS

Verso 1.1

139

2005

Programao I Prof. Andr Carlos Silva

APNDICES

A.1. BASES NUMRICAS


A necessidade da criao de uma base numrica remonta ao tempo em que o ser humano comeava a caminhar pelas rduas trilhas da matemtica. Obviamente a base adotada foi a base decimal, uma vez que o primeiro instrumento de clculo que o ser humano adotou foram os dedos das suas mos, e como a soma destes igual a dez, esta foi a base numrica adotada para a realizao das operaes algbricas.

A.1.1. A BASE BINRIA


Apesar de extremamente funcional para a matemtica, a base decimal no a base numrica utilizada pelos computares, uma vez que estes utilizam (atualmente) a base binria que, como o prprio nome j diz, utiliza a base dois (2) ao invs da base dez (10). Quando os primeiros computadores foram construdos eles trabalham com a idia do 0 ou 1. Por exemplo, LED apagado ou acesso, resultado da conta TRUE ou FALSE. Este conceito computacional ainda no mudou de todo, mesmo nos PCs mais modernos de hoje em dia. Internamente um PC faz contas apenas utilizando os bits 0 e/ou 1 e esta a base binria, base qual so aplicados os operadores binrios. Se o leitor tentar entender um operador binrio apenas lendo as representaes decimais dos nmeros antes e depois da aplicao do operador binrio, provavelmente este nunca conseguir correlacionar os dois nmeros. J lendo os dois nmeros em sua representao binria a correlao , alm de banal, imediata. Uma vez que a base binria formada apenas com os algarismos 0 e 1, pode-se estabelecer a seguinte correlao entre as duas bases: BASE 10 0 1 2 3 4 5 6 7 8 9 10 BASE 2 0 1 10 11 100 101 110 111 1000 1001 1010

Verso 1.1

140

2005

Programao I Prof. Andr Carlos Silva

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.

A.1.2. A BASE OCTAL

A.1.3. A BASE HEXADECIMAL

Verso 1.1

141

2005

Você também pode gostar