Você está na página 1de 207

Curso de Linguagem C Em Constru c ao v0.

001
Adriano Joaquim de Oliveira Cruz Instituto de Matem atica N ucleo de Computa c ao Eletr onica UFRJ c 2009 Adriano Cruz 31 de Agosto de 2010

Conte udo
1 Introdu c ao 1.1 1.2 Sucessos e Fracassos da Computa ca o . . . . . . . . . . . . . . . . Um Pouco da Hist oria da Computa ca o . . . . . . . . . . . . . . . 1.2.1 1.2.2 1.2.3 1.2.4 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.4 1.5 1.6 O In cio . . . . . . . . . . . . . . . . . . . . . . . . . . . . A Era Moderna . . . . . . . . . . . . . . . . . . . . . . . . O Desenvolvimento durante as Grandes Guerras . . . . . As Gera co es . . . . . . . . . . . . . . . . . . . . . . . . . . Microcomputadores . . . . . . . . . . . . . . . . . . . . . Mem orias . . . . . . . . . . . . . . . . . . . . . . . . . . . Bits e Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . Perif ericos . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 13 15 15 15 18 20 21 22 23 25 26 26 32 33 34 34 35 37 37 37 38 40 41 42 42 43

O Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

O Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Um programa em C . . . . . . . . . . . . . . . . . . . . . . . . . Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 Algoritmos 2.1 2.2 2.3 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Primeiros Passos . . . . . . . . . . . . . . . . . . . . . . . . . . . Representa ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 2.3.2 2.3.3 2.4 2.5 Linguagem Natural . . . . . . . . . . . . . . . . . . . . . . Fluxogramas . . . . . . . . . . . . . . . . . . . . . . . . . Pseudo-Linguagem . . . . . . . . . . . . . . . . . . . . . .

Modelo de von Neumann . . . . . . . . . . . . . . . . . . . . . . . Estruturas B asicas de Algoritmos . . . . . . . . . . . . . . . . . . 2.5.1 2.5.2 2.5.3 Comandos de leitura . . . . . . . . . . . . . . . . . . . . . Comandos de escrita . . . . . . . . . . . . . . . . . . . . . Express oes . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2.5.4 2.5.5 2.5.6 2.6 2.7

Comandos de atribui ca o . . . . . . . . . . . . . . . . . . . Comandos de controle . . . . . . . . . . . . . . . . . . . . Comandos de repeti ca o . . . . . . . . . . . . . . . . . . .

45 46 47 48 53 55 55 55 55 56 56 57 58 59 59 60 61 62 62 63 63 64 65 67 67 67 68 69 71 73 73 74 75 75 76 78

Exemplos de Algoritmos . . . . . . . . . . . . . . . . . . . . . . . Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3 Tipos de Dados, Constantes e Vari aveis 3.1 3.2 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.4 3.5 3.4.1 3.5.1 3.5.2 3.5.3 3.6 Tipos B asicos . . . . . . . . . . . . . . . . . . . . . . . . . Modicadores de tipos . . . . . . . . . . . . . . . . . . . . Constantes Inteiras na base 10 . . . . . . . . . . . . . . . Constantes Inteiras Octais . . . . . . . . . . . . . . . . . . Constantes Inteiras Hexadecimais . . . . . . . . . . . . . . Convers ao entre Bases . . . . . . . . . . . . . . . . . . . . Constantes em Ponto Flutuante . . . . . . . . . . . . . . . Constantes Cadeias de Caracteres . . . . . . . . . . . . . Nomes das Vari aveis . . . . . . . . . . . . . . . . . . . . . Declara ca o de vari aveis . . . . . . . . . . . . . . . . . . . Atribui ca o de valores . . . . . . . . . . . . . . . . . . . . .

Constantes Num ericas . . . . . . . . . . . . . . . . . . . . . . . .

Constantes Caracteres . . . . . . . . . . . . . . . . . . . . . . . . Vari aveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4 Entrada e Sa da pelo Console 4.1 4.2 4.3 4.4 4.5 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Biblioteca Padr ao . . . . . . . . . . . . . . . . . . . . . . . . . . . Sa da - A Fun ca o printf . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 C odigos de Convers ao . . . . . . . . . . . . . . . . . . . . Entrada - A Fun ca o scanf . . . . . . . . . . . . . . . . . . . . . . Lendo e Imprimindo Caracteres . . . . . . . . . . . . . . . . . . . 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6 Fun co es getchar e putchar . . . . . . . . . . . . . . . . . Lendo e Imprimindo Cadeias de Caracteres . . . . . . . . Lendo e Imprimindo cadeias com scanf e printf . . . . . Lendo e Imprimindo cadeias com gets e puts . . . . . . . A Fun ca o fgets . . . . . . . . . . . . . . . . . . . . . . .

Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

5 Operadores e Express oes 5.1 5.2 5.3 5.4 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Operador de Atribui ca o . . . . . . . . . . . . . . . . . . . . . . . Operadores Aritm eticos . . . . . . . . . . . . . . . . . . . . . . . Operadores Relacionais e L ogicos . . . . . . . . . . . . . . . . . . 5.4.1 5.4.2 5.5 5.6 5.7 5.8 5.9 Operadores Relacionais . . . . . . . . . . . . . . . . . . . Operadores L ogicos . . . . . . . . . . . . . . . . . . . . .

79 79 79 80 81 81 81 83 85 86 86 87 88 89 91 91 91 91 92 93 95 97 97

Operadores com Bits . . . . . . . . . . . . . . . . . . . . . . . . . Operadores de Atribui ca o Composta . . . . . . . . . . . . . . . . Operador v rgula . . . . . . . . . . . . . . . . . . . . . . . . . . . Operador sizeof() . . . . . . . . . . . . . . . . . . . . . . . . . . Convers ao de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . .

5.10 Regras de Preced encia . . . . . . . . . . . . . . . . . . . . . . . . 5.11 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Comandos de Controle 6.1 6.2 6.3 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Blocos de Comandos . . . . . . . . . . . . . . . . . . . . . . . . . Comandos de Teste . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.1 6.3.2 6.3.3 6.4 6.4.1 6.4.2 6.4.3 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.6 Comando if . . . . . . . . . . . . . . . . . . . . . . . . . . Comando switch . . . . . . . . . . . . . . . . . . . . . . . Comando Tern ario . . . . . . . . . . . . . . . . . . . . . . Comando for . . . . . . . . . . . . . . . . . . . . . . . . .

La cos de Repeti ca o . . . . . . . . . . . . . . . . . . . . . . . . . .

Comando while . . . . . . . . . . . . . . . . . . . . . . . 100 Comando do-while . . . . . . . . . . . . . . . . . . . . . 101 Comando break . . . . . . . . . . . . . . . . . . . . . . . 102 Comando continue . . . . . . . . . . . . . . . . . . . . . 102 Comando goto . . . . . . . . . . . . . . . . . . . . . . . . 103 Fun ca o exit() . . . . . . . . . . . . . . . . . . . . . . . . 103 Comando return . . . . . . . . . . . . . . . . . . . . . . . 103

Comandos de Desvio . . . . . . . . . . . . . . . . . . . . . . . . . 102

Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

7 Vetores e Cadeias de Caracteres 7.1 7.2 7.3 7.4 7.5 7.6 7.7

107

Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Declara ca o de Vetores Unidimensionais . . . . . . . . . . . . . . . 107 Cadeias de Caracteres . . . . . . . . . . . . . . . . . . . . . . . . 108 Declara ca o de Vetores Multidimensionais . . . . . . . . . . . . . 112 Vetores de Cadeias de Caracteres . . . . . . . . . . . . . . . . . . 114 Inicializa ca o de Vetores e Matrizes . . . . . . . . . . . . . . . . . 116 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 122

8 Fun co es 8.1 8.2 8.3 8.4 8.5 8.6

Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Forma Geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Prot otipos de Fun co es . . . . . . . . . . . . . . . . . . . . . . . . 124 Escopo de Vari aveis . . . . . . . . . . . . . . . . . . . . . . . . . 125 8.4.1 Vari aveis Locais . . . . . . . . . . . . . . . . . . . . . . . 125 Vari aveis Globais . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Par ametros Formais . . . . . . . . . . . . . . . . . . . . . . . . . 127 8.6.1 8.6.2 8.6.3 Passagem de Par ametros por Valor . . . . . . . . . . . . . 128 Passagem de Par ametros por Refer encia . . . . . . . . . . 129 Passagem de Vetores e Matrizes . . . . . . . . . . . . . . . 129

8.7 8.8 8.9

O Comando return . . . . . . . . . . . . . . . . . . . . . . . . . 132 Recurs ao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 Argumentos - argc e argv . . . . . . . . . . . . . . . . . . . . . . 133

8.10 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 9 Ponteiros 9.1 9.2 138

Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Opera co es com Ponteiros . . . . . . . . . . . . . . . . . . . . . . 139 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 Declara ca o de Ponteiros . . . . . . . . . . . . . . . . . . . 139 Os Operadores Especiais para Ponteiros . . . . . . . . . . 140 Atribui ca o de Ponteiros . . . . . . . . . . . . . . . . . . . 141 Incrementando e Decrementando Ponteiros . . . . . . . . 142 Compara ca o de Ponteiros . . . . . . . . . . . . . . . . . . 144 . . . . . . . . . . . . . . . . . 145

9.3 9.4 9.5 9.6 9.7 9.8 9.9

Ponteiros e Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Ponteiros e Cadeias de Caracteres Aloca ca o Din amica de Mem oria . . . . . . . . . . . . . . . . . . . 146 Ponteiros e Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . 147 Vetores de Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . 148 Ponteiros para Ponteiros . . . . . . . . . . . . . . . . . . . . . . . 151 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 4

10 Estruturas

160

10.1 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 10.2 Deni co es B asicas . . . . . . . . . . . . . . . . . . . . . . . . . . 160 10.3 Atribui ca o de Estruturas . . . . . . . . . . . . . . . . . . . . . . . 163 10.4 Matrizes de Estruturas . . . . . . . . . . . . . . . . . . . . . . . . 163 10.5 Estruturas e Fun co es . . . . . . . . . . . . . . . . . . . . . . . . . 164 10.6 Ponteiros para Estruturas . . . . . . . . . . . . . . . . . . . . . . 166 10.7 Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 11 Entrada e Sa da por Arquivos 171

11.1 Introdu ca o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 11.2 Fluxos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 11.2.1 Fluxos de Texto . . . . . . . . . . . . . . . . . . . . . . . 171 11.2.2 Fluxo Bin ario . . . . . . . . . . . . . . . . . . . . . . . . . 172 11.2.3 Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 11.3 Fun co es de Entrada e Sa da . . . . . . . . . . . . . . . . . . . . . 173 11.4 In cio e Fim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 11.4.1 Abrindo um Arquivo . . . . . . . . . . . . . . . . . . . . . 174 11.4.2 Fechando um Arquivo . . . . . . . . . . . . . . . . . . . . 175 11.4.3 Fim de Arquivo . . . . . . . . . . . . . . . . . . . . . . . . 176 11.4.4 Volta ao In cio . . . . . . . . . . . . . . . . . . . . . . . . 176 11.5 Lendo e Escrevendo Caracteres . . . . . . . . . . . . . . . . . . . 177 11.6 Testando Erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 11.7 Lendo e Escrevendo Cadeias de Caracteres . . . . . . . . . . . . . 180 11.8 Entrada e Sa da Formatada . . . . . . . . . . . . . . . . . . . . . 181 11.9 Lendo e Escrevendo Arquivos Bin arios . . . . . . . . . . . . . . . 182 11.10Exerc cios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 12 Problemas Extras A Tabela ASCII B Palavras Reservadas 188 199 201

Lista de Figuras
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 Fotograa de um circuito integrado de microprocessador Pentium. 14 Imagem de um abaco. . . . . . . . . . . . . . . . . . . . . . . . . Blaise Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Charles Babbage . . . . . . . . . . . . . . . . . . . . . . . . . . . Fotograa da Dierence Engine . . . . . . . . . . . . . . . . . . . Computador Eniac . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama B asico de um Computador Digital . . . . . . . . . . . N veis de hierarquia da mem oria de um computador. . . . . . . . Tamanho de Bits, Bytes e Palavras . . . . . . . . . . . . . . . . . 15 16 17 17 19 22 23 25 30 38 39 42 46 48 50

1.10 Ciclo de desenvolvimento de um programa. . . . . . . . . . . . . 2.1 2.2 2.3 2.4 2.5 2.6 7.1 9.1 9.2 9.3 9.4 9.5 9.6 9.7 S mbolos mais comumente usados em uxogramas. . . . . . . . . Fluxograma para resolver uma equa ca o do primeiro grau. . . . . Modelo de mem oria . . . . . . . . . . . . . . . . . . . . . . . . . Fluxograma do comando se ... ent~ ao ... sen~ ao. . . . . . . Fluxograma para decidir se deve levar um guarda-chuva. . . . . . Fluxograma do comando enquanto. . . . . . . . . . . . . . . . .

Mapa de mem oria de uma matriz. . . . . . . . . . . . . . . . . . 116 Mapa de mem oria com duas vari aveis e ponteiro. . . . . . . . . . 138 Ponteiro apontando para area de mem oria contendo vetor. . . . . 139 Declara ca o de ponteiros. . . . . . . . . . . . . . . . . . . . . . . . 140 Atribui ca o de endere co de uma vari avel a um ponteiro. . . . . . . 141 Uso de um ponteiro para copiar valor de uma vari avel. . . . . . . 141 Exemplos de atribui co es de ponteiros. . . . . . . . . . . . . . . . 142 Armazenamento de matrizes com vetores de ponteiros. . . . . . . 152

11.1 Fluxos de dados. . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

Lista de Tabelas
1.1 1.2 1.3 1.4 1.5 2.1 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 4.1 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 7.1 Transistores por circuito integrado nos microprocessadores da Intel 14 Tempo de execu ca o das instru co es aritm eticas no ENIAC . . . . Exemplos de Microprocessadores . . . . . . . . . . . . . . . . . . Abrevia co es usadas em refer encias ` as mem orias. . . . . . . . . . . Exemplos de perif ericos . . . . . . . . . . . . . . . . . . . . . . . Operadores Aritm eticos. . . . . . . . . . . . . . . . . . . . . . . . Tipos de dados denidos pelo Padr ao ANSI C. . . . . . . . . . . Constantes Inteiras na Base 10 . . . . . . . . . . . . . . . . . . . Constantes octais . . . . . . . . . . . . . . . . . . . . . . . . . . . Constantes hexadecimais . . . . . . . . . . . . . . . . . . . . . . . Constantes em ponto utuante . . . . . . . . . . . . . . . . . . . Exemplos de constantes caractere . . . . . . . . . . . . . . . . . . Exemplos de caracteres invis veis. . . . . . . . . . . . . . . . . . . Tabela do exercicio 6 . . . . . . . . . . . . . . . . . . . . . . . . . C odigos de Convers ao para leitura e entrada de dados. . . . . . . Operadores aritm eticos. . . . . . . . . . . . . . . . . . . . . . . . Operadores Relacionais. . . . . . . . . . . . . . . . . . . . . . . . Operador L ogico E. . . . . . . . . . . . . . . . . . . . . . . . . . . Operador L ogico OU. . . . . . . . . . . . . . . . . . . . . . . . . . Operador L ogico N~ AO. . . . . . . . . . . . . . . . . . . . . . . . . Preced encia dos operadores l ogicos e relacionais. . . . . . . . . . Operadores com bits. . . . . . . . . . . . . . . . . . . . . . . . . . Operador L ogico OU. . . . . . . . . . . . . . . . . . . . . . . . . . Preced encia dos operadores. . . . . . . . . . . . . . . . . . . . . . 19 22 26 26 45 57 58 59 59 61 62 62 66 69 80 81 82 83 83 83 84 84 88

Passos executados durante o algoritmo da bolha. . . . . . . . . . 109

11.1 Exemplos de fun co es de Entrada e Sa da. . . . . . . . . . . . . . 174 A.1 Conjunto de caracteres ASCII . . . . . . . . . . . . . . . . . . . . 199 A.2 Conjunto de c odigos especiais ASCII e seus signicados . . . . . 200

Lista de Algoritmos
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 Exemplo de Algoritmo. . . . . . . . . . . . . . . . . . . . . . . . . Algoritmo para resolver uma equa ca o do primeiro grau. . . . . . . Algoritmo para calcular a m edia das notas de um aluno. . . . . . Algoritmo para calcular a maior nota de um grupo de notas. . . . Modelo de mem oria e funcionamento de um algoritmo . . . . . . . Comando se em pseudo-linguagem . . . . . . . . . . . . . . . . . . Algoritmo para decidir o que fazer no domingo. . . . . . . . . . . Algoritmo para decidir se deve levar um guarda-chuva. . . . . . . Algoritmo para ler 10 n umeros e imprimir se s ao pares ou n ao. . . 36 36 38 40 41 46 47 47 49 51 51 52 54 54 60

2.10 Algoritmo para ler n umeros e imprimir se s ao pares ou n ao. A quantidade de n umeros a ser lida e de 2.11 Algoritmo para calcular a maior nota de uma turma de 25 alunos. 2.12 Algoritmo para calcular a nota m edia de uma turma de 25 alunos. 2.13 Algoritmo para calcular a maior temperatura do ano. . . . . . . . 2.14 Algoritmo do exerc cio 11. . . . . . . . . . . . . . . . . . . . . . . 2.15 Algoritmo do exerc cio 11. . . . . . . . . . . . . . . . . . . . . . . 3.1 Algoritmo para converter inteiros na base 10 para uma base b. . .

Listings
1.1 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 5.1 5.2 5.3 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 Exemplo de Programa em C. . . . . . . . . . . . . . . . . . . . . Exemplo de impress ao de resultados . . . . . . . . . . . . . . . . Exemplo de justica ca o de resultados. . . . . . . . . . . . . . . . Exemplo de uso de especicador de precis ao. . . . . . . . . . . . Exemplo de uso de scanf. . . . . . . . . . . . . . . . . . . . . . Exemplo de uso de getchar e putchar. . . . . . . . . . . . . . . Exemplo de uso de getchar e putchar. . . . . . . . . . . . . . . Exemplo de uso de printf e scanf na leitura de cadeias. . . . . Exemplo de uso de puts e gets na leitura de cadeias. Exemplo de operadores de deslocamento. Exemplo do operador sizeof. Vari aveis da quest ao 9. Exemplo de comandos if. Exemplo de switch. . . . . . . . . . . . . . . . . . . . 32 68 70 71 73 74 74 75 76 85 86 90 92 94 96 97 98 99 99

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Programas com ifs em escada e aninhados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemplo de comando tern ario. . . . . . . . . . . . . . . . . . . . Exemplo de comando for. . . . . . . . . . . . . . . . . . . . . . . Exemplo de comando for com testes sobre outras vari aveis. . . . Exemplo de comando for sem altera ca o da vari avel de controle. Exemplo de comando for sem teste de m. Comando for aninhados.

. . . . . . . . . . . . 100

. . . . . . . . . . . . . . . . . . . . . . 100 . . . . . . . . . . . . . . . . . 101 . . . . . . . . . . . . . . . . . . . . . 106 . . . . . . . . . . . . . . . . . . 110 . . . . . . . . . . . . . . . . . 111

6.10 Comando while com uma fun ca o. 6.11 Programa do exercicio 17. 7.1 7.2 7.3 7.4 7.5

Exemplo de vetores. . . . . . . . . . . . . . . . . . . . . . . . . . 108 Produto escalar de dois vetores. Ordena ca o pelo m etodo da bolha. Leitura de uma matriz.

Exemplos de fun co es para cadeias. . . . . . . . . . . . . . . . . . 113 . . . . . . . . . . . . . . . . . . . . . . . 114

10

7.6 7.7 7.8 7.9 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9

Multiplica ca o de duas matrizes.

. . . . . . . . . . . . . . . . . . 115

Leitura de um vetor de nomes. . . . . . . . . . . . . . . . . . . . 117 Exemplos de tratamento de vetores. . . . . . . . . . . . . . . . . 118 Exemplos de tratamento de vetores. . . . . . . . . . . . . . . . . 118 . . . . . . . . . . . . . . . . . . . . . 121 Exemplo de prot otipos. . . . . . . . . . . . . . . . . . . . . . . . 124 Exemplos de vari aveis locais. . . . . . . . . . . . . . . . . . . . . 126 Deni ca o de vari avel dentro de um bloco. . . . . . . . . . . . . . 126 Deni ca o de vari avel global. . . . . . . . . . . . . . . . . . . . . 127 Exemplo de passagem por valor. . . . . . . . . . . . . . . . . . . 128 Uso indevido de vari aveis locais. . . . . . . . . . . . . . . . . . . 129 Passagem de vetor com dimens oes. . . . . . . . . . . . . . . . . 130 Passagem de vetores sem dimens oes. . . . . . . . . . . . . . . . . 131 Fun ca o recursiva para calcular xn . . . . . . . . . . . . . . . . . . 133 . . . . . . . . . . . . . . . . . . . . . . 136

7.10 Programa do exercicio 14.

8.10 Uso de argc e argv. . . . . . . . . . . . . . . . . . . . . . . . . . 134 8.11 Programa do exerc cio 8. 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 8.12 Programa do problema 9. . . . . . . . . . . . . . . . . . . . . . . 136 Exemplo de atribui ca o de ponteiros. . . . . . . . . . . . . . . . . 142 Exemplos de opera co es com ponteiros. . . . . . . . . . . . . . . 143 Exemplo de subtra ca o de ponteiros. . . . . . . . . . . . . . . . . 144 Exemplo de compara ca o de ponteiros. . . . . . . . . . . . . . . . 144 Exemplo de altera co es inv alidas sobre ponteiros. . . . . . . . . . 145 Exemplo de nota co es de vetores. . . . . . . . . . . . . . . . . . . 145 Exemplo de ponteiro vari avel. . . . . . . . . . . . . . . . . . . . 146 . . . . . . . . . 146 Exemplo de ponteiro para cadeia de caracteres.

Exemplo de c opia de cadeias de caracteres. . . . . . . . . . . . . 147 . . . . . . . . . . . . . . . . . 148 . . . . . . . . 150 . . . . . . . . . . . . . . . . . . . . . 149 . . . . . . . . . . . . 150 . . . . . . . . . . . 153 . . 154

9.10 Exemplo de uso de calloc e free. 9.11 Exemplo de uso de malloc.

9.12 Exemplo de matriz normal sem uso de ponteiros. 9.13 Exemplo de matriz mapeada em um vetor. 9.14 Exemplo de uso de vetor de ponteiros. 9.15 Exemplo de uso de ponteiros para ponteiros. 9.17 Continua ca o do exemplo 9.16. 9.18 Programa do exercicio 11. 9.19 Programa do exercicio 12.

. . . . . . . . . . . . . . 151

9.16 Exemplo de uso de ponteiros para ponteiros usando fun co es.

. . . . . . . . . . . . . . . . . . . 155

. . . . . . . . . . . . . . . . . . . . . 157 . . . . . . . . . . . . . . . . . . . . . 158

9.20 Listagem do exerc cio 13. . . . . . . . . . . . . . . . . . . . . . . 158 11

9.21 Programa do exerc cio 14.

. . . . . . . . . . . . . . . . . . . . . 159

10.1 Deni ca o de uma estrutura. . . . . . . . . . . . . . . . . . . . . . 161 10.2 Atribui ca o de Estruturas. . . . . . . . . . . . . . . . . . . . . . . 163 10.3 Ordena ca o de Estruturas. . . . . . . . . . . . . . . . . . . . . . . 163 10.4 Passando elementos para fun co es. 10.6 Fun ca o que ordena estruturas. . . . . . . . . . . . . . . . . . 164 . . . . . . . . . . . . . . . 165 10.5 Passagem de estruturas para fun co es.

. . . . . . . . . . . . . . . . . . . 166

10.7 Aloca ca o de espa co para estruturas. . . . . . . . . . . . . . . . . 167 10.8 Aloca ca o de espa co para vetores de estruturas. . . . . . . . . . . 168 10.9 Listagem do exercicio 3. 11.1 Uso da fun ca o feof(). . . . . . . . . . . . . . . . . . . . . . . 169 . . . . . . . . . . . . . . . . . . . . . . . 176 . . . . . . . . . . . . 177 . . . . . . . . . . . . 178 . . . . . . 180

11.3 Exemplo de leitura e escrita de caracteres. 11.2 Exemplo de leitura e escrita de caracteres.

11.4 Uso da fun ca o ferror(). . . . . . . . . . . . . . . . . . . . . . . 179 11.5 Exemplo de leitura e escrita de cadeias de caracteres. 11.7 Exemplo de leitura e escrita na forma bin aria. 11.8 Exemplo de leitura e escrita de estruturas. 11.9 (I) Trecho de programa do problema 14. 11.6 Exemplo de leitura e escrita de dados formatados. . . . . . . . . 181 . . . . . . . . . . 182 . . . . . . . . . . . . 184 . . . . . . . . . . . . . 187

11.10(II) Trecho de programa do problema 14. . . . . . . . . . . . . . 187 12.1 Processando o CPF. . . . . . . . . . . . . . . . . . . . . . . . . . 191 12.2 Estrutura do problema 8. . . . . . . . . . . . . . . . . . . . . . . 195

12

Cap tulo 1

Introdu c ao
1.1 Sucessos e Fracassos da Computa c ao

Os objetivos principais deste cap tulo s ao mostrar para o aluno iniciante alguns aspectos da hist oria da computa ca o e denir, informalmente, termos e palavraschave que os prossionais da area de computa ca o usam no seu dia a dia. Adriano Cruz c . A hist oria do desenvolvimento dos computadores tem sido impressionante. O avan co da tecnologia e a presen ca da computa ca o na nossa vida s ao ineg aveis. Embora a hist oria deste fant astico desenvolvimento seja recente e bem documentada, h a lacunas e controv ersias impressionantes sobre diversos pontos. Neste cap tulo iremos ver hist orias de espionagem e brigas na justi ca por roubo de ideias. H a oportunidades perdidas e gente que soube aproveitar a sua chance. H a verdades estabelecidas que tiveram de ser revistas. O avan co na tecnologia dos computadores se deu em passos t ao largos que os primeiros computadores parecem t ao distantes no tempo quanto a Pr e-Hist oria. O aumento de velocidade, desde os anos 40, foi da v arias ordens de grandeza, enquanto que o custo dos computadores caiu de milh oes de d olares para valores em torno de centenas de d olares. As primeiras m aquinas tinham milhares de v alvulas, ocupavam areas enormes e consumiam quilowatts de energia. O microprocessador Pentium, lan cado em 1993, tinha em torno de 3,1 milh oes de transistores, ocupava uma area de aproximadamente 25 cm2 e consumia alguns watts de energia, custando aproximadamente 1000 d olares, somente o microprocessador. A Figura 1.1 mostra a imagem de um circuito integrado de microprocessador Pentium. No entanto, esta hist oria de redu ca o de tamanho, aumento de velocidade e diminui ca o de gasto de pot encia, pode, para alguns pesquisadores, j a ter uma data xada para terminar. Em 1965, Gordon Moore, um dos fundadores da Intel, fabricante do Pentium e uma dos maiores fabricantes de circuitos integrados do mundo, enunciou o que cou conhecido como a Lei de Moore: Cada novo circuito integrado ter a o dobro de transistores do anterior e ser a lan cado dentro de um intervalo de 18 a 24 meses. Moore achava que esta lei seria v alida somente at e 1975, no entanto, ela continua v alida at e hoje. Na tabela 1.1, pode-se observar a evolu ca o dos microprocessadores usados em nossos computadores. 13

Figura 1.1: Fotograa de um circuito integrado de microprocessador Pentium. Ano 1971 1972 1974 1982 1985 1989 1993 1997 1999 2000 Processador 4004 8008 8080 80286 80386 80486 DX Pentium Pentium II Pentium III Pentium 4 Transistores 2.250 2.500 5.000 120.000 275.500 1.180.000 3.100.000 7.500.000 24.000.000 42.000.000

Tabela 1.1: Transistores por circuito integrado nos microprocessadores da Intel

Os transistores, que comp oem os circuitos eletr onicos, est ao diminuindo de tamanho, e estamos nos aproximando da fronteira nal, os el etrons. J a se houve falar em tamanho de transistores medidos em n umeros de el etrons. Devemos nos lembrar que toda a tecnologia atual est a baseada em uxo de el etrons, ou seja uma corrente el etrica. Os os conduzem correntes de el etrons e os transistores controlam este uxo. Se o tamanho diminuir al em dos el etrons estaremos em outro dom nio. No entanto, na hist oria da computa ca o, muitas promessas n ao foram cumpridas e falhas gigantescas aconteceram. Como em diversas quest oes, artistas geniais, apontam o que n ao conseguimos ou n ao queremos ver e mostram que o rei est a nu. H a uma frase de Picasso que diz: Computadores s ao est upidos, eles somente conseguem responder perguntas. Esta frase exp oe com ironia um fracasso da comunidade de computa ca o que havia prometido criar rapidamente computadores inteligentes, computadores que poderiam questionar-se e nos questionar. Muitos acreditaram nesta promessa e muitos livros de c ca o cient ca foram publicados em que este tipo de computador estaria dispon vel em um futuro muito pr oximo. Com not avel exemplo podemos citar o lme 2001 - Uma Odiss eia no Espa co, de Stanley Kubrik que estreou em 1968 e foi baseado no conto The Sentinel, escrito em 1950 por Arthur Clark, um dos mestres da c ca o cient ca. Neste lme o enlouquecido computador HAL 9000, que era capaz de ver, falar, raciocinar etc, mata quase todos os tripulantes de

14

uma nave espacial. Ora, j a passamos por 2001 e n ao existe a menor possibilidade de se ver um computador como o HAL ou t ao louco de pedra como ele. Na computa ca o, um exemplo fant astico de sucesso e a Internet. A Internet est a se tornando essencial para o funcionamento do mundo moderno. Freq uentemente ouvimos dizer que ela e o meio de comunica ca o que mais rapidamente se difundiu pelo mundo. Pode parecer verdade, j a que conhecemos tantos internautas e as empresas est ao se atropelando para fazer parte desta onda e aproveitar as suas possibilidades. Esta corrida provocou alguns acidentes e muitos sonhos de riqueza se esva ram no ar. Hoje, pode-se fazer quase tudo pela Internet, namorar, comprar, pagar contas, fazer amigos, estudar, jogar etc. Quem sabe, em um futuro pr oximo, voltaremos ` a Gr ecia Antiga e nos reuniremos em uma enorme pra ca virtual para, democraticamente, discutir nossas leis, dispensando intermedi arios.

1.2
1.2.1

Um Pouco da Hist oria da Computa c ao


O In cio

A primeira tentativa de se criar uma m aquina de contar foi o abaco. A palavra vem do arabe e signica p o. Os primeiros abacos eram bandejas de areia sobre as quais se faziam guras para representar as opera co es. Aparentemente, os chineses foram os inventores do abaco de calcular. No entanto, h a controv ersias, e os japoneses tamb em reivindicam esta inven ca o, que eles chamam de soroban. Al em disso h a os russos, que inventaram um tipo mais simples, chamado de tschoty. S ao conhecidos exemplares de abaco datados de 2500 A.C. A Figura 1.2 ilustra um exemplar com as suas contas e varetas.

Figura 1.2: Imagem de um abaco. Em 1901 mergulhadores, trabalhando perto da ilha grega de Antikythera, encontraram os restos de um mecanismo, parecido com um rel ogio, com aproximadamente 2000 anos de idade. O mecanismo, de grande complexidade, parece ser um dispositivo para calcular os movimentos de estrelas e planetas.

1.2.2

A Era Moderna

Em 1614 John Napier, matem atico escoc es, inventou um dispositivo feito de marm para demonstrar a divis ao por meio de subtra co es e a multiplica ca o por 15

meio de somas. A semelhan ca entre marm e ossos, fez com que o dispositivo fosse conhecido como os ossos de Napier. Um dos primeiros instrumentos modernos de calcular, do tipo mec anico, foi constru do pelo l osofo, matem atico e f sico franc es Blaise Pascal (Figura 1.3). Em 1642 aos 19 anos, na cidade de Rouen, Pascal desenvolveu uma m aquina de calcular, para auxiliar seu trabalho de contabilidade. A engenhoca era baseada em 2 conjuntos de discos interligados por engrenagens: um para a introdu ca o dos dados e outro para armazenar os resultados. A m aquina utilizava o sistema decimal para calcular, de maneira que quando um disco ultrapassava o valor 9, retornava ao 0 e aumentava uma unidade no disco imediatamente superior.

Figura 1.3: Blaise Pascal Pascal recebeu uma patente do rei da Fran ca, o que lhe possibilitou o lan camento de sua m aquina no mercado. A comercializa ca o das calculadoras n ao foi satisfat oria devido a seu funcionamento pouco con avel, apesar dele ter constru do cerca de 50 vers oes. As m aquinas de calcular, derivadas da Pascalina, como cou conhecida sua m aquina, ainda podiam ser encontradas em lojas at e alguns poucos anos atr as. Antes de morrer, aos 39 anos, em 1662, Pascal que contribu ra em v arios campos da Ci encia, ainda teve tempo de criar uma variante de sua m aquina, a caixa registradora. Em 1666, Samuel Morland adaptou a calculadora de Pascal para resolver multiplica co es por meio de uma s erie de somas sucessivas. Independentemente, em 1671 Leibniz projetou uma outra calculadora que somava e multiplicava. Esta calculadora s o foi conclu da em 1694. O primeiro computador de uso espec co come cou a ser projetado em 1819 e terminou em 1822, ou seja, h a mais de 180 anos atr as, pelo brit anico Charles (1791-1871, Figura 1.4), que o batizou de Dierence Engine (Figura 1.5). A motiva ca o de Babbage era resolver polin omios pelo m etodo das diferen cas. Naquele tempo as t abuas astron omicas e outras tabelas eram calculadas por humanos, em m etodos tediosos e repetitivos. Em 1823, ele iniciou o projeto de construir uma outra m aquina mais avan cada e capaz de calcular polin omios de at e sexta ordem. Ele esperava terminar esta m aquina em tr es anos, mas a constru ca o se arrastou at e 1834. Este projeto que n ao foi completado, usou dinheiro do governo ingl es e possivelmente a maior parte da fortuna pessoal de Babbage. A m aquina, inteiramente mec anica, teria as seguintes caracter sticas: Arredondamento autom atico; 16

Figura 1.4: Charles Babbage

Figura 1.5: Fotograa da Dierence Engine

Precis ao dupla; Alarmes para avisar m de c alculo; Impress ao autom atica de resultados em placas de cobre. Em 1834 ele tinha completado os primeiros desenhos da m aquina que denominou Analytical Engine que tinha as seguintes caracter sticas: 50 d gitos decimais de precis ao; Mem oria para 1000 destes n umeros (165000 bits); Controle por meio de cart oes perfurados das opera co es e endere cos dos dados; Tempo de soma e subtra ca o igual a 1 segundo; tempo de multiplica ca o e divis ao igual a 1 minuto; Sub-rotinas; 17

Arredondamento autom atico e detec ca o de transbordo (overow ); Babagge nunca conseguiu terminar este ambicioso projeto. No entanto, os mais importantes conceitos de computa ca o, que somente vieram a tona nos anos 40 do s eculo vinte, j a tinham sido considerados por Charles Babbage em o seu projeto. Um fato curioso e que entre os auxiliares de Babagge estava Augusta Ada Byron, Countess of Lovelace. Considera-se, hoje, que ela escreveu para Charles Babbage o primeiro programa para computadores. Ada que mudou seu nome para Augusta Ada King, ap os seu casamento, estudava Matem atica com De Morgan que provou um dos teoremas b asicos da Algebra Booleana, que e a base matem atica sobre a qual foram desenvolvidos os projetos dos modernos computadores. No entanto, n ao havia nenhuma liga ca o entre o trabalho do projetista dos primeiros computadores e o do matem atico que estudava o que viria a ser o fundamento te orico de todo a computa ca o que conhecemos hoje.

1.2.3

O Desenvolvimento durante as Grandes Guerras

Antes da Segunda Grande Guerra, em v arios pa ses, cientistas trabalhavam em projetos que visavam construir computadores com rel es, que s ao dispositivos eletromec anicos usados para ligar ou desligar circuitos el etricos. Rel es s ao os dispositivos que antecederam os transistores na constru ca o de computadores. Alguns destes computadores eram de uso geral, outros tinha nalidades espec cas. Alguns destes projetos est ao listados a seguir. Na Alemanha Em 1934 na Alemanha Konrad Zuze, engenheiro projetista de avi oes, concebeu uma m aquina de somar para resolver os c alculos que deveria realizar em seus projetos. Em 1938, ele concluiu o Z1, um calculador mec anico com uma unidade aritm etica que usava a base 2 para representar os n umeros, base que hoje os computadores modernos empregam. Em 1938 ele melhorou o desempenho do Z1, gra cas aos rel es. O governo alem ao patrocinou os trabalhos de Zuze e em 1941 estava pronto o Z2, uma m aquina eletromec anica capaz de receber instru co es por meio de uma ta de papel. Em 1941 foi introduzido o Z3, que calculava tr es a quatro adi co es por segundo, uma multiplica ca o em 4 ou 5 segundos e era capaz de extrair a raiz quadrada. Nos Estados Unidos Em 1944 a IBM e H. Haiken da Universidade de Harvard, conclu am a construca o de um verdadeiro computador: o Harvard Mark I, que operava em base 10. O Mark I efetuava as quatro opera co es fundamentais, mais o c alculo de fun co es trigonom etricas, exponenciais e logar tmicas. As instru co es eram fornecidas por meio de tas de papel e os dados lidos de cart oes perfurados. Os resultados eram fornecidos em forma de cart oes perfurados ou impressos por meio de m aquinas de escrever. 18

Em 1943 na Universidade da Pensilv ania, J. Eckert e J. Mauchly iniciaram a constru ca o de um computador ` a v alvulas, ou seja eletr onico que foi chamado de ENIAC. O projeto foi conclu do em 1946 e usado na segunda guerra mundial. O ENIAC podia ser reprogramado para executar diversas opera co es diferentes atrav es de liga co es por meio de os e conectores. Durante muitos anos o computador ENIAC foi considerado o primeiro computador eletr onico constru do. A m aquina projetada pelos Drs. Eckert and Mauchly era gigantesca quando comparada com os computadores pessoais atuais. Quando foi terminado, o ENIAC (Figura 1.6) enchia um laborat orio inteiro, pesava trinta toneladas, e consumia duzentos quilowatts de pot encia.

Figura 1.6: Computador Eniac Ele gerava tanto calor que teve de ser instalado em um dos poucos espa cos da Universidade que possu a sistemas de refrigera ca o for cada. Mais de 19000 v alvulas, eram os elementos principais dos circuitos do computador. Ele tamb em tinha quinze mil rel es e centenas de milhares de resistores, capacitores e indutores. Toda esta parafern alia eletr onica foi montada em quarenta e dois pain eis com mais 2,70 metros de altura, 60 cent metros de largura e 30 cent metros de comprimento, montados na forma da letra U. Uma leitora de cart oes perfurados e uma perfuradora de cart oes eram usados para entrada e sa da de dados. Os tempos de execu ca o do ENIAC s ao mostrados na Tabela 1.2. Compare estes tempos com os tempos dos computadores atuais que est ao na ordem de nano segundos, ou 109 segundos. Opera c ao soma multiplica ca o divis ao Tempo 200 s 2,8 ms 6,0 ms

Tabela 1.2: Tempo de execu ca o das instru co es aritm eticas no ENIAC Em 1939 John Vincent Atanaso e Cliord E. Berry, na Universidade Estadual de Iowa constru ram um prot otipo de computador digital eletr onico, que usa aritm etica bin aria. Em 19 de outubro de 1973, o juiz federal Earl R. Larson assinou uma decis ao, em seguida a uma longa batalha judicial, que declarava

19

a patente do ENIAC de Mauchly e Eckert inv alida e atribu a a Atanaso a inven ca o computador eletr onico digital, o ABC ou Atanaso-Berry Computer. Na Inglaterra J anos von Neumann, emigrante h ungaro que vivia nos EUA, sugeriu que a mem oria do computador deveria ser usada para armazenar as instru co es do computador de maneira codicada, o conceito de programa armazenado. Esta id eia foi fundamental para o progresso da computa ca o. Os primeiros computadores, como o ENIAC, eram programados por os que os cientistas usavam para conectar as diversas partes. Quando um programa terminava, estes cientistas trocavam os os de posi ca o de acordo com a nova tarefa a ser executada. Com o programa armazenado na mem oria, juntamente com os dados, n ao era mais necess ario interromper as atividades. Carregava-se o programa na mem oria, uma tarefa extremamente r apida, junto com os dados e dava-se partida no programa. Ao t ermino da execu ca o do programa passava-se imediatamente para a pr oxima tarefa sem interrup co es para troca de os. Em 1949, na Inglaterra, dois computadores que usavam a mem oria para armazenar tanto programas como dados foram lan cados. Na Universidade de Cambridge foi lan cado o EDSAC, (Electronic Delay Storage Automatic Calculator) e em Manchester o computador chamado de Manchester Mark I. O EDSAC e considerado o primeiro computador de programa armazenado a ser lan cado. Curiosamente, a Universidade de Manchester reivindica que o primeiro computador de programa armazenado foi o chamado Baby, um prot otipo do Mark I, que come cou a operar onze meses antes do EDSAC. Outro fato curioso em rela ca o ` a Inglaterra e que foi divulgado recentemente relata que um computador chamado COLOSSUS entrou em opera ca o secretamente na Inglaterra em 1943. Este computador foi usado para auxiliar na quebra dos c odigos de criptograa alem aes durante a segunda grande guerra.

1.2.4

As Gera c oes

Costumava-se dividir os projetos de computadores em gera co es. Hoje em dia como a taxa de evolu ca o e muito grande n ao se usa mais este tipo de terminologia. No entanto e interessante mencionar estas divis oes. Primeira Gera c ao: Os computadores constru dos com rel es e v alvulas s ao os da primeira gera ca o. Estes computadores consumiam muita energia e espa co. Segunda Gera c ao: Os computadores da segunda gera ca o foram constru dos com transistores, os quais tinham a vantagem de serem mais compactos e consumirem muito menos energia. Por gerarem menos calor eram m aquinas mais con aveis. Terceira Gera c ao: Com o advento dos circuitos integrados, que s ao componentes em que v arios transistores s ao constru dos em uma mesma base de semicondutor, chegamos aos computadores de terceira gera ca o. Com a integra ca o o tamanho dos computadores e seu consumo diminuiu ainda mais e aumentou a capacidade de processamento. 20

Quarta Gera c ao: Os computadores de quarta gera ca o utilizavam circuitos com a tecnologia (Very Large Scale Integration), que permitia uma escala de integra ca o de transistores muito grande.

1.3

O Hardware

O hardware corresponde aos circuitos eletr onicos e componentes mec anicos que comp oem o computador. Um t pico diagrama em blocos de um computador digital monoprocessado esta mostrado na Figura 1.7. A Unidade Central de Processamento (UCP), em ingl es Central Processing Unit (CPU), como o pr oprio nome diz, e a unidade onde os dados s ao processados, ou seja alterados, no computador. Ou seja, dentro das UCPs os dados s ao somados, subtra dos etc. A UCP tamb em controla a movimenta ca o dos dados dentro de todo o sistema. Os m odulos que constituem a UCP s ao os seguintes: Unidade de Controle (UC): comanda a opera ca o do computador. Esta unidade l e da mem oria tanto as instru co es como os dados e comanda todos os circuitos para executar cada instru ca o lida da mem oria. Atualmente as unidades de controle s ao capazes de executar mais de uma instru ca o por ciclo de m aquina, o que caracteriza o processamento paralelo. A t ecnica mais comum para conseguir este paralelismo e conhecida como pipelining, que ser a detalhada mais adiante. Unidade Aritm etica e L ogica (UAL): local onde as transforma co es sobre os dados acontecem. Atualmente esta unidade e bastante sosticada e diversos m etodos s ao empregadas para acelerar a execu ca o das instru co es. Alguns processadores duplicam circuitos para permitir que mais de uma muito comum, por exemopera ca o aritm etica seja executada por vez. E plo, a exist encia de uma unidade aritm etica para executar instru co es que operam sobre n umeros inteiros e outra sobre n umeros reais, chamada de unidade de ponto utuante. As vezes a UCP conta com mais de uma de cada uma destas unidades. Unidade de Entrada e Sa da (UES): controla a comunica ca o com os usuarios do computador e os equipamentos perif ericos tais como discos e impressoras. Em alguns computadores mais simples esta unidade n ao existe independentemente, sendo distribu da pela Unidade Central de Processamento. Em computadores mais poderosos ao contr ario as Unidades de Entrada e Sa da s ao computadores completos que foram programados para controlar a comunica ca o com os perif ericos. O termo pipelining que mencionamos acima se refere a um dos modos de como o processador pode paralelizar a execu ca o de instru co es. Este termo pode ser traduzido por linha de montagem, porque e exatamente isto que a t ecnica faz, uma linha de montagem de instru co es. Por exemplo, em uma linha de montagem de uma f abrica de autom oveis, mais de um autom ovel e montado ao mesmo tempo. No in cio da linha o carro n ao existe. Em cada est agio da linha de montagem os oper arios v ao adicionando partes e ao m da linha sai um carro novo. Se voc e olhar a linha poder a ver carros em diversos est agios da 21

Unidade de Controle

Unidade de Entrada e Sada Memria Discos Vdeo

Unidade Arimtica

Unidade Central de Processamento

Figura 1.7: Diagrama B asico de um Computador Digital

montagem. Repare que a linha n ao p ara, e a montagem de um carro n ao espera que o que come cou a ser montado antes dele esteja terminado. Nas linhas de montagem muitos carros s ao montados ao mesmo tempo. O efeito nal e que cada carro continua levando bastante tempo para ser montado, mas como v arios v ao sendo montados ao mesmo tempo, algu em que se colocasse no nal da linha de montagem teria a impress ao que cada carro leva muito pouco tempo para ser montado. Isto porque no nal da linha de montagem sai um carro a cada poucos minutos. O mesmo acontece com a linha de montagem de instru co es.

1.3.1

Microcomputadores

Uma UCP integrada em um u nico circuito (chip) e comumente chamada de microprocessador . Os microprocessadores atuais incluem outros circuitos que normalmente cavam fora da UCP, tais como processadores de ponto utuante e mem orias cache. Alguns exemplos de microprocessadores s ao mostrados na Tabela 1.3 Microprocessador Arquitetura Intel X86 PowerPC Power MIPS ARM SPARC Empresa Intel, AMD Cons orcio Apple/IBM/Motorola IBM MIPS Technologies ARM Technologies SUN

Tabela 1.3: Exemplos de Microprocessadores

Usualmente se chama de computador, o processador mais os seus perif ericos e os sistemas para controlar estes perif ericos, ou seja todo o sistema de processamento de dados. Os perif ericos s ao os dispositivos usados para fazer a entrada e sa da dos dados que ser ao processados. Os microcomputadores s ao computadores baseados em microprocessadores. As assim chamadas placas m ae dos microprocessadores atuais in22

cluem diversos componentes que formam o microcomputador. Por exemplo, uma placa m ae pode incluir o microprocessador e seus circuitos de suporte, que, no conjunto s ao conhecidos como o chipset. Al em disso a placa m ae pode incluir tamb em a mem oria principal e as placas de controle de perif ericos, como a placa de v deo, e os conectores para os perif ericos, enm, quase todo o sistema.

1.3.2

Mem orias

Os dados no computador podem ser armazenados em diversos n veis de mem oria semicondutoras ou em perif ericos (discos, tas, etc). Quanto mais r apida a mem oria, usualmente mais cara ela e. A id eia por traz da separa ca o em n veis e colocar mais perto do processador, em mem orias r apidas e mais caras, os dados que o processador ir a precisar mais freq uentemente. A medida que vamos nos afastando do processador as mem orias v ao, ao mesmo tempo, cando mais baratas, aumentando de capacidade e diminuindo de velocidade. A Figura 1.8 ilustra esta hierarquia.

PROCESSADOR

MEMRIA
CACHE
REGISTRADORES

DISCO

Figura 1.8: N veis de hierarquia da mem oria de um computador. No n vel mais pr oximo do processador est ao os registradores , que, na verdade, cam internamente ao processador. S ao poucos e extremamente r apidos e, portanto, n ao podem armazenar grandes quantidades de dados. Somente os dados que s ao necess arios ao processador com rapidez extraordin aria devem ser colocados nos registradores. Durante o processamento normal, e na mem oria principal onde o processador busca instru co es e dados de um programa para executar. Al em da mem oria principal est ao os discos. Devido a sua velocidade menor que a da mem oria principal e a sua grande capacidade, os discos s ao considerados dispositivos de armazenamento secund ario. Os discos tamb em s ao mem orias de armazenamento permanente, isto e, quando os computadores s ao desligados o seu conte udo se mant em. Ao contr ario, a mem oria principal e os registradores s ao mem orias semicondutoras e perdem seus conte udos quando a energia el etrica e desligada. Em alguns computadores os discos est ao sendo substitu dos por mem orias semicondutoras. Para acelerar o acesso aos dados freq uentemente usados, os computadores disp oem de mem orias mais r apidas, por em de menor capacidade, que cam entre os registradores e a mem oria principal. Estas funcionam como as bolsas ou carteiras em que carregamos documentos e outros itens que precisamos freq uentemente. Este tipo de mem oria e conhecido como mem oria cache. O cache opera de forma invis vel para o processador. Ao pedir um dado para mem oria, 23

circuitos especiais vericam se este dado est a no cache, caso esteja, ele e repassado para o processador. Para o processador o que aconteceu e que a mem oria entregou o dado com uma rapidez maior do que o normal. Uma mem oria e como se fosse uma s erie de cofres numerados capazes de armazenar os dados, como est a ilustrado na Figura 2.3. Os dados e instru co es na mem oria s ao apontados ou referenciados por estes n umeros, conhecidos como endere cos. Ou seja, para ler um dado da mem oria e necess ario fornecer um endere co para que a mem oria possa encontrar e devolver o conte udo pedido. Isto e similar ao o que ocorre quando enviamos uma carta, o endere co faz com que o carteiro saiba onde ele deve entregar a correspond encia. Em opera ca o normal, toda vez que o processador precisa de um dado ele envia um pedido de leitura a mem ` oria junto com o endere co da mem oria onde o dado est a. Nas escritas o processador envia o endere co, o dado e pedido de escrita. Normalmente a mem oria somente pode atender um pedido de cada vez. Portanto, para ler 1000 n umeros o processador ter a de fazer 1000 acessos seq uencialmente. Os dois tipos b asicos de mem oria mais comuns s ao ROM e RAM. Estas siglas t em diversas varia co es (PROM, EPROM, DRAM, etc), mas os princ pios b asicos s ao os mesmos. Estas siglas indicam os dois tipos b asicos de mem oria que s ao usadas em computadores. A sigla b asica ROM signica Read Only Memory, ou seja, mem oria de somente de leitura. A outra sigla RAM (Random Access Memory) signica mem oria de acesso rand omico, portanto, mem oria que se pode ler em qualquer endere co. A sigla RAM e muito confusa porque em uma mem oria ROM tamb em se pode ler em qualquer endere co. A diferen ca real e que nas RAMs se pode ler e escrever com a mesma velocidade em qualquer endere co, enquanto que na ROM, o acesso e r apido somente para leituras, a escrita e uma hist oria mais complicada. A ROM normalmente cont em dados que n ao podem ser modicados durante o funcionamento do computador. Outro tipo de dados armazenados em ROMs s ao os que n ao devem ser perdidos quando o computador e desligado. Exemplos de uso de ROM s ao as mem orias que armazenam os programas que s ao executados quando os computadores s ao ligados, os famosos BIOS (Basic Input Output System ). Um computador ao ser ligado deve ter um programa m nimo capaz de iniciar o seu funcionamento normal, caso contr ario seria como uma pessoa que perdeu totalmente a mem oria. Para isto s ao escritos programas simples que fazem acesso aos perif ericos em busca do Sistema Operacional da m aquina. As primeiras mem orias do tipo ROM eram gravadas nas f abricas e nunca mais eram modicadas. Isto trazia algumas diculdades, por exemplo, quando um programa precisava ser atualizado. Para resolver este tipo de problemas surgiram as PROMs, que s ao ROMs program aveis. Ou seja e poss vel desgravar o conte udo antigo e gravar novos programas nesta mem oria. Antigamente este era um processo complicado e exigia que a mem oria fosse retirada sicamente do circuito e colocada em dispositivos especiais capazes de apagar o conte udo antigo. Em seguida um circuito programador de PROMs era usado para gravar o novo conte udo e somente ap os tudo isto a mem oria era recolocada no local. O computador cava literalmente sem a mem oria dos programas iniciais. Hoje em dia existem PROMs que podem ser apagadas e regravadas muito facilmente. Por exemplo, as EEPROMs (Eletricaly Erasable PROMs), que s ao mem orias que podem ser apagadas eletricamente sem a necessidade de serem retiradas

24

dos circuitos. Flash memory e uma forma de mem oria n ao vol atil que pode ser apagada e reprogramada eletricamente. Diferentemente das EEPROMs, ela deve ser apagada em blocos de endere cos. Este tipo de mem oria custa menos do que EEPROMs e portanto s ao preferidas quando e necess ario usar mem oria n ao vol atil em forma de circuitos integrados. As mem orias RAMs s ao as mem orias onde os nossos programas comuns rodam. Elas s ao modic aveis e de acesso r apido tanto na leitura quanto na grava ca o. Muitas siglas aparecem e desaparecem quando falamos de mem orias RAM. Existem as DRAM, mem orias EDO, SIMM, etc. Tudo isto ou se refere ao m etodo de acesso dos dados na mem oria ou a tecnologia de constru ca o ou a outra caracter stica acess oria. O certo e que todas elas tem como caracter stica b asica o fato dos acessos de leitura e escrita poderem ser feitos na mesma velocidade.

1.3.3

Bits e Bytes

A mem oria do computador e composta de bits, a menor unidade de informa ca o que o computador armazena. Um bit pode conter o valor 0 ou 1, que s ao os d gitos usados na base dois, a base usada nos computadores. Um conjunto de 8 bits forma o byte. Uma palavra de mem oria e um conjunto de bytes. Atualmente a maioria dos computadores tem palavras de mem oria com largura de 32 (4 bytes) ou 64 (8 bytes) bits. Na Figura 1.9 mostramos os diversos tamanhos dos dados.
BIT

BYTE 8 BITS

PALAVRA 32 BITS 4 BYTES

Figura 1.9: Tamanho de Bits, Bytes e Palavras

Observar que estamos falando de dados na mem oria e n ao do tamanho dos dados que o computador pode processar. Considere que este tamanho e relacionado com a quantidade m axima de algarismos que um n umero pode ter para ser processado. Um computador pode ter capacidade de processar 64 bits de cada vez. Caso sua mem oria tenha palavras de 32 bits o processador dever a, ent ao, ler duas palavras da mem oria para poder processar um n umero. Lembrese que as duas leituras s ao atendidas uma de cada vez. Da mesma forma o computador pode processar 32 bits de cada vez e a mem oria ter largura 64 bits. Isto pode acelerar o processamento, j a que o processador est a se adiantando e recebendo o que poder a ser o pr oximo dado a ser processado, ou seja economizando uma leitura. Devido a base 2 o fator kilo tem um signicado diferente em computa ca o. Por exemplo 1 Kbyte de mem oria corresponde a 2 elevado a 10 (210 ), ou seja

25

1024 bytes. Da mesma forma 1 Megabyte corresponde a 1024 x 1024 bytes e 1 Gigabyte e igual a 1024 x 1024 x 1024 bytes. Na Tabela 1.4 est ao mostradas as diversas abrevia co es usadas quando se fazem refer encias ` as mem orias. Nome Kilobyte Megabyte Gigabyte Terabyte Petabyte Exabyte S mbolo Kb MB GB TB PB EB Multiplicador 210 = 1024 220 230 240 250 260

Tabela 1.4: Abrevia co es usadas em refer encias ` as mem orias.

1.3.4

Perif ericos

Como j a mencionamos antes, os dados n ao cam guardados somente na mem oria, h a tamb em os perif ericos . H a perif ericos de entrada, outros de sa da e alguns que servem tanto para entrada como sa da de dados. Perif ericos n ao servem somente para armazenar dados. H a perif ericos que s ao usados para permitir a intera ca o entre os usu arios e o computador. A tabela 1.5 ilustra alguns destes perif ericos. Entrada Teclados Mouse CD-ROM Scanner Sa da Impressoras V deo Plotter Alto-falantes Ambos Discos R gidos Fitas Magn eticas Disquetes Discos Zip

Tabela 1.5: Exemplos de perif ericos

1.4

O Software

Tudo isto que sobre o que acabamos de escrever constitui o hardware do computador, o que se v e e o que se toca. A partir de agora falaremos brevemente no software, o que n ao se v e nem se toca, mas tamb em est a l a. Para que um computador execute alguma tarefa primeiro se desenvolve um algoritmo , que e uma esp ecie de receita que diz precisamente, ao computador, como o problema deve ser resolvido. Esta deni ca o informal de algoritmo e enganosamente simples, e a chave para entender o engano est a nas palavras dizer precisamente ao computador. Por exemplo, uma receita em gastronomia normalmente n ao e um algoritmo. Receitas s ao entendidas pela comunidade de cozinheiros, que as seguem facilmente durante o preparo do prato. No entanto, receitas est ao cheias de express oes como, por exemplo, mexer at e car 26

no ponto e colocar sal a gosto. Fora da comunidade de cozinheiros estas express oes s ao pass veis de v arias interpreta co es. Para escrever algoritmos precisamos de uma linguagem matematicamente precisa e sem ambig uidades. A escrita de um algoritmo consta de uma deni ca o do estado inicial do problema a ser resolvido e de regras precisas que estabelecem a cada instante os passos a serem seguidos. Como em um jogo, al em de denir os passos, s ao necess arias regras que denam se ap os a execu ca o de um passo do algoritmo o novo estado do problema e v alido. As regras do xadrez denem o estado inicial do tabuleiro, os movimentos poss veis de cada pe ca e se ap os um movimento de uma pe ca a congura ca o atingida e v alida. Ou seja precisamos vericar em cada instante qual dos movimentos (instru co es) pode ser usado. Algoritmos podem ser chamados de procedimentos efetivos e devem obedecer aos seguintes limites: sempre dar alguma resposta; sempre dar a resposta correta e nunca uma resposta incorreta; terminar em um n umero nito de passos; trabalhar em todos os exemplos da classe de problemas que o algoritmo se prop oe a resolver. Em seguida este algoritmo deve ser traduzido para uma linguagem que possa ser entendida pelo computador ou que possa ser traduzida para esta linguagem. No in cio da computa ca o eletr onica com programas armazenados, estes eram escritos diretamente em linguagem de m aquina que e a linguagem que o computador realmente entende. Estas instru co es s ao conjuntos de bits indicando a opera ca o que deve ser executada e, caso necess ario, onde como achar os dados que ser ao operados. Por esta raz ao tamb em costuma-se dizer que s ao programas escritos em bin ario. Com a evolu ca o da computa ca o os programas passaram a ser escritos em assembly , que e uma representa ca o em mnem onicos das instru co es de m aquina. Deste modo era e mais f acil escrever os algoritmos. Por exemplo, um fragmento de um programa escrito em assembly do processador PowerPC e: li r3,4 * O primeiro numero a ser somado e 4. li r4,8 * 8 e o segundo numero add r5,r4,r3 * Some os conte udos de r3 (4) e r4 (8) * e armazene o resultado em r5 Este pequeno trecho de programa armazena os n umeros 4 e 5 em registradores internos do processador em seguida os soma e armazena o resultado em um terceiro registrador. As informa co es ap os os asteriscos s ao coment arios usados para explicar o que o programa est a fazendo naquela instru ca o. O PowerPC e um microprocessador criado em 1991 por um cons orcio formado pela IBM, Apple e Motorola Os microprocessadores PowerPC podem ser usados para equipar desde sistemas embutidos at e computadores de alto desempenho. A Apple usou este microprocessador para equipar suas m aquinas at e 2006.

27

Um programa escrito em assembly deve ser traduzido para a representa ca o bin aria, tarefa que normalmente se chama de montar o programa. A palavra assembler frequentemente e usada erradamente para signicar a linguagem e n ao o programa que traduz o programa de assembly para linguagem bin aria de m aquina. Este tipo de programa ca o pode levar a se escrever programas muito ecientes, devido ao controle quase que total do programador sobre a m aquina. No entanto devido ao fato de ser uma linguagem pr oxima do computador e afastada da maneira de raciocinar do ser humano e mais dif cil de ser usada. Al em deste fato h a outros problemas tais como: diculdade de leitura por humanos, diculdade de manuten ca o dos programas, maior tempo de desenvolvimento etc. Para evitar estes problemas foram desenvolvidas as linguagens de programa ca o chamadas de linguagens de alto n vel, por estarem mais pr oximas da linguagem natural empregada pelos serem humanos. Alguns exemplos de linguagens de programa ca o s ao: Fortran: Usada em programa ca o cient ca e engenharia; Pascal: Usada em ensino de linguagens e desenvolvimento de sistemas; COBOL: Usada em ambientes comerciais; Basic: O nome diz tudo, b asica; C: Mesmas caracter sticas do Pascal com facilidades que permitem mais controle do computador; C++: Linguagem origin aria do C com metodologia de orienta ca o ` a objetos; Java: Linguagem tamb em baseada na sintaxe do C e tamb em seguindo o modelo de orienta ca o ` a objetos. Delphi: Linguagem origin aria do Pascal com metodologia de orienta ca o ` a objetos; Lisp e Prolog: Linguagens usadas para desenvolver programas de Intelig encia Articial. Aplicativos importantes para os programadores s ao os compiladores. Estes programas traduzem programas escritos em linguagens de alto n vel para a linguagem de m aquina, de modo que o computador possa execut a-los. De maneira geral um compilador e um programa que traduz um programa de uma linguagem para outra. Podemos resumir os passos necess arios para criar um programa em uma linguagem de programa ca o, por exemplo C, nos passos descritos a seguir. A Figura 1.10 ilustra a ordem em que se desenvolvem estes passos. Cria c ao do Algoritmo: neste passo e criado o algoritmo que ir a resolver o problema. As diversas maneiras de descrever um algoritmo ser ao apresentadas no pr oximo cap tulo.

28

Codica c ao do Algoritmo: O algoritmo preparado no passo anterior e escrito em uma linguagem de programa ca o. Neste passo o programador conta, normalmente, com a ajuda de um editor de textos (n ao processador de textos). Para esta edi ca o qualquer editor pode ser usado. Hoje em dia muitos ambientes de desenvolvimento integram todas as ferramentas necess arias para criar um programa, inclusive o editor, em um u nico aplicativo. Compila c ao do Programa: O arquivo texto contendo o programa passa por um programa especial chamado compilador que gera, caso n ao hajam erros, uma sa da que e quase o programa execut avel, ou seja o programa em c odigo bin ario do processador em que ser a executado. Os erros mais comuns nesta etapa s ao erros de uso correto da linguagem de programa ca o. Estes erros s ao chamados de erros de compila ca o. As linguagens de programa ca o s ao baseadas em regras gramaticais muito r gidas e qualquer viola ca o destas regras pode implicar em erro. No caso de erros serem encontrados o programador deve voltar ao passo de codica ca o para a corre ca o dos erros. Liga c ao: Em ingl es este passo e conhecido por link edition. Um programa completo e composto por v arios m odulos que podem ter sido criados pelo pr oprio programador ou por outras programadores. Por exemplo, em C os trechos de programa que interagem com os usu arios, os comandos de entrada e sa da de dados, normalmente v em com o programa compilador. Estes trechos podem estar guardados em bibliotecas de programas e s ao ligados ao programa do usu ario para completar o programa. Depura c ao e Testes: Nesta etapa o programa ser a testado para a retirada dos poss veis erros de l ogica que o programador cometeu. Caso algum erro de execu ca o seja encontrado o programador deve reelaborar o que estiver errado no algoritmo e em seguida ir para a etapa de codica ca o do algoritmo. Este ciclo pode repetir-se in umeras vezes at e que o desenvolvedor acredite que os erros foram corrigidos. Uso do Programa: O programa foi entregue aos seus usu arios para ser usado. Durante o uso, erros que n ao foram encontrados durante o desenvolvimento do programa podem ser descobertos e precisam ser corrigidos. A corre ca o pode ser feita pelos mesmos programadores que desenvolveram o programa ou por outro grupo devidamente treinado. Costuma-se chamar esta corre ca o de manuten ca o do programa. Algumas linguagens de programa ca o n ao s ao compiladas e sim interpretadas. Isto signica que o programa para ser executado n ao precisa ser traduzido diretamente para linguagem de m aquina, gerando um arquivo execut avel. Este arquivo nal, se torna independente do programa fonte. Para executar o programa podemos usar somente o arquivo execut avel. Em um programa interpretado um aplicativo l e o programa instru ca o por instru ca o, diretamente na pr opria linguagem de alto n vel, traduz cada uma destas instru co es para linguagem de m aquina e as executa. N ao h a, portanto, o processo de tradu ca o antecipada do programa. A interpreta ca o de um programa funciona como o processo de tradu ca o simult anea do discurso de um orador. A medida que ele pronuncia seu 29

Incio Ligao

Criao de Algoritmo

Depurao e Testes

Codificao do Algoritmo

Sim

Erros de Execuo? No

Compilacao do Programa

Uso do programa

Sim Erros de Compilao? No

Sim Erros de Execuo?

Figura 1.10: Ciclo de desenvolvimento de um programa.

discurso um tradutor repete as frases na linguagem destino. Um programa compilado funciona como se primeiro, o tradutor traduzisse todo o discurso e depois o lesse. A linguagem Basic e uma linguagem interpretada. Em Java ocorre um processo um pouco diferente. Um programa em Java e traduzido para uma linguagem intermedi aria e depois interpretado por meio de uma chamada m aquina virtual. N ao h a efetivamente uma compila ca o para linguagem de m aquina. A execu ca o de um programa escrito em uma linguagem interpretada e mais lenta, j a que o processo de interpreta ca o e execu ca o ao mesmo tempo e mais lento do que a simples execu ca o de um programa traduzido antecipadamente. Hoje em dia a maior parte dos usu arios de computadores n ao s ao programadores e sim pessoas que usam programas para resolver seus problemas do dia a dia. Aplicativos t picos que rodam nos computadores s ao: editores de texto, processadores de texto, planilhas eletr onicas, compiladores, bancos de dados, jogos, etc. Para gerenciar os recursos do computador existe um programa especial normalmente chamado de Sistema Operacional (S. O.). Por exemplo, considere o problema de gerenciar como os diversos programas que um usu ario normalmente utiliza partilhar ao o processador do computador. Um usu ario pode estar ouvindo m usica, digitando um texto e imprimindo um outro documento ao mesmo tempo. Portanto, os computadores s ao capazes de executar um n umero de tarefas muito maior do que o n umero de processadores dispon veis. Atualmente a maior parte dos computadores possui somente um processador. O Sistema Operacional controla a aloca ca o de recursos tais como: comunica ca o com os usu arios, espa co em discos, uso de mem oria, tempo que cada programa pode rodar etc. Alguns dos sistemas operacionais conhecidos s ao os baseados no padr ao UNIX, por exemplo o LINUX. Outros sistemas muito usados s ao os da fam lia

30

Windows. Compilando Programas Simples em C Para resolver os exerc cios deste livro voc e ir a precisar de um compilador para a linguagem C e de um editor de textos simples (n ao processador como o Word). O editor pode ser t ao simples quanto o Notepad, na verdade recomendamos fortemente que o editor seja simples para que voc e possa ter contato com todas as etapas do processo de desenvolvimento de um programa. Para compilar empregaremos o compilador gcc que e gratuito e pode ser obtido na Internet como veremos adiante. N ao ser a necess ario nenhum ambiente mais complexo, tal como um Integrated Development Environment (IDE). A cole ca o de compiladores da GNU (GNU Compiler Collection) usualmente abreviada por gcc, e uma cole ca o de compiladores produzidos pelo projeto GNU. A abrevia ca o gcc, originalmente, signicava GNU C Compiler. Este aplicativo e distribu do gratuitamente pela Free Software Foundation (FSF) sob a licen ca GNU GPL e GNU LGPL. Este e o compilador padr ao para os sistemas operacionais livres do tipo Unix, como o LINUX, e diversos sistemas operacionais propriet arios como o Apple Mac OS X. Atualmente o gcc pode compilar C++, Objective-C, Java, Fortran e ADA, entre outras linguagens. Vamos considerar, como exemplo, um programa chamado teste.c. Para compilar e gerar o execut avel para este programa digitamos o comando gcc -o teste teste.c -Wall em uma janela de comandos no sistema Windows ou em um terminal nos sistemas Unix. O suxo .c no nome do programa normalmente e usado para indicar que o arquivo e de um programa C. Este comando deve ser digitado no diret orio onde est a o arquivo fonte teste.c. O arquivo execut avel ser a armazenado no mesmo diret orio. Nos sistemas Unix normalmente o gcc faz parte da distribui ca o padr ao e nada precisa ser feito. No Windows uma maneira f acil de obter uma vers ao do gcc e instalar o MinGW (Minimalist GNU for Windows). MinGW e uma cole ca o de arquivos e bibliotecas distribu das livremente as quais combinadas com outras ferramentas da GNU permitem que programas para Windows sejam produzidos sem a necessidade de bibliotecas extras e pagas. O MinGW disp oe de um programa instalador que facilita enormemente o processo. Este programa pode ser obtido no s tio ocial do MinGW. Caso ap os a instala ca o, o comando indicado n ao funcione uma das raz oes para a falha pode ser que o sistema operacional n ao sabe onde se encontra o compilador gcc. Suponha que o programa gcc foi instalado no diret orio C:\MinGW\bin. Uma solu ca o e digitar o caminho completo do compilador. Neste caso o comando se torna C:\MinGW\bin\gcc -o teste teste.c -Wall Para que n ao seja necess ario digitar o caminho completo, e preciso adicionar este caminho ` a vari avel PATH do Windows. Consulte o manual para obter informa co es de como fazer este passo no seu sistema Windows.

31

1.5

Um programa em C

Vamos terminar este cap tulo mostrando um exemplo simples de programa escrito em C(Listagem 1.1). A u nica coisa que este programa faz e imprimir Alo Mundo! e terminar [1, 2, 3]. A primeira linha do programa avisa ao compilador que ir a usar fun co es de entrada e sa da de dados guardadas na biblioteca stdio. Neste caso a fun ca o usada e printf. A segunda linha e o in cio real do programa. A linha indica que esta e a fun ca o main que todo programa C deve conter, pois e nesta fun ca o que o programa obrigatoriamente come ca sua execu ca o. A fun c ao vai retornar um valor inteiro (int) ao nal de sua execu ca o e n ao vai precisar receber nenhum argumento para sua execu ca o (void). As chaves ({ e }) marcam o in cio e o m da fun ca o. Para imprimir o texto Alo Mundo! o programa usa a fun ca o printf. O in cio e o m do texto a ser impresso s ao marcados pelo caractere ". A fun ca o termina com o comando return 0, que avisa ao sistema operacional, que foi quem iniciou a execu ca o do programa, que o programa terminou sem problemas. Este programa simples ilustra alguns das estruturas b asicas que ser ao usadas nos programas C que ser ao apresentados neste livro. Listing 1.1: Exemplo de Programa em C.
#i ncl ude < stdio .h > i n t main ( void ) { printf ( " Alo Mundo !\ n " ); return 0; }

32

1.6

Exerc cios

1.1: O que e o hardware do computador? 1.2: Quais os principais componentes de um computador? 1.3: Quais as diferen cas entre um microprocessador e o microcomputador? 1.4: D e exemplos de microprocessadores e de microcomputadores. 1.5: Qual o n umero exato de bytes em 64 Kbytes? 1.6: Se voc e j a usa computadores, liste alguns aplicativos que voc e normalmente usa. 1.7: Dena Sistema Operacional. 1.8: Qual a diferen ca b asica entre mem orias ROM e RAM? 1.9: Procure em manuais, internet e outras fontes quais s ao os tempos de acesso das mem orias RAMs atuais. 1.10: Fa ca tr es listas, uma de perif ericos de entrada, outra de perif ericos de sa da e nalmente uma de perif ericos de entrada e sa da. 1.11: Explique o que faz um compilador. 1.12: Discuta as vantagens e desvantagens das linguagens interpretadas e as compiladas. 1.13: O que s ao erros de compila ca o e de execu ca o. 1.14: Procure nomes de linguagens de programa ca o n ao listadas no texto e diga quais s ao as suas caracter sticas principais.

33

Cap tulo 2

Algoritmos
2.1 Introdu c ao

O objetivo deste cap tulo e fazer uma breve introdu ca o ao conceito de algoritmos e apresentar algumas formas mais comuns de representar algoritmos para facilitar o entendimento dos demais cap tulos deste livro. Iremos apresentar as constru co es mais comuns empregadas no desenvolvimento de algoritmos e apresentaremos exemplos b asicos de algoritmos usando algumas destas formas de representa ca o e constru co es. Para resolver um problema no computador e necess ario que seja primeiramente encontrada uma maneira de descrever este problema de uma forma clara preciso que encontremos uma seq e precisa. E u encia de passos que permitam que o problema possa ser resolvido de maneira autom atica e repetitiva. Al em disto e preciso denir como os dados que ser ao processados ser ao armazenados no computador. Portanto, a solu ca o de um problema por computador e baseada em dois pontos: a seq u encia de passos e a forma como os dados ser ao armazenados no computador. Esta seq u encia de passos e chamada de algoritmo. Usamos algoritmos em diversas atividades que realizamos diariamente. Uma grande parte destas atividades n ao est ao relacionadas com computa ca o. Um exemplo simples e prosaico, de como um problema pode ser resolvido caso forne camos uma seq u encia de passos que mostrem a maneira de obter a solu ca o, e uma receita para preparar um bolo. Uma vez que foi criado um algoritmo para resolver um determinado problema usando computadores passamos para a pr oxima fase que e a escrita deste algoritmo em alguma linguagem de programa ca o. A no ca o de algoritmo e central para toda a computa ca o. A cria ca o de algoritmos para resolver os problemas e uma das maiores diculdades dos iniciantes em programa ca o em computadores. Isto porque n ao existe um conjunto de regras, ou seja um algoritmo, que nos permita criar algoritmos. Caso isto fosse poss vel a fun ca o de criador de algoritmos desapareceria. Claro que existem linhas mestras e estruturas b asicas, a partir das quais podemos criar algoritmos, mas a solu ca o completa depende em grande parte do criador do algoritmo.

34

Geralmente existem diversos algoritmos para resolver o mesmo problema, cada um segundo o ponto de vista do seu criador. No seu livro Fundamental Algorithms vol. 1 Donald Knuth [4] apresenta uma vers ao para a origem desta palavra. Ela seria derivada do nome de um famoso matem atico persa chamado Abu Jafar Maom e ibn M us a al-Khow arism (825) que traduzido literalmente quer dizer Pai de Jafar, Maom e, lho de Mois es, de Khow arizm. Khow arizm e hoje a cidade de Khiva, na ex Uni ao Sovi etica. Este autor escreveu um livro chamado Kitab al jabr wal-muqabala (Regras de Restaura ca o e Redu ca o). O t tulo do livro deu origem tamb em a palavra Algebra. O signicado da palavra e muito similar ao de uma receita, procedimento, t ecnica, rotina. Um algoritmo e um conjunto nito de regras que fornece uma seq u encia de opera co es para resolver um problema espec co. Segundo o dicion ario do prof. Aur elio Buarque de Holanda um algoritmo e um: Processo de c alculo, ou de resolu ca o de um grupo de problemas semelhantes, em que se estipulam, com generalidade e sem restri c oes, regras formais para a obten ca o de resultado ou de solu ca o de problema. Um algoritmo opera sobre um conjunto de entradas (no caso do bolo, farinha ovos, fermento, etc.) de modo a gerar uma sa da que seja u til (ou agrad avel) para o usu ario (o bolo pronto). Um algoritmo computacional tem cinco caracter sticas importantes: Finitude: Um algoritmo deve sempre terminar ap os um n umero nito de passos. Deni c ao: Cada passo de um algoritmo deve ser precisamente denido. As a co es devem ser denidas rigorosamente e sem ambiguidades. Entradas: Um algoritmo deve ter zero ou mais entradas. Entradas s ao as quantidades que s ao lhe s ao fornecidas para processamento. Sa das: Um algoritmo deve ter uma ou mais sa das, isto e quantidades que tem uma rela ca o espec ca com as entradas. Efetividade: Um algoritmo deve ser efetivo. Isto signica que todas as operaco es devem ser sucientemente b asicas de modo que possam ser, em princ pio, executadas com precis ao em um tempo nito por um humano usando papel e l apis.

2.2

Primeiros Passos

claro que todos n E os sabemos construir algoritmos. Se isto n ao fosse verdade, n ao conseguir amos sair de casa pela manh a, ir ao trabalho, decidir qual o melhor caminho para chegar a um lugar, voltar para casa, etc. Para que tudo isto seja feito e necess ario uma s erie de entradas do tipo: a que hora acordar, que hora 35

sair de casa, qual o melhor meio de transporte etc. Um fator importante e que pode haver mais de um algoritmo para resolver um determinado problema. Por exemplo, para ir de casa at e o trabalho, posso escolher diversos meios de transporte em fun ca o do pre co, conforto, rapidez, etc. A escolha ser a feita em fun ca o do crit erio que melhor se adequar as nossas necessidades. Um exemplo de algoritmo pode ser as instru co es que um professor passa aos seus alunos em uma academia de gin astica, mostrado no Algoritmo 2.1. Observar que nesta representa ca o do algoritmo cada linha cont em uma instru ca o. Algoritmo 2.1: Exemplo de Algoritmo. in cio enquanto n ao fez 10 vezes fa ca Levantar e abaixar bra co direito Levantar e abaixar bra co esquerdo Levantar e abaixar perna esquerda Levantar e abaixar perna direita m enqto m Computadores s ao m aquinas muito ecientes na resolu ca o de problemas matem aticos ou que envolvam n umeros. Como exemplo de um algoritmo matem atico, vamos considerar o problema de resolver uma equa ca o do primeiro grau da forma ax + b = 0 A solu ca o desta equa ca o e x = b/a se o valor de a for diferente de 0. Caso a seja igual a 0, a equa ca o n ao possui solu ca o, j a que n ao e poss vel dividir por 0. Este algoritmo escrito (Algoritmo 2.2) em uma pseudo-linguagem de programa ca o caria da seguinte maneira: Algoritmo 2.2: Algoritmo para resolver uma equa ca o do primeiro grau. Entrada: Coecientes a e b da equa ca o ax + b = 0 Sa da: Resultado x da Equa ca o in cio ler a ler b se a = 0 ent ao imprimir A equa c~ ao nao tem solu c~ ao sen ao x b/a imprimir A raiz da equa c~ ao vale , x m se m As instru co es do algoritmo s ao executadas passo a passo e uma instru ca o somente e executada quando a anterior terminou sua tarefa. Os dois primeiros passos do algoritmo servem para o algoritmo obter os valores dos coecientes a e

36

b. Os valores podem, por exemplo, serem digitados em um teclado pelo usu ario que est a usando o algoritmo. O valor digitado vai para uma posi ca o da mem oria do computador, que para facilitar o manuseio do dado, recebe um nome. Neste exemplo demos os nomes a, b e x as posi co es de mem oria usadas pelo programa para armazenar dados. Ap os os dois primeiros passos o algoritmo executa uma instru ca o de teste para vericar se o valor de a e diferente de 0. Neste caso podemos ter duas respostas e o computador ir a escolher entre dois caminhos independentes e exclusivos. Caso a seja igual a zero, o algoritmo executa as instru co es entre a palavra ent~ ao e sen~ ao, e portanto, imprime uma mensagem de aviso para o usu ario e termina. Esta mensagem normalmente aparece em um monitor de v deo. No caso de a ser diferente de zero, o algoritmo executa as instru co es entre sen~ ao e fim se. Isto signica calcular o resultado da equa ca o e atribuir este resultado ` a x. O u ltimo passo, desta op ca o e a impress ao do resultado da equa ca o.

2.3

Representa c ao

As formas mais comuns de representa ca o de algoritmos s ao as seguintes: Linguagem Natural: Os algoritmos s ao expressos diretamente em linguagem natural, como nos exemplos anteriores. Fluxograma Convencional: Esta e um representa ca o gr aca que emprega formas geom etricas padronizadas para indicar as diversas a co es e decis oes que devem ser executadas para resolver o problema. Pseudo-linguagem: Emprega uma linguagem intermedi aria entre a linguagem natural e uma linguagem de programa ca o para descrever os algoritmos. N ao existe consenso entre os especialistas sobre qual seria a melhor maneira de representar um algoritmo. Atualmente a maneira mais comum de representarse algoritmos e atrav es de uma pseudo-linguagem ou pseudo-c odigo. Esta forma de representa ca o tem a vantagem de fazer com que o algoritmo seja escrito de uma forma que est a mais pr oxima de uma linguagem de programa c ao de computadores.

2.3.1

Linguagem Natural

A representa ca o em linguagem natural tem a desvantagem de colocar uma grande dist ancia entre a solu ca o encontrada e o resultado nal do processo que e um programa em linguagem de programa ca o. O Algoritmo 2.3 mostra um algoritmo, escrito em linguagem natural, para calcular a m edia de um aluno que faz tr es provas e precisa de obter m edia acima de 5.0 para ser aprovado.

2.3.2

Fluxogramas

Esta forma de representa ca o de algoritmos emprega v arias formas geom etricas para descrever cada uma das poss veis a co es durante a execu ca o do algoritmos. Existem algumas formas geom etricas que usualmente s ao empregadas 37

Algoritmo 2.3: Algoritmo para calcular a m edia das notas de um aluno. Entrada: Notas n1 , n2 e n3 . Sa da: Resultado media do aluno e se ele foi aprovado ou n ao. in cio Obter as notas n1 , n2 e n3 Calcular m edia. Usar a f ormula ((n1 + n2 + n3 )/3.0). Se a m edia for maior que 5.0 imprimir que o aluno foi aprovado Caso contr ario imprimir que o aluno foi reprovado. Imprimir a m edia. m neste m etodo. Estas formas est ao mostradas na Figura 2.1. Cada uma destas formas se aplica a uma determinada a ca o como est a indicado na gura. Estas formas s ao apenas alguns exemplos, existindo outras, no entanto, nesta apostila estas ser ao sucientes para os exemplos que ser ao mostrados.
Incio e Fim de Fluxograma Processamento

Ponto de Deciso

Entrada de Dados Manual

Impresso de Resultados

Conector para mesma pgina

Figura 2.1: S mbolos mais comumente usados em uxogramas. Como exemplo de um algoritmo escrito em forma de uxograma, vamos considerar o algoritmo 2.2 para resolver uma equa ca o do primeiro grau da forma ax + b = 0. A Figura 2.2 mostra um uxograma para resolver este problema. Os dois primeiros passos do algoritmo l eem os valores dos coecientes a e b da equa ca o. Em seguida h a um teste para descobrir se o valor de a e igual a zero. Se o valor de a for igual a zero o algoritmo manda que seja impressa uma mensagem informando que a equa ca o n ao tem solu ca o. Caso o valor de a seja diferente os pr oximos passos calculam o valor da solu ca o e em seguida imprimem este resultado

2.3.3

Pseudo-Linguagem

Este modo de representar algoritmos procura empregar uma linguagem que esteja o mais pr oximo poss vel de uma linguagem de programa ca o de computadores de alto n vel, mas evitando de denir regras de constru ca o gramatical muito r gidas. A id eia e usar as vantagens do emprego da linguagem natural, mas restringindo o escopo da linguagem. Normalmente estas linguagens s ao vers oes ultra reduzidas de linguagens de alto n vel do tipo Pascal ou C. O algoritmo 2.2 foi escrito em uma pseudo-linguagem. A maioria destas linguagens s ao muito parecidas e t em a vantagem de serem facilmente entendidas. Vamos apresentar agora um outro exemplo (Algoritmo 2.4) escrito em pseudo-linguagem. 38

Incio

Obter a

Obter b

Sim a =0 No x=-b/a No h razes reais

Imprime x

Fim

Figura 2.2: Fluxograma para resolver uma equa ca o do primeiro grau.

Este algoritmo serve para descobrir qual e a maior nota de um grupo de tr es notas de um aluno. O algoritmo inicialmente l e a primeira nota e guarda esta nota como a maior nota. Em seguida, l e cada uma das outras notas e compara com a nota guardada como a maior nota. Caso a nota lida seja maior substitui o valor anterior pelo novo valor. Apesar destas pseudo-linguagens terem poucas regras existem algumas que normalmente s ao usadas para facilitar o entendimento entre os programadores. Vamos detalhar algumas delas. As palavras in cio e m indicam onde come ca e termina o algoritmo. As palavras em negrito indicam instru co es que devem ser executadas pelo computador onde o algoritmo ser a rodado. Por exemplo, ler notaAluno e uma instru ca o do algoritmo que ordena ao computador para obter a nota de um aluno para ser processada. Em algoritmos esta nota normalmente ser a obtida de um perif erico de entrada de dados, sendo mais comum o teclado. As palavras em it alico s ao normalmente chamadas de vari aveis e representam locais na mem oria do computador onde os valores a serem usados durante o processamento est ao armazenados. Os programadores podem incluir nos algoritmos explica co es que facilitem o entendimento do seu funcionamento. Estes coment arios n ao s ao executados pelos computadores e somente s ao lidos pelos programadores. Existem diversas maneiras de indicar que o texto no algoritmo e apenas um coment ario. Neste exemplo usamos dois caracteres -- para indicar que o restante da linha e apenas um coment ario. Mais adiante outras explica co es ser ao apresentadas.

39

Algoritmo 2.4: Algoritmo para calcular a maior nota de um grupo de notas. Entrada: Tr es notas de um aluno, (notaAluno). Sa da: Maior das notas do aluno, (maiorN ota) in cio -- L^ e primeira nota ler notaAluno maiorN ota notaAluno -- L^ e segunda nota ler notaAluno se notaAluno > maiorN ota ent ao maiorN ota notaAluno m se -- L^ e terceira nota ler notaAluno se notaAluno > maiorN ota ent ao maiorN ota notaAluno m se imprimir A maior nota das notas e , maiorN ota m

2.4

Modelo de von Neumann

Algoritmos para computadores se baseiam em alguns conceitos b asicos e em um modelo de computador, os quais devem ser bem entendidos para que se possa criar algoritmos ecientes. Este modelo foi proposto pelo matem atico h ungaro Neumann J anos Lajos Margittai. Em h ungaro o nome de fam lia aparece antes. Assim em portugu es o seu nome seria J anos Lajos Margittai Neumann. O seu pai, que era rico, comprou um t tulo de nobreza e ele passou a se chamar J anos Lajos Margittai von Neumann. No modelo de computador proposto por von Neumann as instru co es e os dados cam juntos na mem oria. O processador busca na mem oria e executa uma instru ca o de cada vez. Para ilustrar como este modelo funciona vamos analisar passo a passo a execu ca o de um algoritmo simples. Na Figura 2.3 mostramos nos endere cos 0, 1 e 2, de uma mem oria, um grupo de instru co es formando parte de um algoritmo. As instru co es tamb em podem ser acompanhadas no Algoritmo 2.5. Vamos assumir que o computador inicie executando o algoritmo a partir da instru ca o que est a no endere co 0. O procedimento normal e a Unidade de Controle (UC) do computador continuar buscando e executando uma instru ca o de cada vez nos endere cos seguintes, a n ao ser que haja uma ordem para desviar importante observar que o computador executa uma o uxo das instru co es. E instru ca o de cada vez, e como veremos adiante, tamb em um dado e buscado de cada vez. Portanto, as transfer encias entre a mem oria e o processador s ao feitas passo a passo. O ciclo normal da execu ca o de um programa e ent ao: 1. Busca instru ca o; 2. Decodica instru ca o;

40

3. Executa instru ca o; 4. Volta para o passo 1 buscando a instru ca o seguinte na mem oria. Portanto, ap os a instru ca o do endere co 0 ser lida da mem oria e trazida para a UCP, ela e decodicada pela UC, que descobre que a instru ca o manda carregar o valor inteiro 2 na posi ca o de mem oria 10, que e chamada de a para facilitar. A instru ca o seguinte ordena a carga do valor inteiro 8 na posi ca o de mem oria chamada de b, que e a posi ca o 11. A u ltima instru ca o ordena a soma dos valores armazenados em a e b e que o resultado seja armazenado na posi ca o 12, que e chamada c. Algoritmo 2.5: Modelo de mem oria e funcionamento de um algoritmo -- Armazena 2 na mem oria no lugar chamado a a2 -- Armazena 8 na mem oria no lugar chamado b b8 -- Soma a com b e armazena no lugar chamado c ca+b Observe que no modelo de von Neumann instru co es e dados cam na mem oria. Considere a u ltima instru ca o do programa que pede para que os dados da posi ca o 10 (a) e 11 (b) sejam somados e o resultado armazenado na posi ca o 12 (c). Para executar esta instru ca o, o computador faz as seguintes opera co es na mem oria: 1. ler a instru ca o no endere co 2; 2. ler o dado a na posi ca o 10; 3. ler o dado b na posi ca o 11; 4. escrever o resultado da soma no endere co 12. Portanto, temos 3 leituras e uma escrita. Destas opera co es, a primeira e uma leitura de instru ca o e as restantes opera co es com dados.

2.5

Estruturas B asicas de Algoritmos

Com a nalidade de ilustrar como criar algoritmos para computadores usando este modelo, vamos discutir alguns tipos b asicos de estruturas usados nesta tarefa. Para isto, iremos usar a representa ca o que for apropriada no momento. N ao iremos neste livro discutir em detalhes estes t opicos, nem apresentar de uma maneira formal qualquer uma destas formas. O interesse e apenas apresentar e discutir algumas estruturas b asicas para ilustrar o pensamento usado pelos programadores quando criam um algoritmo para resolver um problema espec co. Estas estruturas s ao importantes e ser ao reapresentadas quando formos apresentar a linguagem C. Para o programador iniciante esta discuss ao serve como introdu ca o.

41

a<-2
8

b<-8
9

c<-a+b
10 11 12 13 14 15

2
16 17 18

8
19

10
20 21 22 23

24

25

26

27

28

29

30

31

Endereo Endereo Endereo Endereo Endereo Endereo

0: Instruo a <--2 1: Instruo b <--8 2: Instruo c <--a+b 10: Dado a 11: Dado b 12: Dado c

Figura 2.3: Modelo de mem oria

2.5.1

Comandos de leitura

Estes comandos servem para obter dados do mundo exterior, normalmente digitados por um usu ario em um teclado. Outros exemplos de lugares de onde podem ser obtidos dados s ao os arquivos em discos r gidos, disquetes e tas magn eticas. Estes dados s ao lidos e guardados na mem oria para posterior uso. Normalmente os lugares para onde v ao estes dados recebem um nome para facilitar o seu manuseio durante a execu ca o do algoritmo. Por exemplo, o comando ler a signica que o algoritmo ir a obter um dado do teclado e ir a armazen a-lo em uma posi ca o de mem oria que passar a a ser conhecida pelo nome a. Estas posi co es s ao conhecidas por vari aveis em computa ca o. Costuma-se dizer ent ao que a e uma vari avel do algoritmo. Apesar de a no algoritmo 2.2 representar uma das constantes da equa ca o do primeiro grau no algoritmo ela e uma das vari aveis. Observe que cada vez que o algoritmo e executado a pode assumir um valor diferente, portanto varia de acordo com a execu ca o do algoritmo. O comando pode ser seguido por uma lista de nomes separados por v rgulas. Por exemplo o comando ler a, b l e dois valores do teclado e os atribui as vari aveis a e b. Observe que a ordem em que os valores foram digitados determina como os valores ser ao atribu dos. O primeiro valor lido e atribu do a primeira vari avel, no caso a. O segundo valor lido e atribu do a segunda vari avel (b). Os valores normalmente s ao digitados separados por um ou mais espa cos em branco ou em linhas diferentes.

2.5.2

Comandos de escrita

Ap os a obten ca o dos resultados do algoritmo, estes devem ser apresentados ao usu ario, e para isto usamos os comandos de escrita. Por exemplo o comando 42

imprimir x imprime o valor atual que est a na mem oria representada pelo nome x. Da mesma forma que nos comandos de leitura e poss vel colocar uma lista de nomes de vari aveis ap os o comando. Por exemplo, o comando imprimir x1, x2 imprime os valores das vari aveis x1 e x2. O meio de apresenta ca o dos resultados, normalmente, e um monitor de v deo. O comando imprimir pode ser usado para mandar mensagens de texto para o usu ario do algoritmo das formas mais variadas. Alguns exemplos de comandos de impress ao s ao os seguintes:

imprimir Entre com o valor do coeciente imprimir O valor de x e , x imprimir O valor de x1 e , x1, e o de x2 e , x2 Notar que os textos entre aspas indicam um texto que deve ser impresso no perif erico de sa da sem nenhuma modica ca o. Vamos considerar que as vari aveis destes exemplos valem x = 10, x1 = 5 e x2 = 8. Os tr es comandos mostrariam no perif erico de sa da os seguintes resultados: Entre com o valor do coeficiente. O valor de x e 10 O valor de x1 e 5 e o de x2 e 8

2.5.3

Express oes

Express oes s ao usadas para denir os c alculos requeridos pelo algoritmo, por exemplo b/a. Iremos discutir dois tipos b asicos de express oes: express oes aritm eticas e express oes l ogicas. Express oes manipulam dados dentro dos algoritmos. Uma pergunta importante neste momento e: que tipo de dados poderemos manipular? As linguagens de programa ca o normalmente estabelecem regras precisas para denir que tipos de dados elas ir ao manipular. Nesta discuss ao vamos estabelecer, ainda que informalmente, algumas regras que limitam os conjuntos de dados existentes na Matem atica e estabelecem que dados poder ao ser manipulados pelos algoritmos. Isto ocorre porque os computadores possuem limita co es que os impedem de manipular todos os tipos de dados que um ser humano pode tratar. Mais adiante, quando formos estudar a linguagem C iremos apresentar mais formalmente as regras desta linguagem para estas representa co es. Existem tr es tipos b asicos de dados que iremos discutir: Dados num ericos: como o nome indica s ao os n umeros que ser ao operados. Dados alfa-num ericos: s ao os dados representados por caracteres. Como caracteres podem ser letras, algarismos e sinais diversos estes dados recebem este nome. 43

Dados L ogicos: estes dados podem assumir dois valores verdadeiro e falso. Estes dados resultam de express oes do tipo x > 0. Os dados num ericos que os algoritmos que iremos construir podem manipular s ao de dois tipos: inteiros e reais. S ao exemplos de n umeros inteiros: +3 3 -324 -50 S ao exemplos de n umeros reais: +0.5 0.5 -8.175 2.0 Dados alfa-num ericos servem para tratamento de textos e normalmente s ao compostos por uma seq u encia de caracteres contendo letras, algarismos e caracteres de pontua ca o. Nos algoritmos s ao normalmente representados por uma seq u encia de caracteres entre aspas, por exemplo: Linguagem de programa c~ ao Qual e o seu nome? 12345 Dados l ogicos s ao intensamente aplicados durante o processo de tomada de decis oes que o computador frequentemente e obrigado a fazer. Em muitos textos este tipo de dados tamb em e chamado de tipo de dados booleanos, devido a George Boole, matem atico que deu ao nome ` a algebra ( algebra booleana) que manipula este tipo de dados. Os dados deste tipo somente podem assumir dois valores: verdadeiro e falso. Computadores tomam decis oes, durante o processamento de um algoritmo, baseados nestes dois valores. Por exemplo, considere a decis ao abaixo:

se a = 0 ent ao imprimir A equa c~ ao nao tem solu c~ ao sen ao x b/a imprimir A raiz da equa c~ ao vale , x m se Neste algoritmo aparece a express ao a = 0, que procura descobrir se o valor de raiz e igual a 0. Esta express ao somente pode ter como resultado os valores: verdadeiro ou falso. Nos nossos algoritmos estes valores ser ao representados por verdadeiro e falso.

44

Express oes Aritm eticas Para os nossos exemplos iniciais iremos adotar os operadores aritm eticos bin arios mostrados na Tabela 2.1. A coluna prioridade indica a prioridade relativa dos operandos. O menor n umero indica a maior prioridade. Quando temos dois operandos de mesma prioridade o computador ir a executar primeiro a opera ca o mais ` a esquerda. Em computa ca o, as express oes devem ser escritas em linhas e para alterar a prioridade deve-se usar par enteses. Maiores detalhes sobre express oes ser ao apresentados no Cap tulo 5. No momento, estamos apenas apresentando alguns conceitos b asicos para facilitar a discuss ao de alguns algoritmos. Operador / * % + Descri c ao Divis ao Multiplica ca o M odulo (resto da divis ao de operandos inteiros) Soma Subtra ca o Prioridade 0 0 0 1 1

Tabela 2.1: Operadores Aritm eticos. Para ilustrar o uso de operadores aritm eticos vamos considerar alguns exemplos de express oes. Os exemplos a seguir mostram como converter uma express ao matem atica para a forma que usaremos em pseudo-linguagem. Observer o uso de par enteses para alterar a prioridade das opera co es. Express ao Matem atica
a b+c a+b c +d 2

b 4ac
1 1 1+ a+ b

Express ao em Pseudo-linguagem a/(b+c) (a+b)/(c+d) b*b-4*a*c 1/(1 + 1/(a+b))

2.5.4

Comandos de atribui c ao

Servem para atribuir valores ` a posi co es de mem oria. Normalmente estes valores podem ser constantes ou resultados de express oes dos diversos tipos. Exemplos de comandos de atribui ca o s ao mostrados a seguir. x b/a media (n1 + n2)/2 inicio 0 nome Ze Sa ii+1 A seta aponta sempre da direita para a esquerda. O valor ou o resultado da express ao a direita da seta e armazenado na vari avel que est a no lado esquerdo da seta. A dire ca o da seta n ao pode ser alterada. No caso da u ltima 45

express ao temos que o valor atual de i e incrementado e depois substitui este valor, portanto, se ele valia 10, ao nal da instru ca o ele vale 11.

2.5.5

Comandos de controle

S ao usados para controlar o uxo de execu ca o das instru co es. Nas linguagens de programa ca o existem diversos tipos de comandos de controle. Para estes exemplos iniciais vamos mostrar somente o comando mais b asico que serve para o computador escolher entre dois poss veis caminhos qual o algoritmo deve seguir. Este comando, representado em uxograma, pode ser visto na Figura 2.4 e em pseudo linguagem tem a forma mostrada no algoritmo 2.6.

Algoritmando

Falso Condio

Verdadeiro

Faa isto

Faa aquilo

Continuo algoritmando

Figura 2.4: Fluxograma do comando se ...

ent~ ao ...

sen~ ao.

Algoritmo 2.6: Comando se em pseudo-linguagem se Condi c ao sendo testada ent ao Fa ca isto sen ao Fa ca aquilo m se Um exemplo de uso desta constru ca o, escolhido a partir da vida real, pode ser o seguinte. Tenho que decidir o que fazer em um domingo de folga. Se estiver chovendo irei ao cinema, caso contr ario irei ` a praia. Observe que para ir para a praia basta apenas que n ao esteja chovendo, nenhum outro teste foi

46

feito. Esta decis ao em forma de pseudo-linguagem ca da maneira mostrada no Algoritmo 2.7. Algoritmo 2.7: Algoritmo para decidir o que fazer no domingo. se est a chovendo ent ao vou ao cinema sen ao vou ` a praia m se Nem sempre nos algoritmos precisamos de duas alternativas. As vezes precisamos somente de decidir se devemos fazer algo ou n ao Por exemplo, vamos assumir que decidimos ir ao cinema no domingo chova ou fa ca sol. No entanto, preciso decidir se levo um guarda-chuva. O algoritmo para este caso est a mostrado no Algoritmo 2.8. Observe que no caso de n ao estar chovendo nada precisa ser feito. A Figura 2.5 mostra esta decis ao em forma de uxograma. Algoritmo 2.8: Algoritmo para decidir se deve levar um guarda-chuva. Vestir para ir ao cinena se est a chovendo ent ao pego guarda-chuva m se Vou ao cinema

2.5.6

Comandos de repeti c ao

As linguagens de programa ca o normalmente possuem diversos comandos que permitem que um trecho de algoritmo seja repetido um n umero de vezes. Para estes exemplos iniciais iremos apresentar um comando de repeti ca o que e sucientemente geral para substituir todos os outros. Este comando, que chamaremos de comando enquanto tem a forma mostrada na Figura 2.6. O comando funciona da seguinte maneira: Passo 1: Testar se a condi ca o e verdadeira. Caso seja verdade executar o bloco de comandos situados entre o in cio do comando e o nal do comando. O nal do comando enquanto normalmente e marcado de alguma forma. Em nossa pseudo-linguagem marcaremos o m pelas palavras fim enquanto ou fim eqto. Passo 2: Executar o bloco de comandos at e o m do enquanto. Quando chegar ao m retornar automaticamente para o in cio do comando e refazer o passo 1. Como exemplo consideremos o caso em que precisamos ler um conjunto de 10 n umeros e imprimir se cada um dos n umeros lidos e par ou n ao. Para descobrir se o n umero e par vamos dividi-lo por 2 e testar o resto. Para simplicar, vamos considerar que caso o resto da divis ao seja igual a zero o n umero e par. 47

Vestir para ir ao cinema

Falso Chovendo?

Verdadeiro

Pegar guarda-chuva

Ir ao cinema

Figura 2.5: Fluxograma para decidir se deve levar um guarda-chuva.

Neste algoritmo sabemos a quantidade de n umeros a serem lidos e portanto o n umero de repeti co es e pr e-determinado. O Algoritmo 2.9 mostra como seria implementada uma solu ca o para este problema. Vamos mostrar um exemplo onde o n umero de repeti co es n ao e conhecido. Considere no exemplo anterior que o total de n umeros a ser lido n ao e conhecido. Mas ent ao, como o algoritmo ir a terminar de ler n umeros? Usaremos o que costuma-se chamar de sentinela em computa ca o. O algoritmo ir a se manter lendo n umeros enquanto os n umeros forem positivos. No momento que for lido um n umero negativo o algoritmo p ara. A sentinela que indica o nal da lista de n umeros e um n umero negativo. O Algoritmo 2.10 mostra como ca em pseudo-linguagem o algoritmo modicado. Observe que neste algoritmo o primeiro n umero tem de ser lido antes do comando enquanto. Isto porque assumimos que o primeiro n umero que for digitado pode ser negativo e portanto a lista de n umeros n ao tem nenhum n umero.

2.6

Exemplos de Algoritmos

Nesta se ca o iremos apresentar uma s erie de algoritmos escritos na pseudolinguagem que acabamos de apresentar. Exemplo 2.1: Este algoritmo serve para descobrir qual e a maior nota de uma turma de alunos. Neste algoritmo iremos considerar que as notas podem variar entre 0.0 e 10.0 e que a turma tem 25 alunos. O algoritmo 2.11 inicialmente inicia a maiorN ota com zero, depois compara cada nota com esta maiorN ota caso ela seja maior substitui o valor anterior pelo novo valor. Observar que 48

Algoritmo 2.9: Algoritmo para ler 10 n umeros e imprimir se s ao pares ou n ao. Entrada: 10 n umeros, (numero). Sa da: Se o n umero e par ou n ao in cio totalN umeros 10 enquanto totalN umeros > 0 fa ca ler numero se numero%2 = 0 ent ao imprimir numero, par sen ao imprimir numero, impar m se totalN umeros totalN umeros 1 m enqto m

Algoritmo 2.10: Algoritmo para ler n umeros e imprimir se s ao pares ou n ao. A quantidade de n umeros a ser lida e desconhecida. Entrada: n umeros, (numero). O algoritmo para quando um n umero negativo e lido Sa da: Se o n umero e par ou n ao in cio ler numero enquanto numero > 0 fa ca se numero % 2 = 0 ent ao imprimir numero, par sen ao imprimir numero, impar m se ler numero m enqto m

49

Algoritmando

Falso Testa Condio

Verdadeiro

Bloco de comandos do enquanto

Continuo algoritmando

Figura 2.6: Fluxograma do comando enquanto.

criamos uma vari avel para armazenar a quantidade de alunos. Voc e poderia perguntar porque n ao usar o n umero 25 toda vez que for necess ario. A raz ao e simples. Suponha que voc e gostaria de usar este algoritmo para calcular a maior nota de uma turma de 40 alunos. Neste algoritmo bastaria substituir o n umero 25 por 40. No entanto, existe uma solu ca o mais geral ainda que permite que o algoritmo possa ser usado para qualquer tamanho de turma. Este problema est a apresentado na lista de exerc cios deste cap tulo. Exemplo 2.2: Vamos mostrar outro exemplo de algoritmo muito usado. Precisamos ler as notas de uma turma de alunos e calcular a m edia destas notas. Vamos assumir que a turma tem 25 alunos e as notas est ao entre 0 e 10. O algoritmo est a mostrado em Algoritmo 2.12. Exemplo 2.3: Neste exemplo considere o seguinte problema. Um escrit orio de previs ao do tempo armazena diariamente a temperatura m edia de uma determinada regi ao. A tarefa e descobrir qual e a maior temperatura do ano passado. Assuma que foram armazenadas 365 temperaturas, uma para cada dia do ano. Neste caso n ao podemos aplicar o algoritmo 2.11 usado para descobrir a maior nota da turma. Antes de continuar procure encontrar a raz ao. Como dica, considere que estamos no p olo sul e portanto todas as temperaturas lidas s ao negativas. Uma solu ca o poss vel para este exemplo est a mostrada no algoritmo 2.13. Este algoritmo faz o seguinte. Pega a primeira temperatura e a anota como a maior j a encontrada. A partir da o algoritmo ca repetidamente lendo temperaturas dos registros do escrit orio comparando com a temperatura que no 50

Algoritmo 2.11: Algoritmo para calcular a maior nota de uma turma de 25 alunos. Entrada: Nota de cada um dos dos 25 alunos da turma, (notaAluno). Sa da: Maior das notas dos alunos, (maiorN ota) in cio totalAlunos 25 maiorN ota 0.0 enquanto totalAlunos > 0 fa ca ler notaAluno se notaAluno > maiorN ota ent ao maiorN ota notaAluno m se totalAlunos totalAlunos 1 m enqto imprimir A maior nota das notas e , maiorN ota m

Algoritmo 2.12: Algoritmo para calcular a nota m edia de uma turma de 25 alunos. Entrada: Nota de cada um dos dos 25 alunos da turma, (notaAluno). Sa da: M edia das notas dos alunos, (mediaN otas) in cio totalAlunos 25 i0 somaN otas 0.0 enquanto i < totalAlunos fa ca ler notaAluno somaN otas somaN otas + notaAluno ii+1 m enqto mediaN otas somaN otas/totalAlunos imprimir A m edia das notas e , mediaN otas m

51

momento consta como a maior de todas. Se a temperatura tirada dos arquivos for maior que a menor atual, o algoritmo joga fora a temperatura anotada e guarda a que foi lida como a nova maior temperatura. Quando n ao houver mais temperaturas para ler a que estiver anotada como a maior e a maior verdadeiramente. Algoritmo 2.13: Algoritmo para calcular a maior temperatura do ano. Entrada: Temperaturas registradas em ano, (temperatura). Sa da: Maior das temperaturas, (maiorT emperatura) in cio totalT emperaturas 365 ler temperatura -- J a li uma temperatura totalT emperaturas totalT emperaturas 1 -- A primeira temperatura e a maior temperatura maiorT emperatura temperatura enquanto totalT emperaturas > 0 fa ca ler temperatura se temperatura > maiorT emperatura ent ao maiorT emperatura temperatura m se totalT emperaturas totalT emperaturas 1 m enqto imprimir A maior nota das temperaturas e , maiorT emperatura m

52

2.7

Exerc cios

2.1: Uma empresa paga R$10.00 por hora normal trabalhada e R$ 15.00 por hora extra. Escreva um algoritmo que leia o total de horas normais e o total de horas extras trabalhadas por um empregado em um ano e calcule o sal ario anual deste trabalhador. 2.2: Assuma que o trabalhador do exerc cio anterior deve pagar 10% de imposto se o seu sal ario anual for menor ou igual a R$ 12000.00. Caso o sal ario seja maior que este valor o imposto devido e igual a 10% sobre R$ 12000.00 mais 25% sobre o que passar de R$ 12000.00. Escreva um programa que calcule o imposto devido pelo trabalhador. 2.3: Escreva um algoritmo que descubra a maior nota de uma turma de alunos. O tamanho da turma deve ser o primeiro dado pedido ao usu ario. 2.4: Modique o algoritmo anterior de modo que ele imprima tamb em quantas vezes a maior nota aparece. 2.5: Nos exerc cios anteriores assumimos que os usu arios sempre digitam uma nota entre 0 e 10. Vamos assumir agora que o usu ario sempre digita um n umero, mas este n umero pode estar fora do intervalo 0 a 10. Ou seja, poderemos ter uma nota menor que zero ou maior que 10. Modique o algoritmo anterior para que ele verique a nota digitada e, caso o aluno tenha digitado uma nota inv alida, uma mensagem avisando o usu ario seja impressa e uma nova nota seja pedida. O algoritmo deve insistir at e que o usu ario digite um valor v alido. 2.6: Escreva um programa que leia um conjunto de 100 temperaturas e imprima a menor temperatura lida. Observe que temperaturas podem assumir valores menores do que zero. 2.7: Escreva um algoritmo que leia tr es n umeros e os imprima em ordem crescente. 2.8: Escreva um algoritmo que leia um n umero inteiro entre 100 e 999 e imprima na sa da cada um dos algarismos que comp oem o n umero. Observe que o n umero e lido com um valor inteiro, e, portanto, ele tem de ser decomposto em tr es n umeros: os algarismos das centenas, dezenas e unidades. 2.9: Escreva um algoritmo que leia uma hora em horas, minutos e segundos e some um segundo a hora lida. 2.10: Escreva um algoritmo que leia duas datas em dia, m es e ano e imprima a data mais recente. 2.11: Um aluno est a escrevendo um programa que l e uma nota no intervalo entre 0 e 100, inclusive. Foi pedido ao aluno que o programa aceite as notas v alidas e rejeite as inv alidas. Marque a letra que mostra a express ao que falta no trecho pontilhado do algoritmo mostrado em 2.14. (a) (nota < 0) e (nota > 100) (b) (nota <= 0) e (nota >= 100) 53

(c) (nota < 0) ou (nota > 100) (d) (nota <= 0) ou (nota >= 100) (e) (nota >= 0) e (nota <= 100)

Algoritmo 2.14: Algoritmo do exerc cio 11. in cio imprimir Entre com a nota ler nota se .............. ent ao imprimir Nota inv alida sen ao imprimir Nota v alida m se m 2.11: Considere que os valores -3, -4 e -5, nesta ordem, foram fornecidos ao algoritmo 2.15: Algoritmo 2.15: Algoritmo do exerc cio 11. Dados: t1, t2, t3, maior in cio ler (t1, t2, t3) maior 0 se t1 > maior ent ao maior t1 m se se t2 > maior ent ao maior t2 m se se t3 > maior ent ao maior t3 m se imprimir (maior) m Marque a letra que indica o que foi impresso em cada vez que o programa foi executado. (a) 0 (b) -3 (c) -4 (d) -5 (e) nenhuma das respostas anteriores.

54

Cap tulo 3

Tipos de Dados, Constantes e Vari aveis


3.1 Introdu c ao

Vari aveis e constantes s ao os elementos b asicos que um programa manipula. Uma vari avel corresponde a um espa co reservado na mem oria do computador para armazenar um determinado tipo de dado. Vari aveis devem receber nomes para poderem ser mais facilmente referenciadas e modicadas sempre que necess ario. Muitas linguagens de programa ca o exigem que os programas declarem todas as vari aveis antes que elas possam ser usadas. Estas declara co es especicam de que tipo s ao as vari aveis usadas pelos programas e as vezes um valor inicial. Tipos podem ser por exemplo: inteiros, reais, caracteres, etc. As express oes combinam vari aveis e constantes para calcular novos valores.

3.2
3.2.1

Tipos de Dados
Tipos B asicos

Os dados em C podem assumir cinco tipos b asicos que s ao os seguintes: char: O valor armazenado e um caractere. Caracteres geralmente s ao armazenados em c odigos (usualmente o c odigo ASCII). A Tabela A.1 mostra este c odigo. Caracteres s ao armazenados em um byte. int: O valor armazenado e um n umero inteiro e o tamanho do subconjunto que pode ser representado pelo computador normalmente depende da m aquina em que o programa est a rodando. Atualmente em C os n umeros inteiros s ao armazenados em 32 bits. oat: N umero em ponto utuante de precis ao simples, normalmente 32 bits. S ao conhecidos como n umeros reais, no entanto, os computadores somente podem armazenar e trabalhar com uma pequena parte do conjunto dos n umeros reais. 55

double: N umero em ponto utuante de precis ao dupla, com isto a precis ao e as vezes a excurs ao dos n umeros aumenta. Este tipo e armazenado em 64 bits. void: Este tipo serve para indicar que um resultado n ao tem um tipo denido. Uma das aplica co es deste tipo em C e criar um tipo vazio que pode posteriormente ser modicado para um dos tipos anteriores.

3.2.2

Modicadores de tipos

Modicadores podem ser aplicados a estes tipos. Estes modicadores s ao palavras que alteram o tamanho do conjunto de valores que o tipo pode representar. Por exemplo, um modicador permite que possam ser usados mais bits para armazenar n umeros inteiros. Um outro modicador obriga que s o n umeros inteiros sem sinal possam ser armazenados pela vari avel. Deste modo n ao e necess ario guardar o bit de sinal do n umero e somente n umeros positivos s ao armazenados. O resultado pr atico e que o conjunto praticamente dobra de tamanho. Os modicadores de tipos s ao os seguintes: unsigned: Este modicador pode ser aplicado aos tipos int e char e faz com que o bit de sinal n ao seja usado, ou seja o tipo passa a ter um bit a mais. signed: Este modicado tamb em pode ser aplicado aos tipos int e char. O uso de signed com int e redundante. long: Modicador que pode ser aplicado aos tipos int e double aumentando o n umero de bytes reservado para armazenamento de dados. poss E vel combinar estes modicadores de diversas maneiras como est a mostrado na Tabela 3.1 que lista os tipos b asicos denidos no padr ao ANSI e a sua excurs ao.

3.3

Constantes Num ericas

Constantes s ao valores que o programa n ao pode modicar durante a execu ca o de um programa. Elas s ao usadas em express oes para representar v arios tipos de valores. Em C existem regras r gidas para determinar como devem ser escritos estes valores. A seguir iremos mostrar estas regras. Para escrever constantes num ericas vamos usar as seguintes deni co es: d gito: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 d gito sem zero: 1, 2, 3, 4, 5, 6, 7, 8, 9 d gito octal: 0, 1, 2, 3, 4, 5, 6, 7 d gito hexa: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, A, b, B, c, C, d, D, e, E, f, F 56

Tipo char unsigned char signed char int unsigned int signed int short int, short unsigned short int signed short int long int, long signed long int unsigned long int long long int long long signed long long int signed long long unsigned long long int unsigned long long oat double long double

Bytes 1 1 1 4 4 4 2 2 2 4 4 4 8 8 8 4 8 12

Faixa M nima -127 a 127 0 a 255 -127 a 127 -2.147.483.648 a 2.147.483.647 0 a 4.294.967.295 -2.147.483.648 a 2.147.483.647 -32.768 a 32.767 0 a 65.535 -32.768 a 32.767 -2.147.483.648 a 2.147.483.647 -2.147.483.648 a 2.147.483.647 0 a 4.294.967.295 -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 0 a 18.446.744.073.709.551.615 oito d gitos de precis ao 16 d gitos de precis ao 16 d gitos de precis ao

Tabela 3.1: Tipos de dados denidos pelo Padr ao ANSI C.

sinal: +, ponto decimal: . suxo: sufixo sem sinal, sufixo longo suxo sem sinal: u, U suxo longo: l, L suxo utuante: f, F, l, L O uso destas caracteres ser a mostrado com exemplos nas se c oes seguintes.

3.3.1

Constantes Inteiras na base 10

S ao valores num ericos sem ponto decimal, precedidos ou n ao por um sinal. N ao e poss vel separar, por espa cos em branco, o sinal do valor num erico. Podemos descrever este formato com uma nota ca o simplicada da seguinte maneira: gito}[sufixo sem sinal|sufixo longo] [sinal]d gito sem zero{d Esta nota ca o deve ser entendida da seguinte maneira. Colchetes indicam op ca o, portanto, o fato de sinal (+ ou -) estar entre colchetes signica que um 57

n umero inteiro pode ou n ao ter sinal, isto e o sinal e opcional. Em seguida temos um d gito sem zero que e obrigat orio. Isto e dados inteiros devem come car por, pelo menos, um algarismo entre 1 e 9. A seguir temos a palavra d gito entre chaves. As chaves indicam que o fator entre elas pode ser repetido zero ou mais vezes. Portanto, um n umero inteiro, ap os o algarismo inicial obrigat orio, pode ser seguido por uma seq u encia de zero ou mais algarismos. Como suxo podemos ter opcionalmente as letras u (U) ou l (L) ou uma mistura, em qualquer ordem, das duas. Para constantes inteiras o suxo U (u) representa o modicador unsigned. O suxo L (l) representa o modicador long. Um par de Ls (ls) indica que a constante e do tipo long long. A tabela 3.2 mostra exemplos de n umeros inteiros: Tipo int unsigned int long int unsigned long int long long unsigned long long Constantes -3 +5 45u 12345U 1997L -3l 45Lu 23Ul 1997Ll -3ll 45LLu 23Ull

1997 1997U 1234L 1997UL 134LL 1997ULL

7 0U +0L 0LU +0LL 0LLU

Tabela 3.2: Constantes Inteiras na Base 10 Alguns exemplos de erros na escrita de constantes inteiras s ao: 1.0 (N ao e poss vel usar ponto decimal.) - 345 (N ao e poss vel colocar um espa co entre o sinal e o valor num erico.) 23 (N ao e poss vel usar nota ca o de expoentes.) Nos compiladores modernos o n umero de bytes usados para armazenar os valores inteiros e o mesmo tanto para tipos inteiros (int) quanto para tipos inteiros longos (long int), como est a mostrado na Tabela 3.1. Por esta raz ao, a diferen ca entre estes dois tipos de constantes perdeu a raz ao de ser. Alguns exemplos de constantes inteira longas est ao mostrados na Tabela 3.2.

3.3.2

Constantes Inteiras Octais

S ao constantes representadas na base 8. Normalmente s ao representadas sem sinal e devem come car com um 0. Usando a nota ca o apresentada na se ca o anterior podemos denir a forma que deve ter uma constante octal como: 0 {d gito octal}[sufixo sem sinal|sufixo longo] Na Tabela 3.3 mostramos exemplos de constantes octais e o seu valor na base 10. N umeros escritos na base 8 somente podem ser escritos com algarismos entre 0 e 7 inclusive.

58

Base 8 025 077 011 010ul 0175

Base 10 21 63 9 8 125

Tabela 3.3: Constantes octais

3.3.3

Constantes Inteiras Hexadecimais

S ao constantes representadas na base 16. S ao iniciadas com um 0x ou 0X. Usando a nota ca o podemos denir uma contante hexadecimal como: gito hexa}[sufixo sem sinal|sufixo longo] [0x|0X]d gito hexa{d Na Tabela 3.4 mostramos exemplos de constantes hexadecimais e o seu valor na base 10. Para escrever constantes na base 16 usamos todos os algarismos e ainda as letras A (ou a), B (ou b), C (ou c), D (ou d), E (ou e), F (ou f), que representam respectivamente os seguintes valores 10, 11, 12, 13, 14 e 15. Base 16 0xF 0X25 0XAB 0XBEEF Base 10 15 37 171 48879

Tabela 3.4: Constantes hexadecimais

3.3.4

Convers ao entre Bases

A convers ao de n umeros inteiros entre a base 8 e a base 10 tem uma f ormula simples, que pode ser estendida para converter n umeros entre qualquer base e a base 10. Vamos considerar que um n umero (N )8 escrito na base 8 tenha a seguinte forma (N )8 = dn1 dn2 . . . d1 d0 onde 7 di 0 A f ormula para converter um n umero da base 8 para a base 10 e a seguinte N10 = dn1 8n1 + dn2 8n2 + + d1 81 + d0 80 (3.1)

Esta equa ca o est a escrita na base 10. Por exemplo, aplicando a equa ca o 3.1 para converter o n umero 0175 da base 8 para a base 10 camos com (0175)8 = 1 82 + 7 81 + 5 80 = (125)10

59

A f ormula para convers ao da base 8 para a base 10 pode se estendida para uma base qualquer com a substitui ca o do algarismo 8. Considere uma base qualquer representada por b. Nesta base os d gitos di cam no intervalo b 1 di 0. A equa ca o 3.2 mostra a f ormula para converter um n umero em uma base b qualquer para a base 10. N10 = dn1 bn1 + dn2 bn2 + + d1 b1 + d0 b0 (3.2)

Vamos considerar a contante inteira (3AB )16 . Aplicando a f ormula 3.2 temos (3AF )16 = 3 162 + 10 161 + 15 160 = (943)10 O algoritmo para converter um n umero inteiro da base 10 para uma determinada base b e feito por um conjunto de divis oes sucessivas do n umero pela base at e que o resultado da divis ao seja 0. O Algoritmo 3.1 mostra como converter importante notar que os algarismos na um n umero (N )10 para uma base b. E base b v ao sendo impressos na ordem inversa, do menos signicativo para o mais signicativo. Por exemplo, caso forne camos para o algoritmo o n umero (943)10 e a base 16, o algoritmo iria imprimir os resultados 15, 10 e 3 nesta ordem. Isto corresponderia aos seguintes d gitos da base 16: F, A e 3 e, portanto, a resposta seria (3AF )16 . Algoritmo 3.1: Algoritmo para converter inteiros na base 10 para uma base b. Entrada: n umero, (numero) e base b (baseb). Sa da: D gitos do n umero na base b in cio ler numero ler base enquanto numero > 0 fa ca resto numero % base numero numero / base imprimir resto m enqto m

3.3.5

Constantes em Ponto Flutuante

Constantes em ponto utuante s ao usadas para representar n umeros reais. O nome ponto utuante e devido ao modo como os valores s ao armazenados pelo computador. Constantes de ponto utuante podem ser do tipo oat , double, long ou long double. Constantes sem nenhum suxo s ao consideradas do tipo double. Caso seja usado o suxo F ou o f a constante ser a considerada como do tipo oat . O suxo L ou o l torna a constante long double. Uma constante em ponto utuante pode ser denida de duas maneiras. Voc e pode escrever um n umero com ponto decimal (1.5) ou na chamada forma cient ca, em que um expoente e usado (0.15E1). Na segunda forma o n umero poss e igual a 0.15 101 . E vel omitir ou os d gitos antes do ponto (a parte 60

poss inteira) ou ap os (a parte fracion aria), mas nunca os dois grupos. E vel escrever um n umero em ponto utuante sem ponto, desde que um expoente seja usado. Portanto, os n umeros .8, 1234., 1E1 s ao n umeros de ponto utuante. Para mostrar mais formalmente como se deve escrever as constantes de ponto utuante vamos usar a mesma nota ca o usada at e aqui, mas usando uma hierarquia de deni co es para facilitar o entendimento. Primeiro damos uma deni ca o mais geral que vai sendo mais detalhada a medida que avan camos. Lembrar que termos entre chaves podem ser repetidos 0 ou mais vezes e termos entre colchetes s ao opcionais. Portanto, usando a forma hier arquica, uma constante de ponto utuante (CPF) pode ser denida das seguintes maneiras: CPF = [sinal]fra c~ ao[expoente][sufixo flutuante] gitos expoente[sufixo flutuante] CPF = [sinal]seq d A seguir denimos cada um dos componentes. Uma fra c~ ao e denida como: fra c~ ao = [seq digitos] ponto decimal seq d gitos ou gitos ponto decimal fra c~ ao = seq d O expoente e a seq uencia de d gitos s ao denidos como: gitos expoente = [e | E][sinal]seq d seq d gitos = d gito{d gito} A Tabela 3.5 mostra exemplos de constantes em ponto utuante. Descri c ao sinal fra c~ ao expoente fra c~ ao fra c~ ao expoente fra c~ ao sufixo seq d gitos ponto decimal N umero +23.45e-10 123.45 123.45E+10 123.45F 123.

Tabela 3.5: Constantes em ponto utuante

3.4

Constantes Caracteres

Uma constante caractere e um u nico caractere escrito entre , como em a. Al em disso, uma constante de tamanho igual a um byte pode ser usada para denir um caractere, escrevendo-se, por exemplo, \ddd, onde ddd e uma constante com entre um e tr es d gitos octais. Em C, caracteres podem participar normalmente de express oes aritm eticas. O valor que entra na express ao e o do c odigo usado para representar o caractere. Exemplos de constantes do tipo caractere s ao mostrados na Tabela 3.6. Certos caracteres que n ao s ao vis veis podem ser representados antepondo-se o caractere \ (barra invertida), como no exemplo nova linha da Tabela 3.6. Este caractere e tamb em conhecido como caractere de escape. Exemplos s ao mostrados na Tabela 3.7. 61

Caractere a A \0141 ( 9 \n

Signicado caractere a caractere A Constante octal correspondente ao caractere a caractere abre par enteses algarismo 9 Nova linha, posiciona o cursor no in cio da nova linha. Tabela 3.6: Exemplos de constantes caractere

Caractere \n \t \b \f \r \a \0

Signicado Passa para uma nova linha. Tabula ca o horizontal, move o cursor para a pr oxima parada de tabula ca o. Retorna um caractere. Salta uma p agina. Carriage return, posiciona o cursor no in cio da linha atual. Alerta, faz soar a campainha do sistema. Null, caractere que em C termina uma cadeia de caracteres.

Tabela 3.7: Exemplos de caracteres invis veis.

3.4.1

Constantes Cadeias de Caracteres

Neste livro vamos usar em alguns casos a palavra cadeia para signicar cadeia de caracteres (string em ingl es). Uma constante do tipo cadeia de caracteres e uma seq u encia de qualquer n umero de caracteres entre " como no exemplo: "alo mundo!!!". importante notar que a linguagem C insere automaticamente ao nal de E uma cadeia de caracteres um caractere null (\0). Este caractere ser a usado em diversos algoritmos como sinal de m de cadeia. Os caracteres \ (caractere escape) e " (in cio e m de cadeia) t em signicados especiais em cadeias de caracteres e para serem representados precisam ser antecedidos pelo caractere escape. Portanto, \\ e \" devem ser usados dentro de cadeias de caracteres para representar \ e " respectivamente. Por exemplo, "Estas s~ ao \" (aspas) dentro de cadeias." As aspas no meio da cadeia n ao indicam o m, j a que elas est ao precedidas do caractere de escape.

3.5

Vari aveis

Vari aveis s ao nomes dados para posi co es de mem oria a m de facilitar o manuseio dos dados durante a cria ca o dos programas. Os dados podem ser de qualquer 62

dos tipos denidos para a linguagem C.

3.5.1

Nomes das Vari aveis

Existem algumas regras b asicas que regulam o batismo de vari aveis. Estas regras s ao as seguintes: Nomes de vari avel s o podem conter letras, d gitos e o caractere _; Todo primeiro caractere deve ser sempre uma letra ou o caractere _; Letras mai usculas e min usculas s ao consideradas caracteres diferentes, isto e, C diferencia a caixa das letras; Palavras reservadas n ao podem ser usadas como nome de vari aveis. Palavras reservadas s ao palavras usadas para indicar os comandos da linguagem, tipos de dados ou outras fun co es. O Anexo B mostra as palavras reservadas da linguagem C. boa pol E tica escolher nomes que indiquem a fun ca o da vari avel. Por exemplo: soma mediaNotas total salarioMensal nome taxa imposto raio inicio

Em C nomes como raio, Raio e RAIO referem-se a diferentes vari aveis. No entanto, para afastar confus oes, evite diferenciar nomes de vari aveis por letras mai usculas e min usculas. Normalmente, os programadores usam letras mai usculas para representar constantes. Observe que em alguns nomes combinamos duas palavras para melhor indicar o dado armazenado na vari avel. Note tamb em que o caractere espa co n ao pode ser usado em nomes de vari aveis. Os programadores ao longo do tempo desenvolveram algumas regras informais para fazer esta combina ca o. Por exemoem o nome, como plo, usa-se o caractere para separar as palavras que comp em taxa_imposto . Outra maneira e usar letras mai usculas para indicar quando come ca uma palavra, como em mediaNotas. Alguns programadores usam a conven ca o de n ao come car nomes de vari aveis por letras mai usculas. N ao existem regras formais para denir como nomes devem ser criados. O melhor e analisar as regras que programadores mais experientes usam ou os padr oes que empresas adotam, para ent ao escolher o que mais lhe agrada e segui-lo. Uma vez adotado um padr ao ele deve ser seguido para evitar incoer encias.

3.5.2

Declara c ao de vari aveis

Para serem usadas, as vari aveis precisam ser declaradas de modo que o compilador possa reservar espa co na mem oria para o valor a ser armazenado. A forma geral de uma declara ca o e: aveis; tipo lista de vari onde uma lista de vari aveis e uma lista de nomes de vari aveis separadas por v rgulas. Por exemplo: 63

int i; unsigned i n t a , b , c ; unsigned short i n t dia , mes , ano ; f l o a t raio , diametro ; double salario ;

3.5.3

Atribui c ao de valores

Ap os ser declarada, uma vari avel pode receber valores. O operador de atribui ca o = indica que o resultado da express ao ` a direita do operador ser a atribu do ` a vari avel. Nada se pode armar sobre o conte udo de uma uma vari avel que j a foi declarada mas ainda n ao recebeu um valor. A seguir s ao mostrados exemplos de atribui co es de valores ` as vari aveis durante as declara co es.
i n t i = 0 , j = 10; f l o a t raio = 2.54; char c = d ; double precisao = 0.00001 L ;

A seguir mostramos um trecho de programa com exemplos de atribui ca o de valores ap os a deni ca o das vari aveis.
int i, j; f l o a t raio ; char c ; i = 0; j = 10; raio = 2.54; c = d ;

64

3.6

Exerc cios

3.1: Indique os nomes de vari aveis que s ao v alidos. Justique os nomes inv alidos. (a) tempo (e) 2dias (b) nota final (f) teste 1 (c) us$ (g) raio.do.circulo (d) char (h) DiaHoje 3.2: Marque a letra que cont em pelo menos um nome de vari avel inv alido. (a) (b) (c) (d) (e) raio, nome, hoje, provaFinal 2dia, aluno, real, podeSer = 2dia Alo, ALO, alo, aLO errado, certo, ok, dia2 nome , prova final, raio, nao sei nao

3.3: Indique quais dos n umeros abaixo s ao constantes inteiras (longas ou n ao) v alidas. Justique suas respostas. (a) 100 (e) - 234 (b) 2 345 123 (f) 0L (c) 3.0 (g) 21 (d) -35 (h) 0xF1 3.4: Qual o valor na base 10 das constantes abaixo? (a) (b) (c) (d) 025 0123 0xD 0x1D

3.5: Considere um computador que armazene n umeros inteiros em 32 bits. (a) Caso um bit seja reservado para o sinal diga qual e o menor n umero inteiro negativo que este computador pode armazenar? (b) Para os n umeros sem sinal, qual e o maior n umero positivo? 3.6: Indique na tabela 3.8 os tipos que voc e usaria para armazenar os dados indicados. 3.7: Marque a op ca o que indica quantos dos n umeros abaixo representam resultados da opera ca o (175)8 + (AB)16 . (602)7 , (100101000)2, (128)16 , (450)8 (a) (b) (c) (d) (e) 0 1 2 3 4

65

Descri c ao total de alunos em uma sala a nota de aluno em Computa ca o I Primeira letra de um nome pontos de um jogador de voleibol ao nal do ano; o raio de um c rculo. Tabela 3.8: Tabela do exercicio 6

Tipo da vari avel

66

Cap tulo 4

Entrada e Sa da pelo Console


4.1 Introdu c ao

Neste cap tulo vamos apresentar conceitos b asicos de entrada e sa da de dados para que os exemplos e exerc cios iniciais possam ser constru dos. Um programa que n ao fornece resultados nem pede valores para operar n ao deve ter grande utilidade. A entrada de dados ser a feita pelo teclado e a sa da poder a ser vista na tela do computador. Em C, quando um programa se inicia, normalmente tr es uxos (arquivos) de dados s ao abertos para opera co es de entrada e sa da: um para entrada, um para sa da e um para imprimir mensagens de erro ou diagn ostico. Normalmente o uxo de entrada est a conectado ao teclado, enquanto que o uxo de sa da e o de mensagens de erro, para serem visualizados, est ao conectados ao monitor. Estas congura co es podem ser alteradas de acordo com as necessidades dos usu arios e estas opera co es s ao chamadas de redirecionamento. O uxo de entrada e chamado de entrada padr ao (standard input); o uxo de sa da e chamado de sa da padr ao (standard output) e o uxo de erros e chamado de sa da padr ao de erros (standard error output). Estes termos s ao substitu dos pelas suas formas abreviadas: stdin, stdout e stderr.

4.2

Biblioteca Padr ao

Na linguagem C n ao existem comandos de entrada e sa da. As opera co es de entrada e sa da s ao executadas com aux lio de vari aveis, macros e fun co es especiais. Para termos acesso ` a biblioteca que cont em estas ferramentas o programa deve conter a declara ca o
#include <stdio.h>

no in cio do programa. A diretiva #include instrui o compilador a ler o arquivo indicado entre < e >, e process a-lo como se ele fosse parte do arquivo original e seu conte udo

67

estivesse no ponto onde a diretiva foi escrita. Se o nome do arquivo estiver entre os sinais de maior e menor, como no exemplo, ele ser a procurado em um diret orio espec co de localiza ca o pr e-denida, onde est ao os arquivos de inclus ao. Quando se usa aspas o arquivo e procurado de maneira denida pela implementa ca o, isso pode signicar procurar no diret orio de trabalho atual, ou em um diret orio indicado no comando usado para compilar o programa. Normalmente os programadores usam maior e menor para incluir os arquivos de cabe calho padr ao e aspas para a inclus ao de arquivos do pr oprio projeto.

4.3

Sa da - A Fun c ao printf

A fun ca o printf faz com que dados sejam escritos na sa da padr ao, que normalmente e a tela do computador. O prot otipo da fun ca o e:
int printf(controle, arg1, arg2, ...);

onde os argumentos arg1, arg2, ... s ao impressos de acordo com o formato indicado pela cadeia de caracteres que comp oe controle. O formato e ao mesmo tempo de uso simples e bastante ex vel, permitindo que os resultados possam ser apresentados de diversas maneiras. A fun ca o retorna o n umero de caracteres impressos, n ao incluindo o nulo em vetores de caracteres. No caso de um erro de sa da um valor negativo e retornado. Um exemplo simples pode tornar a explica ca o mais clara. O programa 4.1 imprime o valor da vari avel ano. Listing 4.1: Exemplo de impress ao de resultados
#i ncl ude < stdio .h > i n t main ( void ) { i n t ano = 1997; /* Imprime o valor do ano */ printf ( " Estamos no ano % d " , ano ); return 0; }

Este programa ir a imprimir na tela do computador: Estamos no ano 1997 Como controle e uma cadeia ele aparece entre " ". Ele dene como ser ao impressos os valores representados pelos argumentos. No controle podem existir dois tipos de informa co es: caracteres comuns e c odigos de formata ca o. Os caracteres comuns, como no exemplo o texto Estamos no ano, s ao escritos na tela sem nenhuma modica ca o. Os c odigos de formata ca o, aparecem precedidos por um caractere% e s ao aplicados aos argumentos na ordem em que aparecem. Deve haver um c odigo de formata ca o para cada argumento. O c odigo %d indica que o valor armazenado em ano deve ser impresso na nota ca o inteiro importante notar que o campo de controle aparece somente uma decimal. E vez na fun ca o printf e sempre no in cio.

68

4.3.1

C odigos de Convers ao

Os c odigos de convers ao est ao mostrados na tabela 4.3.1. C odigo %c %d %i %E %e %f %G %g %o %s %u %x %X %p %% Coment ario Caracter simples Inteiro decimal com sinal Inteiro decimal com sinal Real em nota ca o cient ca com E Real em nota ca o cient ca com e Real em ponto utuante %E ou %f, o que for mais curto %g ou %f, o que for mais curto Inteiro em base octal Cadeia Caracteres Inteiro decimal sem sinal Inteiro em base hexadecimal (letras min usculas) Inteiro em base hexadecimal (letras mai usculas) Endere co de mem oria Imprime o caractere %

Tabela 4.1: C odigos de Convers ao para leitura e entrada de dados. Entre o caractere % e o c odigo de convers~ ao podem ser inseridos caracteres que alteram o formato. A seguir s ao mostrados a ordem de inser ca o destes caracteres e o seu signicado: %[modificadores][largura][.precis~ ao][comprimento]c odigo modificadores: Usados logo ap os o caractere %. - Um sinal de menos serve para especicar que o argumento deve ser justicado ` a esquerda no seu campo de impress ao. Caso nenhum sinal seja usado o argumento ser a ajustado ` a direita. O programa 4.2 ilustra os dois tipos de justica ca o. + For ca que o resultado seja precedido por sinal de menos ou de mais, mesmo para n umeros positivos. O padr ao e que somente negativos sejam precedidos por sinal de menos. espa co Caso nenhum sinal v a ser escrito, um espa co e inserido antes do valor. # Usado com o, x ou X precede o valor com 0, 0x ou 0X respectivamente para valores diferentes de zero. Usado com e, E e f, for ca que a sa da contenha um ponto decimal mesmo que n ao haja parte fracion aria. Por padr ao, se n ao h a parte fracion aria o ponto decimal n ao e escrito. Usado com g ou G o resultado e o mesmo que com e ou E, mas os zeros nais n ao s ao retirados. 0 Completa o campo, pela esquerda, com zeros (0) ao inv es de espa cos, sempre que a op ca o para completar seja especicada (ver especicador de largura do campo). 69

largura: Caso seja usado um n umero inteiro, este especica o tamanho m nimo do campo onde o argumento ser a impresso. Na listagem 4.2 o n umero especica que 8 espa cos s ao reservados para imprimir o resultado. Os espa cos livres ser ao completados com espa cos em branco. Se o argumento precisar de mais espa co que o especicado ele ser a escrito normalmente e o tamanho m nimo e ignorado. .precis~ ao Este n umero tem diferentes signicados dependendo do c odigo usado. caracteres: No caso de impress ao de cadeia de caracteres (s), este n umero especica o n umero m aximo de caracteres de uma cadeia de caracteres a serem impressos. ponto utuante: No caso de formato (e, E, f) e o n umero de d gitos a serem impressos a direita do ponto, ou seja o n umero de casas decimais. Para o formato g ou G e o n umero m aximo d gitos signicativos. inteiros: No formatos inteiros (d, i, o, u, x, X) a precis ao especicou o n umero m aximo de d gitos a serem impressos. Se o n umero de caracteres a serem impressos e menor que este o resultado e completado com brancos. O valor n ao e truncado comprimento: Modica os formatos da seguinte maneira: l Aplicado aos formatos de tipo d, i, o, u, x e X indicando que o dado e do tipo long int e n ao int. h Modica o dado, nos formatos d, i, o, u, x e X para tipo short int. L Nos formatos e, E, f, g e G o argumento e modicado para long double. O programa 4.2 ir a imprimir o seguinte resultado: Justificado para direita Ano = 1997 Justificado para esquerda Ano = 1997 Listing 4.2: Exemplo de justica ca o de resultados.
#i ncl ude < stdio .h > i n t main ( void ) { i n t ano = 1997; printf ( " Justificado para direita Ano = %8 d \ n " , ano ); printf ( " Justificado para esquerda Ano = % -8 d \ n " , ano ); return 0; }

O programa exemplo 4.3 imprimir a o seguinte resultado: O resultado e = 0.333 . Alo

70

Listing 4.3: Exemplo de uso de especicador de precis ao.


#i ncl ude < stdio .h > i n t main () { f l o a t r = 1.0/3.0; char s [] = " Alo Mundo " ; printf ( " O resultado e = %9.3 f \ n " , r ); printf ( " %9.3 s \ n " , s ); return 0; }

Nos exemplos anteriores verique que \n n ao e impresso. A barra inclinada e chamada de seq uencia de escape, indicando que o pr oximo caractere n ao e para ser impresso mas representa caracteres invis veis ou caracteres que n ao est ao representados no teclado. Esta seq u encia de escape indica que o programa deve passar a imprimir na pr oxima linha.

4.4

Entrada - A Fun c ao scanf

A fun ca o scanf pode ser utilizada para entrada de dados a partir do teclado e seu prot otipo e:
scanf(controle, arg1, arg2, ...);

Uma diferen ca fundamental que existe entre esta fun ca o e a fun ca o printf est a nos argumentos que v em depois do controle. No caso de scanf os argumentos s ao os endere cos das vari aveis que ir ao receber os valores lidos e n ao, como em printf, as pr oprias vari aveis. A indica ca o que estamos referenciando um endere co e n ao a vari avel se faz pelo operador &. Por exemplo, o comando
scanf("%d %d", &a, &b);

espera que dois valores inteiros sejam digitados no teclado. O primeiro e armazenado na vari avel a e o segundo em b. Os valores ser ao armazenados diretamente nos endere cos indicados por &a e &b respectivamente. Um outro exemplo incluindo vari aveis reais e:
int i; fl oat x; scanf ( " % d % f " , &i , & x );

Assumindo que a linha de entrada no teclado fosse 34 56.43 a execu ca o do exemplo iria terminar com o valor inteiro 34 sendo armazenado na vari avel i e o valor real 56.43 em x. Usualmente o campo de controle s o cont em especica co es de convers ao, como os listados na Tabela 4.3.1, que s ao utilizadas para interpretar os dados que ser ao lidos, no entanto, como em printf, outros caracteres podem aparecer. O campo de controle pode conter: 71

Caracteres branco: A fun ca o l e e ignora todos os caracteres branco e/ou <enter> e/ou tab que aparecerem antes de qualquer caractere diferente destes. Caracteres comuns: (n ao %) que devem casar com o pr oximo caractere diferente de branco da entrada. Isto signica que qualquer caractere que n ao for igual a branco e/ou <enter> e/ou tab ou parte de um especicador de formato faz com que a fun ca o leia o pr oximo caractere da entrada (stdin) e se for igual a este ele e descartado. Caso os caracteres sejam diferentes a fun ca o falha e retorna deixando os caracteres seguintes n ao lidos. Especica co es de convers ao: Um especicador de convers ao de formato seguindo um modelo similar ao da fun ca o printf. O modelo e o seguinte: %{*}{largura}{modificadores}tipo O caracteres entre chaves s ao opcionais. O asterisco indica que o dado ser a lido de stdin mas ignorado. A largura especica o n umero m aximo de caracteres a serem lidos. Os modicadores alteram o tamanho do especicadores de tipo que v em logo a seguir. Existem os seguintes modicadores: h: Os tipos d, i e n, que s ao int passam a ser short int e os tipos o, u e x, tamb em int passam a ser unsigned short int. l: Os tipos d, i e n passam a ser long int e os tipos o, u e x passam a unsigned long int. Os tipos e, f e g passam de oat para double. L: Os tipos e, f e g passam de oat para long double. Por exemplo, para que os valores digitados sejam separados por v rgulas, o comando deveria ser escrito da seguinte maneira:
scanf("%d, %f", &i, &x);

Observar que deve haver uma correspond encia exata entre os caracteres n ao brancos do controle e os caracteres digitados. Neste caso a entrada deveria ser: 35, 46.3 O programa 4.4 mostra exemplos de uso da fun ca o scanf. O resultado da execu ca o deste programa e: Entre com um caractere qualquer. d Codigo ASCII do caractere d vale 100. Agora dois inteiros separados por espaco. 2 4 A soma destes numeros vale 6. A fun ca o scanf retorna o n umero de itens lidos com sucesso. Este n umero pode ser usado para vericar se todos os valores pedidos foram lidos. No caso de ocorrer uma falha antes da leitura se iniciar a constante EOF e retornada. 72

Listing 4.4: Exemplo de uso de scanf.


#i ncl ude < stdio .h > i n t main () { char c ; i n t num1 , num2 ; printf ( " Entre com um caractere qualquer .\ n " ); scanf ( " % c " , & c ); printf ( " Codigo ASCII do caractere % c vale % d .\ n " , c , c ); printf ( " Agora dois inteiros separados por espaco .\ n " ); scanf ( " % d % d " , & num1 , & num2 ); printf ( " A soma destes numeros vale % d .\ n " , num1 + num2 ); return 0; }

4.5
4.5.1

Lendo e Imprimindo Caracteres


Fun c oes getchar e putchar

Para ler e escrever caracteres do teclado as fun co es de entrada e sa da mais simples s ao getchar e putchar, que est ao na biblioteca stdio.h e cujos prot otipos s ao os seguintes:
i n t getchar ( void ); i n t putchar ( i n t c );

Apesar da fun ca o getchar retornar um par ametro inteiro e poss vel atribuir este valor a uma vari avel do tipo char porque o c odigo do caractere est a armazenado no byte ordem mais baixa. O mesmo acontece com a fun c ao putchar que recebe um inteiro, mas somente o byte de ordem mais baixa e passado para a tela do computador. A fun ca o putchar retorna o caractere que foi escrito e EOF em caso de erro. O programa da listagem 4.5 mostra exemplos de uso destas fun co es, e o seu resultado e: Entre com um algarismo entre 0 e 9. 7 O caractere lido foi o 7 Observar que, normalmente, quando algum dado e fornecido pelo teclado termina-se a digita ca o com a tecla <enter>. No entanto, o <enter> e um caractere tamb em, e isto pode causar problemas. Vamos analisar o que acontece quando antes do comando getchar, se l e um dado do tipo inteiro, por exemplo. O comando scanf l e o n umero inteiro mas n ao o <enter> digitado. Deste modo, quando logo em seguida o programa executar a fun ca o getchar, o que ser a lido e o <enter> digitado ao nal do n umero. A listagem 4.6 e um exemplo de programa onde isto pode ocorrer. Considere que o usu ario digitou 35<enter> como resposta ao comando scanf. O comando getchar ir a ler o <enter> e em seguida o programa ir a imprimir o n umero 35, lido no scanf, e apenas uma linha em branco correspondente ao caractere <enter>, lido pelo getchar, como est a indicado a seguir. Mais adiante mostraremos como resolver este problema.

73

Listing 4.5: Exemplo de uso de getchar e putchar.


#include < stdio .h > i n t main ( void ) { char c ; printf ( " Entre com um algarismo entre 0 e 9.\ n " ); c = getchar (); printf ( " O caractere lido foi o " ); putchar ( c ); return 0; }

Entre com um numero inteiro. 35 Agora um caractere. Numero lido 35 Caractere lido

Listing 4.6: Exemplo de uso de getchar e putchar.


#i ncl ude < stdio .h > i n t main ( void ) { char c ; int i; printf ( " Entre com um numero inteiro .\ n " ); scanf ( " % d " , & i ); printf ( " Agora um caractere .\ n " ); c = getchar (); printf ( " Numero lido % d \ n " , i ); printf ( " Caractere lido % c \ n " , c ); return 0; }

4.5.2

Lendo e Imprimindo Cadeias de Caracteres

Uma cadeia de caracteres (string) em C e um vetor de caracteres. Vetores, que ser ao vistos mais adiante no Cap tulo 7, s ao conjuntos de caracteres em que cada um deles pode ser acessado independentemente dos outros por meio de um endere co. Nesta etapa iremos apresentar rapidamente alguns conceitos que nos permitir ao criar alguns exemplos simples com cadeias de caracteres. Para usar cadeias e preciso primeiro denir um espa co para armazen a-las. Para isto e preciso declarar o nome, o tamanho e o tipo do vetor. Considere que precisamos armazenar uma cadeia de caracteres chamada nome com 40 caracteres. 74

A deni ca o desta cadeia caria da seguinte maneira:


char nome [41];

Quando denir o tamanho do vetor de caracteres, observar que toda cadeia em C termina com o caractere NULL (\0), que e automaticamente inserido pelo compilador. Portanto o vetor nome deve ser denido com um espa co a mais. Ap os este passo, o vetor nome pode ser usado durante a execu ca o do programa.

4.5.3

Lendo e Imprimindo cadeias com scanf e printf

O programa 4.7 mostra como ler e imprimir um cadeia usando os comandos scanf e printf respectivamente. Listing 4.7: Exemplo de uso de printf e scanf na leitura de cadeias.
#de fi ne DIM 40 #include < stdio .h > i n t main ( void ) { char nome [ DIM ]; /* linha de caracteres lidos */ /* Entrada de dados do vetor */ printf ( " Por favor , qual o seu nome ?\ n " ); scanf ( " % s " , nome ); printf ( " Sou um computador . Posso ajuda - lo % s ?\ n " , nome ); return 0; }

Considere que este programa se chama util. Uma poss vel intera ca o entre este programa e um usu ario poderia ser da seguinte maneira. $ util Por favor, qual o seu nome? Ze Sa Sou um computador. Posso ajuda-lo Ze? O s mbolo $ e o prompt t pico dos sistemas Unix. Aparentemente o computador se tornou ntimo do usu ario Ze Sa e o tratou apenas pelo primeiro nome. A explica ca o para esta intimidade est a no modo de leitura. Quando se usa scanf para ler uma cadeia deve-se empregar o c odigo de convers ao %s. Este comando n ao l e o nome todo, mas encerra a leitura dos caracteres quando encontra um caractere espa co (ou branco), ou seja o separador de cadeias no comando scanf e o caractere espa co. Mas como ler para um vetor um nome inteiro, ou um cadeia que contenha brancos? Para isto deve-se usar a fun ca o gets que ser a nosso pr oximo assunto.

4.5.4

Lendo e Imprimindo cadeias com gets e puts

Diferentemente do comando scanf a fun ca o gets l e toda a cadeia at e que a tecla <enter> seja digitada. No vetor s ao colocados todos os c odigos dos caracteres 75

lidos excetuando-se o da tecla <enter>, que n ao e armazenado sendo substitu do pelo c odigo NULL. Caso a fun ca o scanf do exemplo anterior fosse substitu da pela gets o programa imprimiria Posso ajuda-lo Ze Sa? O comando que substitui o scanf e gets(nome). O prot otipo da fun ca o gets e o seguinte:
#include < stdio .h > char * gets ( char * str );

A fun ca o gets retorna str caso nenhum erro ocorra. Caso o nal do arquivo seja encontrado antes de qualquer caractere ser lido, o vetor permanece inalterado e um ponteiro nulo e retornado. Caso um erro ocorra durante a leitura, o conte udo do array ca indeterminado e novamente um ponteiro nulo e retornado. A fun ca o puts tem o seguinte prot otipo:
#include < stdio .h > i n t puts ( const char * str );

Ela imprime a cadeia apontado por str. O programa 4.8 e semelhante ao exemplo anterior com as fun co es printf substitu das por puts. Observe que a impress ao sempre termina e passa para a pr oxima linha. A fun ca o puts retorna um valor positivo caso nenhum erro ocorra. Em caso de erro e retornado um valor negativo. Entre com o seu nome, por favor. Ze Sa Alo Ze Sa Eu sou um computador, em que posso ajuda-lo?

Listing 4.8: Exemplo de uso de puts e gets na leitura de cadeias.


#de fi ne DIM 41 #i ncl ude < stdio .h > i n t main ( void ) { char nome [ DIM ]; /* linha de caracteres lidos */ /* Entrada de dados do vetor */ puts ( " Entre com o seu nome , por favor . " ); gets ( nome ); puts ( " Alo " ); puts ( nome ); puts ( " Eu sou um computador , em que posso ajuda - lo ? " ); return 0; }

4.5.5

A Fun c ao fgets

A fun ca o gets pode abrir porta para invas oes de computadores pelo fato dela n ao controlar o n umero de caracteres lido de stdin. Apesar do usu ario denir 76

um tamanho m aximo para o vetor que ir a armazenar os caracteres a fun ca o ignora o limite e continua lendo valores at e que o usu ario digite o caractere <enter>. Para evitar este problema recomenda-se o emprego da fun ca o fgets cujo prot otipo e
#include < stdio .h > i n t * fgets ( const char * str , i n t tam , FILE * fluxo );

A fun ca o fgets l e no m aximo um caractere a menos que o n umero de caracteres especicado no par ametro tam a partir do uxo de entrada de dados denido por fluxo. No caso de leitura do teclado, como temos feito, uxo e igual a stdin. A leitura e interrompida quando um caractere <enter> e encontrado ou o nal do arquivo foi atingido. Diferentemente do que ocorre na fun ca o gets, aqui o caractere <enter> e armazenado no vetor onde os demais caracteres est ao sendo guardados. O caractere nulo e adicionado ap os o u ltimo caractere lido. A fun ca o retorna str caso seja bem sucedida. Se o nal do arquivo for atingido e nenhum caractere tiver sido lido, o vetor str permanece inalterado e um ponteiro nulo e retornado. Caso ocorra um erro de leitura o conte udo do vetor ca indeterminado e um ponteiro nulo e retornado.

77

4.6

Exerc cios

4.1: Escreva um programa que declare vari aveis do tipo int, char e float, inicialize-as, e imprima os seus valores. 4.2: Escreva um programa que dena vari aveis do tipo int e armazene nelas constantes octais e hexadecimais e imprima o seu conte udo no formato original e em formato decimal. 4.3: Fa ca um programa que leia um valor inteiro no formato decimal e escreva, na tela, este mesmo valor nas bases hexadecimal e octal. Exemplo de Entrada e Sa da: Entre com o valor: 10 Hexadecimal: A Octal: 12 4.4: Fa ca um programa capaz de ler um valor real e escrev e-lo com apenas uma casa decimal. 4.5: Fa ca um programa que leia tr es palavras de at e 10 letras e reescreva estas palavras alinhadas ` a direita da tela. 4.6: Sabendo que os argumentos da fun ca o printf podem ser express oes (a+b, a/b, a*b, 3*a...), e n ao somente argumentos, fa ca um programa capaz de ler um valor inteiro e escrever seu triplo, seu quadrado, e a sua metade. Exemplo de Entrada e Sa da: Valor: 6 Triplo: 18 Quadrado: 36 Meio: 3 4.7: Escreva um programa que leia 3 n umeros reais e imprima a m edia aritm etica destes n umeros. 4.8: Escreva um programa que pegue o valor de uma conta de restaurante e imprima o valor total a ser pago, considerando que o restaurante cobra 10% de taxa para os atendentes. 4.9: Fa ca um programa que pe ca ao usu ario a quilometragem atual, a quilometragem anterior, os litros consumidos e informe a taxa de consumo (quil ometros por litro) de um autom ovel. 4.10: Escreva um programa que converta uma temperatura de Farenheit para Celsius. 4.11: Escreva um programa que, dado o per metro de um c rculo, calcule sua area. 4.12: Fa ca um programa que utilize a fun ca o gets para ler duas cadeias de tamanho at e 20 e em seguia ` as reescreva na linha de baixo, uma ao lado da outra e separadas por /-/ ; 78

Cap tulo 5

Operadores e Express oes


5.1 Introdu c ao

O objetivo deste cap tulo e apresentar os operadores existentes na linguagem C e a forma correta de construir express oes que envolvam estes operadores, constantes e vari aveis.

5.2

Operador de Atribui c ao

Este e o operador usado para transferir o resultado de uma express ao para uma vari avel. Em C este operador e o sinal de igual (=). Esta escolha do sinal de igual para servir de operador de atribui ca o pode causar problemas. Isto porque este sinal n ao est a representando que o resultado da express ao do lado direito e igual ao resultado do lado esquerdo e sim uma atribui ca o. Observe que o comando de atribui ca o termina em ponto e v rgula. Isto faz parte das regras da linguagem C, que determina que comandos terminam com este caractere. Por exemplo: soma = a + b; pi = 3.1415; poss E vel fazer-se v arias atribui co es em uma u nica linha, como no exemplo a seguir: a = b = c = 1.0; as tr es vari aveis recebem o mesmo valor. As atribui co es s ao feitas na seguinte ordem: 1. c = 1.0; c recebe o valor 1.0. 2. b recebe o resultado da express ao ` a sua direita, que e o valor atribu do ` a c, ou seja 1.0. 3. a recebe o resultado da express ao ` a sua direita, que e o valor atribu do ` a b, ou seja 1.0. 79

5.3

Operadores Aritm eticos

A Tabela 5.3 mostra os operadores aritm eticos e as suas ordens de preced encia. Operador + ++ -* / % + Descri c~ ao Mais un ario Menos un ario Incremento Decremento Multiplica ca o Divis ao Resto da divis ao Soma Subtra ca o Prioridade 0 0 1 1 2 2 2 3 3

Tabela 5.1: Operadores aritm eticos. Os s mbolos mostrados na Tabela 5.3 s ao os u nicos que podem ser usados para representar as opera co es acima listadas. Express oes aritm eticas em C devem ser escritas no formato linear para facilitar a digita ca o dos programas e tamb em porque alguns s mbolos usados em Matem atica n ao existem nos teclados. O exemplo mais comum deste formato e a opera ca o de divis ao que deve ser escrita a/b. Par enteses t em um papel importante nas express oes e permitem que a ordem das opera co es seja alterada. Express oes entre par enteses s ao calculadas em primeiro lugar, portanto eles conferem o maior grau de prioridade as express oes que eles envolvem. Podemos ter pares de par enteses envolvendo outros pares. Dizemos que os par enteses est ao aninhados. Neste caso as express oes dentro dos par enteses mais internos s ao avaliadas primeiro. Outro ponto importante s ao as regras de preced encia que determinam que opera ca o deve ser executada primeiro. Na tabela os operadores est ao listados em ordem decrescente de prioridade. Para os operadores aritm eticos a opera ca o de mais alta preced encia e o - un ario, vindo em seguida ++, -- com a mesma prioridade. Os operadores de multiplica ca o, divis ao e m odulo tem a mesma prioridade. O operador menos un ario multiplica seu operador por -1. Quando duas opera co es de mesmo n vel de prioridade t em de ser avaliadas, a opera ca o mais ` a esquerda ser a avaliada primeiro. Um ponto importante que deve ser sempre levado em considera ca o quando uma express ao for calculada s ao os tipos das vari aveis, porque eles alteram radicalmente os resultados das express oes. Por exemplo, a divis ao entre operandos do tipo inteiro tem como resultado um valor inteiro. Portanto, se o resultado possuir uma parte fracion aria ela ser a truncada. N ao e poss vel aplicar a opera ca o de m odulo a operandos do tipo float e double. Algumas regras de convers ao simples existem e ser ao discutidas em detalhes mais adiante. Por exemplo a opera ca o 1/3 em C fornece como resultado o valor 0, enquanto que 1 % 3 e igual a 1. A seguir mostramos alguns exemplos de express oes aritm eticas escritas na 80

nota ca o da linguagem C. Observe o uso de par enteses para evitar ambig uidades que poderiam fazer com que a express ao fosse calculada erradamente. Exemplo 5.4: 1. a +
b b+c

= a + b/(b+c)

2. b2 + c2 = b*b + c*c 3.
x b a+ c

= x/(a+b/c)

5.4
5.4.1

Operadores Relacionais e L ogicos


Operadores Relacionais

Os operadores relacionais est ao mostrados na Tabela 5.2. Nesta tabela mostramos somente a ordem de preced encia destes operadores. A ordem de preced encia que inclui todos os operadores est a mostrada na Tabela 5.10. Operador >= > <= < == != Descri c ao Maior ou igual a Maior que Menor ou igual a Menor que Igual a Diferente de Prioridade 0 0 0 0 1 1

Tabela 5.2: Operadores Relacionais. Os operadores >, >=, < e <= t em a mesma preced encia e est ao acima de == e !=. Estes operadores t em preced encia menor que os aritm eticos, portanto express oes como ( i < limite - 1) e i < (limite -1) t em o mesmo signicado.

5.4.2

Operadores L ogicos

Os operadores l ogicos denem as maneiras como as rela co es acima podem ser conectadas. Por exemplo podemos querer testar se ao mesmo tempo uma nota e maior ou igual a 5.0 e a taxa de presen ca e maior que 75%. Para simplicar a apresenta ca o destes operadores ser ao usadas vari aveis para substituir as rela co es. Neste caso a express ao acima seria representada como p e q, onde p est a representando nota maior ou igual a 5.0 e q taxa de presen ca maior que 75%. Estas express oes podem ter dois resultados verdadeiro e falso. Observar que, assim como em opera co es aritm eticas, podemos ter combina co es de mais de duas rela co es em uma u nica express ao. Por exemplo, podemos ter a seguinte combina ca o: ano maior que 2000 e m es menor que 6 e dia maior que 15. Nas linguagens de programa ca o os valores verdadeiro e falso podem ser representados de diversas maneiras. Uma das maneiras mais 81

comum e representar verdadeiro por true e falso por false. Em C o valor falso e representado por 0 e verdadeiro por qualquer valor diferente de 0. A seguir iremos mostrar os operadores l ogicos existentes na linguagem C. E l ogico O s mbolo usado para representar o operador E l ogico e &&. A Tabela 5.3 mostra a tabela verdade do operador. O resultado da express ao e verdadeiro se e somente se todas as vari aveis forem iguais a verdadeiro. Por exemplo, considere o seguinte trecho de programa:
i n t i = 3 , j = -5; f l o a t z = 3.0; i n t resultado ; resultado = (10 > 5) && ( i > -5) && ( z != 0); printf ( " O resultado e vale % d . " , resultado );

O resultado deste trecho e a impress ao de um valor diferente de 0, ou seja o valor correspondente a verdadeiro. Isto porque 10 e maior que 5 E i e maior que -5 E z e diferente de 0. p 0 0 1 1 q 0 1 0 1 p && q 0 0 0 1

Tabela 5.3: Operador L ogico E.

OU l ogico O s mbolo usado para representar o operador OU l ogico e ||. A Tabela 5.4 mostra a tabela verdade do operador. Para que o resultado da express ao seja verdade basta que uma das vari aveis seja verdade. Por exemplo, considere o seguinte trecho de programa:
f l o a t x = 3.0; i n t n = 55 , i = 0; i n t resultado ; resultado = ( i != 0) || ( x == 0) || ( n < 100); printf ( " O resultado e % d " , resultado );

O resultado deste trecho e a impress ao do valor 1. Isto porque, apesar de i n ao ser diferente de 0 e x n ao ser diferente de zero, temos que n e menor que 100. Como basta um dos testes ser verdade para o resultado ser verdade ser a impresso um valor diferente de 0.

82

p 0 0 1 1

q 0 1 0 1

p || q 0 1 1 1

Tabela 5.4: Operador L ogico OU.

N ao l ogico O s mbolo usado para representar o operador N~ AO l ogico e !. A Tabela 5.5 mostra a tabela verdade do operador. Este operador e un ario e quando aplicado ` a uma vari avel ele troca seu valor. Por exemplo, considere o seguinte trecho de programa:
i n t dia = 25 , ano = 1959; i n t resultado ; resultado = ! ( ( dia < 30) && ( ano > 1950) ) printf ( " O resultado vale \% d . " , resultado );

Este trecho de programa imprime 0 (falso), porque dia e menor que 30 E ano e maior que 1950. Portanto, o resultado do par enteses vale 1 (verdadeiro). No entanto, o operador ! nega este valor que vira 0. p 0 1 !p 1 0

Tabela 5.5: Operador L ogico N~ AO. A tabela 5.6 mostra, em ordem decrescente, a preced encia dos operadores l ogicos e relacionais. Operador ! >, >=, <, <= ==, != && || Prioridade 0 1 2 3 4

Tabela 5.6: Preced encia dos operadores l ogicos e relacionais.

5.5

Operadores com Bits

Para opera co es com bits, a linguagem C disp oe de alguns operadores que podem ser usados nos tipos char, int, long e long long mas n ao podem ser usados 83

em float, double, long double e void. A diferen ca entre estes operadores e os l ogicos e que estes operam em pares de bits enquanto que os operadores l ogicos anteriores consideram a palavra toda. Por exemplo, para um valor int ser falso e necess ario que todos os 32 bits sejam iguais a zero. Os operadores em bits est ao mostrados na Tabela 5.7. Operador & | ^ ~ >> << Descri c ao E OU Ou exclusivo N ao Desloca para direita Desloca para esquerda Prioridade

Tabela 5.7: Operadores com bits.

Os operadores &, | e ~ t em a mesma tabela verdade que os operadores &&, || e ! respectivamente. O operador ^ (OU Exclusivo) est a descrito pela Tabela 5.8. O resultado da opera ca o e verdadeiro se e somente se os dois operandos s ao diferentes. p 0 0 1 1 q 0 1 0 1 p ^ q 0 1 1 0

Tabela 5.8: Operador L ogico OU.

Os operandos de deslocamento t em os seguintes modos de opera ca o: operando >> vezes: o operando e deslocado vezes bits para a direita. operando << vezes: o operando e deslocado vezes bits para a esquerda. Observa co es: Nos deslocamentos ` a direita em vari aveis unsigned e nos deslocamentos a esquerda, os bits que entram s ` ao zeros; Nos deslocamentos ` a direita em vari aveis signed, os bits que entram correspondem ao sinal do n umero (1= sinal negativo, 0 = sinal positivo). Um deslocamento para a direita e equivalente a uma divis ao por 2. Deslocamento para a esquerda e equivalente a uma multiplica ca o por 2. Assim a = a * 2; e a = a << 1; s ao equivalentes. O exemplo 5.1 ilustra o uso dos operandos de deslocamento: Este programa teria como resposta os seguintes resultados. 84

Listing 5.1: Exemplo de operadores de deslocamento.


#include < stdio .h > i n t main ( void ) { unsigned i n t c = 7; i n t d = -7; c = c < <1; printf ( " %3 d = %08 X \ n " , c , c ); c = c > >1; printf ( " %3 d = %08 X \ n " , c , c ); d = d < <1; printf ( " %3 d = %08 X \ n " , d , d ); d = d > >1; printf ( " %3 d = %08 X \ n " , d , d ); return 0; }

14 7 -14 -7

= = = =

0000000E 00000007 FFFFFFF2 FFFFFFF9

Os resultados mostram que o n umero 7 ap os o primeiro deslocamento de 1 bit para a esquerda cou igual a 14, portanto um 0 entrou no n umero. Quando o n umero foi deslocado para direita 1 bit, ele retornou ao valor original. Observe que quando o n umero -14 foi deslocado para a direita entrou um bit 1, que e igual ao sinal negativo.

5.6

Operadores de Atribui c ao Composta

Em C qualquer express ao da forma: variavel = variavel operador expressao pode ser escrita como: variavel operador= expressao Por exemplo: ano = ano + 10; e equivalente a ano += 10; Outros exemplos s ao: raiz = raiz * 4; raiz *= 4; soma = soma / ( a + b); soma /= (a + b); a = a >> 1; a >>= 1; i = i % 2; i %= 2; 85

5.7

Operador v rgula

O operador v rgula (,) e usado para separar duas ou mais express oes que s ao escritas onde somente uma e esperada. Quando o conjunto de express oes tem de ser reduzido a somente um valor, somente a express ao mais ` a direita e considerada. Por exemplo, considere o seguinte trecho de c odigo:
y = ( x =5 , x +2);

A express ao come ca a ser avaliada da esquerda para a direita. Portanto, primeiro seria atribu do o valor 5 a vari avel x. Em seguida atribui x+2 para a vari avel y. Ao nal a vari avel x cont em o valor 5 e y o valor 7.

5.8

Operador sizeof()

O operador sizeof() e um operador un ario que retorna o tamanho em bytes da express ao ou tipo fornecido entre par enteses. Por exemplo, suponha que o tipo float tenha quatro bytes ent ao o operador sizeof(float) retorna o valor 4. Para se calcular o tamanho de bytes de uma express ao n ao e necess ario o uso de par enteses. No exemplo 5.2 ilustramos alguns exemplos de uso do operador sizeof(). Listing 5.2: Exemplo do operador sizeof.
#de fi ne DIM 10 #include < stdio .h > #include < conio .h > i n t main () { i n t i =0; f l o a t f =3.0; char c = a ; i n t v [ DIM ]; printf ( " Tamanho em bytes de alguns tipos \ n " ); printf ( " Tamanho de int % d \ n " , s i z e o f i ); printf ( " Tamanho do float % d \ n " , s i z e o f f ); printf ( " Tamanho do double % d \ n " , s i z e o f ( double )); printf ( " Tamanho do char % d \ n " , s i z e o f c ); printf ( " Tamanho do vetor de % d inteiros % d \ n " , DIM , s i z e o f ( v )); return 0; }

Este programa imprime os seguintes resultados: Tamanho Tamanho Tamanho Tamanho Tamanho Tamanho em de do do do do bytes de alguns tipos int 4 float 4 double 8 char 1 vetor de 10 inteiros 40 86

5.9

Convers ao de Tipos

Quando operandos de tipos diferentes aparecem em express oes s ao convertidos para um tipo comum, que permita o c alculo da express ao da forma mais eciente. Por exemplo, uma opera ca o que envolva um tipo int e um float, o valor int e convertido para float. Observar que convers oes ocorrem somente quando necess ario. Por exemplo, em uma divis ao de inteiros o resultado e do tipo inteiro. Isto pode causar surpresas desagrad aveis para programadores iniciantes. A express ao 1/3*3 tem como resultado o valor inteiro 0. J a que a primeira express ao executada 1/3 tem como resultado 0. Operandos do tipo char e int podem ser livremente misturados em express oes aritm eticas. Os tipos char s ao convertidos para int. Caso o conjunto de caracteres esteja codicado segundo a tabela ASCII, esta facilidade permite a realiza ca o de algumas transforma co es interessantes. Por exemplo, a convers ao de uma letra mai uscula para min uscula pode ser facilmente implementada com o comando: l = l - A + a; A letra mai uscula armazenada na vari avel l e subtra da do c odigo da letra mai uscula A, fornecendo a posi ca o desta letra no alfabeto. Em seguida este valor e somado ao c odigo da letra min uscula a, resultando da convers ao para min uscula. Portanto, convers oes aritm eticas ocorrem de maneira quase que natural. Em opera co es bin arias as seguintes convers oes ocorrem quando diferentes tipos est ao envolvidos: char e convertido para int; float e convertido para double. Ent ao, se algum dos operandos e double o outro e convertido para double e o resultado e double. Caso contr ario, se algum dos operandos e long, o outro e convertido para long e o resultado e long. Caso contr ario, se algum dos operandos e unsigned, o outro e convertido para unsigned e o resultado e deste tipo. Caso contr ario os operandos s ao int e o resultado e int. Note que todos os floats em uma express ao s ao convertidos para double e a express ao e avaliada em double. O resultado de uma express ao e convertido para o tipo da vari avel onde o resultado ser a armazenado. Um resultado float ao ser carregado em uma vari avel do tipo int causa o truncamento da parte fracion aria, porventura existente. A convers ao de inteiro para caractere e bem comportada, mas o contr ario nem sempre ocorre convenientemente. A linguagem n ao especica se o tipo char e um tipo com sinal ou n ao. Quando um caractere e armazenado em uma vari avel do tipo inteiro podem ocorrer problemas com caracteres que t em o bit mais ` a esquerda igual a 1. Isto porque algumas arquiteturas podem estender este bit e outras n ao.

87

5.10

Regras de Preced encia

A Tabela 5.10 mostra, em ordem decrescente de prioridade, as regras de preced encia dos operadores em C. Os operadores que est ao na mesma linha da tabela e com a mesma ordem t em a mesma prioridade. Alguns dos operadores listados na Tabela somente ser ao mostrados nos cap tulos seguintes. Pri 0 1 1 2 3 4 5 6 7 8 9 10 11 12 13 13 14 Operador () [] -> . ! ~ ++ -- * & (tipo) sizeof() * / % + >> << < <= >= > == != & ^ | && || ? () : () = += -= *= /= %= >>= <<= &= |= , Descri c ao Agrupamento; acesso vetor; acesso membro Un arias l ogicas, aritm eticas e com ponteiros; Conforma ca o de tipo; tamanho Multiplica ca o, divis ao e m odulo soma e subtra ca o Deslocamento de bits ` a direita e esquerda Operadores relacionais Igualdade e diferen ca E bit a bit Ou exclusivo bit a bit Ou bit a bit E Ou Tern ario Atribui co es Atribui co es Separador de express oes

Tabela 5.9: Preced encia dos operadores.

88

5.11

Exerc cios

5.1: Escreva as express oes C abaixo na sua forma matem atica usual: 1. (a/b)*(c/d) 2. (a/b*c/d) 3. (a/(b*c)/d) 4. a*x*x+b*x+c 5.2: Escreva as express oes matem aticas na linguagem C. 1. b2 4 b c 2. 3.
1 1+
1+ 1 1 1+x

a+b c +d x c +d

4. a

5.3: Diga a ordem de c alculo e o resultado das express oes abaixo: 1. x = 5 * 4 / 6 + 7; 2. x = 5 * 4.0 / 6 + 7; 3. x = 5 * 4 % 6 + 7; 4. x = ((4 / 2) + (3.0 * 5)); 5.4: Escreva um programa que imprima a tabela verdade da fun ca o ou exclusivo. 5.5: Escreva um programa que calcule o produto entre um valor x e 2n , onde n e x s ao inteiros. Utilize operadores bin arios. 5.6: Escreva um programa que leia um angulo em segundos e imprima quantos graus, minutos e segundos h a neste angulo. 5.7: Escreva um programa que leia um tempo em segundos e imprima quantas horas, minutos e segundos h a neste tempo. 5.8: Escreva um programa que leia um comprimento em cent metros e imprima quantos metros, dec metros e cent metros h a neste comprimento. 5.9: Uma empresa est a selecionando entre seus empregados os que ir ao fazer um treinamento especial. O funcion ario selecionado deve satisfazer a dois crit erios. O primeiro crit erio para que um funcion ario seja pr e-selecionado e que ele deve ter um sal ario menor ou igual a R$ 400,00 ou maior ou igual a R$ 1.000,00. O segundo crit erio leva em conta o tempo de trabalho e o funcion ario deve ter mais de 5 anos na empresa. Marque a resposta que indica a express ao l ogica que representa este crit erio. Considere que existem as seguintes vari aveis. 89

Listing 5.3: Vari aveis da quest ao 9.


f l o a t salario ; i n t tempo ;

(a) (salario <= 400.00) && (salario >= 1000.00) && (tempo > 5) (b) (salario <= 400.00) || (salario >= 1000.00) && (tempo > 5) (c) ((salario <= 400.00) || (salario >= 1000.00)) || (tempo > 5) (d) ((salario <= 400.00) || (salario >= 1000.00)) && (tempo > 5) (e) ((salario <= 400.00) && (salario >= 1000.00)) || (tempo > 5)

90

Cap tulo 6

Comandos de Controle
6.1 Introdu c ao

Este cap tulo tem por objetivo apresentar os comandos de controle da linguagem C. Estes comandos servem para controlar o uxo de execu ca o das instru co es de um programa. Estes comandos permitem que o computador tome decis oes independentemente do usu ario que est a rodando o programa.

6.2

Blocos de Comandos

Blocos de comando s ao grupos de comandos que devem ser tratados como uma unidade l ogica. O in cio de um bloco em C e marcado por uma chave de abertura ({) e o t ermino por uma chave de fechamento (}). O bloco de comandos serve para agrupar comandos que devem ser executados juntos. Por exemplo, usase bloco de comandos quando em comandos de teste deve-se escolher entre executar dois blocos de comandos. Um bloco de comandos pode ser utilizado em interessante qualquer trecho de programa onde se pode usar um comando C. E observar que um bloco de comandos pode ter zero comandos C. Um bloco de comandos com 0 ou 1 comando pode dispensar as chaves. Um bloco de comandos e mostrado a seguir.
/* bloco_de_co ma n do s */ { i = 0; j = j + 1; printf ( " % d % d \ n " , i , j ); }

6.3

Comandos de Teste

Os comandos de teste permitem ao computador decidir o caminho a seguir, durante a execu ca o do programa, independentemente do usu ario. Estes testes 91

s ao baseados em estados internos dispon veis ao processador. Estes estados podem ser resultantes de uma opera ca o aritm etica anterior, de uma opera ca o anterior etc.

6.3.1

Comando if

O comando if e utilizado quando for necess ario escolher entre dois caminhos. A forma geral do comando if e a seguinte:
i f ( express~ ao ) bloco_de_co m an d os 1 ; else bloco_de_co m an d os 2 ;

Neste comando a express ao e avaliada, e caso o resultado seja verdadeiro (qualquer resultado diferente de zero) o bloco de comandos1 e executado, caso contr ario o bloco de comandos2 e executado. Pela deni ca o do comando a express ao deve ter como resultado um valor diferente de zero para ser considerada verdade. Observar que somente um dos dois blocos ser a executado. Como a cl ausula else e opcional a forma abaixo do comando if e perfeitamente v alida.
i f ( express~ ao ) bloco_de_co ma nd o s ;

Lembrar que os blocos de comandos devem ser delimitados pelas chaves, a n ao ser quando o bloco e composto por 0 ou 1 comando. Na listagem 6.1 mostramos alguns exemplos de uso de comando if. Listing 6.1: Exemplo de comandos if.
scanf ( " % d " , & dia ); i f ( dia > 31 || dia < 1 ) printf ( " Dia invalido \ n " ); scanf ( " % d " , & numero ); i f ( numero > 0 ) printf ( " Numero positivo \ n " ); else printf ( " Numero negativo \ n " ); scanf ( " % f " , & salario ); i f ( salario < 800.00) { printf ( " Aliquota de imposto = 0.1\ n " ); imposto = salario * 0.1; } else { printf ( " Aliquota de imposto = 0.25\ n " ); imposto = salario * 0.25; }

Uma constru ca o que pode aparecer s ao os comandos ifs em escada, cuja forma geral e a seguinte:

92

i f ( express~ ao ) bloco_de_co ma n do s e l s e i f ( express~ a o1 ) bloco_de_c om a nd o s1 e l s e i f ( express~ a o2 ) bloco_de_co ma n do s 2 ... else bloco_de_co ma n do s n

O programa 6.2 mostra um exemplo com ifs em escada e aninhados. Um exemplo de uso deste programa e o seguinte: Este programa simula uma calculadora simples. Por favor entre com os dois operandos. 3 5 Qual a operacao + O resultado da + vale 8.000000. Para evitar que o recuo da escada seja muito profundo o comando if em escada foi escrito da seguinte maneira:
i f ( express~ ao ) bloco_de_co ma nd o s ; e l s e i f ( express~ ao ) bloco_de_co ma nd o s ; e l s e i f ( express~ ao ) bloco_de_co ma nd o s ; ... e l s e bloco_de_co ma n do s ;

6.3.2

Comando switch

O comando if, em todas suas formas, e suciente resolver problemas de sele ca o de comandos. Por em em alguns casos, como no exemplo 6.2 o programa se torna mais trabalhoso para ser escrito e entendido. O comando switch facilita a escrita de trechos de programa em que a sele ca o deve ser feita entre v arias alternativas. A forma geral do comando switch e a seguinte:
switch ( express~ ao ) { case constante1 : seq u^ e ncia _d e _ co m an d o s ; break ; case constante2 : seq u^ e ncia _d e _ co m an d o s ; break ; case constante3 : seq u^ e ncia _d e _ co m an d o s ; break ; ...

93

Listing 6.2: Programas com ifs em escada e aninhados.


#i ncl ude < stdio .h > i n t main ( void ) { f l o a t num1 , /* primeiro operando */ num2 , /* segundo operando */ res ; /* resultado da operacao */ char oper ; /* caractere que define a operacao */ printf ( " \ nPrograma que simula calculadora simples .\ n " ); printf ( " Entre com os dois operandos .\ n " ); scanf ( " % f % f " , & num1 , & num2 ); getchar (); /* tirar o cr */ printf ( " Qual a operacao ? \ n " ); oper = getchar (); i f ( oper == + ) res = num1 + num2 ; e l s e i f ( oper == - ) res = num1 - num2 ; e l s e i f ( oper == * ) res = num1 * num2 ; e l s e i f ( oper == / ) { i f ( num2 == 0.0) { printf ( " Operacao de divisao por 0 invalida !\ n " ); return 1; } e l s e res = num1 / num2 ; } else { printf ( " Operacao invalida !\ n " ); return 1; } printf ( " O resultado da % c vale % f .\ n " , oper , res ); return 0; }

94

default: seq u^ e ncia_ d e_ c o ma n do s ; }

Uma seq u encia de comandos e diferente de um bloco de comandos. Um bloco de comandos inicia com uma chave e termina com uma chave, enquanto que uma seq u encia e apenas uma s erie de comandos. Por exemplo, uma vez que um bloco de comandos foi selecionado por um comando if ele ser a executado at eau ltima instru ca o do bloco, a menos que haja um comando de desvio. Uma s erie de comandos s ao apenas comandos colocados um ap os outro. A execu ca o do comando switch segue os seguintes passos: 1. A express ao e avaliada; 2. O resultado da express ao e comparado com os valores das constantes que aparecem nos comandos case; 3. Quando o resultado da express ao for igual a uma das constantes, a execu ca o se inicia a partir do comando associado com esta constante. A execu ca o continua at e o m do comando switch, ou at e que um comando break seja encontrado; 4. Caso n ao ocorra nenhuma coincid encia os comandos associados ao comando default s ao executados. O comando default e opcional, e se ele n ao aparecer nenhum comando ser a executado. O comando break e um dos comandos de desvio da linguagem C. O break e usado dentro do comando switch para interromper a execu ca o da seq u encia de comandos e pular para o comando seguinte ao comando switch. H a alguns pontos importantes que devem ser mencionados sobre o comando switch. O resultado da express ao deve ser um tipo enumer avel, por exemplo o tipo int. Tamb em podem ser usados tipos compat veis com int, isto e, express oes com resultados tipo char podem ser usadas; Notar que caso n ao apare ca um comando de desvio, todas as instru co es seguintes ao teste case que teve sucesso ser ao executadas, mesmo as que estejam relacionadas com outros testes case; O comando switch s o pode testar igualdade; N ao podem aparecer duas constantes iguais em um case; O programa 6.3 mostra um exemplo de uso de comandos switch.

6.3.3

Comando Tern ario

O comando tern ario tem este nome porque necessita de tr es operandos para ser avaliado. O comando tern ario tem a seguinte forma: express~ ao1 ? express~ ao2 : express~ ao3 95

Listing 6.3: Exemplo de switch.


#i ncl ude < stdio .h > i n t main ( void ) { float num1 , /* primeiro operando */ num2 , /* segundo operando */ res ; /* resultado da operacao */ char oper ; /* caracter que define a operacao */ printf ( " \ nEste programa simula uma calculadora simples .\ n " ); printf ( " Por favor entre com os dois operandos .\ n " ); scanf ( " % f % f " , & num1 , & num2 ); getchar (); printf ( " Qual a operacao \ n " ); oper = getchar (); printf ( " A operacao e % c \ n " , oper ); switch ( oper ) { case + : res = num1 + num2 ; break ; case - : res = num1 - num2 ; break ; case * : res = num1 * num2 ; break ; case / : i f ( num2 == 0.0){ printf ( " Divisao por zero e uma opcao invalida .\ n " ); return 1; } else { res = num1 / num2 ; break ; } default: printf ( " Operacao invalida !\ n " ); return 2; } printf ( " O resultado da % c vale % f .\ n " , oper , res ); return 0; }

96

Para avaliar o resultado total da express ao, primeiro a express~ ao1 e avaliada. Caso este resultado seja correspondente ao valor verdadeiro ent ao o resultado da express ao ser a igual ao resultado da express~ ao2. Caso contr ario a express~ ao3 e avaliada e se torna o resultado. O programa 6.4 mostra um exemplo de uso de comando tern ario. Listing 6.4: Exemplo de comando tern ario.
#i ncl ude < stdio .h > i n t main ( void ) { float num1 , /* primeiro operando */ num2 , /* segundo operando */ max ; /* resultado da operacao */ printf ( " Imprime o maior valor de dois numeros .\ n " ); printf ( " Por favor entre com os dois mumeros .\ n " ); scanf ( " % f % f " , & num1 , & num2 ); max = ( num1 > num2 )? num1 : num2 ; printf ( " O maior dos numeros lidos e % f .\ n " , max ); return 0; }

6.4

La cos de Repeti c ao

Estes comandos permitem que trechos de programa sejam repetidos um certo n umero de vezes controlado pelo programa. O n umero de vezes que um la co ser a executado pode ser xo ou depender de condi co es que mudam durante a execu ca o do la co.

6.4.1

Comando for

Este comando aparece em v arias linguagens de programa ca o, mas na linguagem C ele apresenta um grau maior de exibilidade. A id eia b asica do comando for e a seguinte. Uma vari avel de controle, geralmente um contador, recebe um valor inicial. O trecho de programa que pertence ao la co e executado e ao nal a vari avel de controle e incrementada ou decrementada e comparada com o valor nal que ela deve alcan car. Caso a condi ca o de t ermino tenha sido atingida o la co e interrompido. A forma geral do comando for e a seguinte:
f o r ( express~ a o1 ; express~ a o2 ; express~ a o3 ) blocodecoman do s ;

As tr es express oes geralmente t em os seguintes signicados: 1. A express~ ao1 e utilizada para inicializar a vari avel de controle do la co; 2. A express~ ao2 e um teste que controla o m do la co; 3. A express~ ao3 normalmente faz um incremento ou decremento da vari avel de controle. 97

A execu ca o do comando for segue os seguintes passos: 1. A express~ ao1 e avaliada; 2. A express~ ao2 e avaliada para determinar se o comando deve ser executado; 3. Se o resultado da express~ ao2 for verdadeiro o bloco de comandos e executado, caso contr ario o la co e terminado; 4. A express ao3 e avaliada; 5. Voltar para o passo 2. O trecho a seguir imprime todos os n umeros entre 1 e 100.
f o r ( i = 1; i <= 100; i ++) { printf ( " Numero % d \ n " , i ); }

O programa 6.5 mostra como se pode calcular o fatorial de um n umero usando-se o comando for. Listing 6.5: Exemplo de comando for.
#i ncl ude < stdio .h > #include < stdlib .h > i n t main () { i n t numero , fat =1 , i ; printf ( " \ nEntre com um numero positivo . " ); scanf ( " % d " , & numero ); f o r ( i = numero ; i >1; i - -) fat = fat * i ; printf ( " O fatorial de % u vale % u . " , numero , fat ); return 0; }

La cos for com mais de um comando por express ao Outra possibilidade que o comando for em C permite e a inclus ao de v arios comandos, separados por v rgulas, nas express oes. O trecho de programa a seguir mostra um exemplo de uso de comando for com v arios comandos nas express oes.
int i,j; f o r ( i =1 , j = 10; i <= 10; i ++ , j += 10) { printf ( " i = %d , j = % d \ n " , i , j ); }

98

La cos for com testes usando outras vari aveis A express ao de controle n ao precisa necessariamente envolver somente um teste com a vari avel que controla o la co. O teste de nal do la co pode ser qualquer express ao relacional ou l ogica. No programa 6.6 o la co pode terminar porque a vari avel de controle j a chegou ao seu valor limite ou foi batida a tecla *, e neste caso o la co termina antecipadamente. Listing 6.6: Exemplo de comando for com testes sobre outras vari aveis.
#include < stdio .h > i n t main () { char c = ; int i; f o r ( i =0 ; (i <5) && ( c != * ); i ++ ) { printf ( " % c \ n " , c ); c = getchar (); } return 0; }

La cos for com express oes faltando Um outro ponto importante do for e que nem todas as express oes precisam estar presentes. No exemplo 6.7 a vari avel de controle n ao e incrementada. A u nica maneira do programa terminar e o usu ario bater o n umero -1. Listing 6.7: Exemplo de comando for sem altera ca o da vari avel de controle.
#include < stdio .h > i n t main () { int i; f o r ( i =0 ; i != -1 ; ) { printf ( " % d \ n " ,i ); scanf ( " % d " , & i ); } return 0; }

poss E vel omitir qualquer uma das express oes. Por exemplo, se a express~ ao2 for omitida o programa assume que ela e sempre verdade de modo que o la co s o termina com um comando de desvio como o break. O programa do exemplo 6.8 p ara quando o valor da vari avel de controle for igual a 5. Neste caso o teste ser a verdade o la co termina por meio do break. La co innito Uma constru ca o muito utilizada e o la co innito. No la co innito o programa p ara quando se executa o comando break. O trecho de programa a seguir somente p ara quando for digitada a tecla s ou S . 99

Listing 6.8: Exemplo de comando for sem teste de m.


#include < stdio .h > i n t main () { int i; f o r ( i = 0; ; i ++) { printf ( " numero % d \ n " , i ); i f ( i == 5) break ; } return 0; }

for ( ; ; ) { printf ( " \ nVoce quer parar ?\ n " ); c = getchar (); i f ( c == S || c == s ) break ; }

La cos for aninhados Uma importante constru ca o aparece quando colocamos como comando a ser repetido um outro comando for. Esta constru ca o pode aparecer quando estamos trabalhando com matrizes. O exemplo 6.9 mostra um programa que imprime uma tabuada. Listing 6.9: Comando for aninhados.
#include < stdio .h > i n t main ( void ) { int i, j; printf ( " Imprime tabuada de multiplicacao .\ n " ); f o r ( i =1 ; i <10 ; i ++) { printf ( " Tabuada de % d \ n " , i ); f o r ( j =1; j <10; j ++) { printf ( " % d x % d = % d \ n " , i , j , i * j ); } } return 0; }

6.4.2

Comando while

O comando while tem a seguinte forma geral:


while ( express~ ao ) bloco_de_co ma n do s

A express ao pode assumir o valor falso (igual a 0) ou verdade (diferente de 0). Os passos para execu ca o do comando s ao os seguintes: 100

1. A express ao e avaliada; 2. Se o resultado for verdadeiro ent ao o bloco de comandos e executado, caso contr ario a execu ca o do bloco e terminada; 3. Voltar para o passo 1. Uma caracter stica do comando while, como pode ser visto dos passos acima, e que o bloco de comandos pode n ao ser executado caso a condi ca o seja igual a falso logo no primeiro teste. O trecho de abaixo imprime os 100 primeiros n umeros usando um comando while.
i = 1; while ( i <= 100) { printf ( " Numero % d \ n " , i ); i ++; }

A express ao do comando pode incluir chamadas de fun ca o. Lembrar que qualquer atribui ca o entre par enteses e considerada como uma express ao que tem como resultado o valor da atribui ca o sendo feita. Por exemplo, o programa 6.10 repete um bloco de comandos enquanto o usu ario usar a tecla c para continuar, qualquer outra tecla o bloco e interrompido. Listing 6.10: Comando while com uma fun ca o.
#i ncl ude < stdio .h > i n t main ( void ) { int c; puts ( " Tecle c para continuar .\ n " ); while (( c = getchar ()) == c ) { puts ( " Nao Acabou .\ n " ); getchar (); /* tira o enter */ } puts ( " Acabou .\ n " ); return 0; }

6.4.3

Comando do-while

A forma gen erica do comando e a seguinte:


do bloco_de_co ma n do s while ( express~ a o );

Observar que neste comando a express ao de teste est a ap os a execu ca o do comando, portanto o bloco de comandos e executado pelo menos uma vez. A execu ca o do comando segue os seguintes passos:

101

1. Executa o comando; 2. Avalia a express ao; 3. Se o resultado da express ao for verdadeiro ent ao volta para o passo 1, caso contr ario interrompe o do-while O exemplo de comando for para imprimir os 100 primeiros n umeros escrito com comando do-while ca da seguinte maneira:
i = 1; do { printf ( " Numero % d \ n " , i ); i ++; } while ( i <= 100);

6.5
6.5.1

Comandos de Desvio
Comando break

O comando break pode ser tanto usado para terminar um teste case dentro de um comando switch quanto interromper a execu ca o de um la co. Quando o comando e utilizado dentro de um comando for o la co e imediatamente interrompido e o programa continua a execu ca o no comando seguinte ao comando for. No trecho de programa abaixo o comando for deve ler 100 n umeros inteiros positivos. No entanto, se for digitado um n umero negativo o comando for e interrompido imediatamente sem que o n umero seja impresso.
f o r ( i = 0; i < 100; i ++) { scanf ( " % d " , & num ); i f ( num < 0) break ; printf ( " % d \ n " , num ); }

6.5.2

Comando continue

O comando continue e parecido com o comando break. A diferen ca e que o comando continue simplesmente interrompe a execu ca o da itera ca o corrente passando para a pr oxima itera ca o do la co, se houver uma. No comando for o controle passa a execu ca o da express~ ao3. Nos comandos while e do-while o controle passa para a fase de testes. No trecho de programa abaixo o la co l e 100 n umeros inteiros, caso o n umero seja negativo, um novo n umero e lido.
f o r ( i = 0; i < 100; i ++) { scanf ( " % d " , & num ); i f ( num < 0) continue ; printf ( " % d \ n " , num ); }

102

6.5.3

Comando goto

O comando goto causa um desvio incondicional para um outro ponto da fun ca o em que o comando est a sendo usado. O comando para onde deve ser feito o desvio e indicado por um r otulo, que e um identicador v alido em C seguido por importante notar que o comando goto e o ponto para onde ser dois pontos. E a feito o desvio pode estar em qualquer ponto dentro da mesma fun ca o. A forma geral deste comando e: goto r otulo; ... r otulo: Este comando durante muito tempo foi associado a programas ileg veis. O argumento para esta arma ca o se baseia no fato de que programas com comandos goto perdem a organiza ca o e estrutura porque o uxo de execu ca o pode car saltando erraticamente de um ponto para outro. Atualmente as restri co es ao uso do comando tem diminu do e seu uso pode ser admitido em alguns casos.

6.5.4

Fun c ao exit()

A fun ca o exit provoca a termina ca o de um programa, retornando o controle ao sistema operacional. O prot otipo da fun ca o e a seguinte: void exit (int codigo); Observar que esta fun ca o interrompe o programa como um todo. O c odigo e usado para indicar qual condi ca o causou a interrup ca o do programa. Usualmente o valor 0 indica que o programa terminou sem problemas. Um valor diferente de 0 indica um erro.

6.5.5

Comando return

O comando return e usado para interromper a execu ca o de uma fun ca o e retornar um valor ao programa que chamou esta fun ca o. Caso haja algum valor associado ao comando return este e devolvido para a fun ca o, caso contr ario um valor qualquer e retornado. A forma geral do comando e: return express~ ao; Notar que a express ao e opcional. A chave que termina uma fun ca o e equiv poss alente a um comando return sem a express ao correspondente. E vel haver mais de um comando return dentro de uma fun ca o. O primeiro que for encontrado durante a execu ca o causar a o m da execu ca o. Uma fun ca o declarada como do tipo void n ao pode ter um comando return que retorne um valor. Isto n ao faz sentido, j a que fun co es deste tipo n ao podem retornar valores.

103

6.6

Exerc cios

6.1: Escreva um programa que calcule x elevado a n. Assuma que n e um valor inteiro. 6.2: Escreva um programa que exiba as op co es 1-multiplicar e 2-somar de um menu, leia a op ca o desejada, leia dois valores, execute a opera ca o (utilizando o comando if) e exiba o resultado. 6.3: Utilizando ifs em escada, inclua, no programa do exerc cio anterior, as op co es 3-Subtrair e 4-Dividir. 6.4: Simplique os programas anteriores da seguinte forma: Reescreva o programa do exerc cio 1 substituindo o comando if pelo comando tern ario. Reescreva o programa do exerc cio 2 substituindo os ifs em escada pelo comando switch. 6.5: Utilizando um la co for dentro de outro, escreva um programa que exiba as tabuadas de multiplica ca o dos n umeros de 1 ` a 9. 6.6: Escreva um programa com menu de 5 op co es que utilize o comando de desvio goto para executar a op ca o desejada e s o saia do programa caso a op ca o 5-Sair seja selecionada. 6.7:Escreva um programa que tenha um n umero (inteiro) como entrada do usu ario e escreva como sa da a seq uencia de bits que forma esse numero. Por exemplo, ap os digitado o n umero 10, a sa da deve ser 0000000000001010. 6.8:Escreva um programa que imprima todos os pares entre 0 e 50 e em seguida imprima todos os impares. Deixar um espa co entre os n umeros. 6.9: Escreva um programa que leia 10 n umeros. O programa deve imprimir a media, o maior e o menor deles. Obs: Os n umeros devem ser entre 0 e 10. 6.10: Escreva um programa que leia 10 n umeros. O programa deve imprimir a media, o maior e o menor deles. Obs: Considere agora que os n umeros podem ser quaisquer. 6.11: Escreva um programa que exibe a tabela ascii. 6.12: Crie um programa para vericar se um n umero dado e primo. 6.13: Escreva um programa que leia um numero do teclado e ache todos os seus divisores. 6.14: Escreva um programa que imprima a seq u encia 987654321876543217654321654321543214321321211

104

N ao use nenhuma constante, use apenas vari aveis. Em outra linha imprima as letras mai usculas de A at e Z (ABCD...). 6.15: Escreva um programa que conte de 100 a 999 (inclusive) e exiba, um por linha, o produto dos tr es d gitos dos n umeros. Por exemplo, inicialmente o programa ir a exibir: 0 (1*0*0) 0 (1*0*1) 0 (1*0*2) (...) 0 (1*1*0) 1 (1*1*1) 2 (1*1*2) 9*9*9=729 Fa ca seu programa dar uma pausa a cada 20 linhas para que seja poss vel ver todos os n umeros pouco a pouco. Solicite que seja pressionada alguma tecla para ver a pr oxima seq u encia de n umeros. 6.16: Escreva um programa que imprima uma gura como a mostrada abaixo. O n umero de linhas da gura deve ser pedido ao usu ario. ****** ***** **** *** ** *

6.17: O que ser a impresso pelo programa 6.11. Indique os n umeros que voc e ir a digitar para o programa. Os n umeros devem ser todos diferentes.

105

Listing 6.11: Programa do exercicio 17.


#include < stdio .h > i n t main ( void ) { int i, j, m; f o r ( i = 0; i < 6; i ++) { scanf ( " % d " , & m ); i f ( m % 2) { f o r ( j = 0; j < m ; j ++) { printf ( " # " ); } } else { f o r ( j = m ; j > 0; j - -) { printf ( " * " ); } } printf ( " \ n " ); } return 0; }

106

Cap tulo 7

Vetores e Cadeias de Caracteres


7.1 Introdu c ao

Vetores s ao usados para tratamento de conjuntos de dados que possuem as mesmas caracter sticas. Uma das vantagens de usar vetores e que o conjunto recebe um nome comum e elementos deste conjunto s ao referenciados atrav es de ndices. Pelo nome vetor estaremos referenciando estruturas que podem ter mais de uma dimens ao, como por exemplo matrizes de duas dimens oes. Neste cap tulo estaremos mostrando vetores de tamanhos xos. Somente ap os apresentarmos ponteiros iremos abordar aloca ca o de mem oria para vetores.

7.2

Declara c ao de Vetores Unidimensionais

A forma geral da declara ca o de vetores de uma dimens ao e:


tipo nome [tamanho];

onde tipo e um tipo qualquer de dados, nome e o nome pelo qual o vetor vai ser referenciado e tamanho e o n umero de elementos que o vetor vai conter. Observar que em C o primeiro elemento tem ndice 0 e o u ltimo tamanho - 1. Exemplos de declara co es de vetores s ao:
i n t numeros [1000]; f l o a t notas [65]; char nome [40]; /* vetor de 1000 inteiros */ /* conjunto de 65 numeros reais */ /* conjunto de 40 caracteres */

O espa co de mem oria, em bytes, ocupado por um vetor de tipo qualquer e igual a:
espa co = tamanho * sizeof(tipo)

importante notar que em C n E ao h a verica ca o de limites em vetores. Isto signica que e poss vel ultrapassar o m de um vetor e escrever em outras tarefa do programador fazer com vari aveis, ou mesmo em trechos de c odigo. E 107

que os ndices dos vetores estejam sempre dentro dos limites estabelecidos pela declara ca o do vetor. O programa 7.1 ilustra como se declara um vetor, inicializa seus valores e imprime o conte udo. Notar o uso da diretiva #define DIM 5 para denir uma constante, que posteriormente foi usada para estabelecer o tamanho do vetor. Esta constante passa a ser usada nas refer encias ao vetor, por exemplo no comando de gera ca o do conjunto de dados armazenado no vetor. Caso seja necess ario trocar o tamanho do vetor basta alterar o valor da constante e recompilar o programa. Listing 7.1: Exemplo de vetores.
#de fi ne DIM 5 #i ncl ude < stdio .h > i n t main ( void ) { i n t vetor [ DIM ]; unsigned i n t i , num ; puts ( " Este programa gera um vetor de inteiros .\ n " ); puts ( " Entre com o numero inicial do conjunto . " ); scanf ( " % d " , & num ); /* Geracao do conjunto */ f o r ( i = 0 ; i < DIM ; i ++) vetor [ i ] = num ++; /* Impressao do conjunto */ f o r ( i = 0; i < DIM ; i ++) printf ( " Elemento % d = % d \ n " , i , vetor [ i ]); return 0; }

O programa 7.2 calcula o produto escalar de dois vetores inteiros. Observar como na leitura dos elementos do vetor usa-se o operador de endere co & antes do nome de cada elemento. O programa 7.3 ilustra o m etodo da bolha para ordena ca o em ordem crescente de um vetor de inteiros. Neste m etodo a cada etapa o maior elemento e movido para a sua posi ca o. A cada itera ca o os elementos do vetor s ao comparados dois a dois, sendo trocados caso seja necess ario. Ao t ermino da primeira passada pelo vetor, o maior elemento e levado para a sua posi ca o, no nal do vetor. Portanto, ele n ao precisa ser mais considerado, da o valor da vari avel que aponta para o nal do vetor (fim) e diminu da de 1. O processo e repetido at e que todos os elementos sejam levados para as suas posi co es ou que nenhuma troca seja realizada. Quando nenhuma troca e realizada o vetor est a ordenado. A Tabela 7.1 mostra os passos executados pelo algoritmo at e ordenar o vetor.

7.3

Cadeias de Caracteres

Um cadeia de caracteres (string ) e um conjunto de caracteres terminado por um caractere nulo, que e representado como \0. Para especicar um vetor para 108

Opera c ao Passo 1 v[0] > v[1]? Trocar v[0] e v[1] > v[2]? Trocar v[1] e v[2] > v[3]? Trocar v[2] e v[3] > v[4]? Trocar v[3] e Passo 2 v[0] > v[1]? Trocar v[0] e v[1] > v[2]? Trocar v[1] e v[2] > v[3]? Trocar v[2] e Passo 3 v[0] > v[1]? v[1] > v[2]? Trocar v[1] e Passo 4 v[0] > v[1]? Trocar v[0] e

v[0] 20 15 15 15 15 15 15 15 15 8 8 8 8 8 8 8 8 8 5

v[1] 15 20 20 8 8 8 8 8 8 15 15 12 12 12 12 12 5 5 8

v[2] 8 8 8 20 20 12 12 12 12 12 12 15 15 5 5 5 12 12 12

v[3] 12 12 12 12 12 20 20 5 5 5 5 5 5 15 15 15 15 15 15

v[4] 5 5 5 5 5 5 5 20 20 20 20 20 20 20 20 20 20 20 20

v[1] v[2] v[3] v[4]

v[1] v[2] v[3]

v[2]

v[1]?

Tabela 7.1: Passos executados durante o algoritmo da bolha.

109

Listing 7.2: Produto escalar de dois vetores.


#de fi ne DIM 5 #i ncl ude < stdio .h > i n t main ( void ) { i n t vetor1 [ DIM ] , vetor2 [ DIM ] , i , prod =0; printf ( " Entre com um vetor de % d elementos \ n " , DIM ); f o r ( i = 0; i < DIM ; i ++) { printf ( " Elemento % d " , i ); scanf ( " % d " , & vetor1 [ i ]); } printf ( " Entre com outro vetor de % d elementos \ n " , DIM ); f o r ( i = 0; i < DIM ; i ++) { printf ( " Elemento % d " , i ); scanf ( " % d " , & vetor2 [ i ]); } f o r ( i = 0; i < DIM ; i ++) prod += vetor1 [ i ] * vetor2 [ i ]; printf ( " O produto vale % d " , prod ); return 0; }

armazenar um cadeia deve-se sempre reservar um espa co para este caractere. Por exemplo, para armazenar um cadeia de 40 caracteres deve-se reservar um vetor de 41 de caracteres. Em C e poss vel haver constantes cadeia, que s ao denidas como uma lista de caracteres entre aspas. Por exemplo, "programando em C" N ao e necess ario a coloca ca o do caractere nulo ao nal da cadeia. Em C n ao h a o tipo cadeia (string) e, portanto, conjuntos de caracteres teriam de ser tratados como conjuntos de n umeros inteiros, por exemplo. Para facilitar a programa ca o foram criadas algumas fun co es para manipular cadeias. Algumas das fun co es mais comuns est ao resumidamente descritas a seguir: Nas deni co es a seguir, size_t e o tipo inteiro sem sinal que volta como resultado do operador sizeof. char *strcat(char *dest, const char *orig): Concatena cadeia orig ao nal de dest. O primeiro caractere de orig substitui o caractere nulo de dest. A fun ca o retorna o valor de dest. char *strncat (char *dest, const char *orig, size_t n): Concatena cadeia orig ao nal de dest, usando no m aximo n caracteres de orig. O primeiro caractere de orig substitui o caractere nulo de dest. A fun ca o retorna o valor de dest. char *strcmp (const char *cad1, const char *cad2): Compara lexicogracamente as duas cadeias. Retorna zero se as cadeias s ao iguais, menor que 0 se cad1 < cad2, maior que 0 se cad1 > cad2. 110

Listing 7.3: Ordena ca o pelo m etodo da bolha.


#de fi ne DIM 5 #de fi ne FALSO 0 #de fi ne VERDADE 1 #i ncl ude < stdio .h > i n t main ( void ) { i n t vetor [ DIM ] , i ; i n t trocou = FALSO , fim = DIM , temp ; printf ( " Entre com um vetor de % d elementos \ n " , DIM ); f o r ( i = 0; i < DIM ; i ++) { printf ( " Elemento % d " , i ); scanf ( " % d " , & vetor [ i ]); } do { trocou = FALSO ; f o r ( i =0; i < fim -1; i ++) { i f ( vetor [ i ] > vetor [ i +1]) { temp = vetor [ i ]; vetor [ i ] = vetor [ i +1]; vetor [ i +1] = temp ; trocou = VERDADE ; } } fim - -; } while ( trocou ); f o r ( i =0; i < DIM ; i ++) printf ( " % d \ n " , vetor [ i ]); return 0; }

111

char *strncmp (const char *cad1, const char *cad2, size_t n): Compara lexicogracamente at e n caracteres das duas cadeias. Retorna zero se as cadeias s ao iguais, menor que 0 se cad1 < cad2, maior que 0 se cad1 > cad2. size_t strlen(const char *cad): Calcula o comprimento da cadeia sem contar o caraca ter nulo. O comprimento da cadeia e determinado pelo caractere nulo. N ao confundir o tamanho da cadeia com o tamanho do vetor que armazena a cadeia. char *strcpy(char *dest, const char *orig): Copia cadeia orig para dest. A cadeia destino deve ter espa co suciente para armazenar orig. O valor de dest e retornado. Estas fun co es est ao na biblioteca string.h. O programa 7.4 mostra exemplos de uso de algumas das fun co es de cadeia. Neste exemplo, o programa primeiro l e um nome e em seguida um sobrenome. O programa ir a ent ao concatenar as duas cadeias. Observe que sempre e colocado um branco ao nal do nome para separ a-lo do sobrenome. Este branco e inserido usando a fun ca o strcat, e esta e raz ao das aspas, ou seja, uma cadeia de um caractere apenas. A seguir mostramos um resultado da execu ca o do programa 7.4. Entre com um nome Ze Ze Entre com um sobrenome Sa Sa Ze Sa Qual caracter? a O caractere aparece na posicao 4

7.4

Declara c ao de Vetores Multidimensionais

Em C existe a possibilidade de declararmos vetores de mais de uma dimens ao. A forma geral da declara ca o e a seguinte: tipo nome [dim1][dim2][dim3]...[dimN]; onde dimI e o tamanho da dimens ao I. Deve-se tomar cuidado com armazenamento de matrizes multidimensionais, por que a mem oria necess aria para guardar estes dados e igual a
sizeof(tipo)*dim1*dim2*dim3*...*dimN

Por exemplo a declara ca o


int matriz[10][20];

dene uma matriz quadrada de 10 linhas por 20 colunas, enquanto o comando


c = 2 * matriz[3][8];

armazena o dobro do elemento que est a na quarta linha e nona coluna na vari avel c. Observar que o primeiro ndice indica a linha e o segundo a coluna. Lembrar 112

Listing 7.4: Exemplos de fun co es para cadeias.


#include < string .h > #include < stdio .h > i n t main ( void ) { char c , nome [81] , sobrenome [41]; int i; printf ( " Entre com um nome " ); fgets ( nome , 41 , stdin ); nome [ strlen ( nome ) -1] = \0 ; /* tira cr do fim */ puts ( nome ); printf ( " Entre com um sobrenome " ); fgets ( sobrenome , 41 , stdin ); sobrenome [ strlen ( sobrenome ) -1] = \0 ; puts ( sobrenome ); strcat ( nome , " " ); strcat ( nome , sobrenome ); puts ( nome ); printf ( " Qual caracter ? " ); c = getchar (); f o r ( i =0; i < strlen ( nome ); i ++) { i f ( c == nome [ i ]) { printf ( " O caractere aparece na posicao % d \ n " , i ); } } return 0; }

113

que o n umero da primeira linha (coluna) e igual a 0. O programa 7.5 l e uma matriz de tr es linhas e cinco colunas e imprime os valores lidos. Listing 7.5: Leitura de uma matriz.
#de fi ne DIML 3 #de fi ne DIMC 5 #i ncl ude < stdio .h > i n t main ( void ) { int i, j; i n t matriz [ DIML ][ DIMC ]; f o r ( i =0; i < DIML ; i ++) f o r ( j =0; j < DIMC ; j ++) scanf ( " % d " , & matriz [ i ][ j ]); f o r ( i =0; i < DIML ; i ++) { f o r ( j =0; j < DIMC ; j ++) printf ( " %4 d " , matriz [ i ][ j ]); printf ( " \ n " ); } return 0; }

A matriz e armazenada na mem oria linha a linha e a Figura 7.4 ilustra esta id eia com uma matriz de n umeros inteiros de tr es por tr es. Estamos assumindo que cada n umero inteiro ocupa quatro bytes, o endere co aponta um byte e a matriz est a armazenada a partir do endere co 1000. Uma opera ca o muito comum em matem atica e a multiplica ca o de matrizes. Considere a matriz M 1 com L1 linhas e C 1 colunas e a matriz M 2 com L2 linhas e C 2 colunas. O n umero de colunas C 1 de M 1 deve ser igual ao n umero de linhas L2 de M 2. O elemento M Rij da matriz resultado M R do produto destas matrizes e denido pela equa ca o 7.1. O programa 7.6 multiplica duas matrizes de acordo com a f ormula.
C1

M Rij =
k=1

M 1ik M 2kj

(7.1)

7.5

Vetores de Cadeias de Caracteres

A declara ca o abaixo mostra uma matriz de cadeias de caracteres com 30 linhas de 80 caracteres. char nome turma[30][80]; O Programa 7.7 mostra um programa que l e uma matriz de nomes e imprime importante notar que para ler um nome o programa n os seus conte udos. E ao l e um caracter de cada vez mas usa a fun ca o fgets. Como cada linha da matriz e uma cadeia de caracteres, o programa l e o nome que est a na linha i como fgets(nomes[i], DIMC-1, stdin). 114

Listing 7.6: Multiplica ca o de duas matrizes.


#include < stdio .h > #de fi ne #de fi ne #de fi ne #de fi ne L1 L2 C1 C2 3 3 3 3

i n t main ( void ) { f l o a t m1 [ L1 ][ C1 ] , m2 [ L2 ][ C2 ]; f l o a t mr [ L1 ][ C2 ] , m ; int i, j, k; f o r ( i =0; i < L1 ; i ++) { f o r ( j =0; j < C1 ; j ++) { printf ( " %d , % d " , i , j ); scanf ( " % f " , & m1 [ i ][ j ]); } } f o r ( i =0; i < L2 ; i ++) { f o r ( j =0; j < C2 ; j ++) { printf ( " %d , % d " , i , j ); scanf ( " % f " , & m2 [ i ][ j ]); } } f o r ( i =0; i < L1 ; i ++) { f o r ( j =0; j < C2 ; j ++) { m = 0; f o r ( k =0; k < C1 ; k ++) { m += m1 [ i ][ k ]* m2 [ k ][ j ]; } mr [ i ][ j ] = m ; } } f o r ( i =0; i < L1 ; i ++ ) { f o r ( j =0; j < C2 ; j ++) { printf ( " %.3 f " , mr [ i ][ j ]); } printf ( " \ n " ); } return 0; }

115

1000

m[0][0]

1004

m[0][1]

1008

m[0][2]

1012

m[1][0]

1016

m[1][1]

1020

m[1][2]

1024

m[2][0]

1028

m[2][1]

1032

m[2][2]

Figura 7.1: Mapa de mem oria de uma matriz.

7.6

Inicializa c ao de Vetores e Matrizes

Em C e poss vel inicializar vetores da mesma forma que vari aveis, isto e, no momento em que s ao declarados. A forma de fazer isto e a seguinte: tipo nome[dim] = {lista de valores}; onde lista de valores e um conjunto de valores separados por v rgulas. Por exemplo, a declara ca o abaixo inicializa um vetor inteiro de cinco posi co es. int vetor[5] = { 10, 15, 20, 25, 30 }; Observe que nesta declara ca o e necess ario que o tamanho do conjunto seja conhecido antecipadamente. No entanto, tamb em e poss vel inicializar vetores em que n ao se conhece o seu tamanho. Neste caso, ent ao, e importante que o programador preveja um modo de indicar o m do vetor. O Programa 7.8 mostra os casos ilustrados acima. No primeiro exemplo o tamanho do vetor e conhecido e foi denido pela constante DIM. Para descobrir o como parar de processar o vetor, quando desconhecemos seu tamanho, apresentamos duas solu co es poss veis. No primeiro caso a condi ca o de m do vetor eo n umero negativo -1. Neste caso uma posi ca o do vetor e perdida para armazenar esta condi ca o. No segundo caso e usado o operador sizeof para descobrir o tamanho do vetor. Observe que sizeof calcula o tamanho do vetor em bytes e por esta raz ao e necess ario uma divis ao pelo tamanho em bytes do tipo de cada elemento. 116

Listing 7.7: Leitura de um vetor de nomes.


#de fi ne DIML 5 #de fi ne DIMC 41 #i ncl ude < stdio .h > #i ncl ude < string .h > i n t main ( void ) { int i; char nomes [ DIML ][ DIMC ]; f o r ( i =0; i < DIML ; i ++) { printf ( " Entre com a linha % d " , i ); fgets ( nomes [ i ] , DIMC -1 , stdin ); nomes [ i ][ strlen ( nomes [ i ]) -1] = \0 ; } f o r ( i =0; i < DIML ; i ++) { printf ( " O nome % d e " , i ); puts ( nomes [ i ]); } return 0; }

poss E vel inicializar matrizes multidimensionais e neste caso e necess ario especicar todas as dimens oes menos a primeira, para que o compilador possa reservar mem oria de maneira adequada. A primeira dimens ao somente especica quantos elementos o vetor ir a armazenar e isto lendo a inicializa ca o o compilador pode descobrir. A declara ca o a seguir ilustra como declarar e inicializar uma matriz de tr es linhas por quatro colunas de n umeros reais.
f l o a t mat [][4] = { {1.0 , 2.0 , 3.0 , 4.0} , // linha 0 {8.0 , 9.0 , 7.5 , 6.0} , // linha 1 {0.0 , 0.1 , 0.5 , 0.4} }; // linha 2

O Programa 7.9 ilustra a deni ca o de um vetor de cadeia de caracteres, que nada mais e do que uma matriz de caracteres. Note que as cadeias s ao separadas uma das outras por v rgulas.

117

Listing 7.8: Exemplos de tratamento de vetores.


#de fi ne DIM 5 #include < stdio .h > i n t main () { i n t vetor [ DIM ] = {10 , 15 , 20 , 25 , 30}; i n t vetor1 [] = {10 , 20 , 30 , 40 , 50 , 60 , -1}; i n t vetor2 [] = {3 , 6 , 9 , 12 , 15 , 18 , 21 , 24}; unsigned i n t i , tam ; printf ( " Este programa imprime vetores " ); printf ( " contendo numeros inteiros e \ n " ); printf ( " que foram inicializados durante " ); printf ( " a sua declaracao .\ n " ); /* Impressao dos conjuntos */ printf ( " \ nVetor com tamanho pre - definido \ n " ); f o r ( i =0; i < DIM ; i ++) printf ( " Elemento % d = % d \ n " , i , vetor [ i ]); printf ( " \ nVetor terminando por -1\ n " ); f o r ( i =0; vetor1 [ i ] >0; i ++) printf ( " Elemento % d = % d \ n " , i , vetor1 [ i ]); tam = s i z e o f ( vetor2 ) printf ( " \ nDescobrindo f o r ( i =0; i < tam ; printf ( " Elemento return 0; } / s i z e o f ( i n t ); o tamanho do Vetor \ n " ); i ++) % d = % d \ n " , i , vetor2 [ i ]);

Listing 7.9: Exemplos de tratamento de vetores.


#de fi ne DIM 5 #include < stdio .h > i n t main ( void ) { char disciplinas [][40] = { " disc 0: Computacao para Informatica " , " disc 1: Banco de Dados I " , " disc 2: Banco de Dados II " , " disc 3: Arquitetura de Computadores I " }; int i; printf ( " Qual a disciplina ? " ); scanf ( " % d " , & i ); puts ( disciplinas [ i ]); return 0; }

118

7.7

Exerc cios

7.1: Escreva um programa que leia uma linha de at e 80 caracteres do teclado e imprima quantos caracteres foram lidos. 7.2: Escreva um programa que leia uma linha de caracteres do teclado e imprima quantas vezes um caractere, tamb em fornecido pelo teclado, aparece nesta linha. O programa tamb em deve imprimir em que posi co es o caractere foi encontrado. 7.3: Escreva um programa que leia uma linha do teclado e em seguida um par de caracteres. O programa deve procurar este par na linha e imprimir em que posi co es o par foi encontrado. Obs. N ao use fun co es da biblioteca de strings do C 7.4: Escreva um programa que leia uma linha do teclado e imprima todas as vogais encontradas no texto e o total de vezes que elas aparecem. Obs: Tamanho m aximo da linha deve ser 40 caracteres. 7.5: O imperador romano C esar usava um sistema simples para codicar as mensagens que enviava aos seus generais. Neste sistema cada letra era substitu da por tr es letras ` a frente no alfabeto. A sua miss ao e mais simples ainda, escrever um programa que converta cada letra, e somente as letras, de uma mensagem de at e 80 caracteres para a letra imediatamente posterior. Note que a letra z deve ser convertida para a letra a, e a letra Z para A. 7.6: Escreva um programa que leia uma frase de 80 caracteres e a imprime retirando os espa cos em branco. 7.7: Escreva um programa que leia uma linha de caracteres do teclado de tamanho 80. A linha somente cont em letras. Divida a linha em blocos de 5 letras. Dentro de cada bloco o seu programa deve trocar a primeira letra pela letra seguinte no alfabeto, a segunda letra por duas letras adiante no alfabeto, a terceira por tr es letras adiante e assim at e a quinta. Os espa cos em branco devem ser retirados da frase. Considere o seguinte exemplo. 1. Frase lida: EVA VIU A UVA 2. Retirada dos espa cos em branco: EVAVIUAUVA 3. Divis ao em blocos de 5 (blocos indicados por tipos diferentes): EVAVIUAUVA 4. Criptograa: FYDANVCYAF Portanto, o que ser a impresso pelo programa e: FYDANVCYAF 7.8: Escreva um programa que leia uma matriz de 3x3 que cont em somente caracteres 0 e X e procure linhas que contenham somente um dos dois caracteres. O caractere a ser procurado deve ser lido do teclado. 119

7.9: Escreva um programa que leia uma linha de caracteres do teclado e converta o primeiro caractere de cada palavra para mai usculas. Assuma que as palavras s ao sempre separadas por um branco. 7.10: Escreva um programa que leia para um vetor um conjunto de n umeros inteiros. Assuma que o conjunto de n umeros lidos e menor que o tamanho do vetor. O programa deve inserir no vetor, em uma posi ca o especicada pelo usu ario, um n umero lido do teclado. Assuma que a posi ca o especicada pelo usu ario corresponde ao ndice do vetor. 7.11: Fa ca um programa que inverta uma cadeia de caracteres. O programa deve ler a cadeia com gets e armazen a-la invertida em outra cadeia. Use o comando for para varrer a cadeia at e o seu nal. 7.12: Escreva um programa que leia um conjunto de nomes para uma matriz e imprima estes nomes em ordem alfab etica. Assuma que os nomes ser ao lidos somente em letras mai usculas. Assuma tamb em que os nomes t em no m aximo 40 caracteres e ser ao lidos 10 nomes ao todo. 7.13: Escreva um programa que leia um conjunto N (1 N 1000000000) de n umeros inteiros e imprima os seguintes resultados: media dos n umeros; maior dos n umeros; menor dos n umeros; produto de todos os n umeros. 7.14: Considere que voc e digitou o seu nome para o programa mostrado na listagem 7.10. O que ser a impresso? Indique o que voc e digitou. Justique sua resposta com detalhes.

120

Listing 7.10: Programa do exercicio 14.


#include < stdio .h > #include < string .h > #de fi ne MAX 50 i n t main ( void ) { char texto [ MAX +2] , temp ; i n t tam , i ; gets ( texto ); tam = strlen ( texto ); f o r ( i = 0; i < tam ; i ++) { temp = texto [ i ]; texto [ i ] = texto [ tam -1 - i ]; texto [ strlen ( texto ) -1 - i ] = temp ; } puts ( texto ); return 0; }

121

Cap tulo 8

Fun c oes
8.1 Introdu c ao

Em C, diferentemente de outras linguagens como Pascal, todas as a c oes ocorrem dentro de fun co es. Na linguagem C n ao h a conceito de um programa principal, o que existe e uma fun ca o chamada main que e sempre a primeira a ser executada. Um programa pode ser escrito apenas com a fun ca o main e mais as fun co es existentes nas bibliotecas da linguagem C. No entanto o uso de fun co es pode facilitar o desenvolvimento de programas de diversas maneiras. Em primeiro lugar temos as vantagens do reuso de c odigo desenvolvido por outros programadores. As fun co es de entrada e sa da s ao o exemplo mais direto deste reuso. Em C n ao existem estes tipos de comandos como na maioria das linguagens. Programas escritos em C usam fun co es de entrada e sa da escritas e testadas por outros programadores. Este reuso de c odigo apresenta v arias vantagens. Primeiro, diminui o tempo de desenvolvimento do programas. Em segundo lugar, como estas fun co es foram testadas por diversos usu arios, a quantidade de erros e bastante reduzida. Estes fatores contribuem para a redu ca o dos custos de desenvolvimento dos projetos. Uma outra vantagem do uso de fun co es e a maior facilidade na divis ao do trabalho necess ario para construir um aplicativo. Fun co es podem ser desenvolvidas por programadores trabalhando independentemente. Para isto basta que alguns acordos sejam feitos entre os programadores que ir ao programar a fun ca o e os que ir ao us a-las. Estes acordos precisam denir que par ametros a fun ca o ir a receber, que resultados ir a fornecer e que opera co es ela deve realizar sobre estes par ametros para obter os resultados necess arios. Esta divis ao do trabalho concorre para acelerar o desenvolvimento dos programas e na redu ca o dos custos deste desenvolvimento. A divis ao de um programa em fun co es tamb em permite que os testes do sistema completo sejam feitos mais facilmente e com mais garantia de corre ca o. Os programadores podem testar suas fun co es separadamente em testes menos complexos, j a que as fun co es normalmente s ao simples e t em requisitos menos complicados de serem avaliados. Isto permite que muitos erros do sistema completo possam ser retirados antes que ele esteja completo. Normalmente testar um programa complexo requer testes complexos. 122

Mesmo quando um programa e desenvolvido por um u nico programador a sua divis ao em fun co es traz vantagens, por dividir um trabalho complexo em diversas fatias menores permitindo ao programador se concentrar a cada vez em problemas mais simples.

8.2

Forma Geral

A forma geral de uma fun ca o em C e a seguinte:


tipo nome ( tipo nome1 , tipo nome2 , ... , tipo nomeN ){ declara c~ a o das vari a veis corpo da fun c~ ao }

Uma fun ca o recebe uma lista de argumentos (nome1, nome2, ..., nomeN), executa comandos com estes argumentos e pode retornar ou n ao um resultado para a fun ca o que chamou esta fun ca o. A lista de argumentos, tamb em chamados de par ametros, e uma lista, separada por v rgulas, de vari aveis com seus tipos associados. N ao e poss vel usar uma u nica deni ca o de tipo para v arias vari aveis. A lista de argumentos pode ser vazia, ou seja, a fun c ao n ao recebe nenhum argumento. O nome da fun ca o pode ser qualquer identicador v alido. O tipo que aparece antes do nome da fun ca o especica o tipo do resultado que ser a devolvido ao nal da execu ca o da fun ca o. Caso nenhum tipo seja especicado o compilador assume que um tipo inteiro e retornado. O tipo void pode ser usado para declarar fun co es que n ao retornam valor algum. H a basicamente duas maneiras de terminar a execu ca o de uma fun ca o. Normalmente usa-se o comando return para retornar o resultado da fun ca o. Portanto, quando o comando
return express~ ao;

for executado, o valor da express~ ao e devolvido para a fun ca o que chamou. Quando n ao h a valor para retornar o comando return n ao precisa ser usado e a fun ca o termina quando a chave que indica o t ermino do corpo da fun ca o e atingido. Os par ametros s ao valores que a fun ca o recebe para realizar as tarefas para as quais foi programada. Por exemplo, uma fun ca o que calcule a raiz quadrada de um n umero do tipo oat , deve declarar como par ametro uma vari avel deste tipo para receber o valor. importante notar que diferentemente de declara E co es de vari aveis onde podemos associar v arios nomes de vari aveis a uma declara ca o como em
int a, dia, mes, i;

na lista de par ametros e necess ario associar um tipo a cada vari avel como no exemplo a seguir:
oat media (oat n1, oat n2, oat n3);

Neste exemplo, uma fun ca o chamada media que e do tipo oat , isto e retorna um resultado oat , recebe tr es argumentos (n1, n2, n3) tamb em do tipo oat .

123

Um ponto importante e como usar a fun ca o. Suponha que uma determinada fun ca o, A, deseje usar uma outra fun ca o, B. A fun ca o A deve colocar no local desejado o nome da fun ca o (B) e a lista de valores que deseja passar. Por exemplo, um programador que deseje usar a fun ca o media em seu programa para calcular a m edia de tr es valores, nota1, nota2 e nota3, deve escrever no local onde quer que a m edia seja calculada o seguinte comando:
resultado = media(nota1, nota2, nota3);

onde resultado e a vari avel que vai receber a m edia calculada. E importante notar que o nome da fun ca o pode aparecer em qualquer lugar onde o nome de uma vari avel apareceria. Al em disso os tipos e o n umero de par ametros que aparecem na declara ca o da fun ca o e na sua chamada devem estar na mesma ordem e ser tipos equivalentes. Se os tipos s ao incompat veis, o compilador n ao gera um erro, mas podem ser gerados avisos na compila ca o e resultados estranhos. Outro ponto importante a ser notado e que ser a detalhado mais adiante e que os nomes das vari aveis nos programas que usam a fun ca o media podem ser diferentes dos nomes usados na deni ca o da fun ca o.

8.3

Prot otipos de Fun c oes

O padr ao ANSI estendeu a declara ca o da fun ca o para permitir que o compilador fa ca uma verica ca o mais r gida da compatibilidade entre os tipos que a fun ca o espera receber e ` aqueles que s ao fornecidos. Prot otipos de fun co es ajudam a detectar erros antes que eles ocorram, impedindo que fun co es sejam chamadas com argumentos inconsistentes. A forma geral de deni ca o de um prot otipo e a seguinte:
tipo nome (tipo nome1, tipo nome2, ..., tipo nomeN);

O exemplo 8.1 mostra a declara ca o de uma fun ca o e seu prot otipo. Listing 8.1: Exemplo de prot otipos.
#include < stdio .h > /* Prototipo da funcao */ i n t soma ( i n t a , i n t b ); /* Funcao Principal */ i n t main () { i n t a =5 , b =9; printf ( " % d \ n " , soma (a , b )); return 0; } /* Definicao da funcao */ i n t soma ( i n t a , i n t b ) { return a + b ; }

124

Tamb em e poss vel declarar um prot otipo sem dar os nomes das vari aveis somente os tipos das fun co es. No exemplo 8.1 o prot otipo da fun ca o soma pode ser declarada da seguinte maneira
int soma (int, int)

8.4

Escopo de Vari aveis

Vari aveis podem ser denidas para serem usadas somente dentro de uma fun ca o particular, ou pode ocorrer que vari aveis precisem ser acess veis ` a diversas fun co es diferentes. Por esta raz ao, temos que apresentar os locais onde as vari aveis de um programa podem ser denidas e a partir destes locais podermos inferir onde elas estar ao dispon veis. As vari aveis podem ser declaradas basicamente em tr es lugares: dentro de fun co es, fora de todas as fun co es, na lista de par ametros das fun co es. As vari aveis denidas dentro das fun co es s ao chamadas de vari aveis locais, as que aparecem fora de todas as fun co es chamamos de vari aveis globais e aquelas importante que aparecem na lista de par ametros s ao os par ametros formais. E notar que em C todas as fun co es est ao no mesmo n vel, por esta raz ao n ao e poss vel denir uma fun ca o dentro de outra fun ca o.

8.4.1

Vari aveis Locais

As vari aveis locais s ao aquelas declaradas dentro de uma fun ca o ou um bloco de comandos. Elas passam a existir quando do in cio da execu ca o do bloco de comandos ou fun ca o onde foram denidas e s ao destru das ao nal da execu ca o do bloco. Uma vari avel local s o pode ser referenciada, ou seja usada, dentro da fun ca o (ou bloco) onde foi declarada. Outro ponto muito importante e que como as vari aveis locais deixam de existir ao nal da execu ca o da fun ca o (ou bloco), elas s ao invis veis para outras fun co es do mesmo programa. O c odigo que dene uma fun ca o e os seus dados s ao particulares da fun ca o (do bloco). No programa 8.2 podemos ver o uso de vari aveis locais. A vari avel i e denida em cada uma das fun co es do programa (pares, impares). Os valores da vari avel n ao podem ser acessados a partir de nenhuma outra fun ca o e as modica co es feitas dentro da fun ca o somente valem enquanto a fun ca o est a sendo executada. Alguns autores usam o termo vari aveis autom aticas para se referir as vari aveis locais. Em C existe a palavra chave auto que pode ser usada para declarar que vari aveis pertencem ` a classe de armazenamento padr ao. No entanto, como todas as vari aveis locais s ao por deni ca o autom aticas raramente se usa esta palavra chave. Observe que um bloco de comandos se inicia em um { e termina em um }. O bloco de comandos, dentro do qual mais comumente se dene 125

Listing 8.2: Exemplos de vari aveis locais.


#i ncl ude < stdio .h > void pares ( void ) { int i; f o r ( i = 2; i <= 10; i += 2) { printf ( " % d : " , i ); } } void impares ( void ) { int i; f o r ( i = 3; i <= 11; i += 2) { printf ( " % d : " , i ); } } i n t main ( i n t argc , char * argv []) { pares (); printf ( " \ n " ); impares (); return 0; }

uma vari avel e a fun ca o. Todas as vari aveis que ser ao usadas dentro de um bloco de comandos precisam ser declaradas antes do primeiro comando do bloco. Declara co es de vari aveis, incluindo sua inicializa ca o, podem vir logo ap os o abre chaves que inicia um bloco de comandos, n ao somente o que come ca uma fun ca o. O programa 8.3 ilustra este tipo de declara ca o. Listing 8.3: Deni ca o de vari avel dentro de um bloco.
#include < stdio .h > i n t main () { int i; f o r ( i =0; i <10; i ++) { i n t t = 2; printf ( " % d \ n " , i * t ); } return 0; }

Existem algumas vantagens em se declarar vari aveis dentro de blocos. Como as vari aveis somente existem durante a execu ca o do bloco, o programa pode ocupar menos espa co de mem oria. Por exemplo, se a execu ca o do bloco for condicional a vari avel pode nem ser alocada. Outra vantagem e que como a vari avel somente existe dentro do bloco, pode-se controlar melhor o uso da vari avel, evitando erros de uso indevido da vari avel.

126

8.5

Vari aveis Globais

As vari aveis globais s ao denidas fora de qualquer fun ca o e s ao portanto dispon veis para qualquer fun ca o. Este tipo de vari avel pode servir como uma canal de comunica ca o entre fun co es, uma maneira de transferir valores entre elas. Por exemplo, se duas fun co es tem de partilhar dados, mais uma n ao chama a outra, uma vari avel global tem de ser usada. O programa 8.4 ilustra este tipo de declara ca o. O resultado da execu ca o deste programa e o seguinte: Funcao soma1: i = 1 Funcao sub1: i = 9 Funcao main: i = 1 Observe que a vari avel global i recebe o valor 0 no in cio da fun ca o main. A fun ca o soma1 ao executar um comando que aumenta o valor de i em uma unidade est a aumentando a vari avel global. Em seguida vemos que a fun ca o sub1 dene uma vari avel local tamb em chamada i e, portanto, a altera ca o feita por esta fun ca o somente modica esta vari avel. Finalmente, a fun ca o main imprime o valor nal da vari avel global. Listing 8.4: Deni ca o de vari avel global.
#i ncl ude < stdio .h > int i; void soma1 ( void ) { i += 1; printf ( " Funcao soma1 : i = % d \ n " , i ); } void sub1 ( void ) { i n t i = 10; i -= 1; printf ( " Funcao sub1 : i = % d \ n " , i ); } i n t main ( i n t argc , char * argv []) { i = 0; soma1 (); sub1 (); printf ( " Funcao main : i = % d \ n " , i ); return 0; }

8.6

Par ametros Formais

As vari aveis que aparecem na lista de par ametros da fun ca o s ao chamadas de par ametros formais da fun ca o. Eles s ao criados no in cio da execu ca o da fun ca o e destru dos no nal. Par ametros s ao valores que as fun co es recebem da fun ca o que a chamou. Portanto, os par ametros permitem que uma fun ca o passe valores

127

para outra. Normalmente os par ametros s ao inicializados durante a chamada da fun ca o, pois para isto foram criados. No entanto, as vari aveis que atuam como par ametros s ao iguais a todas as outras e podem ser modicadas, operadas, etc, sem nenhuma restri ca o. Par ametros podem ser passados para fun co es de duas maneiras: passagem por valor ou passagem por refer encia.

8.6.1

Passagem de Par ametros por Valor

Na passagem por valor uma c opia do valor do argumento e passado para a fun ca o. Neste caso a fun ca o que recebe este valor, ao fazer modica co es no par ametro, n ao estar a alterando o valor original que somente existe na fun ca o que chamou. O exemplo 8.5 mostra o uso de passagem de par ametros por valor. Observe que as fun ca o Eleva recebe dois par ametros (a,b) e opera usando os valores recebidos. O resultado da fun ca o e retornado por meio da vari avel local res. Listing 8.5: Exemplo de passagem por valor.
#include < stdio .h > #include < stdlib .h > f l o a t Eleva ( f l o a t a , i n t b ) { f l o a t res = 1.0; f o r ( ; b >0; b - -) res *= a ; return res ; } i n t main () { f l o a t numero ; i n t potencia ; char linha [80]; puts ( " Entre com um numero " ); gets ( linha ); numero = atof ( linha ); puts ( " Entre com a potencia " ); gets ( linha ); potencia = atoi ( linha ); printf ( " \ n % f Elevado a % d e igual a % f \ n " , numero , potencia , Eleva ( numero , potencia )); return 0; }

Para ilustrar o fato de que somente o valor e passado vamos usar o exemplo 8.6. Neste programa as vari aveis a e b recebem os valores 10 e 20 respectivamente. Na fun ca o trocar estes valores s ao recebidos e s ao trocados localmente. Ap os o retorno da fun ca o, o programa imprime os valores originais das vari aveis, j a que estes n ao sofreram nenhuma altera ca o. O resultado da execu ca o deste programa e o seguinte: a = 10, b = 20 128

Listing 8.6: Uso indevido de vari aveis locais.


#i ncl ude < stdio .h > void trocar ( i n t a , i n t b ) { i n t temp ; temp = a ; a = b ; b = temp ; } i n t main ( i n t argc , char * argv []) { i n t a = 10 , b = 20; trocar (a , b ); printf ( " a = %d , b = % d \ n " , a , b ); return 0; }

8.6.2

Passagem de Par ametros por Refer encia

Na passagem por refer encia o que e passado para a fun ca o e o endere co do par ametro e, portanto, a fun ca o que recebe pode, atrav es do endere co, modicar o valor do argumento diretamente na fun ca o que chamou. Para a passagem de par ametros por refer encia e necess ario o uso de ponteiros. Este assunto ser a discutido no pr oximo cap tulo e portanto, por agora, usaremos somente fun co es com passagem por valor.

8.6.3

Passagem de Vetores e Matrizes

Matrizes s ao um caso especial e exce ca o a regra que par ametros s ao passados sempre por valor. Como veremos mais adiante, o nome de um vetor corresponde ao endere co do primeiro elemento do array, Quando um vetor e passado como par ametro, apenas o endere co do primeiro elemento e passado. Existem basicamente tr es maneiras de declarar um vetor como um par ametro de uma fun ca o. Na primeira ele e declarado como tem sido apresentado em todos os exemplos at e agora. O exemplo 8.7 mostra um programa que usa uma fun ca o para descobrir quantas vezes um caractere ocorre em um vetor. Observe que na deni ca o da fun ca o a dimens ao do vetor foi declarada explicitamente. Uma outra maneira, leva em conta que apenas o endere co do vetor e passado. Neste modo o par ametro e declarado como um vetor sem dimens ao. Isto e perfeitamente poss vel porque a fun ca o somente precisa receber o endere co onde se encontra o vetor. Al em disso C n ao confere limites de vetores e portanto a fun ca o precisa do endere co inicial do vetor e uma maneira de descobrir o nal do vetor. Esta maneira pode ser, por exemplo, uma constante, ou o caractere \0 em um vetor de caracteres. O exemplo 8.8 mostra este modo de passar vetores com um programa que inverte o conte udo de um vetor. A terceira maneira de passagem de par ametros implica no uso de ponteiros, o que somente iremos ver no pr oximo cap tulo.

129

Listing 8.7: Passagem de vetor com dimens oes.


#include < stdio .h > #include < conio .h > #de fi ne DIM 80 char conta ( char v [] , char c ); i n t main () { char c , linha [ DIM ]; i n t maiusculas [26] , minusculas [26]; puts ( " Entre com uma linha " ); gets ( linha ); f o r ( c = a ; c <= z ; c ++) minusculas [c - a ] = conta ( linha , c ); f o r ( c = A ; c <= Z ; c ++) maiusculas [c - A ] = conta ( linha , c ); f o r ( c = a ; c <= z ; c ++) i f ( minusculas [c - a ]) printf ( " % c apareceu % d vezes \ n " , c , minusculas [c - a ]); f o r ( c = A ; c <= Z ; c ++) i f ( maiusculas [c - A ]) printf ( " % c apareceu % d vezes \ n " , c , maiusculas [c - A ]); return 0; } char conta ( char v [ DIM ] , char c ) { i n t i =0 , vezes =0; while ( v [ i ] != \0 ) i f ( v [ i ++] == c ) vezes ++; return vezes ; }

130

Listing 8.8: Passagem de vetores sem dimens oes.


#include < stdio .h > #include < conio .h > #de fi ne DIM 6 void Le_vetor ( i n t v [] , i n t tam ); void Imprime_vetor ( i n t v [] , i n t tam ); void Inverte_vetor ( i n t v [] , i n t tam ); i n t main () { i n t v [ DIM ]; Le_vetor (v , DIM ); Imprime_vetor (v , DIM ); Inverte_vetor (v , DIM ); Imprime_vetor (v , DIM ); return 0; } void Le_vetor ( i n t v [] , i n t tam ) { int i; f o r ( i = 0; i < tam ; i ++) { printf ( " % d = ? " , i ); scanf ( " % d " , & v [ i ]); } } void Imprime_vetor ( i n t v [] , i n t tam ) { int i; f o r ( i = 0; i < tam ; i ++) printf ( " % d = % d \ n " , i , v [ i ]); } void Inverte_vetor ( i n t v [] , i n t tam ) { i n t i , temp ; f o r ( i = 0; i < tam /2; i ++){ temp = v [ i ]; v [ i ] = v [ tam -i -1]; v [ tam -i -1] = temp ; } }

131

8.7

O Comando return

O comando return e usado para retornar o valor calculado para a fun ca o que chamou. Qualquer express ao pode aparecer no comando, que tem a a seguinte forma geral:
return express~ ao

A fun ca o que chamou e livre para ignorar o valor retornado. Al em disso a fun ca o pode n ao conter o comando e portanto nenhum valor e retornado e neste caso a fun ca o termina quando o u ltimo comando da fun ca o e executado. Quando o comando return n ao existe o valor de retorno e considerado indenido. As fun co es que n ao retornam valores devem ser declaradas como do tipo void. E importante observar que fun co es que s ao declaradas com um tipo v alido podem ser inclu das em qualquer express ao v alida em C.

8.8

Recurs ao

Fun co es em C podem ser usadas recursivamente, isto e uma fun ca o pode chamar como se procur a si mesmo. E assemos no dicion ario a deni ca o da palavra recurs ao e encontr assemos o seguinte texto: recurs ao: s.f. Veja a deni ca o em recurs ao Um exemplo simples de fun ca o que pode ser escrita com chamadas recursivas e o fatorial de um n umero inteiro. O fatorial de um n umero, sem recurs ao, e denido como n! = n (n 1) (n 2) 2 1 A partir desta deni ca o podemos escrever a fun ca o fatorial como
unsigned long i n t fat ( unsigned long i n t num ) { unsigned long i n t fato =1 , i ; f o r ( i = num ; i >1; i - -) fato = fato * i ; return fato ; }

Alternativamente, o fatorial pode ser denido como o produto deste n umero pelo fatorial de seu predecessor, ou seja n! = n (n 1)! Deste modo podemos escrever uma fun ca o recursiva em que cada chamada da fun ca o que calcula o fatorial chama a pr opria fun ca o fatorial. O exemplo, mostrado a seguir, mostra como a fun ca o pode ser escrita recursivamente.
unsigned long i n t fat ( unsigned long i n t num ) { i f ( num == 0) return 1; lese

132

return num * fat ( num -1); }

Quando a fun ca o fatorial recursiva e chamada, primeiro e vericado se o n umero recebido como par ametro vale 0 e neste caso a fun ca o retorna o valor 1. No caso contr ario ela devolve o valor da express ao num * fat(num-1), ou seja o produto do n umero pelo valor do fatorial do n umero predecessor. Ou seja para retornar um valor a fun ca o precisa chamar ela mesma passando como par ametro o valor do n umero menos 1. Este processo continua se repetindo at e que o valor passado e igual a 0, o que indica o nal da recurs ao. Neste ponto o processo se reverte e as chamadas come cam a ser respondidas. Um ponto importante e que toda fun ca o recursiva deve prever cuidadosamente como o processo de recurs ao deve ser interrompido. No caso da fun ca o fat o processo e interrompido quando o valor do n umero passado como par ametro vale 0. Se este teste n ao tivesse sido inclu do na fun ca o as chamadas continuariam indenidamente com valores negativos cada vez menores sendo passados como par ametro. Quando uma fun ca o chama a si mesmo recursivamente ela recebe um conjunto novo de vari aveis na pilha que e usada para transfer encia de valores entre importante notar que recurs fun co es. E ao n ao traz obrigatoriamente economia de mem oria porque os valores sendo processados tem de ser mantidos em pilhas. Nem ser a mais r apido, e as vezes pode ser at e mais lento porque temos o custo de chamada as fun co es. As principais vantagens da recurs ao s ao c odigos mais compactos e provavelmente mais f aceis de serem lidos. Um outro exemplo simples de fun ca o que pode ser resolvida por recurs ao e xn , assumindo que n 0. Esta fun ca o pode escrita na sua forma recursiva como xn = x x(n1) que nos leva a escrever a fun ca o da maneira mostrada no exemplo 8.9. Na fun ca o consideramos que x e do tipo oat . Listing 8.9: Fun ca o recursiva para calcular xn .
f l o a t Elevar ( f l o a t x , i n t n ) { i f ( n <= 1) { return x ; } else { return x * Elevar (x , b -1); } }

8.9

Argumentos - argc e argv

A fun ca o main como todas as fun co es podem ter par ametros. Como a fun ca o main e sempre a primeira a ser executada, os par ametros que ela recebe s ao fornecidos

133

pela linha de comando ou pelo programa que iniciou a sua execu ca o. No caso da fun ca o main s ao usados dois argumentos especiais int argc e char **argv. O primeiro argumento, argc, e uma vari avel inteira que indica quantos argumentos foram fornecidos para a fun ca o. Observar que argc vale sempre pelo menos 1, porque o nome do programa e sempre o primeiro argumento fornecido ao programa. A partir do segundo argumento em diante e que aparecem os outros argumentos. O outro par ametro e um vetor de cadeias de caracteres, e portanto, caso sejam fornecidos n umeros, estes devem ser convertidos para o formato requerido. Cada um dos argumentos do programa e um elemento deste vetor. A primeira linha da fun ca o main pode ter a seguinte forma
void main (int argc, char *argv[])

O programa exemplo 8.10 calcula o fatorial dos n umeros fornecidos como argumentos. Listing 8.10: Uso de argc e argv.
#i ncl ude < stdio .h > #i ncl ude < stdlib .h > unsigned long i n t fat ( unsigned long i n t num ) { i f ( num == 0) return 1; else return num * fat ( num -1); } i n t main ( i n t argc , char * argv []) { unsigned long i n t numero , fatorial , i ; i f ( argc < 2) { printf ( " Para rodar : % s num1 num2 ... .\ n " , argv [0]); return 1; } f o r ( i =1; i < argc ; i ++) { numero = ( unsigned long i n t ) ( atoi ( argv [ i ])); fatorial = fat ( numero ); printf ( " O fatorial de % lu vale % lu .\ n " , numero , fatorial ); } return 0; }

Os nomes argc e argv s ao comumente usados mas o programador e livre para escolher os nomes mais apropriados.

134

8.10

Exerc cios

8.1: Escrever um programa que declare, inicialize e imprima um vetor de 10 inteiros. O vetor deve conter os 10 primeiros m ultiplos de 5. A inicializa ca o do vetor e a sua impress ao devem ser feitas por fun co es. 8.2: Escreva um programa para declarar um vetor de caracteres de tamanho 26 e imprimir o seu conte udo. O vetor deve ser inicializado com as letras min usculas do alfabeto. A inicializa ca o do vetor e a sua impress ao devem ser feitas por fun co es. 8.3: Escreva um programa que armazene em uma matriz tr es nomes de pessoas e em seguida os imprima. Assuma que o tamanho m aximo de cada nome e 40 caracteres. Neste programa a leitura dos nomes dever ser feita por uma fun ca o e a impress ao dos nomes por outra. 8.4: Escreva um programa que imprima o c odigo ASCII de todos os caracteres, das seguintes maneiras: 1. caractere a caractere, a escolha do usu ario; 2. a tabela inteira, a partir de um determinado valor decimal. Cada item deste exerc cio deve corresponder a uma fun ca o. 8.5: Escreva um programa que crie uma tabela de temperaturas Celsius Fahrenheit. O programa deve usar uma fun ca o que converta de Celsius para Fahrenheit. A tabela deve iniciar na temperatura 0 graus Celsius e terminar na temperatura 100 graus Celsius. 8.6: Escreva um programa, usando fun co es, que gere um vetor a partir de uma matriz. Cada elemento do vetor e igual a soma dos elementos de uma das linhas da matriz. Considere que a matriz tenha tamanho 10 por 10. 8.7: Escreva um programa usando recursividade para gerar a seq u encia do Fibonacci. A seq u encia de Fibonacci e denida como: f (0) = f (1) = f (n) = 0 1 f (n 1) + f (n 2)

O programa deve ler um numero e exibir o valor dele na seq u encia de Fibonacci. Exemplos de entrada e sa da do programa s ao mostrados abaixo. Entre com um numero inteiro: 0 Fibonacci (0) = 0 Entre com um numero inteiro: 1 Fibonacci (1) = 1 Entre com um numero inteiro: 2 Fibonacci (2) = 1 Entre com um numero inteiro: 3 Fibonacci (3) = 2 135

Entre com um numero inteiro: Fibonacci (6) = 8

8.8: O que o programa mostrado na listagem 8.11 imprime, caso sejam fornecidos os valores 48 e 256. Justique a sua resposta. Listing 8.11: Programa do exerc cio 8.
#include < stdio .h > #de fi ne MAX 1000 i n t abc ( i n t x , i n t y ) { printf ( " % d % d \ n " , x , y ); i f ( y == 0) { return x ; } else { return abc (y , x % y ); } } i n t main ( void ) { int a, b; scanf ( " % d % d " , &a , & b ); printf ( " % d \ n " , abc (a , b )); return 0; }

8.9: O programa mostrado na listagem 8.12 converte cadeias de caracteres contendo n umeros na base 16 para a base 10. Neste programa est a faltando um trecho. A sua tarefa e completar o trecho que est a faltando. Listing 8.12: Programa do problema 9.
#include < stdio .h > #include < string .h > #include < stdlib .h > i n t fromHexatoD ec i ma l ( char c []); i n t toNumero ( char ); char toLower ( char ); i n t main ( void ) { char numeroC [80]; fgets ( numeroC , 80 , stdin ); while (! feof ( stdin )) { numeroC [ strlen ( numeroC ) -1] = \0 ; printf ( " % s = % d \ n " , numeroC , fromHexato De c im al ( numeroC )); fgets ( numeroC , 80 , stdin ); } return 0; } i n t fromHexatoD ec i ma l ( char numeroC []) { /* Aqui falta codigo */ }

136

char toLower ( char c ) { i f ( c >= A && c <= Z ) { c = c - A + a ; } return c ; } i n t toNumero ( char c ) { i n t resultado ; i f ( c >= 0 && c <= 9 ) { resultado = c - 0 ; } e l s e i f ( toLower ( c ) >= a && toLower ( c ) <= f ) { resultado = toLower ( c ) - a + 10; } return resultado ; }

137

Cap tulo 9

Ponteiros
9.1 Introdu c ao

Ponteiros s ao usados em situa co es em que e necess ario conhecer o endere co onde est a armazenada a vari avel e n ao o seu conte udo. Um ponteiro e uma vari avel que cont em um endere co de uma posi ca o de mem oria e n ao o conte udo da posi ca o. A mem oria de um computador pode ser vista como uma seq u encia de bytes cada um com seu pr oprio e u nico endere co. N ao h a dois bytes com o mesmo endere co. O primeiro endere co e sempre 0 e o u ltimo geralmente e uma pot encia de 2. Por exemplo um computador com mem oria igual a 512 Mbytes tem 512x1024x1024 bytes. A Figura 9.1 mostra o mapa de um trecho de mem oria que cont em duas vari aveis inteiras (num, res) ocupando 4 bytes cada uma e mais um ponteiro (pint), que tamb em ocupa 4 bytes. Observar que os endere cos est ao pulando de quatro em quatro bytes devido ao espa co que cada um destas vari aveis ocupa.
0 4 8 12 16 10 120 num res *pint

Figura 9.1: Mapa de mem oria com duas vari aveis e ponteiro. Ponteiros s ao importantes, por exemplo, quando se deseja que uma fun ca o retorne mais de um valor. Neste caso uma solu ca o e a fun ca o receber como argumentos n ao os valores dos par ametros mas sim ponteiros que apontem para seus endere cos. Assim esta fun ca o pode modicar diretamente os conte udos 138

destas vari aveis, que ap os o m da fun ca o estar ao dispon veis para a fun ca o que chamou. Neste caso os argumentos podem funcionar como entrada e sa da de dados da fun ca o. Uma outra aplica ca o importante de ponteiros e apontar para areas de mem oria que devem ser gerenciadas durante a execu ca o do programa. Com ponteiros, e poss vel reservar as posi co es de mem oria necess arias para armazenamento destas areas somente quando for necess ario e n ao quando as vari aveis s ao declaradas. Neste esquema o programador pode reservar o n umero exato de posi co es que o programa requer. A Figura 9.2 ilustra como um ponteiro faz refer encia para uma area de mem oria. Na gura a vari avel ponteiro pi aponta para a area de mem oria que cont em um vetor de 10 inteiros. Com ponteiros, o programador precisa, no in cio, denir a vari avel ponteiro e seu tipo. Durante a execu ca o do programa, ap os descobrir o tamanho do vetor, reserva a area necess aria para guardar os dados. Observe a diferen ca do que ocorre quando se usa vetores de tamanho xo. Neste caso a deni ca o do tamanho do vetor e dada na declara ca o do vetor e e mantida at e o nal da execu ca o do programa.
0 4 8 1000 pi ponteiro para vetor

1000

120 Vetor de 10 inteiros

1036

97

Figura 9.2: Ponteiro apontando para area de mem oria contendo vetor.

9.2
9.2.1

Opera c oes com Ponteiros


Declara c ao de Ponteiros

Antes de serem usados os ponteiros, como as vari aveis, precisam ser declarados. A forma geral da declara ca o de um ponteiro e a seguinte: tipo *nome; Onde tipo e qualquer tipo v alido em C e nome e o nome da vari avel ponteiro. Por exemplo:
i n t * res ; /* ponteiro para inteiro */ f l o a t * div ; /* ponteiro para ponto flutuante */

139

Como as vari aveis, os ponteiros devem ser inicializados antes de serem usados. Esta inicializa ca o pode ser feita na declara ca o ou atrav es de uma atribui ca o. Ap os a declara ca o o que temos e um espa co na mem oria reservado para armazenamento de endere cos. O valor inicial da mem oria e indenido como acontece com vari aveis. A Figura 9.3 ilustra esta situa ca o. Um ponteiro pode ser inicializado com um endere co ou com o valor NULL. O valor NULL, que e equivalente a 0, e uma constante denida no arquivo <stdio.h> e signica que o ponteiro n ao aponta para lugar nenhum. A atribui ca o de inteiros a ponteiros n ao faz sentido a n ao ser em aplica co es muito especiais e o u nico valor inteiro que se pode atribuir a um ponteiro e o 0. Esta tipo de atribui ca o n ao faz sentido porque na maioria das aplica co es e o sistema operacional que aloca e gerencia a posi ca o dos programas na mem oria e, portanto, o usu ario n ao tem controle sobre estes endere cos.
996

1000

endereo indefinido

*res

1004

endereo indefinido

*div

Figura 9.3: Declara ca o de ponteiros.

9.2.2

Os Operadores Especiais para Ponteiros

Existem dois operadores especiais para ponteiros: * e &. Os dois operadores s ao un arios, isto e requerem somente um operando. O operador & devolve o endere co de mem oria do seu operando. Considere a Figura 9.1. Ap os a execu ca o da instru ca o
pint = &num; /*o endereco de num e carregado em pint */

a vari avel ponteiro pint termina com o valor 4, como est a mostrado na Figura 9.4. Lembre-se que o valor 4 n ao tem sentido pr atico na maioria das aplica co es. O fato importante e que o ponteiro pint passou a apontar para a vari avel num O operador * e o complemento de &. O operador * devolve o valor da vari avel localizada no endere co apontado pelo ponteiro. Por exemplo, considere que o comando res = *pint; foi executado logo ap os pint = &num;. Isto signica que a vari avel res recebe o valor apontado por pint, ou seja a vari avel res recebe o valor 10, como est a mostrado na Figura 9.5.

140

0 4 8 12 16 10 120 4 num res *pint

Figura 9.4: Atribui ca o de endere co de uma vari avel a um ponteiro.

0 4 8 12 16 10 120 10 4 num res = *pint *pint

Figura 9.5: Uso de um ponteiro para copiar valor de uma vari avel.

Estes operadores n ao devem ser confundidos com os j a estudados em cap tulos anteriores. O operador * para ponteiros n ao tem nada a ver com o operador multiplica ca o *. O operador ponteiro * e un ario e, como o operador &, tem preced encia maior que do que todos os operadores aritm eticos.

9.2.3

Atribui c ao de Ponteiros

Da mesma maneira que ocorre com uma vari avel comum, o conte udo de um ponteiro pode ser passado para outro ponteiro do mesmo tipo. Por exemplo, uma vari avel ponteiro declarada como apontador de dados inteiros deve sempre apontar para dados deste tipo. Observar que em C e poss vel atribuir qualquer endere co a uma vari avel ponteiro. Deste modo e poss vel atribuir o endere co de uma vari avel do tipo oat a um ponteiro do tipo int. No entanto, o programa n ao ir a funcionar da maneira correta. O programa 9.1 mostra exemplos de atribui co es de ponteiros. Neste exemplo o endere co do terceiro elemento do vetor v e carregado em p1 e o endere co da vari avel i e carregado em p2. A Figura 9.6 a situa ca o da mem oria ap os estas opera co es. Al em disso no nal o endere co apontado por p1 e carregado em p2. Os comandos printf imprimem os valores apontados pelos ponteiros respectivos, mostrando os seguintes valores:

141

30 100 30 Listing 9.1: Exemplo de atribui ca o de ponteiros.


#i ncl ude < stdio .h > i n t main ( void ) { i n t vetor [] = { 10 , 20 , 30 , 40 , 50 }; i n t * p1 , * p2 ; i n t i = 100; p1 = & vetor [2]; printf ( " % d \ n " , * p1 ); p2 = & i ; printf ( " % d \ n " , * p2 ); p2 = p1 ; printf ( " % d \ n " , * p2 ); return 0; }

0 4 8 12 16 20 24 28 32 10 20 30 40 50 12 32 100 v[0] v[1] v[2] v[3] v[4] *p1 *p2 p2 = &i; i p1 = &v[2];

Figura 9.6: Exemplos de atribui co es de ponteiros.

9.2.4

Incrementando e Decrementando Ponteiros

O exemplo 9.2 mostra que opera co es de incremento e decremento podem ser aplicadas em operandos. O primeiro printf imprime 30, que e o elemento de ndice igual a 2 no vetor vetor. Ap os o incremento do ponteiro o segundo printf imprime 40 e o mesmo acontece com o terceiro printf que imprime 50. Pode parecer estranho que um ponteiro para um n umero inteiro, que e armazenado em quatro bytes, seja incrementado por um e passe para apontar para 142

Listing 9.2: Exemplos de opera co es com ponteiros.


i n t main ( void ) { i n t vetor [] = { 10 , 20 , 30 , 40 , 50 }; i n t * p1 ; p1 = & vetor [2]; printf ( " % d \ n " , * p1 ); p1 ++; printf ( " % d \ n " , * p1 ); p1 = p1 + 1; printf ( " % d \ n " , * p1 ); return 0; }

o pr oximo n umero inteiro. A primeira vista, para que passasse a apontar para o pr oximo endere co, seria necess ario aumentar o endere co em quatro. Ou seja, sempre que um ponteiro e incrementado (decrementado) ele passa a apontar para a posi ca o do elemento seguinte (anterior). O compilador interpreta o comando p1++ como: passe a apontar para o pr oximo n umero inteiro e, portanto, aumenta o endere co do n umero de bytes correto. Este ajuste e feito de acordo com o tipo do operando que o ponteiro est a apontando. Do mesmo modo, somar tr es a um ponteiro faz com que ele passe apontar para o terceiro elemento ap os o atual. Portanto, um incremento em um ponteiro que aponta para um valor que ent e armazenado em n bytes faz que n seja somado ao endere co. E ao poss vel somar-se e subtrair-se inteiros de ponteiros. A opera ca o abaixo faz com que o ponteiro p passe a apontar para o terceiro elemento ap os o atual.
p = p + 3;

Tamb em e poss vel usar-se o seguinte comando


*(p+1)=10;

Este comando armazena o valor 10 na posi ca o seguinte ` aquela apontada por


p. A opera ca o e realizada nos seguintes passos:

1. A express ao p+1 e calculada e o seu resultado aponta para o pr oximo endere co de dado inteiro; 2. A express ao do lado direito do sinal de atribui ca o, e calculada e fornece como resultado o valor 10; 3. Este resultado e atribu do ao endere co calculado no primeiro passo. A diferen ca entre ponteiros fornece quantos elementos do tipo do ponteiro existem entre os dois ponteiros. No exemplo 9.3 e impresso o valor 2. N ao e poss vel multiplicar ou dividir ponteiros, e n ao se pode adicionar ou subtrair o tipo oat ou o tipo double a ponteiros.

143

Listing 9.3: Exemplo de subtra ca o de ponteiros.


#i ncl ude < stdio .h > i n t main ( void ) { f l o a t vetor [] = { 1.0 , 2.0 , 3.0 , 4.0 , 5.0 }; f l o a t * p1 , * p2 ; p1 = & vetor [2]; /* endereco do terceiro elemento */ p2 = vetor ; /* endereco do primeiro elemento */ printf ( " Diferenca entre ponteiros % d \ n " , p1 - p2 ); return 0; }

9.2.5

Compara c ao de Ponteiros

poss E vel comparar ponteiros em uma express ao relacional. No entanto, s o e poss vel comparar ponteiros de mesmo tipo. O Programa 9.4 ilustra um exemplo deste tipo de opera ca o. Listing 9.4: Exemplo de compara ca o de ponteiros.
#include < stdio .h > i n t main ( void ) { char *c , *v , a , b ; scanf ( " % c % c " , &a , & b ); c = &a; v = &b; i f ( c == v ) printf ( " As vari a veis estao na mesma posicao . " ); else printf ( " As variaveis nao estao na mesma posicao . " ); return 0; }

9.3

Ponteiros e Vetores

Ponteiros e Vetores est ao fortemente relacionados na linguagem C. O nome de um vetor e um ponteiro que aponta para a primeira posi ca o do vetor. A declara ca o int vetor[100] cria um vetor de inteiros de 100 posi co es e permite que algumas opera co es com ponteiros possam ser realizadas com a vari avel vetor. No entanto, existe uma diferen ca fundamental entre declarar um conjunto de dados como um vetor ou atrav es de um ponteiro. Na declara c ao de vetor, o compilador automaticamente reserva um bloco de mem oria para que o vetor seja armazenado. Quando apenas um ponteiro e declarado a u nica coisa que

144

o compilador faz e alocar um ponteiro para apontar para a mem oria, sem que espa co seja reservado. O nome de um vetor e chamado de ponteiro constante e, portanto, n ao pode ter o seu valor alterado. O nome de um ponteiro constante n ao pode aparecer em express oes no lado esquerdo do sinal de igual, ou seja, n ao pode receber valores diferentes do valor inicial atribu do na declara ca o da vari avel. Assim, os comandos que alteram o ponteiro list, mostrados no exemplo 9.5, n ao s ao v alidos: Listing 9.5: Exemplo de altera co es inv alidas sobre ponteiros.
i n t list [5] , i ; /* O ponteiro list nao pode ser modificado recebendo o endereco de i */ list = & i /* O ponteiro list nao pode ser incrementado */ list ++;

O conte udo de vetores pode ser acessado usando-se o operador * para obter o conte udo do vetor. O Programa 9.6 mostra a nota ca o que usa ndices para buscar o elemento de um vetor e o uso do operador * de ponteiros. Neste programa o conte udo do vetor e impresso usando-se estas duas nota co es. Listing 9.6: Exemplo de nota co es de vetores.
#include < stdio .h > i n t main ( void ) { f l o a t v [] = {1.0 , 2.0 , 3.0 , 4.0 , 5.0 , 6.0 , 7.0}; int i; f o r ( i = 0; i < 7; i ++) printf ( " %.1 f " , v [ i ]); printf ( " \ n " ); f o r ( i = 0; i < 7; i ++) printf ( " %.1 f " , *( v + i )); return 0; }

Para percorrer um vetor al em da maneira mostrada no programa 9.6 e poss vel usar um ponteiro vari avel como ilustrado no Programa 9.7. Observe como o ponteiro p recebe seu valor inicial e a maneira como ele e incrementado.

9.4

Ponteiros e Cadeias de Caracteres

Uma cadeia de caracteres constante e escrita como no exemplo:


"Esta e uma cadeia de caracteres."

At e agora um dos usos mais comuns de cadeias de caracteres constantes tem sido na fun ca o printf, como no exemplo abaixo
printf("Acabou o programa.\n");

145

Listing 9.7: Exemplo de ponteiro vari avel.


#i ncl ude < stdio .h > i n t main ( void ) { f l o a t v [] = {1.0 , 2.0 , 3.0 , 4.0 , 5.0 , 6.0 , 7.0}; int i; fl oat *p; f o r ( i = 0; i < 7; i ++) printf ( " %.1 f " , v [ i ]); printf ( " \ n " ); f o r ( i = 0; i < 7; i ++) printf ( " %.1 f " , *( v + i )); printf ( " \ n " ); f o r ( i = 0 , p = v ; i < 7; i ++ , p ++) printf ( " %.1 f " , * p ); return 0; }

Quando uma cadeia de caracteres como esta e enviada para a fun ca o, o que poss e passado e o ponteiro para a cadeia. E vel ent ao carregar o endere co da cadeia em um ponteiro do tipo char, como no exemplo 9.8. Neste programa e contado o n umero de caracteres de uma cadeia. Observe o ponteiro *(s+tam++) apontando caractere a caractere. Listing 9.8: Exemplo de ponteiro para cadeia de caracteres.
#i ncl ude < stdio .h > i n t main ( void ) { char *s , * lista = " 1234567890 " ; i n t tam =0; s = lista ; while (*( s + tam ++) != \0 ); tam - -; printf ( " O tamanho do string \"% s \" e % d caracteres .\ n " , lista , tam ); return 0; }

Um outro exemplo (Programa 9.9) mostra uma fun ca o que copia um cadeia de caracteres para outra.

9.5

Aloca c ao Din amica de Mem oria

O uso de ponteiros e vetores exige que ap os a deni ca o da vari avel ponteiro uma area de mem oria deve ser reservada para armazenar os dados do vetor. Para obter esta area o programa deve usar fun co es existentes na biblioteca stdlib. Estas fun co es pedem ao sistema operacional para separar peda cos da mem oria e devolvem ao programa que pediu o endere co inicial deste local. As fun co es b asicas de aloca ca o de mem oria que iremos discutir s ao:
void *malloc(size_t size); Reserva espa co na mem oria para algum item

146

Listing 9.9: Exemplo de c opia de cadeias de caracteres.


#include < stdio .h > i n t strcop ( char *d , char * o ); i n t main ( void ) { char destino [20]; char * origem = " cadeia de caractere de origem " ; strcop ( destino , origem ); printf ( " % s \ n " , origem ); printf ( " % s \ n " , destino ); return 0; } i n t strcop ( char *d , char * o ) { while ((* d ++ = * o ++) != \0 ); return 0; }

de um programa. O tamanho em bytes reservado e denido pela vari avel size. O valor armazenado no espa co e indenido. A fun ca o retorna um ponteiro de tipo void para o espa co reservado ou NULL no caso de algum erro ocorrer.
void *calloc(size_t num, size_t size); Reserva espa co na mem oria para um vetor de num itens do programa. Cada item tem tamanho size e todos os bits do espa co s ao inicializados com 0. A fun ca o retorna um ponteiro de tipo void para o espa co reservado ou NULL no caso de algum erro ocorrer. void free(void *pont); O espa co apontado por pont e devolvido ao sistema para uso. Caso pont seja um ponteiro nulo nenhuma a ca o e executada. No caso do ponteiro n ao ter sido resultado de uma reserva feita por meio de uma das fun co es calloc, realloc ou malloc o resultado e indenido. void realloc(void *pont, size_t size); A fun ca o altera o tamanho do objeto na mem oria apontado por pont para o tamanho especicado por size. O conte udo do objeto ser a mantido at e um tamanho igual ao menor dos dois tamanhos, novo e antigo. Se o novo tamanho requerer movimento, o espa co reservado anteriormente e liberado. Caso o novo tamanho for maior, o conte udo da por ca o de mem oria reservada a mais car a com um valor sem especica ca o. Se o tamanho size for igual a 0 e pont n ao e um ponteiro nulo o objeto previamente reservado e liberado.

Estas fun co es podem ser encontradas na biblioteca stdlib.h. O Programa 9.10 ilustra o uso das fun ca o calloc e free. Um outro exemplo, agora empregando a fun ca o malloc() est a mostrado no Programa 9.11. Observe que neste programa tamb em mostramos exemplos onde um endere co de vari avel foi passado para uma fun ca o de modo que a fun ca o main possa receber um valor (vezes).

9.6

Ponteiros e Matrizes

Um ponteiro aponta para uma area de mem oria que e endere cada de maneira linear. Portanto, vetores podem ser facilmente manipulados com ponteiros. No 147

Listing 9.10: Exemplo de uso de calloc e free.


#i ncl ude < stdio .h > #i ncl ude < stdlib .h > i n t main ( void ) { fl oat *v; i n t i , tam ; printf ( " Qual o tamanho do vetor ? " ); scanf ( " % d " , & tam ); v = calloc ( tam , s i z e o f ( f l o a t )); i f (! v ) { printf ( " Nao consegui alocar memoria . " ); return 1; } f o r ( i =0; i < tam ; i ++) { printf ( " Elemento % d ? " , i ); scanf ( " % f " , v + i ); printf ( " Li valor % f \ n " , *( v + i )); } free ( v ); return 0; }

entanto, quando usamos estruturas de dados com maior dimensionalidade, como matrizes, por exemplo, que s ao arranjos bidimensionais de dados, e necess ario mapear o espa co bidimensional (ou de maior ordem) para uma dimens ao. No caso das matrizes e necess ario mapear o endere co de cada elemento na matriz, que e denido por um par (linha, coluna) em um endere co linear. Considere uma matriz chamada matriz de tamanho LIN,COL que poderia ser declarada e ter um de seus elementos lidos da maneira mostrada no trecho de programa listado em 9.12. Caso o programa utilizasse ponteiros ao inv es de nota ca o de matrizes, poder amos usar uma solu ca o que mapeasse a matriz que e um objeto de duas dimens oes em um vetor que tem apenas uma. Neste caso o programa deve fazer a transla ca o de endere cos toda vez que precisar ler ou escrever na matriz. O trecho de programa caria como mostrado no exemplo 9.13. A express ao matriz+(i*COL+j) calcula a posi ca o do elemento matriz[i][j] a partir do primeiro elemento da matriz que est a no endere co inicial matriz. No entanto, esta solu ca o ainda n ao e a melhor j a que o usu ario necessita escrever diretamente uma express ao para mapear o endere co bidimensional da matriz matriz[i][j] em um endere co linear. O ideal e usar uma nota ca o que use somente ponteiros. Esta nota ca o ser a discutida nas se co es seguintes.

9.7

Vetores de Ponteiros

Uma possibilidade mais interessante e utilizar vetores de ponteiros. Esta n ao e a nota ca o ideal, mas e um passo na dire ca o da nota ca o mais efetiva. Neste caso cada linha da matriz corresponde a um vetor que e apontado por um ponteiro armazenado no vetor de ponteiros. Como ponteiros tamb em s ao vari aveis e

148

Listing 9.11: Exemplo de uso de malloc.


#i ncl ude < stdio .h > #i ncl ude < stdlib .h > void LeVetor ( f l o a t *v , i n t tam ); float ProcuraMaior ( f l o a t *v , i n t tam , i n t * vezes ); i n t main ( void ) { f l o a t *v , maior ; i n t i , tam , vezes ; printf ( " Qual o tamanho do vetor ? " ); scanf ( " % d " , & tam ); v = ( f l o a t *) malloc ( tam * s i z e o f ( f l o a t )); i f (v) { LeVetor (v , tam ); maior = ProcuraMaior (v , tam , & vezes ); printf ( Maior = % f e aparece % d vezes .\ n . " , maior , vezes ); free ( v ); } else { printf ( " Nao consegui alocar memoria . " ); return 1; } return 0; } void LeVetor ( float *v , int tam ) { int i ; for ( i =0; i < tam ; i ++) { printf ( " Elemento % d ? " , i ); scanf ( " % f " , v + i ); printf ( " Li valor % f \ n " , *( v + i )); } } float ProcuraMaior ( float *v , int tam , int * vezes ) { int i ; float maior ; maior = v [0]; * vezes = 1; for ( i =1; i < tam ; i ++) { if ( v [ i ] & gt ; maior ) { maior = v [ i ]; * vezes = 1; } else if ( maior == v [ i ]) * vezes =* vezes +1; } return maior ; }

149

Listing 9.12: Exemplo de matriz normal sem uso de ponteiros.


#de fi ne LIN 3 #de fi ne COL 4 i n t matriz [ LIN ][ COL ]; f o r ( i =0; i < LIN ; i ++) { f o r ( j =0; j < COL ; j ++) { printf ( " Elemento % d % d = " , i , j ); scanf ( " % d " , & matriz [ i ][ j ]); } }

Listing 9.13: Exemplo de matriz mapeada em um vetor.


#de fi ne LIN 3 #de fi ne COL 4 i n t * matriz ; int i, j; matriz = malloc ( LIN * COL * s i z e o f ( i n t )); i f (! matriz ) { printf ( " Erro .\ n " ); return 1; } f o r ( i = 0; i < LIN ; i ++) { f o r ( j = 0; j < COL ; j ++) { printf ( " Elemento % d % d = " , i , j ); scanf ( " % d " , matriz +( i * COL + j )); } }

150

poss vel ent ao criar vetores de ponteiros e utiliz a-los. O exemplo mostrado em 9.14 mostra um programa onde e utilizado um vetor de ponteiros para v arias linhas de caracteres. Observe na fun ca o main a declara ca o char *linha[LINHAS]; que dene um vetor de tamanho LINHAS. Este vetor contem ponteiros e n ao valores. At e este momento do programa temos apenas posi co es reservadas para armazenar ponteiros. A aloca ca o de espa co e a inicializa ca o dos ponteiros e feito no primeiro comando for. Como cada elemento do vetor linha e um ponteiro temos que o endere co retornado pela fun ca o malloc e armazenado em cada um dos elementos deste vetor. A leitura das linhas de caracteres e feita pela fun ca o gets(linha[i]) que passa o elemento do vetor onde os caracteres ser ao armazenados. Listing 9.14: Exemplo de uso de vetor de ponteiros.
#include < stdio .h > #include < stdlib .h > #de fi ne LINHAS 10 #de fi ne COLUNAS 60 i n t main ( void ) { char * linha [ LINHAS ]; int i; f o r ( i = 0; i < LINHAS ; i ++) { i f (!( linha [ i ] = malloc ( COLUNAS * s i z e o f ( char )))) { printf ( " Sem mem o ria para vetor % d .\ n " , i ); return i ; } } f o r ( i = 0; i < LINHAS ; i ++) { printf ( " Entre com a linha % d .\ n " , i ); gets ( linha [ i ]); } f o r ( i = 0; i < LINHAS ; i ++) { printf ( " Linha % d % s .\ n " , i , linha [ i ]); } return 0; }

9.8

Ponteiros para Ponteiros

No exemplo anterior podemos observar que o n umero de linhas da matriz e xa, e portanto, h a uma mistura de nota ca o de ponteiros com matrizes. Vamos considerar um exemplo onde tanto o n umero de linhas como o de colunas e desconhecido. Neste exemplo iremos criar um vetor de ponteiros que ir a armazenar o endere co inicial de cada linha. Portanto, para obter um elemento da matriz primeiro devemos descobrir onde est a a linha no vetor que armazena os

151

endere cos das linhas, em seguida procuramos na linha o elemento. A Figura 9.7 ilustra como ser a feito o armazenamento desta matriz.
Vetor de ponteiros **matriz *(matriz+0) *(matriz+1) *(matriz+2) linha 2 linha 1 linha 0

*(matriz+n) linha n

Figura 9.7: Armazenamento de matrizes com vetores de ponteiros.

O Programa 9.15, listado a seguir, ir a pedir ao usu ario que digite o n umero de linhas e colunas da matriz. Em seguida ler a todos os elementos da matriz e por u ltimo ir a trocar duas linhas da matriz de posi ca o. Observe que agora foi criado um ponteiro para ponteiro chamado de **matriz. O programa primeiro pergunta o n umero de linhas da matriz para poder alocar espa co para armazenar os ponteiros para cada uma das linhas. Em seguida e alocado espa co para armazenar cada uma das linhas. O comando
matriz = (int **) malloc (lin * sizeof(int *));

foi usado pelo programa para reservar espa co para armazenar lin linhas de ponteiros para ponteiros. Observe que o comando sizeof(int *) calcula o espa co para armazenar um ponteiro na mem oria. Note tamb em que o valor retornado pela fun ca o malloc foi conformado ao tipo ponteiro para ponteiro pela opera ca o (int **). O interessante do programa e que a troca de linhas da matriz envolve simplesmente a troca de dois ponteiros e n ao a troca de todos os elementos das linhas. Esta solu ca o e muito mais r apida do que trocar elemento a elemento, especialmente para matrizes grandes. A seguir mostramos o programa nas listagens 9.16 e 9.17 que e o exemplo anterior modicado para utilizar fun co es. O prop osito e mostrar como cam as chamadas e as deni co es das fun co es que utilizam ponteiros para ponteiros.

152

Listing 9.15: Exemplo de uso de ponteiros para ponteiros.


#include < stdio .h > #include < stdlib .h > i n t main ( void ) { i n t ** matriz ; /* ponteiro para os ponteiros */ i n t lin , col ; /* n u mero de linhas e colunas */ int i, j; i n t linha1 , linha2 ; /* linhas que serao trocadas */ char linha [80]; /* linha de caracteres com os dados */ i n t * temp ; puts ( " Qual o numero de linhas ? " ); gets ( linha ); lin = atoi ( linha ); matriz = ( i n t **) malloc ( lin * s i z e o f ( i n t *)); i f (! matriz ) { puts ( " Nao h a espa c o para alocar mem o ria " ); return 1; } puts ( " Qual o numero de colunas ? " ); gets ( linha ); col = atoi ( linha ); f o r ( i =0; i < lin ; i ++) { *( matriz + i ) = ( i n t *) malloc ( col * s i z e o f ( i n t )); i f (! *( matriz + i ) ) { printf ( " Sem espa c o para alocar a linha % d " , i ); return 1; } } puts ( " Entre com os dados " );} f o r ( i =0; i < lin ; i ++) { printf ( " Entre com a linha % d \ n " , i ); f o r ( j =0; j < col ; j ++) { printf ( " Elemento % d % d \ n " , i , j ); scanf ( " % d " , *( matriz + i ) + j ); } } puts ( " Qual a primeira linha a ser trocada ? " ); gets ( linha ); linha1 = atoi ( linha ); puts ( " Qual a segunda linha a ser trocada ? " ); gets ( linha ); linha2 = atoi ( linha ); temp = *( matriz + linha1 ); *( matriz + linha1 ) = *( matriz + linha2 ); *( matriz + linha2 ) = temp ; puts ( " Dados trocados . " ); f o r ( i =0; i < lin ; i ++) { f o r ( j =0; j < col ; j ++) { printf ( " %7 d " , *(*( matriz + i ) + j )); } printf ( " \ n " ); } return 0; }

153

Listing 9.16: Exemplo de uso de ponteiros para ponteiros usando fun co es.
#include < stdio .h > #include < stdlib .h >} i n t ** aloca_linhas ( i n t ); void aloca_colunas ( i n t ** , i nt , i n t ); void le_dados ( i n t ** , i nt , i n t ); void imprime_matri z ( i n t ** , i nt , i n t ); void troca_linhas ( i n t ** , i nt , i n t ); i n t main ( void ) { i n t ** matriz ; i n t lin , col ;& nbsp ;& nbsp ; i n t linha1 , linha2 ; char linha [80]; puts ( " Qual o numero de linhas ? " ); gets ( linha ); lin = atoi ( linha ); matriz = aloca_linhas ( lin ); puts ( " Qual o numero de colunas ? " ); gets ( linha ); col = atoi ( linha ); printf ( " Alocando espa c o para linhas .\ n " ); aloca_colunas ( matriz , lin , col ); le_dados ( matriz , lin , col ); imprime_matri z ( matriz , lin , col ); puts ( " Qual a primeira linha a ser trocada ? " ); gets ( linha ); linha1 = atoi ( linha ); puts ( " Qual a segunda linha a ser trocada ? " ); gets ( linha ); linha2 = atoi ( linha ); troca_linhas ( matriz , linha1 , linha2 ); imprime_matri z ( matriz , lin , col ); return 0; } i n t ** aloca_linhas ( i n t lin ) { i n t ** m ;} m = ( i n t **) malloc ( lin * s i z e o f ( i n t *)); i f (! m ) { puts ( " Sem espa c o para alocar mem o ria " ); return 1; } return m ; } void aloca_colunas ( i n t ** matriz , i n t lin , i n t col ) { int i; f o r ( i =0; i < lin ; i ++) { *( matriz + i ) = ( i n t *) malloc ( col * s i z e o f ( i n t )); i f (! *( matriz + i ) ) { printf ( " Sem espa c o para linha % d " , i ); return 1; } } }

154

Listing 9.17: Continua ca o do exemplo 9.16.


void le_dados ( i n t ** matriz , i n t lin , i n t col ) { int i, j; puts ( " Entre com os dados " ); f o r ( i =0; i < lin ; i ++) { printf ( " Entre com a linha % d \ n " , i ); f o r ( j =0; j < col ; j ++) { printf ( " Elemento % d % d \ n " , i , j ); scanf ( " % d " , *( matriz + i ) + j ); } } } void imprime_matri z ( i n t ** matriz , i n t lin , i n t col ) { int i, j; f o r ( i =0; i < lin ; i ++) { f o r ( j =0; j < col ; j ++) { printf ( " %7 d " , *(*( matriz + i ) + j )); } printf ( " \ n " ); } } void troca_linhas ( i n t ** matriz , i n t linha1 , i n t linha2 ) { i n t * temp ; temp = *( matriz + linha1 ); *( matriz + linha1 ) = *( matriz + linha2 ); *( matriz + linha2 ) = temp ; }

155

9.9

Exerc cios

9.1: Escreva um programa que gere um vetor de tr es dimens oes (X, Y e Z) em que cada posi ca o guarda a soma de suas coordenadas. As dimens oes da matriz dever ao ser determinadas em tempo de execu ca o e o programa dever a informar os valores gerados. 9.2: Escreva um programa que leia uma frase de at e 80 caracteres do teclado e imprima a freq u encia com que aparece cada uma das letras do alfabeto na frase. 9.3: Escreva um programa que leia uma frase de at e 80 caracteres e a imprima em ordem reversa convertendo todos os caracteres min usculos para mai usculos. 9.4: Escreva um programa que leia uma matriz e a imprima. O programa deve ler o numero de colunas e linhas do teclado. O programa deve ainda trocar duas linhas da matriz de posi ca o. Os n umeros das linhas a serem trocadas devem ser lidos do teclado. 9.5: Escreva um programa que simule uma pilha usando vetores. O programa deve implementar as seguintes opera co es na pilha: Inserir Remover Listar 9.6: Escreva uma fun ca o que receba um ponteiro para uma cadeia de caractere e troque todo o caracter ap os um branco pelo seu equivalente mai usculo. 9.7: Escreva um programa que leia seu nome completo e pergunte quantas letras tem o seu primeiro nome. Assuma que a letra a tem ndice 0, a letra b ndice 1 e assim por diante. O programa deve imprimir quantas letras iguais a letra cujo ndice e o n umero de letras do seu primeiro nome existem no seu nome completo. 9.8: Escreva um programa que leia seu nome completo e pergunte quantas letras tem o seu primeiro nome. O seu programa deve usar a fun ca o posicao que tem o seguinte prot otipo:
int posicao(char *substr, char *str);

Esta fun ca o deve vericar se a cadeia apontada por substr est a presente na cadeia apontada por str e retornar a posi ca o em que a sub-cadeia aparece em cadeia. 9.9: Escreva um programa que procure em uma matriz elementos que sejam ao mesmo tempo o maior da linha e o menor coluna. As dimens oes da matriz devem ser pedidas ao usu ario. 9.10: Escreva um programa que leia duas cadeias de caracteres e concatene a segunda cadeia ao nal da primeira. 156

Listing 9.18: Programa do exercicio 11.


#include < string .h > #include < stdio .h > #de fi ne MAX 80 void misterio ( char * p1 , char * p2 ); i n t main ( void ) { char palavra1 [ MAX ]; char palavra2 [ MAX ]; puts ( " Palavra 1? " ); fgets ( palavra1 , MAX , stdin ); palavra1 [ strlen ( palavra1 ) -1] = \0 ; puts ( " Palavra 2? " ); fgets ( palavra2 , MAX , stdin ); palavra2 [ strlen ( palavra2 ) -1] = \0 ; misterio ( palavra1 , palavra2 ); return 0; } void misterio ( char * p1 , char * p2 ) { while (* p1 != \0 && * p2 != \0 ) { putchar (* p1 ); putchar (* p2 ); p1 = p1 + 1; p2 = p2 + 1; } i f (* p1 != \0 ) { while (* p1 != \0 ) { putchar (* p1 ); p1 = p1 + 1; } } i f (* p2 != \0 ) { while (* p2 != \0 ) { putchar (* p2 ); p2 = p2 + 1; } } }

157

9.11: O que ser a impresso pelo programa mostrado na listagem 9.18 caso a primeira palavra fornecida seja o seu primeiro nome e a segunda o seu u ltimo sobrenome. 9.12: O que ser a impresso pelo programa mostrado na listagem 9.19 caso a primeira palavra fornecida seja o seu primeiro nome e a segunda o seu u ltimo sobrenome. Indique os nomes que usou e justique a sua resposta. Listing 9.19: Programa do exercicio 12.
#include < string .h > #include < stdio .h > #de fi ne MAX 80 void nMisterio ( char * p1 , char * p2 ) { while (* p1 != \0 ) { p1 = p1 + 1; } while (* p2 != \0 ) { * p1 = * p2 ; p1 = p1 + 1; p2 = p2 + 1; } * p1 = \0 ; } i n t main ( void ) { char palavra1 [ MAX ]; char palavra2 [ MAX ]; puts ( " Palavra 1? " ); fgets ( palavra1 , MAX , stdin ); palavra1 [ strlen ( palavra1 ) -1]= \0 ; puts ( " Palavra 2? " ); fgets ( palavra2 , MAX , stdin ); palavra2 [ strlen ( palavra2 ) -1]= \0 ; nMisterio ( palavra1 , palavra2 ); puts ( palavra1 ); return 0; }

9.13: O que ser a impresso pelo programa 9.20. Justique sua resposta. Listing 9.20: Listagem do exerc cio 13.
#i ncl ude < stdio .h > #i ncl ude < string .h > i n t main ( void ) { char * frase = " Otimo teste " ; char *p , misterio [80]; i n t i = 0; i n t j = 0;

158

p = frase + strlen ( frase ) - 1; while (* p != ) { misterio [ i ] = * p ; i ++; p - -; } misterio [ i ] = ; i ++; while ( frase [ j ] != ) { misterio [ i ] = frase [ j ]; j ++; i ++; } misterio [ i ] = \0 ; puts ( misterio ); return 0; }

9.14: O que ser a impresso pelo programa mostrado na listagem 9.21. Justique sua resposta. Listing 9.21: Programa do exerc cio 14.
#include < stdio .h > void f1 ( i n t v ) { v = v + 1; printf ( " f1 = % d \ n " , v ); } void f2 ( i n t * v ) { * v = * v + 1; printf ( " f2 = % d \ n " , * v ); } i n t f3 ( i n t v ) { v = v + 1; printf ( " f3 = % d \ n " , v ); return v ; } i n t main ( void ) { i n t v = 1; f1 ( v ); f2 (& v ); v = f3 ( v ); printf ( " main = % d \ n " , v ); return 0; }

159

Cap tulo 10

Estruturas
10.1 Introdu c ao

Uma estrutura e um conjunto de uma ou mais vari aveis, que podem ser de tipos diferentes, agrupadas sob um u nico nome. O fato de vari aveis agrupadas em uma estrutura poderem ser referenciadas por um u nico nome facilita a manipula ca o dos dados armazenados nestas estruturas. Um exemplo poderia ser uma estrutura que armazenasse as diversas informa co es sobre os alunos de uma Universidade. Nesta estrutura estariam armazenadas, sob o mesmo nome, informa co es do tipo: nome, registro, data de nascimento, data de ingresso, CPF, etc. Uma estrutura pode incluir outras estruturas al em de vari aveis simples. As estruturas facilitam manipular estes agrupamentos complexos de dados. Por exemplo, considere o problema de ordenar as informa co es sobre os alunos da Universidade exemplo. A ordena ca o pode ser efetuada como se todos os dados que comp oem a estrutura fossem uma entidade u nica.

10.2

Deni c oes B asicas

Uma estrutura, ent ao, e uma cole ca o de vari aveis, de tipos diversos ou n ao, agrupadas sob um u nico nome. As vari aveis que comp oem a estrutura s ao os seus membros, elementos ou campos. Normalmente os elementos da estrutura tem alguma rela ca o sem antica. Por exemplo: alunos de uma universidade, discos de uma cole ca o, elementos de uma gura geom etrica, etc. Vamos considerar o exemplo do aluno e assumir que estaremos armazenando o seu nome, registro, ano de entrada e curso. Para este m podemos criar uma estrutura como a descrita no trecho de programa 10.1. A palavra chave struct inicia a declara ca o da estrutura, em seguida pode aparecer um identicador (ALUNO), que subseq uentemente pode ser usado como abrevia ca o da deni ca o da estrutura. A declara ca o continua com a lista de declara co es entre chaves e termina com um ;. Um membro da estrutura e uma vari avel n ao membro da estrutura podem ter o mesmo nome, j a que e poss vel distingui-las por contexto.

160

Listing 10.1: Deni ca o de uma estrutura.


s t r u c t ALUNO { char nome [40]; i n t registro ; i n t ano_entrada ; char curso [20]; };

A declara ca o acima ainda n ao alocou espa co de mem oria j a que nenhuma vari avel foi realmente denida. Esta declara ca o e apenas um modelo de como estruturas do tipo ALUNO devem ser constru das. Para denir estruturas deste tipo podemos usar a seguinte declara ca o.
struct ALUNO paulo, carlos, ana;

Nesta declara ca o tr es estruturas do tipo ALUNO foram criadas. Esta declara ca o alocou espa co para armazenar os dados dos tr es alunos. A declara ca o acima e id entica, na forma, a declara ca o de vari aveis de um tipo pr e-denido, como por exemplo:
int a, b, c;

poss E vel declarar ao mesmo tempo o modelo da estrutura e as vari aveis do programa. Por exemplo,
s t r u c t ALUNO { char nome [40]; i n t registro ; i n t ano_entrada ; char curso [20]; } paulo , carlos , ana ;

Para referenciar um elemento da estrutura usa-se o nome da vari avel do tipo da estrutura seguida de um ponto e do nome do elemento. Por exemplo,
paulo.ano_entrada = 1999;

armazena o ano em que aluno paulo entrou na universidade. Para ler o nome do curso que paulo cursa pode-se usar o comando
gets(paulo.curso);

Estruturas podem conter outras estruturas como membros. Por exemplo, vamos denir uma estrutura para armazenar uma data com a seguinte deni ca o:
s t r u c t DATA { i n t dia , mes , ano ; };

Agora vamos modicar a estrutura aluno de modo que ela inclua a data de nascimento do aluno. A estrutura ca com a seguinte deni ca o:
s t r u c t aluno { char nome [40]; i n t registro ; i n t ano_entrada ; char curso [20];

161

s t r u c t DATA data_nascime nt o ; };

Para se referir ao m es de nascimento de uma vari avel paulo do tipo estrutura


aluno usamos a declara ca o paulo.data_nascimento.mes

Note que o operador ponto (.) associa da esquerda para a direita. Uma forma mais conveniente de deni ca o de estruturas e poss vel com o uso do comando typedef. Este comando permite dar a um tipo de dados um novo nome. A inten ca o e aumentar a legibilidade do programa. Por exemplo, e poss vel usar o seguinte c odigo
typedef i n t cores ; typedef i n t laranja ; typedef i n t manga ; ... laranja lima ; manga espada ; cores = AMARELO ; ... espada ++;

Ao mesmo tempo que typedef tem a vantagem de tornar mais claro a nalidade de cada vari avel ele pode trazer problemas na medida em que esconde o real tipo da vari avel. comum o uso de typedef em conjunto com struct. Considere a deni E ca o de uma estrutura para guardar tempos gastos em tarefas. Esta estrutura deve guardar horas, minutos e segundos. Usando esta combina ca o, a deni ca o e usualmente feita da seguinte maneira:
s t r u c t _TEMPO { i n t hora , minuto , segundo ; }; typedef s t r u c t _TEMPO TEMPO ; ... TEMPO t1 ;

Uma forma ainda mais abreviada, junta as duas deni co es, cando a deni ca o da estrutura da seguinte maneira:
typedef s t r u c t _TEMPO { i n t hora , minuto , segundo ; } TEMPO ; ... TEMPO t1 ;

poss E vel dispensar o nome da estrutura (_TEMPO) e a deni ca o ca ainda mais simples, com a seguinte forma:
typedef s t r u c t { i n t hora , minuto , segundo ; } TEMPO ; ... TEMPO t1 ;

162

10.3

Atribui c ao de Estruturas

poss E vel atribuir o conte udo de uma estrutura a outra estrutura do mesmo tipo, n ao sendo necess ario atribuir elemento por elemento da estrutura. Esta e uma das grandes vantagens de estruturas j a que o tamanho do c odigo e reduzido e a clareza dos programas aumenta. O programa 10.2 ilustra como podemos atribuir uma estrutura a outra. O comando temp = emp1; faz com que todos os dados armazenados na estrutura emp1 sejam transferidos para a estrutura temp. Listing 10.2: Atribui ca o de Estruturas.
#include < stdio .h > typedef s t r u c t _EMPREGADO { char nome [40]; f l o a t salario ; } EMPREGADO ; i n t main () { EMPREGADO temp , emp1 ; puts ( " Entre com nome . " ); gets ( emp1 . nome ); puts ( " Qual o salario ? " ); scanf ( " % f " , & emp1 . salario ); temp = emp1 ; printf ( " O salario de % s e %.2 f \ n " , temp . nome , temp . salario ); return 0; }

10.4

Matrizes de Estruturas

Estruturas aparecem freq uentemente na forma de matrizes. Por exemplo, a declara ca o struct ALUNO turma[100]; dene uma matriz de 100 estruturas do tipo struct ALUNO. O exemplo 10.3 mostra atribui co es entre estruturas e opera c oes aritm eticas envolvendo membros de estruturas. O programa coloca um vetor de estruturas em ordem crescente usando como chave de ordena ca o um dos membros da estrutura (media). Listing 10.3: Ordena ca o de Estruturas.
#i ncl ude < stdio .h > #i ncl ude < string .h > typedef s t r u c t _ALUNO { char nome [40]; f l o a t n1 , n2 , media ; } ALUNO ; i n t main ( void ) { ALUNO turma [4] , temp ;

163

i n t jaOrdenados = 0 , foraOrdem , i ; f o r ( i = 0; i < 4; i ++) { gets ( turma [ i ]. nome ); scanf ( " % f " , & turma [ i ]. n1 ); do {} while ( getchar ()!= \ n ); scanf ( " % f " , & turma [ i ]. n2 ); do {} while ( getchar ()!= \ n ); turma [ i ]. media =( turma [ i ]. n1 + turma [ i ]. n2 )/2.0; } do { foraOrdem = 0; f o r ( i = 0; i < 4 - 1 - jaOrdenados ; i ++) { i f ( turma [ i ]. media > turma [ i +1]. media ) { temp = turma [ i ]; turma [ i ] = turma [ i +1]; turma [ i +1] = temp ; foraOrdem = 1; } } jaOrdenados ++; } while ( foraOrdem ); f o r ( i =0; i <4; i ++) { printf ( " \ nDados do aluno % d \ n " , i ); printf ( " % s : %0.1 f , %0.1 f , %0.1 f \ n " , turma [ i ]. nome , turma [ i ]. n1 , turma [ i ]. n2 , turma [ i ]. media ); } return 0; }

10.5

Estruturas e Fun c oes

Primeiro vamos considerar o caso de passar elementos da estrutura para fun co es. Caso os elementos da estrutura sejam vari aveis de um dos tipos j a vistos, a passagem e efetuada da maneira normal. O exemplo 10.4 mostra como passar um elemento (c.raio) de uma estrutura para uma fun ca o. Listing 10.4: Passando elementos para fun co es.
#include < stdio .h > typedef s t r u c t _CIRCULO { f l o a t x , y , raio ; } CIRCULO ; f l o a t Area ( f l o a t r ) { return 3.141516 * r * r ; } i n t main ( void ) { CIRCULO c ; c . x = c . y = c . raio = 1.0; printf ( " % f \ n " , Area ( c . raio )); return 0;

164

A fun ca o que recebe este par ametro est a preparada para receber uma vari avel de ponto utuante simples. Caso seja necess ario passar o endere co de um dos membros ou elementos da estrutura basta colocar o operador & antes do nome da estrutura. Por exemplo, para trocar os valores das coordenadas x dos centros de dois c rculos c1 e c2 usar amos chamadas da seguinte forma.
troca_x (& c1 .x , & c2 . x );

Para trabalhar com endere cos e necess ario usar ponteiros dentro da fun ca o Antes vamos vericar como e poss vel passar uma estrutura inteira para uma fun ca o.
troca_x, mas isto veremos no pr oximo item.

Estruturas, quando passadas para fun co es, se comportam da mesma maneira que as vari aveis dos tipos que j a estudamos. Ao passar uma estrutura para uma fun ca o estaremos passando os valores armazenados nos membros da estrutura. Como este tipo de passagem e feito por valor, altera co es nos membros da estrutura n ao modicam os valores da estrutura na fun ca o que chamou. A passagem de estruturas para fun co es e ilustrada no exemplo 10.5 onde o comprimento da reta que liga dois pontos p1 e p2 e calculado e impresso. Listing 10.5: Passagem de estruturas para fun co es.
#include < stdio .h > #include < math .h > typedef s t r u c t _PONTO { fl oat x, y; } PONTO ; f l o a t comp ( PONTO p1 , PONTO p2 ) { return sqrt ( pow ( p2 .x - p1 .x ,2)+ pow ( p2 .y - p1 .y ,2)); } i n t main ( void ) { PONTO p1 , p2 ; puts ( " Coordenadas do ponto 1 " ); printf ( " x1 = ? " ); scanf ( " % f " , & p1 . x ); printf ( " y1 = ? " ); scanf ( " % f " , & p1 . y ); puts ( " Coordenadas do ponto 2 " ); printf ( " x2 = ? " ); scanf ( " % f " , & p2 . x ); printf ( " y2 = ? " ); scanf ( " % f " , & p2 . y ); printf ( " \ nComprimento da reta = % f \ n " , comp ( p1 , p2 )); return 0; }

Para ilustrar a passagem de vetores de estruturas para fun co es considere o programa 10.3. Neste programa iremos substituir o trecho que ordena o vetor de alunos por uma fun ca o, cujo c odigo e mostrado na listagem 10.6. No programa o trecho que chama a fun ca o tem a seguinte forma
Ordena(turma, 4);

165

Listing 10.6: Fun ca o que ordena estruturas.


void Ordena ( ALUNO turma [] , i n t tam ) { i n t i , foraOrdem , jaOrdenados = 0; ALUNO temp ; do { foraOrdem = 0; f o r ( i = 0; i < 4 - 1 - jaOrdenados ; i ++) { i f ( turma [ i ]. media > turma [ i +1]. media ) { temp = turma [ i ]; turma [ i ] = turma [ i +1]; turma [ i +1] = temp ; foraOrdem = 1; } } jaOrdenados ++; } while ( foraOrdem ); }

10.6

Ponteiros para Estruturas

Para denir ponteiros para estruturas a declara ca o e similar a declara ca o de um ponteiro normal. O exemplo abaixo mostra a deni ca o de um ponteiro chamado maria para uma estrutura chamada aluno.
s t r u c t aluno { char nome [40]; i n t ano_entrada ; f l o a t n1 , n2 , media ; } * maria ;

Ponteiros s ao uteis quando passamos estruturas para fun co es. Ao passar apenas o ponteiro para estrutura economizamos tempo e mem oria. O espa co de mem oria, e economizado por que se evita passar os dados que comp oem a estrutura um por um. O tempo e economizado porque n ao e necess ario gastar o tempo de empilhar e desempilhar todos os elementos da estrutura no processo de passagem para a fun ca o. Empilhar e desempilhar se referem a pilha de dados usada para transferir os dados entre fun co es. Para acessar elementos da estrutura apontada por um ponteiro usa-se o chamado operador seta (->). Por exemplo para imprimir a m edia da aluna maria usar amos o comando
printf ( " A media vale %.1 f " , maria - > media );

Para alocar espa co para estruturas apontadas por ponteiros e necess ario usar o operador un ario sizeof, isto porque o tamanho de uma estrutura e sempre igual ou maior que a soma dos tamanhos dos seu componentes. Para explicar esta fato devemos considerar como os dados s ao armazenados na mem oria dos computadores. Algumas arquiteturas de computadores endere cam os dados na mem oria por bytes, isto e cada endere co de mem oria se refere a um byte. No entanto, estas arquiteturas l eem sempre uma palavra inteira da mem oria. Usualmente, palavras 166

podem ser compostas de dois bytes e come cam em endere cos pares, como est a mostrado na gura abaixo. Sabemos que existem vari aveis que ocupam mais de um byte, por exemplo inteiros que s ao compostos de dois bytes. Imagine ent ao uma estrutura composta de um caractere (1 byte) e um n umero de inteiro (2 bytes). Caso a mem oria do computador seja organizada em palavras de 16 bits ou 2 bytes a estrutura acima ocuparia 3 bytes ou uma palavra e meia. Para ler o n umero inteiro o programa deveria ler duas palavras. Lembrar que se os dados fossem sempre armazenados seq uencialmente, metade do n umero inteiro estaria em uma palavra e a metade restante na outra, como est a indicado na gura abaixo (parte a). Para facilitar o acesso ` as vari aveis, alguns compiladores armazenam as vari aveis de acordo com o que est a indicado na gura (parte b). Observar que agora a estrutura ocupa quatro bytes. Neste caso o acesso ao n umero inteiro ser a sempre feito em um passo e portanto ganhou-se em tempo de acesso ao custo de gasto de mem oria. Este e uma troca constante em computa ca o. Vimos ent ao que embora o total de bytes dos elementos da estrutura fosse tr es o compilador pode armazenar a estrutura em quatro bytes, da a necessidade de sempre usar o operador sizeof quando alocar espa co. O programa 10.7 mostra como alocar espa co para uma vari avel simples e como usar esta vari avel em diversos tipos de comandos. Listing 10.7: Aloca ca o de espa co para estruturas.
#i ncl ude < stdio .h > #i ncl ude < string .h > #i ncl ude < stdlib .h > typedef s t r u c t _ALUNO { char nome [40]; f l o a t n1 , n2 , media ; } ALUNO ; i n t main ( void ) { ALUNO * maria ; maria = ( ALUNO *) malloc ( s i z e o f ( ALUNO )); i f (! maria ) exit (1); gets ( maria - > nome ); scanf ( " % f % f " , &( maria - > n1 ) , &( maria - > n2 )); maria - > media = ( maria - > n1 + maria - > n2 ) / 2; printf ( " A media de % s vale %0.2 f \ n " , maria - > nome , maria - > media ); return 0; }

O programa 10.8 mostra como utilizar ponteiros para vetores de estruturas e a forma mais segura de alocar espa co para os dados. Observar as nota co es usadas na fun ca o que l e os dados dos funcion arios. Notar que (cadastro+i)->salario e o valor da sal ario.
fgets (( cadastro + i ) - > nome , 39 , stdin ); sscanf ( linha , " % f " , &(( cadastro + i ) - > salario ));

167

Listing 10.8: Aloca ca o de espa co para vetores de estruturas.


#include < stdio .h > #include < stdlib .h > typedef s t r u c t _func { char nome [40]; f l o a t salario ; } Tfunc ; void le ( Tfunc * cadastro , i n t funcionarios ) { int i; char linha [40]; f o r ( i =0; i < funcionarios ; i ++) { puts ( " Nome ? " ); fgets (( cadastro + i ) - > nome , 39 , stdin ); puts ( " Salario ? " ); fgets ( linha , 39 , stdin ); sscanf ( linha , " % f " , &(( cadastro + i ) - > salario )); } } f l o a t media ( Tfunc * cadastro , i n t funcionarios ) { f l o a t media =0.0; int i; f o r ( i =0; i < funcionarios ; i ++) { media += ( cadastro + i ) - > salario ; } return media /= funcionarios ; } i n t main ( void ) { Tfunc * cadastro ; i n t funcionarios ; char linha [40]; puts ( " Quantos funcionarios ? " ); fgets ( linha , 39 , stdin ); sscanf ( linha , " % d " , & funcionarios ); i f (!( cadastro = ( Tfunc *) malloc ( funcionarios * s i z e o f ( Tfunc )))) { exit (1); } le ( cadastro , funcionarios ); printf ( " Salario medio = %.2 f \ n " , media ( cadastro , funcionarios )); return 0; }

168

10.7

Exerc cios

10.1: Considere que uma empresa precisa armazenar os seguintes dados de um cliente: Nome completo com no m aximo 50 caracteres; renda mensal do do cliente; ano de nascimento; possui ou n ao carro. Dena um tipo e uma estrutura para armazenarem estes dados e escreva um programa que leia estes dados armazene-os em uma vari avel e em seguida os imprima. 10.2: Considerando a mesma estrutura do exerc cio anterior, escreva um programa que leia os dados de 100 clientes e imprima: quantos clientes t em renda mensal acima da m edia; quantos clientes t em carro; quantos clientes nasceram entre 1960 (inclusive) e 1980 (exclusive). 10.3: Reescreva o programa 10.3 empregando fun co es para implementar as diversas tarefas do programa. A fun ca o main deve car da maneira indicada na Listagem 10.9. Listing 10.9: Listagem do exercicio 3.
i n t main ( void ) { s t r u c t aluno turma [ MAX ]; le ( turma ); puts ( " Imprimindo dados lidos da turma . " ); puts ( " Digite qualquer coisa para continuar . " ); getchar (); imprime ( turma ); ordena_medias ( turma ); puts ( " Imprimindo dados ordenados da turma . " ); puts ( " Digite qualquer coisa para continuar . " ); getchar (); imprime ( turma ); getchar (); }

10.4: Escrever um programa que utilize structs e ponteiro para struct e imprima o conte udo das vari aveis da struct.

169

10.5: Escrever um programa que utilize enumeradores com as mat erias do seu per odo. Inicialize cada mat eria com um numero. Depois imprime os valores das vari aveis enumeradas. 10.6: Escrever um programa que utilize union. Inicialize as vari aveis com valores diferentes e imprima o conte udo delas. 10.7: Fazer um programa que simule as opera co es de uma pilha push e pop, usando structs. Um exemplo de entrada poderia ser o seguinte: empilha C empilha B empilha A desempilha A desempilha B desempilha C 10.8: Escreva um programa que solicite o nome e telefone de uma pessoa e grave essas informa co es num vetor de uma estrutura que contem esses dados (nome e telefone). O programa deve ter tr es op co es apenas: uma que adiciona um novo dado, outra que lista todos os dados atualmente armazenados na mem oria e outra que sai do programa. Esse vetor de estrutura deve ter apenas 10 elementos e fornecer uma mensagem de erro caso o usu ario tente adicionar mais pessoas que este m aximo permitido. 10.9: Escreva uma estrutura similar as strings do Delphi (possuem um campo armazenando o tamanho da string e um ponteiro para o primeiro caractere da string) e crie as fun co es strcpy e strcat para strings nesse formato. 10.10: Escreva um programa fazendo o uso de estruturas. Voc e dever a criar uma estrutura chamada Ponto, contendo apenas a posi ca o x e y (inteiros) do ponto. Declare 2 pontos, leia a posi ca o (coordenadas x e y) de cada um e calcule a dist ancia entre eles. Apresente no nal a dist ancia entre os dois pontos. 10.11: Crie uma estrutura chamada ret^ angulo, que possua duas estruturas ponto (o ponto superior esquerdo e o ponto inferior direito). Fa ca um programa que receba as informa co es acerca de um ret angulo (as coordenadas dos dois pontos), e informe a area, o comprimento da diagonal e o comprimento de cada aresta 10.12: Escreva um programa que use as mesmas estruturas do exerc cio anterior para descobrir se um ponto est a dentro de um ret angulo. 10.13: Considere que foi denida a seguinte estrutura:
typedef s t r u c t _frac { i n t numerador , denominador ; } FRACAO ;

Escreva um programa em C que calcule as quatro opera co es usando fra co es denidas com estruturas do tipo FRACAO. O programa deve ler duas fra co es e imprimir o resultado de cada uma das quatro opera co es.

170

Cap tulo 11

Entrada e Sa da por Arquivos


11.1 Introdu c ao

Em C n ao existem instru co es especiais de entrada e sa da como em outras linguagens de programa ca o. Estas tarefas, em C s ao executadas por fun co es especialmente criadas para esta nalidade e armazenadas em bibliotecas espec cas. Por esta raz ao todos programas em C que precisam de entrada e/ou sa da de dados necessitam incluir a diretiva #include<stdio.h> no in cio do programa, para permitir o uso da biblioteca padr ao stdio de fun co es de entrada e sa da.

11.2

Fluxos de Dados

Para isolar os programadores dos problemas de manipular os v arios tipos de dispositivos de armazenamento e seus diferentes formatos a linguagem C utiliza o conceito de uxo de dados (stream ). Todos os diferentes sistemas de arquivos se comportam da mesma maneira que foi denida como semelhante a um uxo cont nuo de dados (stream ). Dados podem ser manipulados em dois diferentes tipos de uxos: uxos de texto e uxos bin arios.

11.2.1

Fluxos de Texto

Um uxo de texto (text stream ) e composto por uma seq u encia de caracteres, que pode ou n ao ser dividida em linhas terminadas por um caractere de nal de linha. Um detalhe que deve ser considerado ao escrever um programa e que na u ltima linha n ao e obrigat orio o caractere de m de linha. Nem sempre a tradu ca o entre a representa ca o do caractere no uxo de texto e no sistema de arquivos do computador hospedeiro e um para um byte. Por exemplo, entre UNIX e DOS h a uma diferen ca na representa ca o de nal de linha (linefeed ) que causa problemas na impress ao de arquivos. Em UNIX um nal de linha e representado pelo caractere de alimenta ca o de linha (LF). Em 171

DOS um nal de linha e representado pelo par retorno de carro/alimenta ca o de linha (CR/LF). Deste modo quando um arquivo gerado em UNIX vai para uma impressora que espera nal de linha no modo DOS surge o que e comumente chamado de efeito escada. A impress ao continua na linha seguinte mas sem voltar para o in cio da linha porque em UNIX o caractere de retorno de carro n ao e inserido no uxo de texto. At e agora temos trabalhado com os uxos de dados padr ao: stdin, para entrada de dados e stdout para sa da de dados. Ao iniciar todo programa em C e automaticamente associado a estes dois uxos de dados sem necessitar de nenhuma interven ca o do programador. A deni ca o de que perif ericos estar ao associados a estes uxos depende do sistema operacional. Normalmente o uxo de entrada (stdin) est a associado ao teclado e o uxo de sa da (stdout) ao monitor.

11.2.2

Fluxo Bin ario

Um uxo bin ario e composto por uma seq u encia de bytes lidos, sem tradu ca o, diretamente do dispositivo externo. Existe uma correspond encia um para um entre os dados do dispositivo e os que est ao no uxo que o programa manipula. A Figura 11.1 ilustra estes dois tipos de uxos. No uxo de texto os dados s ao armazenados como caracteres sem convers ao para representa ca o bin aria. Cada um dos caracteres ocupa um byte. O numero 12 ocupa dois bytes e o n umero 113 ocupa 3. Um caractere em branco foi inserido entre cada um dos n umeros para separ a-los, de modo que a fun ca o de entrada e sa da possa descobrir que s ao dois n umeros inteiros (12 e 113) e n ao o n umero 12113. No uxo bin ario cada n umero inteiro ocupa 32 bits e e armazenado na forma bin aria. Os caracteres do exemplo est ao armazenados seguindo a tabela ASCII. Observe que, em arquivos bin arios, n ao h a necessidade de separar os n umeros j a que eles sempre ocupam 32 bits.

fluxo de texto 1 2 b 1 1 3 b a b

fluxo binrio
000...01100 000...01110001 01100001 01100010

32 bits 12

32 bits 113

8 bits 8 bits a b

Figura 11.1: Fluxos de dados.

172

11.2.3

Arquivos

Um arquivo pode estar associado ` a qualquer dispositivo de entrada e sa da como, por exemplo: impressora, teclado, disquete, disco r gido etc. No entanto, os programas v eem os arquivos atrav es de uxos. Para que um determinado arquivo em um perif erico seja associado a um uxo e necess ario que o arquivo seja aberto e somente ap os esta opera ca o, o programa pode manipular os dados. Normalmente a intera ca o entre o programa e os arquivos e feita por meio de buers que intermediam a transfer encia dos dados entre os programas e os perif ericos. Isto serve para facilitar a opera ca o do sistema operacional. Opera co es comuns em arquivos s ao: abertura e fechamento de arquivos; remover um arquivo; leitura e escrita de um caractere ou byte; procurar saber se o m do arquivo foi atingido; posicionar o arquivo em um ponto determinado. Obviamente algumas dessas fun co es n ao se aplicam a todos os tipos de dispositivos. Por exemplo, para uma impressora pode n ao ser poss vel usar a fun ca o que reposiciona o arquivo no in cio. Um arquivo em disco permite acesso aleat orio enquanto um teclado n ao. Ao nal das opera co es nos arquivos o programa deve fech a-los. Caso o programador esque ca de executar esta opera ca o, ao nal do programa todos os arquivos associados s ao fechados automaticamente e os conte udos dos buers s ao descarregados para o dispositivo externo. Caso o arquivo seja de entrada o conte udo do buer e esvaziado.

11.3

Fun c oes de Entrada e Sa da

As fun co es de Entrada e Sa da normalmente utilizadas pelos programadores est ao armazenadas na biblioteca stdio.h. As fun co es mais comuns est ao mostradas na tabela 11.1. Para ter acesso aos dados em um arquivo e necess ario a deni c ao de um ponteiro do tipo especial FILE. Este tipo tamb em est a denido na biblioteca stdio.h. Um ponteiro deste tipo permite que o programa tenha acesso a uma estrutura que armazena informa co es importantes sobre o arquivo. Para denir uma vari avel deste tipo o programa deve conter a seguinte declara ca o
FILE *arq;

onde arq e o ponteiro que ser a usado para executar as opera co es no arquivo.

173

Fun c ao
fopen() fputc() getc(), fgetc() fprintf() sscanf() fscanf() fseek() rewind() feof() ferror() fflush() fread() fwrite()

Descri c ao Abre um arquivo Escreve um caractere em um arquivo L e um caractere de um arquivo Equivalente a printf() Equivalente a scanf(). L e de uma cadeia de caracteres Equivalente a scanf() Posiciona o arquivo em um ponto espec co Posiciona o arquivo no in cio Retorna verdade se chegou ao m do arquivo Verica a ocorr encia de um erro Descarrega o buer associado ao arquivo Leitura de dados no modo bin ario Escrita de dados no modo bin ario

Tabela 11.1: Exemplos de fun co es de Entrada e Sa da.

11.4

In cio e Fim

As opera co es mostradas a seguir mostram opera co es que devem ser realizadas antes e depois de usar um arquivo (fopen() e fclose()). As outras duas fun co es servem para que o usu ario possa detectar o m de um arquivo ou voltar para seu in cio.

11.4.1

Abrindo um Arquivo

Antes de qualquer opera ca o ser executada com o arquivo, ele deve ser aberto . Esta opera ca o associa um uxo de dados a um arquivo. Um arquivo pode ser aberto de diversas maneiras, de acordo com as opera co es que dever ao ser executadas: leitura, escrita, leitura/escrita, adi ca o de texto etc. A fun ca o utilizada para abrir o arquivo e chamada fopen() e tem o seguinte prot otipo:
FILE *fopen (const char *parq, const char *modo)

onde parq e um ponteiro de arquivo para o arquivo a ser manipulado e modo e um ponteiro para uma cadeia de caracteres que dene a maneira como o arquivo vai ser aberto. Este ponteiro n ao deve ser modicado e a fun c ao retorna um ponteiro nulo (NULL) se o arquivo n ao puder ser aberto. A seguir listamos os diversos modos que podem ser usados para abrir um arquivo. r: Abre um arquivo para leitura, o arquivo deve existir ou um erro ocorre. w: Cria um arquivo vazio para escrita, caso um arquivo com o mesmo nome exista o seu conte udo e apagado. a: Adiciona ao nal de um arquivo. O arquivo e criado caso ele n ao exista. r+: Abre um arquivo para leitura e escrita. O arquivo deve existir ou um erro ocorre. 174

w+: Cria um arquivo vazio para leitura e escrita. Se um arquivo com o mesmo nome existe o conte udo e apagado. a+: Abre um arquivo para leitura e adi ca o. Todas as opera co es de escrita poss s ao feitas no nal do arquivo. E vel reposicionar o ponteiro do arquivo para qualquer lugar em leituras, mas as escritas mover ao o ponteiro para o nal do arquivo. O arquivo e criado caso n ao exista. Observar que se um arquivo for aberto com permiss ao de escrita todo o seu conte udo anterior ser a apagado. Caso o arquivo n ao exista ele ser a criado. O trecho de programa abaixo ilustra os passos necess arios para abrir um arquivo para escrita. Primeiro e declarado o ponteiro pa para o arquivo. Em seguida a fun ca o fopen e chamada para associar o nome externo do programa (arquivo.txt) no modo escrita ao ponteiro pa. Um teste para ponteiro nulo e feito para vericar se ocorreu algum problema com a opera ca o de abertura do arquivo.
FILE * pa ; /* declaracao do ponteiro para arquivo */ /* nome externo associado ao interno */ pa = fopen ( " arquivo . txt " , " w " ); i f ( pa == NULL ) { /* verifica erro na abertura */ printf ( " Arquivo nao pode ser aberto . " ); return 1; }

Lembrar que abrir, para escrita, um arquivo que j a existe, implica em apagar todo o conte udo anterior e a prepara ca o do arquivo para receber dados a partir de seu ponto inicial. Se o programador deseja acrescentar dados ao nal de um arquivo j a existente o modo de abertura deve ser a.

11.4.2

Fechando um Arquivo

Um arquivo aberto por meio da fun ca o fopen() deve ser fechado com a fun ca o
fclose() cujo prot otipo e int fclose (FILE *parq);

onde parq e um ponteiro de arquivo para o arquivo que deve ser fechado. Todos os buers internos associados com o uxo de dados do arquivo s ao descarregados. O conte udo de qualquer buer n ao escrito e escrito e dados n ao lidos de buers s ao perdidos. Este ponto e importante de ser considerado porque em muitos sistemas operacionais uma opera ca o de escrita em um arquivo n ao ocorre imediatamente a emiss ao da ordem de escrita. O sistema operacional pode executar a ordem no momento que achar mais conveniente. Um valor zero de retorno signica que a opera ca o foi executada com exito, qualquer outro valor implica em erro.

175

11.4.3

Fim de Arquivo

A fun ca o feof() indica que um arquivo chegou ao seu nal. A pergunta que pode surgir e a seguinte - Se j a existe o valor EOF para indicar o nal de arquivo, por que precisamos de uma fun c ao extra do tipo feof()? O problema e que EOF e um valor inteiro e ao ler arquivos bin arios este valor pode ser lido como parte do arquivo e n ao por ser o nal do arquivo. A fun ca o feof() serve para indicar que o nal de um arquivo bin ario foi encontrado. Naturalmente esta fun ca o pode ser aplicada tamb em a arquivos texto. O prot otipo da fun ca o e o seguinte:
int feof(FILE *parq)

Um valor diferente de zero e retornado no caso de ter sido atingido o nal do arquivo. O valor zero indica que ainda n ao se chegou ao nal do arquivo. O exemplo 11.1 mostra um programa que l e um caractere do teclado e o mostra na tela. Neste exemplo a leitura termina quando o usu ario digita o caractere <ctl>+D, que indica nal de arquivo pelo teclado em Unix (no outro sistema e <ctl>+Z). Listing 11.1: Uso da fun ca o feof().
#include < stdio .h > i n t main ( void ) { char c ; c = getchar (); while ( c != EOF ) { putchar ( c ); c = getchar (); } return 0; }

11.4.4

Volta ao In cio

A fun ca o rewind() recoloca o indicador de posi ca o de arquivo no inicio do arquivo. Uma opera ca o semelhante ao que fazemos em uma ta cassete de m usica ou v deo. O prot otipo da fun ca o e o seguinte:
void rewind(FILE *parq)

e importante observar que o arquivo deve estar aberto em um modo que permita a execu ca o das opera co es desejadas. Por exemplo, um arquivo aberto somente para escrita e em seguida reposicionado para o in cio, n ao ir a permitir outra opera ca o que n ao seja escrita.

176

11.5

Lendo e Escrevendo Caracteres

As opera co es mais simples em arquivos s ao a leitura e escrita de caracteres. Para ler um caractere de um arquivo, que foi previamente aberto, pode-se usar as fun co es getc() e fgetc(), que s ao equivalentes. Os prot otipos destas fun co es s ao os seguintes:
int fgetc (FILE *parq); int getc (FILE *parq);

As fun co es getc() e fgetc() s ao equivalentes e muitos compiladores implementam getc() como uma macro do seguinte modo:
#dene getc(parq) fgetc(parq)

A fun ca o l e o caractere como um unsigned char mas retorna o valor como um inteiro, onde o byte mais signicativo vale zero. O apontador do arquivo avan ca um caractere e passa a apontar para o pr oximo caractere a ser lido. A fun ca o devolve o c odigo EOF ao chegar ao nal do arquivo ou caso um erro ocorra. O valor EOF tamb em e um inteiro v alido e portanto ao usar arquivos bin arios e necess ario que a fun ca o feof() seja utilizada para vericar o nal do arquivo. A fun ca o ferror() pode ser usada para determinar se um erro ocorreu. Para escrever caracteres h a duas fun co es denidas putc() e fputc(). Os prot otipos das fun co es s ao os seguintes:
int putc(int ch, FILE *parq); int fputc(int ch, FILE *parq)

onde parq e um ponteiro de arquivo para o arquivo que foi previamente aberto por meio da fun ca o fopen() e ch e o caractere a ser escrito. O programa 11.2 mostra como um arquivo pode ser criado para leitura e escrita. Em seguida um conjunto de caracteres lido do teclado e escrito no arquivo. O pr oximo passo e a leitura do arquivo que e iniciada ap os uma chamada a fun ca o rewind(), fazendo com que o indicador de posi ca o do arquivo volte a apontar para seu in cio. Uma outra alternativa mostrada em 11.3 mostra um exemplo onde o arquivo e criado para escrita em seguida e fechado e reaberto para leitura cando automaticamente posicionado no in cio para a leitura. Listing 11.3: Exemplo de leitura e escrita de caracteres.
#include < stdio .h > i n t main ( void ) { int c; FILE * pa ; char * nome = " texto . txt " ; i f (( pa = fopen ( nome , " w + " )) == NULL ) { printf ( " \ n \ nErro ao abrir o arquivo - escrita .\ n " ); return 1; } c = getchar ();

177

Listing 11.2: Exemplo de leitura e escrita de caracteres.


#include < stdio .h > #include < stdlib .h > i n t main ( void ) { int c; FILE * pa ; char * nome = " texto . txt " ; /* Abre o arquivo para leitura e escrita */ i f (( pa = fopen ( nome , " w + " )) == NULL ) { printf ( " \ n \ nNao foi possivel abrir o arquivo .\ n " ); exit (1); } /* Cada caractere digitado sera gravado no arquivo */ c = getchar (); while (! feof ( stdin )) { fputc (c , pa ); c = getchar (); } rewind ( pa ); /* volta ao inicio do arquivo */ printf ( " \ nTerminei de escrever , agora vou ler .\ n " ); c = fgetc ( pa ); while (! feof ( pa )) { putchar ( c ); c = fgetc ( pa ); } fclose ( pa ); return 0; }

178

while (! feof ( stdin )) { fputc (c , pa ); c = getchar (); } fclose ( pa ); printf ( " \ nTerminei de escrever , agora vou ler .\ n " ); i f (( pa = fopen ( nome , " r " )) == NULL ) { printf ( " \ n \ nErro ao abrir o arquivo - leitura .\ n " ); exit (1); } c = fgetc ( pa ); while (! feof ( pa )) { putchar ( c ); c = fgetc ( pa ); } fclose ( pa ); return 0; }

11.6

Testando Erros

A fun ca o ferror(FILE *parq) serve para vericar se ocorreu um erro associado ao uxo de dados sendo usado. Um valor diferente de zero e a indica ca o do erro, que ocorre geralmente quando a opera ca o previamente executada no uxo falhou. O par ametro parq e um ponteiro para o uxo a ser testado. O programa 11.4 abre um arquivo para leitura, mas tenta escrever um caractere o que provoca um erro que e testado pela fun ca o ferror. Listing 11.4: Uso da fun ca o ferror().
#i ncl ude < stdio .h > i n t main () { FILE * pArq ; pArq = fopen ( " MeusDados . txt " ," r " ); i f ( pArq == NULL ) { printf ( " Erro abrindo arquivo . " ); return 1; } else { fputc ( x , pArq ); i f ( ferror ( pArq )) { printf ( " Erro escrevendo arquivo \ n " ); fclose ( pArq ); return 1; } } return 0; }

179

11.7

Lendo e Escrevendo Cadeias de Caracteres

As fun co es fgets() e fputs() servem para ler e escrever cadeias de caracteres em arquivos. Os prot otipos das fun co es s ao:
int fputs(char *str, FILE *parq); int fgets(char *str, int comp, FILE *parq);

A fun ca o fputs() escreve a cadeia de caracteres apontada por str no uxo apontado por parq. O c odigo nulo ao nal da cadeia n ao e copiado para o uxo. O c odigo correspondente ` a EOF ser a retornado se ocorrer um erro e um valor n ao negativo em caso de sucesso. A fun ca o fgets() l e uma cadeia de caracteres do uxo especicado por parq at e que um caractere de nova linha seja encontrado ou comp-1 caracteres sejam lidos. O caractere de nova linha interrompe a leitura. Observar que diferentemente de gets() o caractere de nova linha encontrado passa a fazer parte da cadeia que recebe um caractere nulo ao seu nal. O ponteiro str e retornado caso a leitura ocorra sem erro. No caso de erro o ponteiro str recebe o valor NULL. Se o m do arquivo for encontrado e nenhum caractere foi lido, o conte udo de str e mantido e um NULL e retornado. O exemplo 11.5 mostra um exemplo de uso destas fun co es para ler e escrever cadeias de caracteres em um arquivo. Listing 11.5: Exemplo de leitura e escrita de cadeias de caracteres.
#include < stdio .h > #de fi ne MAX 80 i n t main ( void ) { char linha [ MAX ]; FILE * pa ; char * nome = " texto . txt " ; i f (( pa = fopen ( nome , " w + " )) == NULL ) { printf ( " \ n \ nNao foi possivel abrir o arquivo .\ n " ); return 1; } fgets ( linha , MAX , stdin ); while (! feof ( stdin )) { fputs ( linha , pa ); fgets ( linha , MAX , stdin ); } rewind ( pa ); /* volta ao inicio do arquivo */ printf ( " \ nTerminei de escrever , agora vou ler .\ n \ n " ); fgets ( linha , MAX , pa ); while (! feof ( pa )) { puts ( linha ); fgets ( linha , MAX , pa ); } fclose ( pa ); return 0; }

180

11.8

Entrada e Sa da Formatada

As fun co es fprintf() e fscanf() s ao equivalentes as fun co es printf() e scanf() usadas at e agora, sendo a u nica modica ca o o fato de que elas trabalham com uxos de dados (arquivos). Os prot otipos das duas fun co es s ao os seguintes:
int fprintf(FILE *parq, const char *formatacao, ...); int fscanf(FILE *parq, const char *formatacao, ...);

onde parq e um ponteiro de arquivo recebido ap os uma chamada a fopen(). Em leituras, a fun ca o retorna o n umero de itens lidos com sucesso. Esta contagem pode igualar o n umero esperado de leituras ou ser menor no caso de falha. Caso ocorra uma falha antes de que uma leitura possa ser feita com sucesso, EOF e retornado. Em escritas, caso a opera ca o de escrita tenha sucesso, o n umero total de caracteres escrito e retornado. Um n umero negativo e retornado em caso de falha. Embora estas duas fun co es, por sua semelhan ca com printf() e scanf(), sejam maneiras convenientes de escrever e ler dados de arquivos, elas t em a desvantagem de serem mais lentas do que uso de arquivos bin arios. A perda de tempo e devido ao fato dos dados serem gravados em ASCII, o que obriga a uma convers ao dos dados a cada opera ca o realizada. Em alguns casos o fato dos dados serem gravados em ASCII pode ser considerado um vantagem que se sobrep oe a desvantagem da redu ca o de velocidade. Dados gravados em ASCII podem ser facilmente vericados pelos usu arios, o que n ao acontece com dados em bin ario. O exemplo 11.6 mostra o uso destas fun co es para ler e escrever v arios tipos de dados em um arquivo. Listing 11.6: Exemplo de leitura e escrita de dados formatados.
#include < stdio .h > i n t main ( void ) { char palavra [20]; int i; fl oat f; FILE * pa ; char * nome = " format . txt " ; i f (( pa = fopen ( nome , " w + " )) == NULL ) { printf ( " \ n \ nNao foi possivel abrir o arquivo .\ n " ); return 1; } puts ( " Entre com uma palavra . " ); scanf ( " % s " , palavra ); puts ( " Entre com um numero inteiro . " ); scanf ( " % d " , & i ); puts ( " Entre com um numero flutuante . " ); scanf ( " % f " , & f ); /* Escreve os dados no arquivo */ fprintf ( pa , " % s % d % f " , palavra , i , f ); rewind ( pa ); /* volta ao inicio do arquivo */ printf ( " \ nTerminei de escrever , agora vou ler .\ n " ); fscanf ( pa , " % s % d % f " , palavra , &i , & f ); printf ( " Palavra lida : % s \ n " , palavra ); printf ( " Inteiro lido : % d \ n " , i ); printf ( " Float lido : % f \ n " , f );

181

fclose ( pa ); return 0; }

11.9

Lendo e Escrevendo Arquivos Bin arios

As fun co es fread e fwrite s ao empregadas para leitura e escrita de dados em modo bin ario. Os prot otipos das fun co es s ao:
size_t fread (void *ptr, size_t size, size_t nmemb, FILE *parq); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *parq);

A fun ca o fread l e nmemb objetos, cada um com size bytes de comprimento, do uxo apontado por stream e os coloca na localiza ca o apontada por ptr. A fun ca o retorna o n umero de itens que foram lidos com sucesso. Caso ocorra um erro, ou o m do arquivo foi atingido o valor de retorno e menor do que nmemb ou zero. Esta fun ca o n ao distingue entre um m de arquivo e erro, portanto e aconselh avel o uso de feof() ou ferror() para determinar que erro ocorreu. A fun ca o fwrite escreve nmemb elementos de dados, cada um com size bytes de comprimento, para o uxo apontado por stream obtendo-os da localiza ca o apontada por ptr. fwrite retorna o n umero de itens que foram lidos com sucesso. Caso ocorra um erro, ou o m do arquivo foi atingido o valor de retorno e menor do que nmemb ou zero. O programa 11.7 ilustra como podemos escrever e ler dados bin arios de diferentes tipos em arquivos. Como um dos par ametros da fun ca o e o n umero de bytes do dado a ser lido, e recomendado o uso de sizeof. Listing 11.7: Exemplo de leitura e escrita na forma bin aria.
#include < stdio .h > i n t main ( void ) { i n t inum =10; f l o a t fnum =2.5; double pi =3.141516; char c = Z ; FILE * pa ; char * nome = " texto . bin " ; i f (( pa = fopen ( nome , " w + " )) == NULL ) { perror ( " fopen : " ); return 1; } fwrite (& inum , s i z e o f ( i n t ) , 1 , pa ); fwrite (& fnum , s i z e o f ( f l o a t ) , 1 , pa ); fwrite (& pi , s i z e o f ( double ) , 1 , pa ); fwrite (& c , s i z e o f ( char ) , 1 , pa ); rewind ( pa ); fread (& inum , s i z e o f ( i n t ) , 1 , pa ); fread (& fnum , s i z e o f ( f l o a t ) , 1 , pa ); fread (& pi , s i z e o f ( double ) , 1 , pa ); fread (& c , s i z e o f ( char ) , 1 , pa ); printf ( " %d , %f , %f , % c \ n " , inum , fnum , pi , c ); fclose ( pa ); return 0; }

182

Uma das principais aplica co es destas fun co es e a leitura e escrita de estruturas criadas pelos usu arios. A grava ca o em bin ario da estrutura permite que o programador ao escrever ou ler do arquivo se preocupe somente com a estrutura como um todo e n ao com cada elemento que a comp oe. O programa 11.8 mostra um exemplo onde estruturas s ao gravadas e lidas de um arquivo. Neste exemplo e usado um la co para gravar uma estrutura de cada vez. No entanto, tamb em e poss vel gravar todas as estruturas de uma vez mudando o terceiro par ametro da fun ca o fwrite(). O la co seria substitu do por
fwrite( &turma[i], sizeof (struct pessoa), MAX, pa);

Para testar erro basta vericar o valor retornado pela fun ca o. Caso ela tenha retornado um valor diferente de MAX ocorreu um erro.

183

Listing 11.8: Exemplo de leitura e escrita de estruturas.


#include < stdio .h > #include < string .h > typedef s t r u c t _PESSOA { char nome [40]; i n t ano ; } PESSOA ; i n t main () { FILE * pa ; char nome [40] , linha [80]; PESSOA turma [4] , back [4]; int i; f o r ( i =0; i <4; i ++) { puts ( " Nome ? " ); fgets ( turma [ i ]. nome , 40 , stdin ); turma [ i ]. nome [ strlen ( turma [ i ]. nome ) -1]= \0 ; puts ( " Ano ? " ); fgets ( linha , 80 , stdin ); sscanf ( linha , " % d " , & turma [ i ]. ano ); } puts ( " \ nGravando \ n " ); puts ( " Qual o nome do arquivo ? " ); fgets ( nome , 40 , stdin ); nome [ strlen ( nome ) -1]= \0 ; i f (( pa = fopen ( nome , " w + " )) == NULL ) { puts ( " Arquivo nao pode ser aberto " ); return 1; } f o r ( i =0; i <4; i ++) { i f ( fwrite ( & turma [ i ] , s i z e o f ( PESSOA ) , 1 , pa ) != 1) puts ( " Erro na escrita . " ); } rewind ( pa ); f o r ( i =0; i <4; i ++) { i f ( fread ( & back [ i ] , s i z e o f ( PESSOA ) , 1 , pa ) != 1) { i f ( feof ( pa )) break ; puts ( " Erro na leitura . " ); } } f o r ( i =0; i <4; i ++) { printf ( " Nome = % s \ n " , back [ i ]. nome ); printf ( " Ano = % d \ n \ n " , back [ i ]. ano ); } return 0; }

184

11.10

Exerc cios

11.1: Escreva um programa que abra um arquivo texto e conte o n umero de caracteres presentes nele. Imprima o n umero de caracteres na tela. 11.2: Considere um arquivo de dados do tipo texto com o seguinte conte udo: 3 ZE SA 8.5 10.0 ANTONIO SANTOS 7.5 8.5 SEBASTIAO OLIVEIRA 5.0 6.0 O arquivo acima e um exemplo. Considere ent ao que nestes arquivos a primeira linha cont em o n umero de alunos no arquivo. As linhas seguintes cont em os seguintes dados: nome do aluno com no m aximo 50 caracteres; nota da primeira prova; nota da segunda prova. Escreva um programa que imprima os nomes de todos os alunos que t em a m edia das duas notas menor que 7.0 11.3: Escreva um programa que grave os dados lidos no exerc cio anterior em um arquivo do tipo bin ario de acesso aleat orio. O n umero que indica quantos alunos devem ser lidos (primeira linha do arquivo) n ao deve ser gravado no arquivo bin ario. Nesta quest ao o programa deve obrigatoriamente usar um vetor de estruturas do seguinte tipo:
typedef s t r u c t _ALUNO { char nome [81]; f l o a t n1 , n2 ; } ALUNO ;

11.4: Escreva um programa que leia de um arquivo, cujo nome sera fornecido pelo usu ario, um conjunto de n umeros reais e armazena em um vetor. O tamanho m aximo do vetor e dado pela constante TAM_MAX. A quantidade de n umeros no arquivo varia entre 0 e TAM_MAX. O programa ao nal calcula a media dos n umeros lidos. 11.5: Fa ca um programa que leia 10 caracteres e armazene em um arquivo 10 c opias de cada um. Exiba o conte udo

185

11.6: Crie uma fun ca o que receba duas strings como par ametros, uma com um endere co de arquivo e outra com um texto qualquer, e adicione o texto no m do arquivo. 11.7: Utilizando a fun ca o do exerc cio anterior fa ca um programa que gere 10 arquivos com o nome Testee extens oes 01, ..., 10. Cada um contendo o texto Texto do arquivo [NUMERO DO ARQUIVO]. 11.8: Escreva um programa para armazenar o telefone de 5 amigos. O programa deve obrigatoriamente usar a estrutura
typedef s t r u c t _PESSOA { char nome [50]; i n t idade ; f l o a t altura ; char telefone [10]; } PESSOA ;

a ser preenchida pelo usu ario antes do armazenamento de cada registro. 11.9: Fa ca um programa que leia os dados do arquivo gerado no exerc cio anterior e salve-os num novo arquivo utilizando uma sa da formatada como indicado abaixo. FORMATO: [nome] tem [idade] anos e [altura] de altura Tel.: [telefone] 11.10: Escreva um programa que leia um arquivo texto contendo linhas de dados. Em cada linha do arquivo h a o nome de um aluno e duas notas. Estes dados est ao separados por ponto e v rgula. Existe um ponto e v rgula ao nal de cada linha. O formato dos dados e o seguinte: ze sa; 10.0; 9.0; antonio silva: 9.0; 7.0; O programa deve ler estes dados e imprimir os valores lidos, a m edia das duas notas e se o aluno foi aprovado ou n ao (media 5). O formato de sa da e: ze sa 10.0 8.0 9.0 aprovado antonio silva 9.0 7.0 8.0 aprovado 11.11: Fa ca um programa que receba o nome de um arquivo e gere uma c opia. 11.12: Escreva um programa que compare dois arquivos especicados pelo usu ario e imprima sempre que os caracteres dos dois arquivos coincidirem. Por exemplo: arquivo1.c Ol a, pessoal! arquivo2.c Oi, como vai? Neste caso, os caracteres na primeira e d ecima primeira posi ca o s ao iguais nos dois arquivos. A sa da do seu programa deve ser algo como: 1 - O 11 - a 186

indicando que os primeiros caracteres dos arquivos s ao iguais (O) bem como o d ecimo primeiro (a) 11.13: Um arquivo do tipo texto, chamado numeros.txt cont em uma quantidade desconhecida de n umeros reais. Escreva um programa que leia estes n umeros, os coloque em ordem crescente e depois os grave em um arquivo bin ario chamado numeros.bin. Observa co es: (a) Neste exerc cio a quantidade de dados gravados no arquivo do tipo texto e desconhecida, portanto, e obrigat orio usar um vetor denido com ponteiro. A deni ca o de um vetor com um n umero constante de elementos, mesmo que seja um n umero grande, e considerado um erro. (b) Para testar o programa crie o arquivo com um editor simples. 11.14: Um programador escreveu os trechos de programas (I) e (II), mostrados nas listagens 11.9 e 11.10, para ler dados inteiros de um arquivo. O n umero de dados armazenados no arquivo e desconhecido. Listing 11.9: (I) Trecho de programa do problema 14.
while (1) { fscanf (p , " % d " , & i ); i f ( feof ( p )) break ; printf ( " % d \ n " , i ); }

Listing 11.10: (II) Trecho de programa do problema 14.


fscanf (p , " % d " , & i ); while (! feof ( p )) { printf ( " % d \ n " , i ); fscanf (p , " % d " , & i ); }

Qual das op co es abaixo e verdadeira? (a) Somente o trecho I funciona. (b) Somente o trecho II funciona. (c) Os dois trechos funcionam. (d) Nenhum dos dois trechos funcionam.

187

Cap tulo 12

Problemas Extras
1a Problema:

Ser a que Zen ao chega l a?


Zen ao estava perdido em uma regi ao des ertica da Terra M edia, ao norte de N arnia e a leste do famoso Castelo de Hogwarts. A cidade mais pr oxima, Forks, cava a v arios dias de caminhada. Sedento e faminto ele j a perdia as esperan cas, quando avistou, a 1000 metros de onde estava, uma fonte jorrando agua. Zen ao come cou a correr, mas chocou-se contra uma barreira m agica que circundava a fonte. No instante em que se chocou contra a barreira ouviu a seguinte mensagem: Forasteiro infeliz, para chegar at e a fonte voc e deve ter muita paci encia e fa ca o seguinte: a cada 5 minutos caminhe metade da dist ancia que ainda falta para chegar at e a fonte. Desobede ca qualquer uma destas instru c oes e a morte ser a o seu destino. Tarefa A sua tarefa e descobrir em quantos minutos Zeno ir a chegar a uma dist ancia da fonte menor do que 103 m. Entrada Este programa n ao tem entradas. Sa da O seu programa deve imprimir em quantos minutos Zeno ir a chegar na dist ancia desejada. 2a Problema:

Estat stica?

188

Uma medida importante em Estat stica e o desvio padr ao representado na equa ca o 12.2 por . Ele d a a medida da variabilidade ou dispers ao de um conjunto de dados. Al em de ser bastante u til e muito f acil de ser calculado. Considere um conjunto de N n umeros S = {x0 , x1 , x2 , . . . , xN 1 } cuja m edia ao pode ser calculado pela vale x. Para este conjunto de dados o desvio padr equa ca o 12.2.
N 1 i=0

= =

xi

N 1 N
N 1

(12.1) (xi x)2 (12.2)

i=0

Tarefa A sua tarefa e ler um conjunto de dados armazenado em um arquivo do tipo texto, chamado estatistica.txt e calcular a m edia e depois o desvio padr ao deste conjunto. Observe que o tamanho do conjunto e desconhecido e s o pode ser descoberto ap os a leitura de todos os dados. Neste exerc cio e obrigat orio o uso de ponteiros para armazenar o vetor. Sa da A sa da deve informar os valores obtidos para a m edia e o desvio padr ao. Exemplo de Arquivo de Entrada e da sa da Arquivo estatistica.txt: 1 2 3 4 5 6 7 8 9 10 3a Problema: Sa da na tela: A media vale 5.500000 O desvio padrao vale 2.872281

Vericando o CPF
Deni co es O CPF e o n umero usado pela Receita Federal no Brasil para identicar os Contribuintes Pessoas F sicas. O CPF e composto por 11 algarismos. Destes 11 algarismos os dois u ltimos s ao usados para vericar se os primeiros 9 foram digitados corretamente. Eles s ao chamados de algarismos vericadores. Por exemplo, considere o CPF exemplo 12345678909. Este CPF na realidade e 123456789,

189

os algarismos 09 servem para que os programas da Receita Federal veriquem se os 9 primeiros est ao corretos e s ao gerados automaticamente pelos computadores da Receita quando algu em se inscreve. O algoritmo de gera ca o dos dois u ltimos algarismos e descrito a seguir. Para o primeiro d gito vericador (v1 ), o 0, no nosso exemplo, o algoritmo e o seguinte: multiplique o primeiro algarismo por 10, o segundo por 9, e assim sucessivamente at e o nono algarismo do c odigo e some todos estes resultados. Neste exemplo ter amos soma1 = (1 10) + (2 9) + (3 8) + + (9 2) Calcule o valor do m odulo 11 de soma1 . Se este valor for 0 ou 1 ent ao o algarismo v1 e 0, caso contr ario o algarismo v1 e o resultado da subtra ca o 11 soma1 % 11. Para o segundo d gito vericador (v2 ), no nosso caso o 9, o algoritmo eo seguinte: multiplique o primeiro algarismo por 11, o segundo por 10, e assim sucessivamente at e o nono algarismo do c odigo e some todos estes resultados. Neste exemplo ter amos soma2 = (1 11) + (2 10) + (3 9) + + (9 3) Some este resultado ao dobro do primeiro d gito vericador (soma2 = soma2 + 2 v1 ). Calcule o valor do m odulo 11 desta nova soma2 . Se este valor for 0 ou 1 ent ao o algarismo v2 e 0, caso contr ario o algarismo v2 e o resultado da subtra ca o 11 soma2 % 11. Tarefa O programa mostrado na listagem 12.1 faz a verica ca o de um CPF fornecido pelo usu ario. Complete as partes que faltam do programa. Observe que o CPF e lido como um vetor de caracteres. Um exemplo de intera ca o do programa com um usu ario e o seguinte: Entre com o cpf. 12345678909 CPF lido: 12345678909 CPF valido. 4a Problema:

Mais perto, mais longe


Tarefa Z e S a est a planejando a sua pr oxima viagem por Pindorama. No momento ele gostaria de saber qual s ao as cidades mais distante e as mais perto da sua. Para fazer estes c alculos ele disp oe de um arquivo com as coordenadas de sua cidade e das v arias cidades que ele ir a visitar Entrada A entrada ser a feita a partir de um arquivo texto chamado cidades.txt. A primeira linha deste arquivo e um n umero inteiro n dizendo quantas cidades h a no arquivo. Considere que o n umero m aximo de cidades e igual a 50. As n 190

Listing 12.1: Processando o CPF.


#i ncl ude < stdio .h > #i ncl ude < stdlib .h > #i ncl ude < string .h > #de fi ne TAMCPF 11 #de fi ne CERTO 1 #de fi ne ERRADO 0 int int int int int cpfs ( char *); verificaCPF ( char *); digito1 ( char *); digito2 ( char * , i n t ); leCPF ( char *);

i n t main ( i n t argc , char * argv []){ char cpfs [ TAMCPF +1]; i n t tam ; tam = leCPF ( cpfs ); i f ( tam != TAMCPF ) { puts ( " CPF deve ter 11 digitos . " ); return 1; } else { i f ( verificaCPF ( cpfs )) { puts ( " CPF valido . " ); return 0; } else { puts ( " CPF invalido . " ); return 1; } } return 0; } i n t leCPF ( char * cpfs ) { puts ( " Entre com o cpf . " ); fgets ( cpfs , TAMCPF +2 , stdin ); cpfs [ strlen ( cpfs ) -1] = \0 ; printf ( " CPF lido : % s \ n " , cpfs ); return strlen ( cpfs ); } i n t verificaCPF ( char * cpfs ) { i n t dig1 , dig2 ; dig1 = digito1 ( cpfs ); dig2 = digito2 ( cpfs , dig1 ); /* AQUI FALTA O FINAL */ } i n t digito1 ( char * cpfs ) /* AQUI FALTA TODA A } i n t digito2 ( char * cpfs , /* AQUI TAMBEM FALTA } { FUNCAO

*/

i n t dig1 ) { TODA A FUNCAO */

191

linhas seguintes cont em pares de n umeros com as coordenadas de cada uma das cidades que Z e S a ir a visitar. O primeiro par de coordenadas pertence a cidade onde Z e S a vive. Sa da A sa da e composta de tr es tipos de linhas e deve ser feita no v deo. A primeira linha informa as coordenadas da cidade onde Z e S a vive. Em seguida deve(m) vir as coordenadas da(s) cidade(s) que ca(m) mais perto da cidade de Z e S a. Ap os devem vir a(s) linha(s) que mostra(m) as coordenadas da(s) cidade(s) que ca(m) mais longe da cidade de Z e S a. O exemplo abaixo mostra o formato do arquivo de entrada e o formato da sa da na tela. Exemplo de entrada e sa da Arquivo : 8 2.0 2.0 0.0 0.0 1.0 1.0 3.0 3.0 4.0 4.0 0.0 4.0 4.0 0.0 7.0 7.0 5a Problema: Sa da na tela: Origem: (2.000000, 2.000000) Mais perto: (1.000000, 1.000000) Mais perto: (3.000000, 3.000000) Mais longe: (7.000000, 7.000000)

Produto Escalar

O produto escalar de dois vetores de n dimens oes A = (a1 , a2 , . . . , an ) e B = (b1 , b2 , . . . , bn ), onde (ai , bi ) e dado pela equa ca o 12.3 A B = a1 b 1 + a2 b 2 + + an b n Tarefa Escreva um programa que calcule o produto escalar de M pares de vetores, todos em um espa co de n dimens oes. Neste problema n ao e preciso saber vetores em C. Entrada A entrada consiste das seguintes linhas de dados: 1. A primeira linha cont em um n umero inteiro M que informa o n umero de pares de vetores a serem lidos. 2. A segunda linha cont em um n umero n que indica a dimens ao de cada um dos vetores. 3. As linhas restantes cont em as coordenadas dos pares de vetores. Primeiro n linhas com as coordenadas do primeiro par, em seguida n linhas com as coordenadas do segundo par e assim sucessivamente. (12.3)

192

As coordenadas de cada par de vetores s ao fornecidas da seguinte maneira. Primeiro s ao fornecidos dois n umeros a1 b1 depois a2 b2 e assim sucessivamente at e an b n . Sa da Imprimir os M produtos escalares calculados. Exemplo de entrada: 2 4 1 1.5 2 2 3 3.5 4 4 2.0 1.0 2.0 2.0 2.0 3.0 4.0 2.5 6a Problema: Exemplo de sa da: 32.000000 22.000000

Desconando do sorteio

H a pessoas que desconam de tudo, como h a pessoas que acreditam em tudo. Em Pindorama se joga em tudo, Ultrasena, Maxisena, Lotoesportiva etc, desde que seja o governo que recebe todos os lucros. Um dos jogos e a Ultrasena, onde os jogadores devem escolher n umeros entre 1 e 60. O jogador que acertar os n umeros sorteados ganha uma fra ca o m nima do total que o governo arrecadou. Um jogador desconado acha que o sorteio e viciado e contratou voc e para descobrir se isto e verdade ou n ao. Voc e deve escrever um programa que leia os N u ltimos n umeros inteiros sorteados e conte a frequ encia com que cada um dos n umeros foi sorteado. Entrada: Primeiro o programa deve ler o valor de N . Em seguida o programa deve ler a lista de N n umeros inteiros entre 1 e 60. Sa da: Imprimir a frequ encia com que cada um dos n umeros apareceu. N umeros com frequ encia zero n ao devem ser impressos. Exemplos de entrada e sa da:

193

Exemplo de entrada 12 8 21 14 5 36 21 43 14 6 21 24 43 7a Problema:

Sa da para o exemplo de entrada 5 = 1 6 = 1 8 = 1 14 = 2 21 = 3 24 = 1 36 = 1 43 = 2

Convertendo para base 2

Escreva um programa que leia uma sequ encia de n umeros inteiros na base 10 e imprima o n umero convertido para base 2 e a maior sequ encia de bits 1 que o n umero bin ario cont em. Considere que o n umero na base 10 e menor que 232 1. Entrada: A entrada cont em v arios casos de teste. Cada linha de um caso de teste cont em um n umero inteiro menor que 232 1 O programa termina quando o usu ario fornecer um n umero negativo. Sa da: Para cada caso de teste da entrada seu programa deve produzir quatro linhas. Na primeira linha o programa deve imprimir o caso de teste no formato Teste n, onde n e n umero do caso de teste come cando em 1. Na segunda linha o n umero convertido para base 2. Zeros ` a esquerda n ao devem ser impressos. Na terceira linha o seu programa deve imprimir a maior sequ encia de 1s do n umero em bin ario. A quarta linha deve ser deixada em branco. Exemplos de entrada e sa da:

194

Exemplo de entrada 6 25 123456 14 -1

Sa da para o exemplo de entrada Teste 1 110 2 Teste 2 11001 2 Teste 3 11110001001000000 4 Teste 4 1110 3

8a Problema:

Calculando Areas
Voc e foi contratado para escrever um programa que calcula areas de c rculos. O programa deve imprimir se um c rculo tem area maior que a area m edia ou area menor ou igual a m edia. O seu programa deve usar a estrutura (12.2) para representar cada c rculo. Listing 12.2: Estrutura do problema 8.
typedef s t r u c t _CIRCULO { i n t x , y , raio ; } CIRCULO ;

Entrada Os dados estar ao organizados da seguinte maneira. Primeiro, a quantidade N de c rculos, em seguida os dados dos N c rculos, na seguinte ordem: coordenada x, coordenada y , raio raio. Obs. N ao e poss vel assumir um valor m aximo para N , aloque o espa co de mem oria necess ario. Sa da O programa de imprimir se um dado c rculo tem area maior que a m edia ou area menor ou igual a m edia. Considerando que o primeiro c rculo recebe o n umero um, o segundo o n umero 2 e assim at e o c rculo N , o formato de sa da e o seguinte: a palavra Circulo seguida do n umero do c rculo e se ele tem area maior ou menor ou igual.

195

Exemplo de Entrada: 5 1 1 1 1 2 2 3 1 2 2 2 4 1 1 3

Exemplo de Sa da: Circulo 1 area menor ou igual Circulo 2 area menor ou igual Circulo 3 area menor ou igual Circulo 4 area maior Circulo 5 area maior

9a Problema:

Lucrando com A c oes


Voc e foi contratado, pela bolsa de valores de Pindorama, para escrever um programa que imprima as a co es com o melhor e o pior desempenho durante o ano de 2325. Entrada A entrada ser a lida de um arquivo texto com o nome de acoes.txt. O arquivo consiste de uma s erie de linhas. Em cada linha h a o nome da a ca o seguido pelas cota co es no dia 01 de janeiro de 2325 e no do dia 31 de dezembro de 2325. Nenhum nome de empresa ter a mais de 20 caracteres. Observe que pode haver mais de uma pior (melhor) a ca o. Sa da A sa da dever a ser um arquivo do tipo texto, com o nome saida.txt. Neste arquivo voc e deve indicar a melhor a ca o e seu rendimento e a pior a ca o com sua perda. Observe que pode haver mais de uma melhor (pior) a ca o. Exemplo de Entrada: lixo 56.00 23.00 bb 100.00 125.00 etai 125.00 110.00 embrair 78.00 156.00 estavel 88.00 88.00 maislixo 56.00 23.00 Exemplo Sa da: Pior acao = lixo, variacao -0.59 Melhor acao = embrair, variacao 1.00 Pior acao = maislixo, variacao -0.59

10a Problema:

Somando Linhas
Escreva um programa que leia de um arquivo texto uma matriz quadrada de n umeros reais. O tamanho m aximo da matriz e 1000 1000. O nome do arquivo de entrada e matrizin.txt. O seu programa deve calcular a soma de todos os elementos de cada linha. Em seguida o seu programa deve descobrir qual e a maior soma e que linha tem soma igual a maior soma. O programa deve 196

gravar a maior soma e o(s) n umero(s) da(s) linha(s) com soma igual a maior em um arquivo texto chamado matrizout.txt. Entrada Os dados no arquivo de entrada tem o seguinte formato. A primeira linha do arquivo cont em o tamanho da matriz (1 N 1000). Em seguida o arquivo cont em N N n umeros inteiros em um formato livre, ou seja quantidade de n umeros por linha do arquivo e vari avel. Sa da O arquivo de sa da tem o seguinte formato. Primeiro o valor da maior soma das linhas. Em seguida as linhas com soma igual a maior soma. Exemplo de 5 1.0 2.0 3.0 2.0 1.0 2.0 3.0 0.0 0.0 5.0 1.0 0.0 1.0 1.0 1.0 11a Problema: Entrada: 4.0 1.0 0.0 2.0 1.0 2.0 8.0 11.0 6.0 1.0 Exemplo de Sa da: 14.000000 1 2 3

Misturando Dados
Uma tarefa muito comum em computa ca o e misturar dois vetores dados j a ordenados para criar um terceiro tamb em ordenado. A sua tarefa e escrever um programa que leia os dados de dois vetores e os misture em um terceiro. Considere que o tamanho m aximo de cada um dos dois vetores originais e desconhecido. Entrada A leitura dos dados vai ser feita da seguinte maneira. Primeiro o programa deve ler o tamanho do primeiro vetor (tam1). Em seguida o programa deve ler tam1 n umeros reais. Ap os estas leituras o programa l e o tamanho do segundo vetor (tam2). Finalmente, o programa l e tam2 n umeros reais. Considerar que os dados do primeiro e do segundo vetor est ao em ordem crescente. Sa da Ap os misturar os dois vetores em um terceiro o programa deve imprimir os tam1 + tam2 n umeros reais armazenados no terceiro vetor. Estes dados devem

197

estar em ordem crescente. Exemplo de Entrada: 5 1.0 4.0 7.0 10.0 12.0 3 1.0 2.0 9.0 Exemplo de Sa da: 1.0 1.0 2.0 4.0 7.0 9.0 10.0 12.0

198

Ap endice A

Tabela ASCII
A tabela ASCII (American Standard for Information Interchange) e usada por grande parte da ind ustria de computadores para a troca de informa co es e armazenamento de caracteres. Cada caractere e representado por um c odigo de 8 bits. A Tabela A.1 mostra os c odigos para a tabela ASCII de 7 bits. Existe uma table estendida para 8 bits que inclui os caracteres acentuados. Para saber qual e o c odigo de um caractere na base 10 junte o d gito da primeira coluna da tabela com o d gito da primeira linha da tabela. Por exemplo, o c odigo da letra a min uscula e 97 na base 10. 0 nul nl dc4 rs ( 2 F P Z d n x 1 soh vt nak us ) 3 = G Q [ e o y 2 stx syn sp * 4 H R \ f p z 3 etx cr etb ! + 5 ? I S ] g q { 4 eot so can , 6 @ J T ^ h r 5 enq si em # 7 A K U _ i s } 6 ack dle sub $ . 8 B L V j t ~ 7 bel dc1 esc % / 9 C M W a k u del 8 bs dc2 fs & 0 : D N X b l v 9 ht dc3 gs 1 ; E O Y c m w

0 1 2 3 4 5 6 7 8 9 10 11 12

Tabela A.1: Conjunto de caracteres ASCII Os caracteres de controle listados acima, servem para comunica ca o com perif ericos e controlar a troca de dados entre computadores. Eles t em o signicado mostrado na Tabela A.2.

199

Carac nul stx eot ack bs lf so dle dc2 dc4 syn can sub fs rs sp

Descri c ao Caractere nulo Come co de texto Fim de transmiss ao Conrma ca o Volta um caractere Passa para pr oxima linha Passa para pr oxima p agina Shift-out Data line escape Controle de dispositivo Controle de dispositivo Synchronous idle Cancela Substitui Separador de arquivo Separador de registro Espa co em branco

Carac soh etx enq bel ht vt cr si dc1 dc3 nak etb em esc gs us

Descri c ao Come co de cabe calho de transmiss ao Fim de texto Interroga Sinal sonoro Tabula ca o horizontal Tabula ca o vertical Passa para in cio da linha Shift-in Controle de dispositivo Controle de dispositivo Negativa de conrma ca o Fim de transmiss ao de um bloco Fim de meio de transmiss ao Escape Separador de grupo Separador de unidade

Tabela A.2: Conjunto de c odigos especiais ASCII e seus signicados

200

Ap endice B

Palavras Reservadas
Palavras reservadas, tamb em as vezes chamadas de palavra chave, servem para prop ositos especiais nas linguagens de programa ca o. Servem para declarar tipos de dados ou propriedades de um objeto da linguagem, indicar um comando al em de v arias outras fun co es. Palavras reservadas n ao podem ser usadas como nomes de vari aveis ou fun co es. asm: Indica que c odigo escrito em assembly ser a inserido junto comandos C. auto: Modicador que dene a classe de armazenamento padr ao. break: Comando usado para sair incondicionalmente dos comandos for, while, switch, and do...while. case: Comando usado dentro do comando switch. char: O tipo de dados mais simples em C, normalmente usado para armazenar caracteres. const: Modicados de dados que impede que uma vari avel seja modicada. Esta palavra n ao existia nas primeiras vers oes da linguagem C e foi introduzida pelo comit e ANSI C. Veja volatile. continue: Comando que interrompe os comandos de repeti ca o for , while , ou do...while e faz que eles passem para a pr oxima itera ca o. usado dentro do comando switch para aceitar qualquer valor n default: E ao denido previamente com um comando case. do: Comando de repeti ca o usado em conjunto com o comando while . Pela deni ca o do comando o la co e sempre executado pelo menos uma vez. double: Tipo de dados usado para armazenar valores de ponto utuante em precis ao dupla. else: Comando que indica um bloco de comandos alternativo que deve ser executado quando a condi ca o testada pelo comando if foi avaliada como FALSA. 201

enum: Tipo denido pelo usu ario que permite a deni ca o de vari aveis que ir ao aceitar somente certos valores. extern: Modicador de dados que indica que uma vari avel ir a ser declarada em outra area do programa. oat: Tipo usado para armazenar valores de ponto utuante. for: Comando de repeti ca o que cont em inicializa ca o de vari aveis, incremento e se co es condicionais. Em C o comando for e um comando de repeti ca o extremamente ex vel, permitindo in umeras possibilidades. goto: Comando que causa um pulo para uma posi ca o do programa marcada com um r otulo. if: Comando de testes usado para mudar o uxo do programa baseada em uma decis ao VERDADE/FALSO. int: Tipo de dados usado para armazenar valores inteiros. long: Tipo de dados usado para armazenar valores inteiros com precis ao maior do que o tipo int. Nos computadores modernos o tipo long tem a mesma precis ao que o tipo int e s ao usados 4 bytes. register: Especicador de classe de armazenamento que pede que, caso seja poss vel, uma vari avel deve ser armazenada nos registradores do processador. return: Comando que causa o uxo de instru co es do programa abandonar a fun ca o em execu ca o e retornar para a fun ca o que chamou. Tamb em pode ser usado para retornar um u nico valor. short: Tipo de dados usado para armazenar valores inteiros em precis ao menor do que o tipo int. Neste tipo 2 bytes s ao usados para armazenar os dados. signed: Modicador usado para indicar que uma vari avel pode armazenar tanto valores positivos como negativos. sizeof: Operador que retorna o tamanho em bytes do item fornecido. static: Modicador usado para signicar que o compilador deve preparar o c odigo de forma a reter o valor da vari avel. struct: Usado para combinar C vari aveis de tipos diferentes na mesma estrutura. switch: Comando de desvio usado para permitir que o uxo do programa possa ser mudado para v arias dire co es diferentes. Usado em conjunto com o comando case. typedef: Modicador usado para criar novos nomes para tipos j a existentes. union: Palavra chave usada para permitir m ultiplas vari aveis partilharem o mesmo espa co na mem oria.

202

unsigned: Modicador usado para signicar que uma vari avel conter a somente valores positivos. void: Palavra usada para signicar que ou a fun ca o n ao retorna nada ou que um ponteiro deve ser considerado gen erico ou ser capaz de apontar para qualquer tipo de dados. volatile: Modicador que signica que uma vari avel pode ser alterada. while: Comando de teste que executa uma se ca o de c odigo enquanto uma condi ca o retorna VERDADE. Em adi ca o a estas as seguintes palavras s ao reservadas em C++: catch, inline, template, class, new, this, delete, operator, throw, except, private, try, finally, protected, virtual, friend, public. Caso queira escrever programas que possam ser convertidas para a linguagem C++ e aconselh avel n ao us a-las.

203

Bibliograa
[1] KERNIGHAN, B. W.; RITCHIE, D. M. The C Programming Language. Englewood Clis, NJ, USA: Prentice-Hall, Inc, 1978. [2] SCHILDT, H. C Completo e Total. S ao Paulo, Brasil: Makron Books do Brasil Editora, 1997. [3] OLIVEIRA, U. de. Programando em C, Fundamentos. Rio de Janeiro, Brasil: Editora Ci encia Moderna, 2009. [4] KNUTH, D. E. The Art of Computer Programming: Fundamental Algorithms - vol. 1. Massachusetts, USA: Addison-Wesley Publishing Company, Inc, 1973.

204

Indice
baco, 21 a algebra booleana, 51 C, 34 abertura de arquivo, 179 algoritmo, 32, 41 Analytical Engine, 23 arquivo, 179 abrir arquivo, 180 fechar arquivo, 181 m de arquivo, 182 assembler, 34 assembly, 33 atribui ca o, 70 atribui co es, 52 Babbage, 22 base 2, 31 Basic, 34 BIOS, 30 bit, 31 byte, 31 C++, 34 cadeia de caractere, 68 char, 61 chipset, 29 circuitos integrados, 26 Cobol, 34 comandos de controle, 53 comandos de repeti ca o, 54 compilador, 35 compiladores, 34 constante caractere, 67 constante em ponto-utuante, 66 constante hexadecimal, 65 constante octal, 64 constantes, 61, 62 declara ca o de vari aveis, 69 Delphi, 34 depura ca o, 35 Dierence Engine, 22 double, 62 DRAM, 30 EDSAC, 26 EEPROM, 30 endere cos de mem oria, 30 ENIAC, 25 EPROM, 30 erros de compila ca o, 35 Exabyte, 32 nal de linha, 177 Flash memory, 31 uxo de dados, 177 uxo bin ario, 178 uxo de texto, 177 Fluxograma, 44, 45 Fortran, 34 gcc, 37 George Boole, 51 Gigabyte, 32 hardware, 27 Harvard Mark I, 24 IDE, 37 int, 61 Integrated Development Environment, 37 Java, 34 Kilobyte, 32 linguagem de alto n vel, 34 linguagem de m aquina, 33 linguagem intermedi aria, 36 Linguagem Natural, 44 linguagem natural, 44 205

linguagens interpretadas, 35 link edition, 35 Lisp, 34 long, 62 Megabyte, 32 mem oria, 29 mem oria cache, 29 mem oria principal, 29 microcomputadores, 28 microprocessador, 28 MINGW, 37 montar, 34 Moore, 19 null, 68 palavra de mem oria, 31 Pascal, 34 Pascalina, 22 perif ericos, 28, 32 Petabyte, 32 pipelining, 27 Prolog, 34 PROM, 30 pseudo-c odigo, 44 Pseudo-linguagem, 44 pseudo-linguagem, 45 RAM, 30 registradores, 29 ROM, 30 signed, 62 sistema operacional, 36 software, 32 soroban, 21 string, 68 Terabyte, 32 text stream, 177 tipos de dados, 61 UCP, 27 Unidade Central de Processamento, 27 Unidade de Controle, 27 Unidade de Entrada e Sa da, 27 Unidade L ogica e Aritm etica, 27 unsigned, 62 vari aveis, 61

vari avel, 68 VLSI, 27 void, 62 von Neumann, 26, 47 Z1, 24 Zuze, 24

206

Você também pode gostar