Baixe o app para aproveitar ainda mais
Prévia do material em texto
Suma´rio 1 Introduc¸a˜o 6 1.1 Histo´rico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2 Arquitetura de Computadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.1 Memo´ria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.2.2 Processador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3 Algoritmos e Programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.4 Te´cnica de Desenvolvimento de Programas . . . . . . . . . . . . . . . . . . . . . 11 1.5 Partes de um Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.6 Traduc¸a˜o de Programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.1 Compilac¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.2 Interpretac¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.8 Exerc´ıcios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2 Conceitos Ba´sicos 18 2.1 Varia´veis e Ce´lulas de Memo´ria . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.2 Identificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.3 Comando de Atribuic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.4 Tipos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4.1 Declarac¸a˜o de Varia´veis . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.4.2 Tipo Inteiro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.4.3 Tipo Ponto Flutuante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.4.4 Tipo Booleano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.5 Tipo Caractere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.6 Conversa˜o de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.5 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.6 Expresso˜es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.6.1 Expresso˜es Aritme´ticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.6.2 Expresso˜es Relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.6.3 Expresso˜es Lo´gicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.7 Comando de Entrada de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1 2 SUMA´RIO 2.8 Comando de Sa´ıda de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.9 Comandos de Selec¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.9.1 Comando de selec¸a˜o simples . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.9.2 Comando de selec¸a˜o dupla . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 2.9.3 Comando de selec¸a˜o mu´ltipla . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.10 Comandos de Repetic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 2.10.1 Comando de repetic¸a˜o com pre´-condic¸a˜o . . . . . . . . . . . . . . . . . . . 49 2.10.2 Comando de repetic¸a˜o com po´s-condic¸a˜o . . . . . . . . . . . . . . . . . . . 52 2.10.3 Comando de repetic¸a˜o condensado . . . . . . . . . . . . . . . . . . . . . . 55 2.11 Problema dos Lotes Encaixantes . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 2.12 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 2.13 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 2.14 Exerc´ıcios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 3 Modularizac¸a˜o 70 3.1 Introduc¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3.2 Subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 3.3 Partes de um Subprograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.3.1 Cabec¸alho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.3.2 Diciona´rio de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 3.3.3 Corpo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 3.3.4 Comenta´rios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 3.4 Chamada de subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 3.5 Passagem de paraˆmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 3.6 Retorno de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 3.6.1 Encerramento antecipado de execuc¸a˜o . . . . . . . . . . . . . . . . . . . . 84 3.7 Func¸o˜es sem lista de paraˆmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 3.8 Func¸o˜es sem retorno de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.9 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 3.9.1 Implementac¸a˜o na˜o recursiva equivalente . . . . . . . . . . . . . . . . . . 90 3.10 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 3.11 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 3.12 Exerc´ıcios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 3.13 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 4 Tipos Abstratos de Dados 109 4.1 Te´cnicas de Programac¸a˜o Top-down e Bottom-up . . . . . . . . . . . . . . . . . . 109 4.2 Tipos Compostos Heterogeˆneos (Estruturas) . . . . . . . . . . . . . . . . . . . . . 110 4.2.1 Definic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 4.2.2 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 4.3 Tipos Abstratos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 4.3.1 Definic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 SUMA´RIO 3 4.3.2 Definic¸a˜o de Atributos de um TAD . . . . . . . . . . . . . . . . . . . . . . 120 4.3.3 Definic¸a˜o de Operac¸o˜es de um TAD . . . . . . . . . . . . . . . . . . . . . 120 4.3.4 Uso do TAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 4.3.5 Tipos de TADs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.4 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 4.6 Lista de Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.7 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 5 Vetores 135 5.1 Vetores e sua importaˆncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 5.2 Representac¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 5.3 Definic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 5.3.1 Definic¸a˜o do Tamanho do Vetor . . . . . . . . . . . . . . . . . . . . . . . . 139 5.4 Operac¸o˜es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.4.1 Acesso indevido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 5.5 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 5.6 TAD Implementacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 5.6.1 Atributos . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 147 5.6.2 Operac¸o˜es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 5.7 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 5.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 5.9 Lista de Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 5.10 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 6 Matrizes 164 6.1 Introduc¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 6.2 Definic¸a˜o e Acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 6.2.1 Definic¸a˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 6.2.2 Acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 6.3 O TAD implementacional tMatriz . . . . . . . . . . . . . . . . . . . . . . . . . . 168 6.3.1 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 6.3.2 Operac¸o˜es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 6.4 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 6.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 6.6 Exerc´ıcios Propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 6.7 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 6.8 To´picos Avanc¸ados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 4 SUMA´RIO 7 Apontadores 187 7.1 Varia´veis Apontadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 7.2 A Sintaxe dos Apontadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 7.2.1 Operador Enderec¸o de Memo´ria . . . . . . . . . . . . . . . . . . . . . . . 190 7.2.2 O Operador Seta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 7.3 Acesso a` Varia´vel por Meio de Apontadores . . . . . . . . . . . . . . . . . . . . . 191 7.4 Uso de Apontadores nas Passagens de Paraˆmetros . . . . . . . . . . . . . . . . . 192 7.5 Alocac¸a˜o Dinaˆmica de Memo´ria . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 7.6 Problemas Gerados por Apontadores . . . . . . . . . . . . . . . . . . . . . . . . . 198 7.6.1 Apontadores Na˜o Inicializados . . . . . . . . . . . . . . . . . . . . . . . . 198 7.6.2 Objetos Pendentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 7.6.3 Refereˆncia Pendente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 7.6.4 Programac¸a˜o Macarroˆnica . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 7.7 TAD Implementacional Lista Encadeada tLista . . . . . . . . . . . . . . . . . . . 200 7.7.1 Definic¸a˜o do Tipo tNo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 7.7.2 Atributos de tLista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 7.7.3 Operac¸o˜es de tLista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 7.7.4 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 7.8 Exerc´ıcios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 7.9 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 7.10 Lista de Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 7.11 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 8 Arquivos 235 8.1 Varia´veis Transientes X Varia´veis Persistentes . . . . . . . . . . . . . . . . . . . . 235 8.2 Tipos de Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236 8.2.1 Tipos de Arquivos - Arquivos Texto . . . . . . . . . . . . . . . . . . . . . 236 8.2.2 Tipos de Arquivos - Arquivos Bina´rios . . . . . . . . . . . . . . . . . . . . 237 8.3 Definic¸a˜o de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 8.4 Operac¸a˜o sobre arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 8.4.1 Abertura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 8.4.2 Fechamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 8.5 Operac¸o˜es sobre arquivos texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 8.5.1 Leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 8.5.2 Escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 8.6 Operac¸o˜es sobre arquivos bina´rios . . . . . . . . . . . . . . . . . . . . . . . . . . 244 8.6.1 Leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 8.6.2 Escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 8.7 Outras func¸o˜es u´teis para arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . 246 8.7.1 feof() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 8.7.2 fseek() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 8.8 Exercicios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 SUMA´RIO 5 8.8.1 O Tipo Abstrato de Dados TDicionario . . . . . . . . . . . . . . . . . . . 250 8.9 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 8.10 Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 8.11 Trabalhos Sugeridos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Cap´ıtulo 1 Introduc¸a˜o Co-autor: Andre´ Boechat Objetivos: • Apresentar um breve histo´rico da Computac¸a˜o; • Apresentar noc¸o˜es sobre arquitetura de computadores, como funcionam o processador e a memo´ria; • Definir o que sa˜o algoritmos e programas, ale´m de apresentar algumas te´cnicas para de- senvolveˆ-los; • Definir as partes de um programa e a importaˆncia da documentac¸a˜o; • Introduzir o conceito de traduc¸a˜o de programas. Basicamente, pode-se considerar a programac¸a˜o de computadores como a forma que se da´ o relacionamento entre a ma´quina e o homem. Para programar de forma correta e eficiente, muitas vezes na˜o basta conhecer apenas os comandos de determinadas operac¸o˜es, e´ necessa´rio saber como a ma´quina, um ser na˜o pensante, faz para compreender e executa´-los. Assim, este cap´ıtulo visa apresentar alguns conceitos fundamentais para o entendimento da programac¸a˜o, desenvolvidos juntamente com a a´rea mais recente da cieˆncia, a Computac¸a˜o. 1.1 Histo´rico Dado o alto grau tecnolo´gico dos computadores atuais, pode ser dif´ıcil imaginar que os primeiros computadores eram totalmente mecaˆnicos. Diversos tipos foram projetados e constru´ıdos ao longo da evoluc¸a˜o, chegando aos modernos computadores digitais; pore´m, alguns se destacam pela inovac¸a˜o e complexidade que marcaram suas e´pocas. 6 1.1. HISTO´RICO 7 A primeira ma´quina programa´vel que se tem not´ıcia foi constru´ıda pelo professor de ma- tema´tica da Universidade de Cambridge, Charles Babbage (1792-1871). A “ma´quina anal´ıtica”, como ficou conhecida, era totalmente mecaˆnica, composta basicamente por engrenagens que formavam quatro componentes: a memo´ria, a unidade de ca´lculo ou computac¸a˜o, a unidade de entrada e a de sa´ıda. A unidade de computac¸a˜o recebia operandos da memo´ria para reali- zar sobre eles as operac¸o˜es de soma, subtrac¸a˜o, multiplicac¸a˜o ou divisa˜o, e depois armazenar o resultado na memo´ria. Como a ma´quina anal´ıtica executava as instruc¸o˜es lidas pela unidade de entrada, era poss´ıvel executar diferentes sequ¨eˆncias de ca´lculos, bastandopara isso que um programa diferente fosse utilizado. Assim, a primeira pessoa no mundo a programar um computador foi a jovem Ada Augusta Lovelace, contratada pelo pro´prio Babbage a fim de produzir o software necessa´rio para o funcionamento da ma´quina. A procura por ma´quinas calculadoras cresceu com a Segunda Guerra Mundial, estimulando o surgimento dos primeiros computadores eletroˆnicos. O professor de f´ısica da Universidade da Pensilvaˆnia, John Mauchley, junto com seu aluno de mestrado, J. Presper Eckert, construiu um computador chamado ENIAC (Electronic Numerical Integrator And Computer)[2], o qual detinava-se ao coˆmputo de trajeto´rias ta´ticas que exigissem conhecimento substancial em ma- tema´tica. O ENIAC tinha 18.000 va´lvulas e 1.500 rele´s, pesava 30 toneladas e consumia 140 quilowatts de energia ele´trica. Para programar o ENIAC, era necessa´rio ajustar a posic¸a˜o de 6.000 chaves de va´rias posic¸o˜es e conectar um nu´mero imenso de soquetes por meio de uma ver- dadeira floresta de cabos. Este gigantesco computador so´ ficou pronto em 1946, apo´s o te´rmino da guerra. Um dos pesquisadores envolvidos no projeto do ENIAC, John von Neumann, construiu para o Instituto de Estudos Avanc¸ado de Princeton (Princeton Institute of Advanced Studies — IAS ) a ma´quina IAS[3], a qual ainda e´ a base de praticamente todas as ma´quina atuais. Ele imaginou que os programas poderiam ser representados em formato digital na memo´ria, junto com os dados. A invenc¸a˜o do trans´ıstor e o desenvolvimento de circuitos integrados revolucionaram os pro- jetos de computadores do final da de´cada de 1950, tornando obsoletos os computadores valvula- dos. Nas de´cadas de 1960 e 1970, as famı´lias de computadores da IBM1 (International Business Machines), System/360, e da DEC2 (Digital Equipament Corporation), PDP-11, dominavam o mercado. Nesse per´ıodo surgiu uma das linguagens de programac¸a˜o mais usadas para o desenvolvi- mento de softwares e tambe´m adotada neste livro, a linguagem C[1]. Ela e´, ainda hoje, muito uti- lizada para a criac¸a˜o de programas diversos, como processadores de texto, planilhas eletroˆnicas, programas para a soluc¸a˜o de problemas de engenharia, e muitos outros. Diversos fatores, como a criac¸a˜o de linguagens de programac¸a˜o mais semelhantes a` linguagem humana3, o que facilitava a vida dos programadores, e a integrac¸a˜o de circuitos em escala muito alta, o que aumentou o desempenho e diminu´ıu o tamanho das ma´quinas, deram in´ıcio a era 1http://www.ibm.com 2http://www.hp.com 3Essas linguagens sa˜o chamadas de “linguagens de alto n´ıvel” 8 CAPI´TULO 1. INTRODUC¸A˜O dos computadores pessoais. E foi nesse contexto, na de´cada de 80, que a IBM construiu o computador mais vendido de toda a histo´ria, o Personal Computer — o famoso PC. O processador utilizado no PC foi constru´ıdo por uma promissora empresa da e´poca, a Intel4. E a versa˜o inicial desse computador vinha com o sistema operacional MS-DOS fornecido por outra empresa, a rece´m-criada Microsoft Corporation. 1.2 Arquitetura de Computadores Para conhecer um pouco mais sobre o funcionamento dos computadores, e´ apresentada nesta Sec¸a˜o uma noc¸a˜o ba´sica sobre processadores e memo´rias. 1.2.1 Memo´ria A memo´ria e´ a parte do computador onde as operac¸o˜es a serem executadas pelo computador (instruc¸o˜es) e as informac¸o˜es a serem processadas pelo mesmo (dados) sa˜o armazenados. Na memo´ria, o processador leˆ e escreve informac¸o˜es ao executar as instruc¸o˜es de um pro- grama. Existem dois tipos de memo´ria: a memo´ria principal e a secunda´ria. A principal, conhecida tambe´m como RAM (Random Access Memory), possui as seguintes caracter´ısticas: • Armazena dados e instruc¸o˜es do programa em execuc¸a˜o; • Proporciona ao computador acesso ra´pido aos dados e instruc¸o˜es armazenados por ela; • So´ mantem as informac¸o˜es armazenadas enquanto o computador estiver ligado. A memo´ria secunda´ria geralmente possui maior capacidade de armazenamento de dados e instruc¸o˜es, pore´m o tempo necessa´rio para acessa´-los e´ bem maior quando comparado ao da memo´ria principal. As informac¸o˜es permanecem armazenadas mesmo apo´s o desligamento do computador. Discos r´ıgidos e CD-ROMs sa˜o exemplos de memo´rias secunda´rias. A unidade ba´sica da memo´ria e´ o digito bina´rio, conhecido como “bit”. Um bit pode assumir apenas dois valores, normalmente 0 ou 1. A memo´ria e´ formada por um conjunto de ce´lulas, ou posic¸o˜es, sendo que cada uma pode guardar uma informac¸a˜o e possui um nu´mero de reconhecimento, conhecido como “enderec¸o de memo´ria”. E´ por meio desse nu´mero de enderec¸o que os programas podem acessar uma determinada ce´lula. Se uma ce´lula possuir k bits, ela podera´ armazenar qualquer uma das 2k combinac¸o˜es poss´ıveis para os bits. A Figura 1.1 mostra um exemplo de memo´ria com seis ce´lulas enderec¸a´veis, onde cada ce´lula possui dezesseis bits. 1.2.2 Processador O processador e´ o “ce´rebro” do computador. Basicamente, o processador e´ responsa´vel por buscar instruc¸o˜es na memo´ria, decodifica´-las para determinar seus operandos (dados que sera˜o 4http://www.intel.com 1.3. ALGORITMOS E PROGRAMAS 9 Figura 1.1: Exemplo de uma memo´ria de 16 bits e 6 enderec¸os. usados ao processar a instruc¸a˜o) e quais operac¸o˜es devem ser realizadas com os mesmos, e executar tais operac¸o˜es. Essas tarefas compo˜em o processo de execuc¸a˜o de um programa. 1.3 Algoritmos e Programas Apesar do nome pouco comum, diversos algoritmos sa˜o executados por pessoas comuns todos os dias. Ao escovar os dentes, fazer um bolo ou trocar o pneu de um carro, diversos procedimentos sa˜o feitos em sequ¨eˆncia, seguindo, muitas vezes, uma certa ordem lo´gica. Para exemplificar a execuc¸a˜o de um algoritmo, descreve-se a seguir alguns passos necessa´rios para fazer algo simples, cotidiano, como o ato de escovar os dentes. 1. Pegar a escova e a pasta de dentes; 2. Colocar um pouco de pasta sobre as cerdas da escova; 3. Escovar os dentes do maxilar inferior; 4. Escovar os dentes do maxilar superior; 5. Expelir da boca o excesso de espuma; 6. Bochechar um pouco de a´gua; 7. Lavar a escova e guarda´-la; 8. Enxugar o rosto. Apo´s conhecer um exemplo comum de algoritmo, torna-se mais fa´cil compreender a sua definic¸a˜o: Algoritmo e´ uma sequ¨eˆncia de operac¸o˜es que deve ser executada em uma ordem definida e na˜o-amb´ıgua, com o propo´sito de solucionar um deter- minado problema. 10 CAPI´TULO 1. INTRODUC¸A˜O Apesar de conseguirem executar operac¸o˜es muito complexas, os computadores na˜o sa˜o do- tados da mesma capacidade de compreensa˜o que os humanos. Uma sequ¨eˆncia de tarefas consi- derada simples e o´bvia para uma pessoa qualquer pode ser incompreens´ıvel e pouco detalhada para um computador. Voltando ao exemplo da escovac¸a˜o, um computador poderia considera´-lo incompleto, pois ha´ diversas questo˜es sobre como algum passo pode ser executado, por exemplo: 1. Onde esta´ a escova a ser usada? 2. Quanto, exatamente, se deve colocar de pasta sobre as cerdas? 3. O que fazer se na˜o houver pasta? Escovar mesmo sem a pasta ou interromper o processo de escovac¸a˜o? Questo˜es como essas sa˜o facilmente contornadas por um humano, decididas instantaˆneamente de acordo com o ambiente que o cerca. Enta˜o, para que uma ma´quina tambe´m possa “decidir” o que fazer em situac¸o˜es semelhantes, e´ necessa´rio que se estabelec¸am as condic¸o˜es iniciais (condic¸o˜es de entrada) e as finais (condic¸o˜es de sa´ıda) do problema. Dessa forma, ela sabera´ quais ferramentas podera˜o ser usadas para atingir a condic¸a˜o de sa´ıda desejada. Assim, o problema da escovac¸a˜o seria mais bem definido da seguinte maneira: Condic¸o˜es de Entrada: Dentes sujos com restos de alimentos, uma escova dental em condic¸o˜es de uso, 90 gramas de creme dental e 300 mililitrosde a´gua tratada. Condic¸o˜es de Sa´ıda: Dentes limpos (sem restos de alimentos vis´ıveis), uma escova dental em condic¸o˜es de uso e 85 gramas de creme dental. Toda a quantidade de a´gua deve ser utilizada. Portanto, para um computador, os algoritmos definem o conjunto de atividades que ele deve desempenhar para solucionar um problema. Contudo, ta˜o importante quanto saber “o que” escrever para a ma´quina e´ saber “como” escrever. Para que um computador possa executar um algoritmo, e´ necessa´rio que esse algoritmo seja traduzido para uma linguagem de programac¸a˜o, geralmente incompreens´ıvel para a maioria das pessoas. Ao se traduzir um algoritmo para uma linguagem de programac¸a˜o, obte´m-se um programa. “Embora os computadores modernos sejam capazes de executar operac¸o˜es dif´ıceis e complexas, eles sa˜o ma´quinas do´ceis e de uma inteligeˆncia restrita. Eles devem ser ensinados exatamente o que fazer, e as instruc¸o˜es devem ser feitas em uma linguagem simples, precisa e limitada que eles possam compreender. Estas instruc¸o˜es sa˜o mais conhecidas como programa” (Darmell,1988). 1.4. TE´CNICA DE DESENVOLVIMENTO DE PROGRAMAS 11 1.4 Te´cnica de Desenvolvimento de Programas Na maioria das vezes, o ato de programar na˜o e´ uma tarefa simples e fa´cil. A sintaxe das linguagens de programac¸a˜o e´ bem r´ıgida e deve ser respeitada fielmente para que o computador a compreenda. Esquecer de um “;” no lugar onde e´ necessa´rio, por exemplo, significa comprometer a execuc¸a˜o de todo o programa (na verdade, o computador pode nem comec¸ar a executa´-lo). Ou pior, um programa teoricamente correto, que na˜o apresente erros de sintaxe, pode fornecer um resultado incorreto. Encontrar o erro torna-se um enorme problema a` medida que o programa cresce em tamanho e complexidade. Para contornar a complexidade dos programas, os construtores de software costumam fazer uso de uma poderosa te´cnica de programac¸a˜o, conhecida como “te´cnica dos refinamentos suces- sivos”5. Ela consiste basicamente em dividir um processo complexo em processos-componentes menores, especificando apenas a entrada e a sa´ıda de cada um deles. E se, mesmo assim, alguns processos menores continuarem complexos, repete-se a divisa˜o no interior dos processos- componentes, gerando processos cada vez mais simplificados. Ale´m de facilitar a depurac¸a˜o de erros, essa te´cnica pode tornar um complexo programa em uma “unia˜o” de programas menores e mais simples. A divisa˜o tambe´m possibilita outra grande vantagem, o reu´so de co´digo, ou seja, o uso de um mesmo trecho de programa para realizar o mesmo tipo de tarefa em diferentes ocasio˜es dentro de um programa maior. Um exemplo pra´tico do uso dos refinamentos sucessivos segue abaixo: =⇒ Algoritmo “Escovac¸a˜o denta´ria”: 1. Pegar a escova e a pasta de dentes; 2. Colocar um pouco de pasta sobre as cerdas da escova; 3. Escovar os dentes do maxilar inferior; 4. Escovar os dentes do maxilar superior; 5. Expelir da boca o excesso de espuma; 6. Bochechar um pouco de a´gua; 7. Lavar a escova e guarda´-la; 8. Enxugar o rosto. =⇒ Processo-componente “pegar a escova e a pasta de dentes”: 1. Enquanto na˜o encontrar a escova e o tubo de pasta, continuar procurando por cada gaveta do arma´rio; 5Tambe´m conhecida como “dividir para conquistar”. 12 CAPI´TULO 1. INTRODUC¸A˜O 2. Caso tenham acabado as gavetas e na˜o tenha encontrado a escova e o tubo, interromper a tarefa. =⇒ Processo-componente “escovar os dentes do maxilar inferior”: 1. Com as cerdas da escova na posic¸a˜o vertical, fazer movimentos de vai-e-vem na regia˜o superior dos dentes; 2. Com as cerdas na posic¸a˜o horizontal, escovar a regia˜o frontal dos dentes; 3. Com as cerdas na posic¸a˜o horizontal, escovar a regia˜o detra´s dos dentes. =⇒ Processo-componente “escovar a regia˜o detra´s dos dentes”: 1. Abrir bem a boca; 2. Afastar a l´ıngua da regia˜o a ser escovada; 3. Esfregar as cerdas da escova atra´s dos dentes. O exemplo anterior mostra apenas parte do processo de refinamentos, que deve prosseguir ate´ que cada atividade esteja suficientemente detalhada, possibilitando que o computador as reconhec¸a e execute. 1.5 Partes de um Programa Como dito anteriormente, os programas podem ser comparados a` diversas atividades do dia-a- dia de qualquer pessoa. Um exemplo e´ o de receitas culina´rias. Geralmente, essas seguem uma determinada estrutura, como abaixo: • Nome da receita; • Ingredientes: descreve todo o material necessa´rio para o preparo da receita; • Modo de preparo: descreve a forma de trabalhar com os ingredientes para que se obtenha o resultado esperado; • Comenta´rios sobre certos procedimentos ou ingredientes a fim de detalhar alguma peculi- aridade que o cozinheiro poderia na˜o conhecer previamente. A estrutura de um bom programa segue um modelo semelhante. Basicamente, um programa deve conter quatro partes: • Cabec¸alho: conte´m informac¸o˜es sobre o programa, como o seu nome; 1.5. PARTES DE UM PROGRAMA 13 • Diciona´rio de dados: define quais sa˜o os dados manipulados pelo programa; • Corpo: define os procedimentos que o programa deve executar; • Documentac¸a˜o: explica certos aspectos na˜o muito claros do programa, tanto no corpo do programa quanto no cabec¸alho ou no diciona´rio de dados. Um dos principais objetivos deste tipo de estrutura e´ aumentar a legibilidade do programa, ou seja, facilitar o entendimento dos diversos processos que o programa executa. Um programa deve valorizar a formatac¸a˜o, disposic¸a˜o f´ısica das linhas de co´digo, para facilitar seu entendimento. Colocar cada comando em uma linha e inserir uma linha em branco entre blocos de comandos de finalidade comum sa˜o regras ba´sicas para uma boa formatac¸a˜o. Os programas devem ser lidos e entendidos por quem os escreveu e por outras pessoas, uma vez que podem necessitar de correc¸a˜o, manutenc¸a˜o, modificac¸a˜o ou apenas de serem compreendidos por um simples usua´rio. Para ilustrar essa estrutura, apresenta-se a seguir um programa, Pseudoco´digo 1.1, que efetua o ca´lculo das ra´ızes reais de uma equac¸a˜o de segundo grau. Os dados de entrada do programa sa˜o os treˆs coeficientes da equac¸a˜o e ele devera´ apresentar ao usua´rio as ra´ızes reais da mesma, caso existam. Pseudoco´digo 1.1 Ca´lculo das ra´ızes reais de uma equac¸a˜o de segundo grau. Descric¸a˜o: programa que calcula as ra´ızes reais de uma equac¸a˜o de segundo grau. Dados de Entrada: os treˆs coeficientes da equac¸a˜o. Sa´ıda do Programa: ra´ızes reais da equac¸a˜o. Leitura dos coeficientes da equac¸~ao; Ca´lculo do discriminante (delta); Ca´lculo das raı´zes pelo processo componente "Ca´lculo das Raı´zes"; Utilizando a te´cnica dos refinamentos sucessivos, na u´ltima linha do Pseudoco´digo 1.1 ocorre a execuc¸a˜o do processo componente Ca´lculo das Ra´ızes, que, a partir dos valores dos coeficien- tes lidos e do discriminante calculado, encontra os valores das ra´ızes reais da equac¸a˜o. No geral, o processo componente Ca´lculo das Ra´ızes deve conter os passos descritos no Pseudoco´digo 1.2. Pseudoco´digo 1.2 Processo componente para o ca´lculo das ra´ızes. Processo-componente "Ca´lculo das Raı´zes": Verificar a existe^ncia de raı´zes reais Se possui raı´zes reais: Exiba para o usua´rio os valores da raı´zes; Sen~ao: Exiba um alerta sobre a n~ao existe^ncia de raı´zes reais; FIM-Processo componente "Ca´lculo das Raı´zes" 14 CAPI´TULO 1. INTRODUC¸A˜O No Exemplo 1.1, o programa para o ca´lculo das ra´ızes esta´ transcrito para a linguagem de programac¸a˜o C. Deve-se destacar que o texto escrito entre os s´ımbolos “/*” e “*/” e´ sempre ignorado pelo computador, na˜o alterando em nada o funcionamento do programa. Pore´m, esse texto serve para comentar o co´digo e deixa´-lo mais claro. Pode-se fazeˆ-los tambe´m utilizando o s´ımbolo “//”, que transformaem comenta´rio tudo aquilo que estiver a sua direita, ate´ o final da linha. 1 /* 2 Programa para ca´lculo das raı´zes de segundo grau. 3 Dados de entrada: os coeficientes a, b e c de uma equac¸~ao 4 da forma ax^2 + bx + c = 0 5 Dados de saı´da: imprime na tela as raı´zes reais da equac¸~ao , caso existam. 6 Restric¸~ao: N~ao se considera o zero como um possı´vel valor de a. 7 */ 8 9 #include <math.h> 10 #include <stdio.h> 11 12 main(){ 13 float a; // Coeficiente angular. 14 float b; // Coeficiente linear. 15 float c; // Termo independente. 16 float delta; // Discriminante. 17 float raiz1; // A primeira raiz. 18 float raiz2; // A segunda raiz. 19 20 // Leitura dos coeficientes. 21 scanf("%f %f %f",&a, &b, &c); 22 23 // Ca´lculo do discriminante (delta). 24 delta = b*b - 4 * a * c; 25 26 // Ca´lculo das raı´zes. 27 if(delta < 0){ 28 printf("A equac¸~ao n~ao possui raı´zes reais"); 29 }else{ 30 raiz1 = (-b + sqrt(delta)) / (2*a); 31 raiz2 = (-b - sqrt(delta)) / (2*a); 32 printf("As raı´zes da equac¸~ao s~ao: %f e %f",raiz1 , raiz2); 33 } 34 } Exemplo 1.1: Programa para o ca´lculo das ra´ızes reais de uma equac¸a˜o de segundo grau. Na linguagem C, o cabec¸alho dos programas sempre tem o nome main() e o in´ıcio do corpo do programa e´ marcado pela chave “{”, assim como o final e´ marcado pela u´ltima chave “}”. As linhas 9 e 10 permitem o uso dos comandos sqrt e printf (o significado desses comandos e´ explicado no pro´ximo cap´ıtulo). 1.6. TRADUC¸A˜O DE PROGRAMAS 15 De acordo com a estrutura de programa apresentada no in´ıcio desta sec¸a˜o, as linhas 13 a 18 compo˜em o diciona´rio de dados e o restante compo˜e o corpo do programa. A documentac¸a˜o esta´ inserida no programa em forma de comenta´rios, como as linhas 1 a 7, 20, 23 e 26. Vale destacar a importaˆncia da disposic¸a˜o f´ısica das linhas de co´digo para o fa´cil entendimento do programa. A hierarquizac¸a˜o de elementos por meio de espac¸os em branco e´ chamada de indentac¸a˜o. O trecho de programa relacionado ao ca´lculo das ra´ızes no Exemplo 1.1 demonstra como a indentac¸a˜o pode facilitar a visualizac¸a˜o da mudanc¸a do fluxo do programa. Normalmente, linhas de co´digo com mesma indentac¸a˜o sa˜o executadas de maneira cont´ınua, uma apo´s a outra. Uma mudanc¸a na indentac¸a˜o indica uma mudanc¸a nesse fluxo de execuc¸a˜o do programa. No pro´ximo cap´ıtulo sa˜o apresentadas diversas maneiras de mudar esse fluxo. 1.6 Traduc¸a˜o de Programas Apesar do que foi dito na Sec¸a˜o 1.3, para ser executado pelo computador, um programa ainda precisa ser traduzido para uma linguagem mais simples que as linguagens de alto n´ıvel: a lingua- gem de ma´quina. Chama-se de “co´digo fonte” o arquivo que conte´m o conjunto de instruc¸o˜es escritas em uma determinada linguagem de programac¸a˜o, normalmente familiares ao programa- dor. Ja´ o arquivo que as conte´m traduzidas para linguagem de ma´quina e´ chamado de “co´digo objeto”. Para efetuar essa traduc¸a˜o, e´ necessa´rio aplicar um programa, ou conjunto de programas, que receba o co´digo fonte e gere o co´digo objeto. A seguir, descrevem-se dois me´todos ba´sicos para um programa tradutor efetuar essa tarefa: a compilac¸a˜o e a interpretac¸a˜o de um co´digo fonte. 1.6.1 Compilac¸a˜o O processo de compilac¸a˜o efetua a traduc¸a˜o integral do programa fonte para o co´digo de ma´quina. Uma vez traduzido, o programa em linguagem de ma´quina pode ser executado diretamente. A Figura 1.2 ilustra esse processo. A grande vantagem desse me´todo de traduc¸a˜o e´ a rapidez na execuc¸a˜o dos programas, pois na˜o e´ necessa´rio fazer qualquer traduc¸a˜o durante a execuc¸a˜o. Pore´m, o co´digo objeto gerado pela compilac¸a˜o e´, geralmente, espec´ıfico para um determinado tipo de arquitetura de computador. Assim, e´ necessa´rio uma nova compilac¸a˜o do programa para cada tipo diferente de computador. A linguagem C, adotada neste livro, e´ um exemplo de linguagem de programac¸a˜o compilada. 1.6.2 Interpretac¸a˜o No processo de interpretac¸a˜o, cada instruc¸a˜o do co´digo fonte e´ traduzida no instante imedia- tamente anterior a` execuc¸a˜o dela. Desse modo, em contraste com a compilac¸a˜o, a traduc¸a˜o e execuc¸a˜o de programas interpretados podem ser vistas como um processo u´nico (veja as Figuras 1.2 e 1.3). 16 CAPI´TULO 1. INTRODUC¸A˜O Figura 1.2: Me´todo de compilac¸a˜o. Figura 1.3: Me´todo de interpretac¸a˜o. Apesar de ser um processo mais lento quando comparado ao me´todo anterior, a interpretac¸a˜o apresenta maior flexibilidade na construc¸a˜o de programas e facilidade de depurac¸a˜o de co´digo. A presenc¸a do interpretador durante a execuc¸a˜o permite, por exemplo, a execuc¸a˜o de trechos de programas criados, alterados ou obtidos durante a pro´pria execuc¸a˜o. 1.7 Resumo • O processador e´ o componente do computador responsa´vel por executar os programas armazenados na memo´ria. • A memo´ria e´ responsa´vel por armazenar os programas e os dados. A unidade ba´sica da memo´ria e´ o bit. • Algoritmo e´ uma sequ¨eˆncia de operac¸o˜es que deve ser executada em uma ordem definida e na˜o-amb´ıgua, com o propo´sito de solucionar um determinado problema. Ao traduzir-se um algoritmo para uma linguagem de programac¸a˜o, obte´m-se um programa. • A Te´cnica de Refinamentos Sucessivos consiste, basicamente, em dividir sucessivamente problemas complexos em diversos problemas menores e mais simples. • Um programa bem estruturado deve conter as seguintes partes bem definidas: cabec¸alho, diciona´rio de dados, corpo e documentac¸a˜o. 1.8. EXERCI´CIOS PROPOSTOS 17 • Basicamente, existem dois mecanismos de traduc¸a˜o de programas para linguagem de ma´quina: compilac¸a˜o e interpretac¸a˜o. Na compilac¸a˜o, o co´digo fonte e´ totalmente tradu- zido antes de ser executado. Ja´ na interpretac¸a˜o, a traduc¸a˜o do co´digo fonte e a execuc¸a˜o do programa ocorrem quase simultaneamente, como um processo u´nico. 1.8 Exerc´ıcios Propostos 1. Qual e´ o papel do processador? 2. Qual e´ o papel da memo´ria? 3. Considere uma memo´ria que possua ce´lulas de 8 bits cada uma. Qual o nu´mero de poss´ıveis informac¸o˜es diferentes cada ce´lula pode armazenar? 4. Utilizando o conceito de algoritmo apresentado no cap´ıtulo, descreva, atrave´s de um al- goritmo, o ato de trocar um pneu furado de um carro. Na˜o se esquec¸a de estabelecer as condic¸o˜es iniciais do problema (por exemplo, carro com um pneu dianteiro furado, se a chave de roda esta´ no carro, se o carro esta´ parado em uma ladeira, etc) e as condic¸o˜es de sa´ıda (por exemplo, carro parado e frenado, etc). 5. Use a Te´cnica de Refinamentos Sucessivos para detalhar as seguintes atividades: (a) Montagem de uma barraca de camping; (b) Preparac¸a˜o de um bolo de aniversa´rio; (c) Ca´lculo da distaˆncia entre dois pontos no plano cartesiano. Cap´ıtulo 2 Conceitos Ba´sicos Co-autores: Andre´ Boechat Bruno Pandolfi Objetivos: • Apresentar o conceito de varia´vel; • Estudar os principais tipos de dados ba´sicos e expresso˜es va´lidas; • Mostrar como e´ feita a definic¸a˜o de varia´veis e constantes; • Apresentar os comandos elementares usados em programas. A ide´ia de resolver problemas formalizando a soluc¸a˜o atrave´s do emprego de algoritmos e´ a espinha dorsal da programac¸a˜o procedural, na qual as tarefas sa˜o prescritas ao computador por meio de uma sequ¨eˆncia de operac¸o˜es ba´sicas. Este cap´ıtulo trata do estudo dos conceitos e operac¸o˜es elementares da programac¸a˜o, forne- cendo uma base so´lida que, mais adiante, serve para construir algoritmos progressivamente mais complexos e resolver problemas cada vez mais elaborados. 2.1 Varia´veis e Ce´lulas de Memo´ria Qualquer algoritmo tem por finalidade produzir algum resultado u´til para compor a soluc¸a˜o de um problema. Os algoritmos computacionais,em sua maioria, operam sobre um conjunto de dados para produzir novos resultados de acordo com a necessidade da tarefa em questa˜o. Quando corretamente transcritos para uma linguagem de programac¸a˜o, os algoritmos sa˜o chamados de programas e podem ser executados pelo computador. E´ necessa´rio, todavia, arma- zenar as informac¸o˜es utilizadas pelos programas em um local organizado e seguro, para que as consultas e alterac¸o˜es sejam efetuadas de maneira coerente e livre de erros. Os computadores utilizam a memo´ria para armazenar os dados de um programa em execuc¸a˜o. 18 2.1. VARIA´VEIS E CE´LULAS DE MEMO´RIA 19 Como dito na Sec¸a˜o 1.2.1, a memo´ria pode ser entendida como uma sequ¨eˆncia de ce´lulas, cada ce´lula podendo armazenar uma porc¸a˜o dos dados de um programa. Grac¸as a essa ordenac¸a˜o sequ¨encial, cada ce´lula possui um nu´mero identificador chamado enderec¸o, que esta´ relacionado com a posic¸a˜o que a ce´lula ocupa na sequ¨eˆncia. Por meio dos enderec¸os e´ poss´ıvel acessar qualquer ce´lula para ler ou alterar seu conteu´do. A Figura 2.1 esboc¸a essa ide´ia, pore´m, em contraste com a Figura 1.1, omite a representac¸a˜o dos bits. Figura 2.1: Modelo para a estrutura da memo´ria do computador, mostrando uma frac¸a˜o de seis ce´lulas, seus enderec¸os e conteu´dos. As seis ce´lulas de memo´ria da Figura 2.1 podem guardar valores nume´ricos ou letras em seus interiores. Cada ce´lula e´ apontada por um enderec¸o u´nico e sequ¨encial. A estrutura da memo´ria favorece a execuc¸a˜o de suas duas operac¸o˜es ba´sicas: leitura e escrita. A leitura e´ o processo de consulta do conteu´do da ce´lula. Essa operac¸a˜o na˜o altera o valor guardado na ce´lula. A escrita e´ o processo de armazenamento de um novo dado na ce´lula indicada por um enderec¸o conhecido. Apo´s a execuc¸a˜o da escrita, o valor que estava anteriormente armazenado na ce´lula e´ perdido. Um algoritmo para o ca´lculo do valor da conta mensal de energia ele´trica e´ um bom exemplo para compreender as operac¸o˜es ba´sicas da memo´ria. Os dados de entrada desse algoritmo sa˜o: a leitura atual do medidor, a leitura registrada no meˆs anterior e o prec¸o do quilowatt-hora (kWh) — unidade comercial de energia ele´trica. Na pra´tica, o que se faz para calcular o valor da conta e´ encontrar a diferenc¸a entre a leitura atual do medidor e a leitura do meˆs anterior e multiplicar esse valor pelo prec¸o do quilowatt-hora. O algoritmo computacional, por sua vez, e´ descrito no Pseudoco´digo 2.1. No Pseudoco´digo 2.1, o computador leˆ os conteu´dos das ce´lulas 43 e 46 (que guardam os valores das leituras atual e anterior, respectivamente), realiza a subtrac¸a˜o e o resultado e´ guar- dado na ce´lula 41. Posteriormente, essa diferenc¸a e´ lida e seu valor multiplicado pelo conteu´do da ce´lula 44, que guarda o valor do prec¸o unita´rio do kWh. Finalmente, o valor da conta e´ guardado na ce´lula 42. Acompanhando a descric¸a˜o acima e´ poss´ıvel chegar a` situac¸a˜o encontrada na Figura 2.2. Nos primo´rdios da programac¸a˜o, percebeu-se que acessar a memo´ria por meio de enderec¸os era trabalhoso demais e causa constante de erros. Isso porque o programador deveria escolher os enderec¸os das ce´lulas com as quais iria trabalhar, tanto das ce´lulas que teriam valores a serem lidos quanto das que seriam usadas para a escrita de resultados. Essa situac¸a˜o confusa e´ observa´vel no exemplo da conta de energia ele´trica. Sem o comenta´rio 20 CAPI´TULO 2. CONCEITOS BA´SICOS Pseudoco´digo 2.1 Ca´lculo da conta de energia ele´trica utilizando os enderec¸os das ce´lulas de memo´ria. Descric¸a˜o: programa que calcula o valor da conta de energia ele´trica. Dados de Entrada: ce´lulas 43 e 46 contendo, respectivamente, a leitura atual e a anterior; e valor unita´rio do kWh na ce´lula 44. Sa´ıda do Programa: valor da conta, armazenada na ce´lula 42. Subtrair o conteu´do da ce´lula 43 do conteu´do da ce´lula 46 e guardar na ce´lula 41; Multiplicar o conteu´do da ce´lula 41 pelo conteu´do da ce´lula 44 e guardar na ce´lula 42; Figura 2.2: Conteu´do da memo´ria apo´s execuc¸a˜o do algoritmo que calcula o valor de uma conta de energia ele´trica. no in´ıcio do Pseudoco´digo 2.1, seria imposs´ıvel ter a mı´nima ide´ia do que o programa faz em cada passo. Isso torna dif´ıcil na˜o so´ a escrita, mas tambe´m a correc¸a˜o dos programas. Para resolver essa questa˜o, o conceito de varia´vel foi criado. Uma varia´vel nada mais e´ do que uma abstrac¸a˜o para o enderec¸o de memo´ria. Com o emprego de varia´veis, as ce´lulas de memo´ria sa˜o referenciadas nos programas por meio de ro´tulos, definidos com ajuda do bom- senso do programador. O compilador fica encarregado do trabalho de transformar ro´tulos em enderec¸os para que as operac¸o˜es de acesso a` memo´ria sejam realizadas. O Pseudoco´digo 2.2 mostra como fica o programa que calcula o valor da conta de energia ele´trica, agora escrito utilizando varia´veis. Pseudoco´digo 2.2 Ca´lculo da conta de energia ele´trica utilizando varia´veis. Descric¸a˜o: programa que calcula o valor da conta de energia ele´trica. Dados de Entrada: a leitura atual, a anterior e o prec¸o unita´rio do kWh. Sa´ıda do Programa: valor da conta. Subtrair o conteu´do da varia´vel ‘leituraAtual’ do conteu´do da varia´vel ‘leituraAnterior’ e guardar na varia´vel ‘diferenca’; Multiplicar o conteu´do da varia´vel ‘diferenca’ pelo conteu´do da varia´vel ‘valorUnitario’ e guardar na varia´vel ‘valorConta’; A partir do Pseudoco´digo 2.2, um compilador pode converter os ro´tulos para posic¸o˜es quais- quer na memo´ria, evitando que o programador tenha que se preocupar em manipula´-las. Uma 2.2. IDENTIFICADORES 21 Figura 2.3: Uma poss´ıvel traduc¸a˜o para enderec¸os de memo´ria, a partir dos ro´tulos do co´digo que utiliza varia´veis. poss´ıvel traduc¸a˜o e´ exibida na Figura 2.3. Como visto nos exemplos desta sec¸a˜o, o uso de varia´veis em um algoritmo reduz a quantidade de comenta´rios explicativos, pois sua leitura e´ mais simples e seu entendimento e´ mais fa´cil. Em caso de erros, a correc¸a˜o do programa e´ muito mais ra´pida e eficiente. Apresentados os conceitos de varia´vel e ce´lulas de memo´ria, e´ va´lido abordar um outro significado de programa. Trata-se de considerar os programas como sendo processos de mudanc¸a de estados. Nessa abordagem, os dados de entrada, escritos em suas respectivas varia´veis, sa˜o conside- rados o estado inicial do programa. A partir da´ı, realiza-se uma sequ¨eˆncia de operac¸o˜es para chegar a um estado final. A cada operac¸a˜o, diz-se que o programa esta´ em um novo estado in- termedia´rio. O estado final e´ atingido quando a tarefa em questa˜o e´ considerada como realizada. A transic¸a˜o do estado inicial para o estado final pode ser efetuada de diversas maneiras. Conforme pode ser visto mais adiante neste cap´ıtulo, e´ poss´ıvel escolher entre duas ou mais sequ¨eˆncias de comandos, bem como repeti-las, de acordo com o estado intermedia´rio em que o programa se encontra. 2.2 Identificadores Em geral, as linguagens de alto n´ıvel possuem dois tipos de elementos: os elementos definidos pela pro´pria linguagem — s´ımbolos para operadores, nome de comandos etc — e os elementos definidos pelo programador — identificadores, comenta´rios etc. Um identificador e´ um s´ımbolo que pode representar alguma entidade criada pelo progra- mador, como uma varia´vel, por exemplo. Cada linguagem define uma regra para formac¸a˜o de identificadores. Em geral, sempre e´ poss´ıvel utilizar uma sequ¨eˆncia de caracteres alfanume´ricos — letras ou d´ıgitos, sem acentos e sem cedilha — sendo que o primeiro caractere deve ser obri- gatoriamente alfabe´tico. Os Exemplos 2.1 e 2.2 apresentam, respectivamente, nomes corretos e nomes inva´lidos de varia´veis na linguagem C. Algumas linguagens, como C, fazem diferenciac¸a˜o entre letras maiu´sculas eminu´sculas. Desta forma, uma varia´vel de nome Saldo e´ considerada diferente de outra de nome saldo, ou, ainda, de nome SALDO. E´ importante ressalvar que na˜o e´ uma boa pra´tica de programac¸a˜o criar identificadores que apenas se diferenciem pelo formato das letras, como no exemplo do saldo, pois isso tem impacto negativo na legibilidade dos programas. 22 CAPI´TULO 2. CONCEITOS BA´SICOS 1 abc 2 x1 3 y2 4 letra 5 SOMA_TOTAL 6 B_32 Exemplo 2.1: Nomes va´lidos de varia´veis, concordando com as regras de nomenclatura. 1 fim? // ‘‘?’’ n~ao e´ um caractere alfanume´rico 2 %percentual% // ‘‘%’’ n~ao e´ um caractere alfanume´rico 3 123 quatro // Iniciado por nu´mero 4 !hola! // ‘‘!’’ n~ao e´ um caracter alfanume´rico 5 @ARROBA // ‘‘@’’ n~ao e´ um caractere alfanume´rico Exemplo 2.2: Nomes inva´lidos de varia´veis. Normalmente, em grandes projetos de software, sa˜o adotados padro˜es para a escrita dos identificadores a fim de que os programadores possam trocar seus co´digos, entendeˆ-los e altera´- los sem grande dificuldade. Neste texto, e´ adotado como regra na escrita: • Nomes simples: comec¸ados com letra minu´scula e demais caracteres minu´sculos; • Nomes compostos: primeira parte e´ iniciada por letra minu´scula e as demais partes inici- adas por letra maiu´scula. Os demais caracteres sa˜o minu´sculos. Como dito na Sec¸a˜o 1.5, um bom programa deve necessariamente ser leg´ıvel e de fa´cil com- preensa˜o. A escolha dos nomes dos identificadores influenciam diretamente esses dois aspectos. Logo, e´ muito importante que os nomes sejam significativos, deixando bem clara a sua refereˆncia. A fim de contrastar com a declarac¸a˜o de varia´veis do Exemplo 2.1, o Exemplo 2.3 ilustra a convenc¸a˜o proposta, apresentando nomes significativos para varia´veis. Neste, o ro´tulo das varia´veis ja´ e´ suficiente para informar a funcionalidade das mesmas, tornando ra´pida a compre- ensa˜o do programa que as utiliza e dispensando a necessidade de comenta´rios. 1 delta 2 raiz1 3 idade 4 letra 5 percentualDeLucro 6 primeiraLetra 7 indiceBovespa Exemplo 2.3: Nomes significativos para varia´veis. 2.3. COMANDO DE ATRIBUIC¸A˜O 23 2.3 Comando de Atribuic¸a˜o Os pseudoco´digos da Sec¸a˜o 2.1 na˜o mostram como os conteu´dos das varia´veis de entrada sa˜o alterados para que o ca´lculo seja efetuado coerentemente. Em outras palavras, na˜o se mostra como as varia´veis leituraAtual, leituraAnterior e valorUnitario sa˜o inicializadas. O responsa´vel pela alterac¸a˜o dessas varia´veis, assim como de qualquer outra, e´ o comando de atribuic¸a˜o. O comando de atribuic¸a˜o e´ muito importante e, com certeza, e´ o mais utilizado. E´ por meio dele que as varia´veis podem ter seus valores (conteu´dos) alterados. Por isso, o comando de atribuic¸a˜o esta´ diretamente ligado a`s operac¸o˜es de memo´ria. No Exemplo 2.4 e´ transcrito o algoritmo do ca´lculo da conta de energia ele´trica para o co´digo de um programa na linguagem C. 1 main(){ 2 leituraAtual = 125; 3 leituraAnterior = 25; 4 valorUnitario = 2; 5 diferenca = leituraAtual - leituraAnterior; 6 valorConta = diferenca * valorUnitario; 7 } Exemplo 2.4: Ca´lculo do valor da conta de energia ele´trica. No Exemplo 2.4, o s´ımbolo “=” representa o comando de atribuic¸a˜o. Em seu lado esquerdo sempre havera´ a varia´vel destino, na qual sera´ escrito o resultado da expressa˜o do lado direito do comando. As expresso˜es mais simples sa˜o as que conteˆm valores constantes, tais como as que ocorrem nas linhas 1, 2 e 3 do Exemplo 2.4. Essas treˆs linhas sa˜o omitidas propositalmente do Pseudoco´digo 2.2 para torna´-lo mais sim- ples. Entretanto, elas na˜o sa˜o dif´ıceis de compreender, pois apenas informam ao computador quais valores ele deve manipular para encontrar o resultado esperado: o valor da conta mensal de energia ele´trica. Dessa forma, o comando da linha 1 do Exemplo 2.4 simplesmente realiza a atribuic¸a˜o do valor 125 a` varia´vel leituraAtual. A partir da efetivac¸a˜o desse comando, o conteu´do dessa varia´vel pode ser usado para os ca´lculos. O mesmo vale para as demais varia´veis. As linhas 4 e 5 do Exemplo 2.4 sa˜o transcric¸o˜es diretas dos dois passos do algoritmo da conta de energia. O que ocorre de diferente e´ que o valor a ser atribu´ıdo a`s varia´veis do lado esquerdo e´ primeiramente calculado na expressa˜o para, em seguida, ser guardado na varia´vel correspondente. A Figura 2.4 representa graficamente essa passagem. O comando de atribuic¸a˜o e´ executado sempre da mesma maneira pelo computador. Em primeiro lugar a expressa˜o que esta´ do lado direito do comando e´ calculada e, para isso, todas as varia´veis que aparecem teˆm seus valores lidos e lanc¸ados na expressa˜o. Apo´s o fim dos ca´lculos na expressa˜o, o computador escreve o resultado na varia´vel destino, no lado esquerdo. Basicamente, a forma geral do comando de atribuic¸a˜o e´ a seguinte: <varia´vel> = <express~ao>; 24 CAPI´TULO 2. CONCEITOS BA´SICOS Figura 2.4: Representac¸a˜o gra´fica da linha 4 do Exemplo 2.4. E´ muito importante compreender a diferenc¸a significativa existente entre o comando de atri- buic¸a˜o e a igualdade matema´tica. Em muitas linguagens de programac¸a˜o (C, por exemplo) a atribuic¸a˜o e´ tambe´m representada pelo s´ımbolo “=”, o que pode provocar interpretac¸o˜es equi- vocadas. O Exemplo 2.5 mostra um trecho de programa que geralmente causa confusa˜o para os programadores iniciantes. 1 contador = 10; 2 contador = contador + 1; Exemplo 2.5: Incremento de uma varia´vel usando o comando de atribuic¸a˜o. No Exemplo 2.5 ocorrem duas atribuic¸o˜es. A primeira ocorre na linha 1, sendo mais um exemplo simples de inicializac¸a˜o de uma varia´vel, como ja´ discutido anteriormente. Na linha 2, a varia´vel contador aparece em ambos os lados da expressa˜o, o que pode parecer um absurdo matema´tico. Pore´m, e´ necessa´rio lembrar que, nesse contexto, o s´ımbolo “=” atribui o valor da expressa˜o da direita a` varia´vel que aparece a` esquerda. Ou seja, avalia-se primeiro o resultado da expressa˜o a` direita (10 + 1 = 11) e, posteriormente, atribui-se o valor a` varia´vel a` esquerda (contador = 11). Isso e´ representado graficamente na Figura 2.5. Figura 2.5: Representac¸a˜o gra´fica do incremento de uma varia´vel. Mais uma observac¸a˜o e´ necessa´ria: O programador deve ficar atento aos tipos de dados manipulados em um comando de atribuic¸a˜o, pois o tipo da expressa˜o a` direita deve ser compat´ıvel com o tipo da varia´vel a` esquerda. A manipulac¸a˜o dos tipos de dados e´ detalhada na Sec¸a˜o 2.4. 2.4. TIPOS DE DADOS 25 2.4 Tipos de Dados Um tipo de dados delimita o conjunto de valores poss´ıveis que uma determinada varia´vel pode representar. Ale´m disso, define as operac¸o˜es ba´sicas poss´ıveis para suas varia´veis. Sua necessidade decorre do fato de que as ce´lulas de memo´ria, sozinhas, conseguem represen- tar apenas conjuntos de dados muito limitados. Entretanto, a maioria dos valores de interesse pertence a conjuntos extensos, os quais na˜o podem ser representados com o uso de apenas uma ce´lula de memo´ria. Os programadores, enta˜o, passaram a utilizar mu´ltiplas ce´lulas para representar um u´nico valor. Essa atitude resolveu a dificuldade de armazenar dados complexos, mas criou um outra questa˜o: os processos de leitura e escrita para valores de mu´ltiplas ce´lulas, bem como as de- mais operac¸o˜es sobre tais valores, exigiam co´digos que, ale´m de na˜o-triviais, fugiam do foco do problema principal. Na˜o demorou para que as linguagens de programac¸a˜o incorporassem a definic¸a˜o dos tipos de dados e suas operac¸o˜es essenciais, poupando os programadores da tarefa de defini-los em seu co´digo e tornando-o mais enxuto e leg´ıvel. Tipos de dados, portanto, abstraem a forma de implementac¸a˜o e disponibilizam operac¸o˜es sobre oselementos do conjunto para que o programador possa utiliza´-las sem ter que implementa´- las. Os tipos ba´sicos mais importantes sa˜o o tipo inteiro, o ponto flutuante, o booleano e o tipo caractere. Cada linguagem de programac¸a˜o possui certas particularidades em relac¸a˜o aos tipos de dados. Primeiramente, e´ preciso abordar um conceito imprescind´ıvel da escrita de programas em linguagem C: a declarac¸a˜o de varia´veis. Em seguida, sa˜o descritas as caracter´ısticas mais comuns dos tipos ba´sicos principais. 2.4.1 Declarac¸a˜o de Varia´veis De acordo com o problema abordado, diferentes conjuntos de dados sa˜o necessa´rios. Conforme visto, os tipos de dados representam os conjuntos de valores poss´ıveis para suas varia´veis, assim como as operac¸o˜es va´lidas sobre elas. Tambe´m ja´ foram abordadas a necessidade e as vantagens do uso de varia´veis em um programa. Entretanto, ainda na˜o foi mencionado como as varia´veis sa˜o criadas, ou seja, como o programador declara formalmente uma varia´vel em seu co´digo. Na linguagem C, o ato de declarar uma varia´vel e´ simples e imprescind´ıvel. Afinal, sem esse procedimento, na˜o e´ poss´ıvel usa´-la. Quando a declarac¸a˜o de varia´veis e´ esquecida, uma mensagem de erro e´ apresentada ao programador, e a compilac¸a˜o do co´digo e´ interrompida. Por isso, toda varia´vel deve ser declarada antes de ser utilizada. A declarac¸a˜o de varia´veis tem uma estrutura simples e algumas regras ba´sicas. Em primeiro lugar, escreve-se o nome do tipo de dados ao qual a varia´vel pertence. Em seguida, separado por um espac¸o em branco, escreve-se o identificador da varia´vel. <tipo> <identificador>; 26 CAPI´TULO 2. CONCEITOS BA´SICOS E´ poss´ıvel declarar mais de uma varia´vel em uma mesma linha, desde que todas sejam do mesmo tipo, conforme o Exemplo 2.6. 1 float valorFracionado , saldo , salarioMinimo; 2 char letra , ultimaLetra; 3 int entrada1 , entrada2 , entrada3; Exemplo 2.6: Declarac¸a˜o mu´ltipla de varia´veis em uma mesma linha de co´digo. 2.4.2 Tipo Inteiro O tipo inteiro, como o pro´prio nome sugere, representa um intervalo finito do conjunto ma- tema´tico dos nu´meros inteiros. De fato, uma linguagem de programac¸a˜o pode definir va´rios tipos inteiros, cada um com intervalo diferente. Na linguagem C, por exemplo, existem va´rios tipos inteiros, tais como o int, long int, unsigned int, short int. Neste livro, para bem da simplicidade, usa-se apenas o tipo int. O intervalo de valores para o tipo int depende do compilador que esta´ sendo empregado. Assumimos aqui que o intervalo do tipo int sempre varia de entre −32768 a 32767. Em C, como na maioria das linguagens, as operac¸o˜es sobre as varia´veis do tipo inteiro ja´ esta˜o implementadas e a` disposic¸a˜o do programador. As operac¸o˜es dispon´ıveis sa˜o as de soma, subtrac¸a˜o, multiplicac¸a˜o, divisa˜o e resto de divisa˜o, conforme o Exemplo 2.7. O uso dessas func¸o˜es e´ bastante simples e intuitivo, pois ha´ ate´ certa relac¸a˜o com os s´ımbolos da escrita matema´tica. No Exemplo 2.7, as varia´veis x e y sa˜o relacionadas entre si e os resultados sa˜o armazenados nas varia´veis de a a f. Os operadores de soma e subtrac¸a˜o funcionam tal qual na aritme´tica. O operador de sub- trac¸a˜o pode ser aplicado para um u´nico valor quando se deseja inverter seu sinal. A linha 12 do Exemplo 2.7 mostra essa situac¸a˜o. Um destaque deve ser dado ao operador de multiplicac¸a˜o. Seu u´nico s´ımbolo e´ “*” (na˜o ha´ o s´ımbolo “×” ou o “·”). Ale´m disso, em oposic¸a˜o ao que ocorre na aritme´tica, a escrita do “*” na˜o pode ser omitida. Logo, a operac¸a˜o da linha 13 do Exemplo 2.7 geraria erro se na˜o estivesse comentada, pois o compilador trataria xy como uma varia´vel na˜o declarada. 1 main(){ 2 int x, y, a, b, c, d, e, f; 3 4 x = 10; 5 y = 3; 6 7 a = x + y; // a armazena 13 8 b = x - y; // b armazena 7 9 c = x * y; // c armazena 30 10 d = x / y; // d armazena 3 11 e = x % y; // e armazena 1 2.4. TIPOS DE DADOS 27 12 f = -a; // f armazena -13 13 // c = xy; 14 } Exemplo 2.7: Operac¸o˜es ba´sicas com o tipo inteiro int. Tambe´m e´ importante destacar o resultado da operac¸a˜o de divisa˜o. No caso do Exemplo 2.7, o resultado correto da divisa˜o de x — que armazena o valor 10 — por y — cujo valor e´ 3 — e´ a d´ızima perio´dica 3, 333 . . . Entretanto, como as varia´veis envolvidas na linha 10 sa˜o todas do tipo inteiro, o compilador trata de truncar o resultado, desconsiderando a parte decimal e fornecendo 3 como resultado da operac¸a˜o. Ainda no Exemplo 2.7, deve-se notar o uso do operador de resto de divisa˜o inteira. Seu s´ımbolo — “%” — deve ficar entre os valores do dividendo e do divisor. A linha 11 mostra a obtenc¸a˜o do resto da divisa˜o de x por y. Apo´s a execuc¸a˜o dessa operac¸a˜o, a varia´vel e guardara´ o valor 1, que e´ o resto da divisa˜o de 10 por 3. 2.4.3 Tipo Ponto Flutuante Esse tipo de dados representa um intervalo dos nu´meros racionais. Assim como o tipo inteiro, ha´ mais do que um intervalo poss´ıvel, dependendo da precisa˜o escolhida. Na linguagem C, os tipos de ponto flutuante sa˜o o float e o double. Neste livro, apenas o tipo float e´ empregado. Dependendo do compilador utilizado, os tipos de dados de ponto flutuante apresentam dife- rentes preciso˜es. Aqui se considera que o tipo float proveˆ seis casas decimais de precisa˜o. As operac¸o˜es pre´-definidas sa˜o as mesmas que as dispon´ıveis para o tipo int, exceto, e´ claro, pela inexisteˆncia do operador de resto de divisa˜o. O Exemplo 2.8 mostra o uso de varia´veis do tipo float em um programa. 1 main(){ 2 float p, q, x, z; 3 int y; 4 5 x = 10; 6 y = 4; 7 8 p = 50 / 30; // p guardara´ 1 9 q = 10.0 / 4; // q guardara´ 2.5 10 11 z = x / y; // z guardara´ 2.5 12 } Exemplo 2.8: Operac¸o˜es com varia´veis do tipo float. As operac¸o˜es entre varia´veis do tipo float sa˜o escritas com os mesmos s´ımbolos das operac¸o˜es do tipo int. O Exemplo 2.8 mostra particularidades do processo de compilac¸a˜o que podem gerar erros nos programas. 28 CAPI´TULO 2. CONCEITOS BA´SICOS A linha 8 do Exemplo 2.8 possui um comenta´rio explicando que a varia´vel p recebe 1 como resultado da operac¸a˜o de divisa˜o. Tal erro na˜o ocorre para a divisa˜o da linha seguinte. A justificativa para essa situac¸a˜o e´ que, conforme e´ mostrado na Sec¸a˜o 2.3, o computador primeiro calcula o resultado da expressa˜o do lado direito do comando de atribuic¸a˜o para, em seguida, escrever esse valor na correspondente varia´vel de destino. Durante a compilac¸a˜o, o compilador checa os tipos das varia´veis envolvidas nos ca´lculos para realizar as operac¸o˜es correspondentes. Entretanto, quando ha´ apenas valores nume´ricos envolvidos, o compilador considera os nu´meros escritos sem ponto decimal como sendo do tipo inteiro. E´ por isso que a divisa˜o realizada na linha 8 do Exemplo 2.8 resulta em 1. O computador entende a operac¸a˜o 50/30 como uma divisa˜o inteira, descartando a parte decimal do resultado. Ja´ na linha 9, o compilador enxerga o valor 10.0 como sendo do tipo float devido a` presenc¸a expl´ıcita do ponto decimal, e realiza a divisa˜o, resultando no valor esperado. No caso da u´ltima linha do Exemplo 2.8, nenhum resultado inesperado ocorre porque o tipo mais abrangente — tipo float da varia´vel x — encontrado na expressa˜o e´ considerado nas operac¸o˜es, garantindo o resultado esperado. Caso a varia´vel x tambe´m fosse do tipo int, enta˜o o mesmo incoveniente da linha 8 ocorreria. 2.4.4 Tipo Booleano O tipo booleano e´ o tipo de dados mais simples. Ele conte´m apenas dois valores poss´ıveis: verdadeiro e falso. E´ usado principalmente quando se precisa verificar condic¸o˜es no programa, em expresso˜es lo´gicas (Sec¸a˜o 2.6.3) e relacionais (Sec¸a˜o 2.6.2). Na linguagem C na˜o ha´ uma representac¸a˜o espec´ıficapara esse tipo de dados e sa˜o utilizados valores inteiros para codifica´-lo. Desta forma, todo valor inteiro diferente de zero e´ considerado valor “verdadeiro”. O valor zero e´ considerado “falso”. 2.4.5 Tipo Caractere Como o pro´prio nome indica, o tipo caractere registra os co´digos para letras, nu´meros e caracteres especiais ($, &, #, @ etc). Normalmente, esses co´digos e caracteres variam para as diversas regio˜es do planeta, conforme suas particularidades lingu´ısticas. Um padra˜o largamente utilizado atualmente, pricipalmente no Ocidente, e´ o ASCII (American Standard Code of Information Interchange — Padra˜o Americano para Intercaˆmbio de Informac¸o˜es), especificado pelo ANSI (American National Standars Institute — Instituto Americano Nacional de Padro˜es). O padra˜o ASCII e´ uma tabela. Cada posic¸a˜o da tabela simboliza um caractere. Na linguagem C, o tipo char e´ empregado para conter o ı´ndice para a posic¸a˜o da tabela que codifica um determinado caractere. Originalmente, essa tabela era composta por apenas 128 s´ımbolos, os quais inclu´ıam todos os caracteres alfanume´ricos do Ingleˆs, sinais de pontuac¸a˜o e alguns outros s´ımbolos. Os primeiros 32 caracteres eram utilizados para controle de fluxo de dados (em comunicac¸o˜es entre o computador e seus perife´ricos) e na˜o imprimı´veis. Atualmente, esses caracteres ca´ıram em desuso. A Tabela 2.1 mostra os 128 caracteres da tabela ASCII original. 2.4. TIPOS DE DADOS 29 Co´digo Caractere Co´digo Caractere Co´digo Caractere Co´digo Caractere 0 NUL (null) 32 SPACE 64 @ 96 ` 1 SOH (start of heading) 33 ! 65 A 97 a 2 STX (start of text) 34 ” 66 B 98 b 3 ETX (end of text) 35 # 67 C 99 c 4 EOT (end of transmission) 36 $ 68 D 100 d 5 ENQ (enquiry) 37 % 69 E 101 e 6 ACK (acknowledge) 38 & 70 F 102 f 7 BEL (bell) 39 ’ 71 G 103 g 8 BS (backspace) 40 ( 72 H 104 h 9 HT (horizontal tab) 41 ) 73 I 105 i 10 LF (NL line feed,new line) 42 * 74 J 106 j 11 VT (vertical tab) 43 + 75 K 107 k 12 FF (NP from feed,new page) 44 , 76 L 108 l 13 CR (carriage return) 45 - 77 M 109 m 14 SO (shift out) 46 . 78 N 110 n 15 SI (shift in) 47 / 79 O 111 o 16 DLE (data link escape) 48 0 80 P 112 p 17 DC1 (device control 1) 49 1 81 Q 113 q 18 DC2 (device control 2) 50 2 82 R 114 r 19 DC3 (device control 3) 51 3 83 S 115 s 20 DC4 (device control 4) 52 4 84 T 116 t 21 NAK (negative acknowledge) 53 5 85 U 117 u 22 SYN (synchronous idle) 54 6 86 V 118 v 23 ETB (end of trans. block) 55 7 87 W 119 w 24 CAN (cancel) 56 8 88 X 120 x 25 EM (end of medium) 57 9 89 Y 121 y 26 SUB (substitute) 58 : 90 Z 122 z 27 ESC (escape) 59 ; 91 [ 123 { 28 FS (file separator) 60 < 92 \ 124 | 29 GS (group separator) 61 = 93 ] 125 } 30 RS (record separator) 62 > 94 ˆ 126 ˜ 31 US (unit separator) 63 ? 95 127 DEL Tabela 2.1: Os 128 caracteres da tabela ASCII original. Com o passar do tempo, a tabela ASCII sofreu modificac¸o˜es. Ela foi atualizada e incorporou mais 128 novos s´ımbolos, os quais incluem, por exemplo, os caracteres acentuados e o cedilha, do Portugueˆs. Essa nova versa˜o e´ conhecida como tabela ASCII estendida. Para fazer com que uma varia´vel do tipo char aponte para um s´ımbolo de interesse, o programador precisa apenas atribuir a essa varia´vel o caractere desejado, colocando-o entre aspas simples. O Exemplo 2.9 exibe essa situac¸a˜o. 1 main(){ 2 char letraA , letraFMaiuscula , simboloSoma; 3 4 letraA = ‘a’; 30 CAPI´TULO 2. CONCEITOS BA´SICOS 5 letraFMaiuscula = ‘F’; 6 simboloSoma = ‘+’; 7 } Exemplo 2.9: Uso de varia´veis do tipo caractere. 2.4.6 Conversa˜o de Tipos Agora, conhecidas algumas informac¸o˜es sobre os tipos de dados ba´sicos, torna-se mais simples compreender o problema existente na atribuic¸a˜o entre tipos diferentes, mencionada na Sec¸a˜o 2.3. Considera-se que os tipos int, float e char ocupam a quantidade de memo´ria representada na Figura 2.6. Figura 2.6: Tamanho da memo´ria utilizada pelos tipos de dados ba´sicos. As diferenc¸as nos tamanhos sa˜o justifica´veis, uma vez que, quanto maior o conjunto a ser representado, mais ce´lulas de memo´ria sa˜o necessa´rias para acomodar uma varia´vel. Desta forma, sendo o conjunto dos caracteres o menor, e´ preciso apenas um byte (uma ce´lula) para representa´-lo. Ja´ o conjunto do tipo float, que e´ o maior dos treˆs, precisa de 4 bytes (4 ce´lulas) para uma representac¸a˜o coerente de seus valores. E´ preciso ter em mente que, devido a essas restric¸o˜es de implementac¸a˜o, na˜o se deve utili- zar operac¸o˜es de atribuic¸a˜o entre varia´veis sem tomar algum cuidado. Se elas forem de tipos diferentes, problemas podem acontecer. Na˜o ha´ problemas em atribuir uma varia´vel do tipo int a outra do tipo float. Tal qual ocorre na matema´tica, toda varia´vel do tipo int e´ poss´ıvel de ser representada por outra do tipo float, pois o conjunto dos nu´meros racionais conte´m o conjunto dos inteiros. Um racioc´ınio similar pode ser empregado para justificar as atribuic¸o˜es de varia´veis char a varia´veis de tipo int ou float, que tambe´m ocorrem sem erros. O problema e´ quando se tenta atribuir uma varia´vel de um conjunto mais amplo a uma de um conjunto mais restrito. Veja o Exemplo 2.10. Observando o Exemplo 2.10, um programador distra´ıdo pode pensar que houve uma atri- buic¸a˜o correta. Entretanto, o valor armazenado pela varia´vel teste e´ 125. Na˜o havendo condic¸o˜es de armazenar corretamente (um co´digo de 4 bytes na˜o pode ser escrito num espac¸o de apenas 2 bytes), o compilador simplesmente descarta a parte decimal do nu´mero, armazenando apenas 2.5. CONSTANTES 31 sua parte inteira na varia´vel. Logo, e´ preciso permanecer atento a`s atribuic¸o˜es desse tipo para na˜o se equivocar sobre o valor armazenado por uma varia´vel. 1 main(){ 2 int teste; 3 4 teste = 125.568; 5 } Exemplo 2.10: Atribuic¸a˜o entre tipos diferentes com perda de informac¸a˜o. 2.5 Constantes Em algumas situac¸o˜es surge a necessidade de se utilizar um determinado valor constante em diversas partes do co´digo. Para simplificar a alterac¸a˜o dessas constantes e facilitar a leitura do co´digo, e´ poss´ıvel definir um nome signicativo para elas de maneira simples, por meio de uma estrutura espec´ıfica. Essa estrutura e´ iniciada pela diretiva #define, seguida pelo identificador da constante e pelo seu respectivo valor, todos separados por um espac¸o em branco. #define <identificador> <valor> Na linguagem C, a declarac¸a˜o de constantes deve ser feita no in´ıcio do co´digo, antes da func¸a˜o main . O Exemplo 2.11 apresenta declarac¸o˜es va´lidas de constantes. 1 #define PI 3.141593 2 #define FALSO 0 3 #define VERDADEIRO 1 4 #define RAIZDEDOIS 1.414214 5 6 main(){ 7 float raio , comprimento , area; 8 9 raio = 10; 10 area = PI * raio * raio; 11 comprimento = 2 * PI * raio; 12 } Exemplo 2.11: Definic¸a˜o de constantes. Na declarac¸a˜o de constantes, a escolha dos nomes segue as mesmas regras para a escrita dos nomes de varia´veis. Geralmente, para diferenciar as constantes no co´digo, opta-se por escrever seus nomes com todas as letras maiu´sculas. O Exemplo 2.11 mostra um exemplo simples onde diversas constantes sa˜o declaradas de acordo com a convenc¸a˜o proposta. Durante a compilac¸a˜o do co´digo, o compilador troca tocas as ocorreˆncias da constante PI por seu respectivo valor, definido na linha 1. 32 CAPI´TULO 2. CONCEITOS BA´SICOS 2.6 Expresso˜es As varia´veis e constantes podem ser combinadas com os operadores associados a cada tipo de dados, gerando expresso˜es. 2.6.1 Expresso˜es Aritme´ticas A expressa˜o aritme´tica e´ aquela cujos operadores e operandos sa˜o de tipos nume´ricos (int ou float, por exemplo). Nas operac¸o˜es aritme´ticas, e´ guardada sempre a seguinte relac¸a˜o de prioridade: 1. Multiplicac¸a˜o, divisa˜oe resto de divisa˜o; 2. Adic¸a˜o e subtrac¸a˜o. Para se obter uma sequ¨eˆncia diferente de ca´lculos, va´rios n´ıveis de pareˆnteses podem ser usados para quebrar as prioridades definidas. Na˜o e´ permitido o uso de colchetes e chaves, uma vez que estes s´ımbolos ja´ sa˜o utilizados com outras finalidades. O Exemplo 2.12 exibe uma se´rie de expresso˜es aritme´ticas va´lidas. 1 main(){ 2 int x, y, z; 3 4 x = 10 * 10 + 25; // x = 125 5 y = 5 * (7 + 3); // y = 50 6 z = 10 * ((x - 25) / y + (x - 25) * 2); // z = 2020 7 } Exemplo 2.12: Expresso˜es aritme´ticas e o uso de pareˆnteses para determinar a precedeˆncia das operac¸o˜es. No Exemplo 2.12, e´ importante notar que, no comando de atribuic¸a˜o a` varia´vel x, a multi- plicac¸a˜o 10 × 10 e´ executada primeiro. Na linha seguinte, a soma 7 + 3 e´ executada primeiro e seu valor e´, em seguida, multiplicado por 5 e atribu´ıdo a` varia´vel y. A ana´lise da linha 6 e´ deixada para o leitor. Ale´m das operac¸o˜es ba´sicas ja´ citadas, e´ poss´ıvel usar, nas expresso˜es aritme´ticas, outras operac¸o˜es bastante comuns na matema´tica, definidas dentro da linguagem na forma de func¸o˜es. A sintaxe geral para o uso dessas func¸o˜es e´ a seguinte: <nome da func¸~ao>(<valor>) Algumas func¸o˜es matema´ticas sa˜o mostradas na Tabela 2.2. O Exemplo 2.13 exibe va´rios usos de func¸o˜es matema´ticas e expresso˜es aritme´ticas. 2.6. EXPRESSO˜ES 33 Nome Descric¸a˜o abs Mo´dulo ou valor absoluto de um valor inteiro fabs Mo´dulo ou valor absoluto de um valor racional sin Seno de um aˆngulo em radianos cos Cosseno de um aˆngulo em radianos sqrt Raiz quadrada de um nu´mero pow Potenciac¸a˜o floor Maior inteiro na˜o maior que o nu´mero de entrada ceil Menor inteiro na˜o menor que o nu´mero de entrada log Logaritmo neperiano exp Exponencial Tabela 2.2: Principais func¸o˜es matema´ticas ja´ definidas na linguagem C. 1 #include <math.h> 2 3 #define PI 3.1415 4 5 main(){ 6 float a, b, c, delta , raiz1 , raiz2; 7 float x, y, z; 8 9 a = 10; 10 b = 50; 11 c = 30; 12 13 delta = b * b - 4 * a * c; 14 raiz1 = -b + sqrt(delta) / (2 * a); 15 raiz2 = -b - sqrt(delta) / (2 * a); 16 17 x = sin(-PI / 2); 18 y = fabs(x); 19 z = pow(y,2); // y elevado a` pote^ncia 2 20 } Exemplo 2.13: Uso de func¸o˜es matema´ticas pre´-definidas. Para o uso das func¸o˜es matema´ticas apresentadas no Exemplo 2.13 e´ necessa´rio a inclusa˜o da biblioteca math.h, como na linha 1. Os mesmos ca´lculos para a procura das ra´ızes de uma equac¸a˜o de segundo grau sa˜o executados nas linhas 13 a 15, onde a func¸a˜o sqrt calcula a raiz quadrada do seu operando — a varia´vel delta. Ja´ as linhas 15 a 17 apresentam ca´lculos avulsos: a linha 17 executa o ca´lculo do seno de −pi/2 e armazena o resultado na varia´vel x; a linha 18 armazena, na varia´vel y, o mo´dulo do valor armazenado em x; e a linha 19 calcula o valor armazenado em y elevado a` poteˆncia de 2 e armazena o resultado na varia´vel z. 34 CAPI´TULO 2. CONCEITOS BA´SICOS 2.6.2 Expresso˜es Relacionais As expresso˜es relacionais comparam valores entre si. Tal qual se faz na pra´tica, o operador relacional trabalha com dois valores: o da expressa˜o que esta´ a sua direita e o da expressa˜o que esta´ a sua esquerda. E´ importante destacar que uma varia´vel ou uma constante isolada, por si so´, pode ser considerada uma expressa˜o. A Tabela 2.3 mostra exemplos de operadores relacionais da linguagem C e alguns casos de uso. S´ımbolo Nome Exemplo < menor que a < 10 <= menor ou igual a x <= y == igual a 4 == 2*2 > maior que t > 0 >= maior ou igual a delta >= 0 != diferente de x != 9+8*8 Tabela 2.3: Operadores relacionais. As expresso˜es relacionais resultam sempre em 0 (zero) para uma comparac¸a˜o falsa ou 1 para uma comparac¸a˜o verdadeira. As varia´veis do tipo char tambe´m podem ser comparadas entre si, respeitando a ordenac¸a˜o do padra˜o de codificac¸a˜o utilizado. E´ importante atentar que, embora sejam escritos de maneira parecida, ha´ uma grande dife- renc¸a entre o operador de comparac¸a˜o “==” e o comando de atribuic¸a˜o “=”. Essa semelhanc¸a e´ uma fonte comum de erros de programac¸a˜o, geralmente dif´ıceis de detectar. 2.6.3 Expresso˜es Lo´gicas As expresso˜es lo´gicas sa˜o utilizadas para relacionar os resultados de um conjunto de operac¸o˜es relacionais. Elas realizam as principais operac¸o˜es da lo´gica booleana e, na linguagem C, teˆm como operadores: • “&&” (AND): Realiza o “E” lo´gico; • “||” (OR): Realiza o “OU” lo´gico; • “!” (NOT): Realiza a negac¸a˜o. Os resultados obtidos das expresso˜es lo´gicas tambe´m sa˜o valores do tipo inteiro: 0 para falso e 1 para verdadeiro. Para melhor entender o que cada operador realiza, sa˜o levados em conta dois valores P e Q de entrada, que podem ser verdadeiros (V) ou falsos (F). A Tabela 2.4 resume todos os casos poss´ıveis. 2.7. COMANDO DE ENTRADA DE DADOS 35 P Q P && Q P || Q !P !Q V V V V F F V F F V F V F V F V V F F F F F V V Tabela 2.4: Todas as combinac¸o˜es poss´ıveis para os operadores lo´gicos. O uso dos operadores relacionais e lo´gicos fica bem mais claro adiante, neste cap´ıtulo, quando os comandos de selec¸a˜o e repetic¸a˜o sa˜o estudados. 2.7 Comando de Entrada de Dados O comando de entrada de dados serve para captar do usua´rio do programa um ou mais valores necessa´rios para a execuc¸a˜o das tarefas. Na verdade, o que se faz e´ ler os dados de uma fonte externa, normalmente do teclado, para depois usa´-los de alguma maneira dentro do programa. Por meio desse comando de leitura de dados, uma ou mais varia´veis podem ter seus valores lidos durante a execuc¸a˜o do programa. Essa caracter´ıstica permite criar programas mais flex´ıveis. Na linguagem C, a sintaxe para o uso do comando e´ a seguinte: scanf("<formato1> <formato2> ... <formatoN>", &var1, &var2, ..., &varN); Essa estrutura e´ dividida em duas partes distintas. A primeira, colocada entre aspas duplas, conte´m os formatos, os quais sa˜o relacionados diretamente com os tipos das varia´veis a serem lidas. A segunda parte e´ uma lista dos nomes dessas varia´veis, com uma relac¸a˜o direta entre a posic¸a˜o nessa lista e o respectivo formato descrito na primeira parte do comando. Conforme mostra a descric¸a˜o da sintaxe, os nomes das varia´veis devem ser precedidos pelo caractere “&”. A Tabela 2.5 mostra alguns dos poss´ıveis formatos. Co´digo Significado %c Leˆ um u´nico caracter %d Leˆ um inteiro decimal %f Leˆ um nu´mero em ponto flutuante Tabela 2.5: Co´digos para formatos de dados do comando de entrada scanf . Um exemplo claro da utilidade do comando de entrada de dados e´ o ca´lculo da conta de energia ele´trica. O exemplo apresentado ate´ agora tinha os valores de consumo e do prec¸o do quilowatt-hora escritos diretamente no co´digo. Isso e´ bastante incoˆmodo, pois, quando se quer calcular o valor de uma conta diferente, o co´digo deve ser alterado e recompilado. Uma maneira de tornar o programa mais flex´ıvel e´ utilizar o comando de entrada de dados. Com ele, e´ poss´ıvel digitar os valores desejados para as varia´veis e efetuar os ca´lculos para 36 CAPI´TULO 2. CONCEITOS BA´SICOS diferentes contas, bastando, para isso, executar novamente o programa. O co´digo modificado e´ exibido no Exemplo 2.14. De acordo com o formato descrito no comando de leitura, os valores das varia´veis leituraA- tual, leituraAnterior e valorUnitario devem ser digitados pelo usua´rio, nesta ordem, separados por espac¸os em branco. 1 #include <stdio.h> 2 main(){ 3 int leituraAtual , leituraAnterior , diferenca; 4 float valorUnitario , valorConta; 5 6 scanf("%d %d %f", &leituraAtual , &leituraAnterior , &valorUnitario); 7 diferenca = leituraAtual - leituraAnterior; 8 valorConta = diferenca * valorUnitario; 9 } Exemplo 2.14: Emprego do comando
Compartilhar