Você está na página 1de 216

Curso de Linguagem C

Em Construo
v0.003.11

Adriano Joaquim de Oliveira Cruz


Instituto de Matemti a
N leo de Computao Eletrni a
UFRJ
2011 Adriano Cruz

18 de fevereiro de 2016

Sumrio
1 Introduo

13

1.1

Sucessos e Fracassos da Computao . . . . . . . . . . . . . . . .

13

1.2

Um Pouco da Histria da Computao . . . . . . . . . . . . . . .

15

1.2.1

O Incio . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

1.2.2

A Era Moderna . . . . . . . . . . . . . . . . . . . . . . . .

16

1.2.3

O Desenvolvimento durante as Grandes Guerras . . . . .

18

1.2.4

As Geraes . . . . . . . . . . . . . . . . . . . . . . . . . .

20

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

21

1.3.1

Microcomputadores . . . . . . . . . . . . . . . . . . . . .

22

1.3.2

Memrias . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

1.3.3

Bits e Bytes . . . . . . . . . . . . . . . . . . . . . . . . . .

25

1.3.4

Perifricos . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

1.4

O Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

1.5

Um programa em C . . . . . . . . . . . . . . . . . . . . . . . . .

32

1.3

2 Algoritmos

35

2.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

2.2

Primeiros Passos . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

2.3

Representao . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

2.3.1

Linguagem Natural . . . . . . . . . . . . . . . . . . . . . .

38

2.3.2

Fluxogramas . . . . . . . . . . . . . . . . . . . . . . . . .

38

2.3.3

Pseudo-Linguagem . . . . . . . . . . . . . . . . . . . . . .

39

2.4

Modelo de von Neumann . . . . . . . . . . . . . . . . . . . . . . .

41

2.5

Estruturas Bsicas de Algoritmos . . . . . . . . . . . . . . . . . .

42

2.5.1

Comandos de leitura . . . . . . . . . . . . . . . . . . . . .

43

2.5.2

Comandos de escrita . . . . . . . . . . . . . . . . . . . . .

43

2.5.3

Expresses . . . . . . . . . . . . . . . . . . . . . . . . . .

44

2.5.4

Comandos de atribuio . . . . . . . . . . . . . . . . . . .

46

2.6

2.5.5

Comandos de controle . . . . . . . . . . . . . . . . . . . .

47

2.5.6

Comandos de repetio . . . . . . . . . . . . . . . . . . .

48

Exemplos de Algoritmos . . . . . . . . . . . . . . . . . . . . . . .

49

3 Tipos de Dados, Constantes e Variveis

56

3.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

3.2

Tipos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

3.2.1

Tipos Bsicos . . . . . . . . . . . . . . . . . . . . . . . . .

56

3.2.2

Modificadores de tipos . . . . . . . . . . . . . . . . . . . .

57

Constantes Numricas . . . . . . . . . . . . . . . . . . . . . . . .

57

3.3.1

Constantes Inteiras na base 10 . . . . . . . . . . . . . . .

58

3.3.2

Constantes Inteiras Octais . . . . . . . . . . . . . . . . . .

59

3.3.3

Constantes Inteiras Hexadecimais . . . . . . . . . . . . . .

60

3.3.4

Converso entre Bases . . . . . . . . . . . . . . . . . . . .

60

3.3.5

Constantes em Ponto Flutuante . . . . . . . . . . . . . . .

61

Constantes Caracteres . . . . . . . . . . . . . . . . . . . . . . . .

62

3.4.1

Constantes Cadeias de Caracteres . . . . . . . . . . . . .

63

Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

3.5.1

Nomes das Variveis . . . . . . . . . . . . . . . . . . . . .

64

3.5.2

Declarao de variveis . . . . . . . . . . . . . . . . . . .

64

3.5.3

Atribuio de valores . . . . . . . . . . . . . . . . . . . . .

65

3.3

3.4
3.5

4 Entrada e Sada pelo Console

68

4.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

4.2

Biblioteca Padro . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

4.3

Sada - A Funo printf . . . . . . . . . . . . . . . . . . . . . . .

69

4.3.1

Cdigos de Converso . . . . . . . . . . . . . . . . . . . .

70

4.4

Entrada - A Funo scanf . . . . . . . . . . . . . . . . . . . . . .

72

4.5

Lendo e Imprimindo Caracteres . . . . . . . . . . . . . . . . . . .

74

4.5.1

Funes getchar e putchar . . . . . . . . . . . . . . . . .

74

4.5.2

Lendo e Imprimindo Cadeias de Caracteres . . . . . . . .

75

4.5.3

Lendo e Imprimindo cadeias com scanf e printf . . . . .

76

4.5.4

Lendo e Imprimindo cadeias com gets e puts . . . . . . .

77

4.5.5

A Funo fgets . . . . . . . . . . . . . . . . . . . . . . .

78

5 Operadores e Expresses

80

5.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

5.2

Operador de Atribuio . . . . . . . . . . . . . . . . . . . . . . .

80

5.3

Operadores Aritmticos . . . . . . . . . . . . . . . . . . . . . . .

81

5.4

Operadores Relacionais e Lgicos . . . . . . . . . . . . . . . . . .

82

5.4.1

Operadores Relacionais . . . . . . . . . . . . . . . . . . .

82

5.4.2

Operadores Lgicos

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

82

5.5

Operadores com Bits . . . . . . . . . . . . . . . . . . . . . . . . .

85

5.6

Operadores de Atribuio Composta . . . . . . . . . . . . . . . .

86

5.7

Operador vrgula . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

5.8

Operador sizeof() . . . . . . . . . . . . . . . . . . . . . . . . . .

87

5.9

Converso de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . .

87

5.10 Regras de Precedncia . . . . . . . . . . . . . . . . . . . . . . . .

89

6 Comandos de Controle

92

6.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

92

6.2

Blocos de Comandos . . . . . . . . . . . . . . . . . . . . . . . . .

92

6.3

Comandos de Teste . . . . . . . . . . . . . . . . . . . . . . . . . .

92

6.3.1

Comando if . . . . . . . . . . . . . . . . . . . . . . . . . .

93

6.3.2

Comando switch . . . . . . . . . . . . . . . . . . . . . . .

94

6.3.3

Comando Ternrio . . . . . . . . . . . . . . . . . . . . . .

97

6.4

6.5

Laos de Repetio . . . . . . . . . . . . . . . . . . . . . . . . . .

97

6.4.1

Comando for . . . . . . . . . . . . . . . . . . . . . . . . .

97

6.4.2

Comando while . . . . . . . . . . . . . . . . . . . . . . . 102

6.4.3

Comando do-while . . . . . . . . . . . . . . . . . . . . . 103

Comandos de Desvio . . . . . . . . . . . . . . . . . . . . . . . . . 104


6.5.1

Comando break . . . . . . . . . . . . . . . . . . . . . . . 104

6.5.2

Comando continue . . . . . . . . . . . . . . . . . . . . . 104

6.5.3

Comando goto . . . . . . . . . . . . . . . . . . . . . . . . 104

6.5.4

Funo exit() . . . . . . . . . . . . . . . . . . . . . . . . 105

6.5.5

Comando return . . . . . . . . . . . . . . . . . . . . . . . 105

7 Vetores e Cadeias de Caracteres

109

7.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

7.2

Declarao de Vetores Unidimensionais . . . . . . . . . . . . . . . 109

7.3

Cadeias de Caracteres . . . . . . . . . . . . . . . . . . . . . . . . 114

7.4

Declarao de Vetores Multidimensionais . . . . . . . . . . . . . . 116

7.5

Vetores de Cadeias de Caracteres . . . . . . . . . . . . . . . . . . 117

7.6

Inicializao de Vetores e Matrizes . . . . . . . . . . . . . . . . . 119


3

8 Funes

125

8.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

8.2

Forma Geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

8.3

Prottipos de Funes . . . . . . . . . . . . . . . . . . . . . . . . 127

8.4

Escopo de Variveis . . . . . . . . . . . . . . . . . . . . . . . . . 127

8.5

8.4.1

Variveis Locais

. . . . . . . . . . . . . . . . . . . . . . . 128

8.4.2

Variveis Globais . . . . . . . . . . . . . . . . . . . . . . . 130

Parmetros Formais . . . . . . . . . . . . . . . . . . . . . . . . . 131


8.5.1

Passagem de Parmetros por Valor . . . . . . . . . . . . . 131

8.5.2

Passagem de Parmetros por Referncia . . . . . . . . . . 132

8.5.3

Passagem de Vetores e Matrizes . . . . . . . . . . . . . . . 132

8.6

O Comando return . . . . . . . . . . . . . . . . . . . . . . . . . 134

8.7

Recurso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

8.8

8.7.1

Como pensar recursivamente? . . . . . . . . . . . . . . . . 138

8.7.2

O que faz recurso trabalhar? . . . . . . . . . . . . . . . . 139

Argumentos - argc e argv . . . . . . . . . . . . . . . . . . . . . . 140

9 Ponteiros

145

9.1

Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

9.2

Operaes com Ponteiros . . . . . . . . . . . . . . . . . . . . . . 146


9.2.1

Declarao de Ponteiros . . . . . . . . . . . . . . . . . . . 146

9.2.2

Os Operadores Especiais para Ponteiros . . . . . . . . . . 147

9.2.3

Atribuio de Ponteiros . . . . . . . . . . . . . . . . . . . 148

9.2.4

Incrementando e Decrementando Ponteiros . . . . . . . . 150

9.2.5

Comparao de Ponteiros . . . . . . . . . . . . . . . . . . 151

9.3

Ponteiros e Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . 152

9.4

Ponteiros e Cadeias de Caracteres

9.5

Alocao Dinmica de Memria . . . . . . . . . . . . . . . . . . . 153

9.6

Ponteiros e Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . 155

9.7

Vetores de Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . 158

9.8

Ponteiros para Ponteiros . . . . . . . . . . . . . . . . . . . . . . . 159

10 Estruturas

. . . . . . . . . . . . . . . . . 153

168

10.1 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168


10.2 Definies Bsicas . . . . . . . . . . . . . . . . . . . . . . . . . . 168
10.3 Atribuio de Estruturas . . . . . . . . . . . . . . . . . . . . . . . 171
10.4 Matrizes de Estruturas . . . . . . . . . . . . . . . . . . . . . . . . 171
10.5 Estruturas e Funes . . . . . . . . . . . . . . . . . . . . . . . . . 172
10.6 Ponteiros para Estruturas . . . . . . . . . . . . . . . . . . . . . . 172
4

11 Entrada e Sada por Arquivos

181

11.1 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181


11.2 Fluxos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
11.2.1 Fluxos de Texto . . . . . . . . . . . . . . . . . . . . . . . 181
11.2.2 Fluxo Binrio . . . . . . . . . . . . . . . . . . . . . . . . . 182
11.2.3 Arquivos

. . . . . . . . . . . . . . . . . . . . . . . . . . . 182

11.3 Funes de Entrada e Sada . . . . . . . . . . . . . . . . . . . . . 183


11.4 Incio e Fim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
11.4.1 Abrindo um Arquivo . . . . . . . . . . . . . . . . . . . . . 184
11.4.2 Fechando um Arquivo . . . . . . . . . . . . . . . . . . . . 185
11.4.3 Fim de Arquivo . . . . . . . . . . . . . . . . . . . . . . . . 185
11.4.4 Volta ao Incio . . . . . . . . . . . . . . . . . . . . . . . . 186
11.5 Lendo e Escrevendo Caracteres . . . . . . . . . . . . . . . . . . . 186
11.6 Testando Erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
11.7 Lendo e Escrevendo Cadeias de Caracteres . . . . . . . . . . . . . 187
11.8 Entrada e Sada Formatada . . . . . . . . . . . . . . . . . . . . . 190
11.9 Lendo e Escrevendo Arquivos Binrios . . . . . . . . . . . . . . . 193
12 Problemas Extras

199

A Tabela ASCII

210

B Palavras Reservadas

212

Lista de Figuras
1.1

Fotografia de um circuito integrado de microprocessador Pentium. 14

1.2

Imagem de um baco. . . . . . . . . . . . . . . . . . . . . . . . .

15

1.3

Blaise Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

1.4

Charles Babbage . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

1.5

Fotografia da Difference Engine . . . . . . . . . . . . . . . . . . .

17

1.6

Computador Eniac . . . . . . . . . . . . . . . . . . . . . . . . . .

19

1.7

Diagrama Bsico de um Computador Digital . . . . . . . . . . .

22

1.8

Nveis de hierarquia da memria de um computador. . . . . . . .

23

1.9

Tamanho de Bits, Bytes e Palavras . . . . . . . . . . . . . . . . .

25

1.10 Ciclo de desenvolvimento de um programa. . . . . . . . . . . . .

30

2.1

Smbolos mais comumente usados em fluxogramas. . . . . . . . .

39

2.2

Fluxograma para resolver uma equao do primeiro grau. . . . .

40

2.3

Modelo de memria . . . . . . . . . . . . . . . . . . . . . . . . .

43

2.4

Fluxograma do comando se ...

seno. . . . . . .

47

2.5

Fluxograma para decidir se deve levar um guarda-chuva. . . . . .

49

2.6

Fluxograma do comando enquanto. . . . . . . . . . . . . . . . .

51

7.1

Mapa de memria de uma matriz. . . . . . . . . . . . . . . . . . 117

9.1

Mapa de memria com duas variveis e ponteiro. . . . . . . . . . 145

9.2

Ponteiro apontando para rea de memria contendo vetor. . . . . 146

9.3

Declarao de ponteiros. . . . . . . . . . . . . . . . . . . . . . . . 147

9.4

Atribuio de endereo de uma varivel a um ponteiro. . . . . . . 148

9.5

Uso de um ponteiro para copiar valor de uma varivel. . . . . . . 148

9.6

Exemplos de atribuies de ponteiros. . . . . . . . . . . . . . . . 149

9.7

Armazenamento de matrizes com vetores de ponteiros. . . . . . . 159

ento ...

11.1 Fluxos de dados. . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

Lista de Tabelas
1.1

Transistores por circuito integrado em microprocessadores . . . .

15

1.2

Tempo de execuo das instrues aritmticas no ENIAC . . . .

20

1.3

Exemplos de Microprocessadores . . . . . . . . . . . . . . . . . .

23

1.4

Abreviaes usadas em referncias s memrias. . . . . . . . . . .

26

1.5

Exemplos de perifricos . . . . . . . . . . . . . . . . . . . . . . .

26

2.1

Operadores Aritmticos. . . . . . . . . . . . . . . . . . . . . . . .

46

3.1

Tipos de dados definidos pelo Padro ANSI C. . . . . . . . . . .

58

3.2

Constantes Inteiras na Base 10 . . . . . . . . . . . . . . . . . . .

59

3.3

Constantes octais . . . . . . . . . . . . . . . . . . . . . . . . . . .

60

3.4

Constantes hexadecimais . . . . . . . . . . . . . . . . . . . . . . .

60

3.5

Constantes em ponto flutuante . . . . . . . . . . . . . . . . . . .

62

3.6

Exemplos de constantes caractere . . . . . . . . . . . . . . . . . .

63

3.7

Exemplos de caracteres invisveis. . . . . . . . . . . . . . . . . . .

63

3.8

Tabela do exercicio 6 . . . . . . . . . . . . . . . . . . . . . . . . .

67

4.1

Cdigos de Converso para escrita de dados. . . . . . . . . . . . .

70

5.1

Operadores aritmticos. . . . . . . . . . . . . . . . . . . . . . . .

81

5.2

Operadores Relacionais. . . . . . . . . . . . . . . . . . . . . . . .

82

5.3

Operador Lgico E. . . . . . . . . . . . . . . . . . . . . . . . . . .

83

5.4

Operador Lgico OU. . . . . . . . . . . . . . . . . . . . . . . . . .

84

5.5

Operador Lgico NO. . . . . . . . . . . . . . . . . . . . . . . . .

84

5.6

Precedncia dos operadores lgicos e relacionais. . . . . . . . . .

84

5.7

Operadores com bits. . . . . . . . . . . . . . . . . . . . . . . . . .

85

5.8

Operador Lgico OU. . . . . . . . . . . . . . . . . . . . . . . . . .

85

5.9

Precedncia dos operadores. . . . . . . . . . . . . . . . . . . . . .

89

7.1

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


7

11.1 Exemplos de funes de Entrada e Sada. . . . . . . . . . . . . . 184


A.1 Conjunto de caracteres ASCII . . . . . . . . . . . . . . . . . . . . 210
A.2 Conjunto de cdigos especiais ASCII e seus significados . . . . . 211

Lista de Algoritmos
2.1

Exemplo de Algoritmo. . . . . . . . . . . . . . . . . . . . . . . . .

37

2.2

Algoritmo para resolver uma equao do primeiro grau. . . . . . .

37

2.3

Algoritmo para calcular a mdia das notas de um aluno.

. . . . .

39

2.4

Algoritmo para calcular a maior nota de um grupo de notas. . . .

41

2.5

Modelo de memria e funcionamento de um algoritmo . . . . . . .

42

2.6

Comando se em pseudo-linguagem . . . . . . . . . . . . . . . . . .

47

2.7

Algoritmo para decidir o que fazer no domingo.

. . . . . . . . . .

48

2.8

Algoritmo para decidir se deve levar um guarda-chuva. . . . . . .

48

2.9

Algoritmo para ler 10 nmeros e imprimir se so pares ou no. . .

50

2.10 Algoritmo para ler nmeros e imprimir se so pares ou no. A quantidade de nmeros a ser lida de
2.11 Algoritmo para calcular a maior nota de uma turma de 25 alunos.

52

2.12 Algoritmo para calcular a nota mdia de uma turma de 25 alunos.

52

2.13 Algoritmo para calcular a maior temperatura do ano. . . . . . . .

53

2.14 Algoritmo do exerccio 11. . . . . . . . . . . . . . . . . . . . . . .

55

2.15 Algoritmo do exerccio 11. . . . . . . . . . . . . . . . . . . . . . .

55

3.1

61

Algoritmo para converter inteiros na base 10 para uma base b. . .

Listings
1.1

Exemplo de Programa em C. . . . . . . . . . . . . . . . . . . . .

32

4.1

Exemplo de impresso de resultados . . . . . . . . . . . . . . . .

69

4.2

Exemplo de justificao de resultados. . . . . . . . . . . . . . . .

71

4.3

Exemplo de uso de especificador de preciso. . . . . . . . . . . .

72

4.4

Exemplo de uso de scanf.

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

74

4.5

Exemplo de uso de getchar e putchar. . . . . . . . . . . . . . .

75

4.6

Exemplo de uso de getchar e putchar. . . . . . . . . . . . . . .

76

4.7

Exemplo de uso de printf e scanf na leitura de cadeias. . . . .

76

4.8

Exemplo de uso de puts e gets na leitura de cadeias.

. . . . . .

78

5.1

Exemplo de operadores de deslocamento.

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

86

5.2

Exemplo do operador sizeof.

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

88

5.3

Variveis da questo 9.

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

91

6.1

Exemplo de comandos if.

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

94

6.2

Programas com ifs em escada e aninhados. . . . . . . . . . . . .

95

6.3

Exemplo de switch.

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

98

6.4

Exemplo de comando ternrio. . . . . . . . . . . . . . . . . . . .

99

6.5

Exemplo de comando for. . . . . . . . . . . . . . . . . . . . . . . 100

6.6

Exemplo de comando for com testes sobre outras variveis. . . . 100

6.7

Exemplo de comando for sem alterao da varivel de controle.

6.8

Exemplo de comando for sem teste de fim.

6.9

Comando for aninhados.

101

. . . . . . . . . . . . 101

. . . . . . . . . . . . . . . . . . . . . . 102

6.10 Comando while com uma funo.


6.11 Programa do exercicio 17.

. . . . . . . . . . . . . . . . . 103

. . . . . . . . . . . . . . . . . . . . . 108

7.1

Exemplo de vetores. . . . . . . . . . . . . . . . . . . . . . . . . . 110

7.2

Produto escalar de dois vetores.

7.3

Ordenao pelo mtodo da bolha.

7.4

Exemplos de funes para cadeias. . . . . . . . . . . . . . . . . . 115

7.5

Leitura de uma matriz.

. . . . . . . . . . . . . . . . . . 111
. . . . . . . . . . . . . . . . . 113

. . . . . . . . . . . . . . . . . . . . . . . 116

10

7.6

Multiplicao de duas matrizes.

7.7

Leitura de um vetor de nomes. . . . . . . . . . . . . . . . . . . . 119

7.8

Exemplos de tratamento de vetores. . . . . . . . . . . . . . . . . 120

7.9

Exemplos de tratamento de vetores. . . . . . . . . . . . . . . . . 121

7.10 Programa do exercicio 14.

. . . . . . . . . . . . . . . . . . 118

. . . . . . . . . . . . . . . . . . . . . 124

8.1

Exemplo de prottipos. . . . . . . . . . . . . . . . . . . . . . . . 128

8.2

Exemplos de variveis locais. . . . . . . . . . . . . . . . . . . . . 129

8.3

Definio de varivel dentro de um bloco. . . . . . . . . . . . . . 129

8.4

Definio de varivel global.

8.5

Exemplo de passagem por valor. . . . . . . . . . . . . . . . . . . 131

8.6

Uso indevido de variveis locais. . . . . . . . . . . . . . . . . . . 132

8.7

Passagem de vetor com dimenses.

8.8

Passagem de vetores sem dimenses.

8.9

Fatorial calculado no recursivamente.

. . . . . . . . . . . . . . . . . . . . 130

. . . . . . . . . . . . . . . . 133
. . . . . . . . . . . . . . . 135
. . . . . . . . . . . . . . 136

8.10 Fatorial calculado recursivamente. . . . . . . . . . . . . . . . . . 136


8.11 Chamada recursiva direta.

. . . . . . . . . . . . . . . . . . . . . 137

8.12 Chamada recursiva indireta.

. . . . . . . . . . . . . . . . . . . . 137

8.13 Funo recursiva para calcular xn . . . . . . . . . . . . . . . . . . 137


8.14 Chamada recursiva com cauda.

. . . . . . . . . . . . . . . . . . 138

8.15 Chamada recursiva sem cauda. . . . . . . . . . . . . . . . . . . . 138


8.16 Soma de vetor recursiva.

. . . . . . . . . . . . . . . . . . . . . . 139

8.17 Uso de argc e argv. . . . . . . . . . . . . . . . . . . . . . . . . . 141


8.18 Programa do exerccio 8.

. . . . . . . . . . . . . . . . . . . . . . 143

8.19 Programa do problema 9. . . . . . . . . . . . . . . . . . . . . . . 144


9.1

Exemplo de atribuio de ponteiros. . . . . . . . . . . . . . . . . 149

9.2

Exemplos de operaes com ponteiros.

9.3

Exemplo de subtrao de ponteiros. . . . . . . . . . . . . . . . . 151

9.4

Exemplo de comparao de ponteiros. . . . . . . . . . . . . . . . 151

9.5

Exemplo de alteraes invlidas sobre ponteiros. . . . . . . . . . 152

9.6

Exemplo de notaes de vetores. . . . . . . . . . . . . . . . . . . 152

9.7

Exemplo de ponteiro varivel.

9.8

Exemplo de ponteiro para cadeia de caracteres.

9.9

Exemplo de cpia de cadeias de caracteres. . . . . . . . . . . . . 154

. . . . . . . . . . . . . . . . . . . 153

9.10 Exemplo de uso de allo e free.


9.11 Exemplo de uso de mallo .

. . . . . . . . . . . . . . 150

. . . . . . . . . 154

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

. . . . . . . . . . . . . . . . . . . . . 156

9.12 Exemplo de matriz normal sem uso de ponteiros.


9.13 Exemplo de matriz mapeada em um vetor.
11

. . . . . . . . 157

. . . . . . . . . . . . 157

9.14 Exemplo de uso de vetor de ponteiros.

. . . . . . . . . . . . . . 158

9.15 Exemplo de uso de ponteiros para ponteiros.

. . . . . . . . . . . 160

9.16 Exemplo de uso de ponteiros para ponteiros usando funes.


9.17 Continuao do exemplo 9.16.

. . 161

. . . . . . . . . . . . . . . . . . . 162

9.18 Programa do exercicio 11.

. . . . . . . . . . . . . . . . . . . . . 164

9.19 Programa do exercicio 12.

. . . . . . . . . . . . . . . . . . . . . 165

9.20 Listagem do exerccio 13. . . . . . . . . . . . . . . . . . . . . . . 166


9.21 Programa do exerccio 14.

. . . . . . . . . . . . . . . . . . . . . 167

10.1 Definio de uma estrutura. . . . . . . . . . . . . . . . . . . . . . 169


10.2 Atribuio de Estruturas. . . . . . . . . . . . . . . . . . . . . . . 171
10.3 Ordenao de Estruturas. . . . . . . . . . . . . . . . . . . . . . . 173
10.4 Passando elementos para funes.

. . . . . . . . . . . . . . . . . 174

10.5 Passagem de estruturas para funes.


10.6 Funo que ordena estruturas.

. . . . . . . . . . . . . . . 174

. . . . . . . . . . . . . . . . . . . 175

10.7 Alocao de espao para estruturas. . . . . . . . . . . . . . . . . 177


10.8 Alocao de espao para vetores de estruturas. . . . . . . . . . . 178
10.9 Listagem do exercicio 3.
11.1 Uso da funo feof().

. . . . . . . . . . . . . . . . . . . . . . 179
. . . . . . . . . . . . . . . . . . . . . . . 186

11.2 Exemplo de leitura e escrita de caracteres.

. . . . . . . . . . . . 188

11.3 Exemplo de leitura e escrita de caracteres.

. . . . . . . . . . . . 189

11.4 Uso da funo ferror(). . . . . . . . . . . . . . . . . . . . . . . 190


11.5 Exemplo de leitura e escrita de cadeias de caracteres.

. . . . . . 191

11.6 Exemplo de leitura e escrita de dados formatados. . . . . . . . . 192


11.7 Exemplo de leitura e escrita na forma binria.
11.8 Exemplo de leitura e escrita de estruturas.
11.9 (I) Trecho de programa do problema 14.

. . . . . . . . . . 193

. . . . . . . . . . . . 195
. . . . . . . . . . . . . 198

11.10(II) Trecho de programa do problema 14. . . . . . . . . . . . . . 198


12.1 Processando o CPF. . . . . . . . . . . . . . . . . . . . . . . . . . 202
12.2 Estrutura do problema 8. . . . . . . . . . . . . . . . . . . . . . . 206

12

Captulo 1

Introduo
1.1 Su essos e Fra assos da Computao
Os objetivos principais deste captulo so mostrar para o aluno iniciante alguns
aspectos da histria da computao e definir, informalmente, termos e palavraschave que os profissionais da rea de computao usam no seu dia a dia. Adriano
Cruz .
A histria do desenvolvimento dos computadores tem sido impressionante.
O avano da tecnologia e a presena da computao na nossa vida so inegveis. Embora a histria deste fantstico desenvolvimento seja recente e bem
documentada, h lacunas e controvrsias impressionantes sobre diversos pontos.
Neste captulo iremos ver histrias de espionagem e brigas na justia por roubo
de ideias. H oportunidades perdidas e gente que soube aproveitar a sua chance.
H verdades estabelecidas que tiveram de ser revistas.
O avano na tecnologia dos computadores se deu em passos to largos que os
primeiros computadores parecem to distantes no tempo quanto a Pr-Histria.
O aumento de velocidade, desde os anos 40, foi da vrias ordens de grandeza,
enquanto que o custo dos computadores caiu de milhes de dlares para valores em torno de centenas de dlares. As primeiras mquinas tinham milhares
de vlvulas, ocupavam reas enormes e consumiam quilowatts de energia. O
microprocessador Pentium, lanado em 1993, tinha em torno de 3,1 milhes
de transistores, ocupava uma rea de aproximadamente 25 cm2 e consumia
alguns watts de energia, custando aproximadamente 1000 dlares, somente o
microprocessador. A Figura 1.1 mostra a imagem de um circuito integrado de
microprocessador Pentium.
No entanto, esta histria de reduo de tamanho, aumento de velocidade e
diminuio de gasto de potncia, pode, para alguns pesquisadores, j ter uma
data fixada 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 ficou conhecido como a Lei de Moore: Cada novo
circuito integrado ter o dobro de transistores do anterior e ser lanado dentro
de um intervalo de 18 a 24 meses. Moore achava que esta lei seria vlida somente at 1975, no entanto, ela continua vlida at hoje. Na tabela 1.1, pode-se
observar a evoluo dos microprocessadores usados em nossos computadores.
13

Figura 1.1: Fotografia de um circuito integrado de microprocessador Pentium.

Os transistores, que compem os circuitos eletrnicos, esto diminuindo de


tamanho, e estamos nos aproximando da fronteira final, os eltrons. J se houve
falar em tamanho de transistores medidos em nmeros de eltrons. Devemos nos
lembrar que toda a tecnologia atual est baseada em fluxo de eltrons, ou seja
uma corrente eltrica. Os fios conduzem correntes de eltrons e os transistores
controlam este fluxo. Se o tamanho diminuir alm dos eltrons estaremos em
outro domnio.
No entanto, na histria da computao, muitas promessas no foram cumpridas e falhas gigantescas aconteceram. Como em diversas questes, artistas
geniais, apontam o que no conseguimos ou no queremos ver e mostram que
o rei est nu. H uma frase de Picasso que diz: Computadores so estpidos, eles somente conseguem responder perguntas. Esta frase expe com ironia
um fracasso da comunidade de computao que havia prometido criar rapidamente computadores inteligentes, computadores que poderiam questionar-se e
nos questionar. Muitos acreditaram nesta promessa e muitos livros de fico cientfica foram publicados em que este tipo de computador estaria disponvel em
um futuro muito prximo. Com notvel exemplo podemos citar o filme 2001 Uma Odissia no Espao, de Stanley Kubrik que estreou em 1968 e foi baseado
no conto The Sentinel, escrito em 1950 por Arthur Clark, um dos mestres da
fico cientfica. Neste filme o enlouquecido computador HAL 9000, que era
capaz de ver, falar, raciocinar etc, mata quase todos os tripulantes de uma nave
espacial. Ora, j passamos por 2001 e no existe a menor possibilidade de se
ver um computador como o HAL ou to louco de pedra como ele.
Na computao, um exemplo fantstico de sucesso a Internet. A Internet
est se tornando essencial para o funcionamento do mundo moderno. Freqentemente ouvimos dizer que ela o meio de comunicao que mais rapidamente se
difundiu pelo mundo. Pode parecer verdade, j que conhecemos tantos internautas e as empresas esto se atropelando para fazer parte desta onda e aproveitar
as suas possibilidades. Esta corrida provocou alguns acidentes e muitos sonhos
de riqueza se esvaram no ar. Hoje, pode-se fazer quase tudo pela Internet,
namorar, comprar, pagar contas, fazer amigos, estudar, jogar etc. Quem sabe,
em um futuro prximo, voltaremos Grcia Antiga e nos reuniremos em uma
enorme praa virtual para, democraticamente, discutir nossas leis, dispensando
intermedirios.

14

Ano
1971
1972
1974
1974
1982
1984
1985
1989
1993
1997
1997
1999
2000
2009
2011
2012
2014
2015

Processador
Intel 4004
Intel 8008
Motorola 6800
Intel 8080
Intel 80286
Motorola 68020
Intel 80386
Intel 80486 DX
Intel Pentium
Intel Pentium II
AMD K6
Intel Pentium III
Intel Pentium 4
AMD Six-core Opteron 2400
Intel Quad-core + GPU Core i7
AMD Quad-core + GPU Trinity
Intel 18-core Xeon Haswell-E5
IBM z13 Storage Controller

Transistores
2.250
2.500
4,100
5.000
120.000
190,000
275.500
1.180.000
3.100.000
7.500.000
8,800,000
24.000.000
42.000.000
904,000,000
1,160,000,000
1,303,000,000
5,560,000,000
7,100,000,000

Tabela 1.1: Transistores por circuito integrado em microprocessadores

1.2 Um Pou o da Histria da Computao


1.2.1 O In io
A primeira tentativa de se criar uma mquina de contar foi o baco. A palavra
vem do rabe e significa p. Os primeiros bacos eram bandejas de areia sobre
as quais se faziam figuras para representar as operaes. Aparentemente, os
chineses foram os inventores do baco de calcular. No entanto, h controvrsias,
e os japoneses tambm reivindicam esta inveno, que eles chamam de soroban.
Alm disso h os russos, que inventaram um tipo mais simples, chamado de
tschoty. So conhecidos exemplares de baco datados de 2500 A.C. A Figura
1.2 ilustra um exemplar com as suas contas e varetas.

Figura 1.2: Imagem de um baco.


Em 1901 mergulhadores, trabalhando perto da ilha grega de Antikythera,
15

encontraram os restos de um mecanismo, parecido com um relgio, 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, matemtico escocs, inventou um dispositivo feito de
marfim para demonstrar a diviso por meio de subtraes e a multiplicao por
meio de somas. A semelhana entre marfim e ossos, fez com que o dispositivo
fosse conhecido como os ossos de Napier.
Um dos primeiros instrumentos modernos de calcular, do tipo mecnico, foi
construdo pelo filsofo, matemtico e fsico francs Blaise Pascal (Figura 1.3).
Em 1642 aos 19 anos, na cidade de Rouen, Pascal desenvolveu uma mquina de
calcular, para auxiliar seu trabalho de contabilidade. A engenhoca era baseada
em 2 conjuntos de discos interligados por engrenagens: um para a introduo
dos dados e outro para armazenar os resultados. A mquina 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 Frana, o que lhe possibilitou o lanamento de sua mquina no mercado. A comercializao das calculadoras no foi
satisfatria devido a seu funcionamento pouco confivel, apesar dele ter construdo cerca de 50 verses. As mquinas de calcular, derivadas da Pascalina,
como ficou conhecida sua mquina, ainda podiam ser encontradas em lojas at
alguns poucos anos atrs. Antes de morrer, aos 39 anos, em 1662, Pascal que
contribura em vrios campos da Cincia, ainda teve tempo de criar uma variante de sua mquina, a caixa registradora.
Em 1666, Samuel Morland adaptou a calculadora de Pascal para resolver
multiplicaes por meio de uma srie de somas sucessivas. Independentemente,
em 1671 Leibniz projetou uma outra calculadora que somava e multiplicava.
Esta calculadora s foi concluda em 1694.
O primeiro computador de uso especfico comeou a ser projetado em 1819
e terminou em 1822, ou seja, h mais de 180 anos atrs, pelo britnico Charles (1791-1871, Figura 1.4), que o batizou de Difference Engine (Figura 1.5).
A motivao de Babbage era resolver polinmios pelo mtodo das diferenas.
Naquele tempo as tbuas astronmicas e outras tabelas eram calculadas por
humanos, em mtodos tediosos e repetitivos.
16

Figura 1.4: Charles Babbage

Figura 1.5: Fotografia da Difference Engine

Em 1823, ele iniciou o projeto de construir uma outra mquina mais avanada e capaz de calcular polinmios de at sexta ordem. Ele esperava terminar
esta mquina em trs anos, mas a construo se arrastou at 1834. Este projeto
que no foi completado, usou dinheiro do governo ingls e possivelmente a maior
parte da fortuna pessoal de Babbage. A mquina, inteiramente mecnica, teria
as seguintes caractersticas:
Arredondamento automtico;
Preciso dupla;
Alarmes para avisar fim de clculo;
Impresso automtica de resultados em placas de cobre.
Em 1834 ele tinha completado os primeiros desenhos da mquina que denominou Analytical Engine que tinha as seguintes caractersticas:
50 dgitos decimais de preciso;
17

Memria para 1000 destes nmeros (165000 bits);


Controle por meio de cartes perfurados das operaes e endereos dos
dados;
Tempo de soma e subtrao igual a 1 segundo; tempo de multiplicao e
diviso igual a 1 minuto;
Sub-rotinas;
Arredondamento automtico e deteco de transbordo (overflow );
Babagge nunca conseguiu terminar este ambicioso projeto. No entanto, os
mais importantes conceitos de computao, que somente vieram a tona nos anos
40 do sculo vinte, j tinham sido considerados por Charles Babbage em o seu
projeto.
Um fato curioso 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, aps seu casamento, estudava Matemtica com DeMorgan que provou um dos teoremas bsicos da lgebra Booleana, que a base
matemtica sobre a qual foram desenvolvidos os projetos dos modernos computadores. No entanto, no havia nenhuma ligao entre o trabalho do projetista
dos primeiros computadores e o do matemtico que estudava o que viria a ser
o fundamento terico de todo a computao que conhecemos hoje.

1.2.3 O Desenvolvimento durante as Grandes Guerras


Antes da Segunda Grande Guerra, em vrios pases, cientistas trabalhavam em
projetos que visavam construir computadores com rels, que so dispositivos
eletromecnicos usados para ligar ou desligar circuitos eltricos. Rels so os
dispositivos que antecederam os transistores na construo de computadores.
Alguns destes computadores eram de uso geral, outros tinha finalidades especficas. Alguns destes projetos esto listados a seguir.
Na Alemanha
Em 1934 na Alemanha Konrad Zuze, engenheiro projetista de avies, concebeu
uma mquina de somar para resolver os clculos que deveria realizar em seus
projetos. Em 1938, ele concluiu o Z1, um calculador mecnico com uma unidade
aritmtica que usava a base 2 para representar os nmeros, base que hoje os
computadores modernos empregam. Em 1938 ele melhorou o desempenho do
Z1, graas aos rels.
O governo alemo patrocinou os trabalhos de Zuze e em 1941 estava pronto
o Z2, uma mquina eletromecnica capaz de receber instrues por meio de uma
fita de papel. Em 1941 foi introduzido o Z3, que calculava trs a quatro adies
por segundo, uma multiplicao em 4 ou 5 segundos e era capaz de extrair a
raiz quadrada.

18

Nos Estados Unidos


Em 1944 a IBM e H. Haiken da Universidade de Harvard, concluam a construo de um verdadeiro computador: o Harvard Mark I, que operava em base 10.
O Mark I efetuava as quatro operaes fundamentais, mais o clculo de funes
trigonomtricas, exponenciais e logartmicas. As instrues eram fornecidas por
meio de fitas de papel e os dados lidos de cartes perfurados. Os resultados eram
fornecidos em forma de cartes perfurados ou impressos por meio de mquinas
de escrever.
Em 1943 na Universidade da Pensilvnia, J. Eckert e J. Mauchly iniciaram a
construo de um computador vlvulas, ou seja eletrnico que foi chamado de
ENIAC. O projeto foi concludo em 1946 e usado na segunda guerra mundial.
O ENIAC podia ser reprogramado para executar diversas operaes diferentes
atravs de ligaes por meio de fios e conectores.
Durante muitos anos o computador ENIAC foi considerado o primeiro computador eletrnico construdo. A mquina 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 laboratrio inteiro,
pesava trinta toneladas, e consumia duzentos quilowatts de potncia.

Figura 1.6: Computador Eniac


Ele gerava tanto calor que teve de ser instalado em um dos poucos espaos
da Universidade que possua sistemas de refrigerao forada. Mais de 19000
vlvulas, eram os elementos principais dos circuitos do computador. Ele tambm tinha quinze mil rels e centenas de milhares de resistores, capacitores e
indutores. Toda esta parafernlia eletrnica foi montada em quarenta e dois
painis com mais 2,70 metros de altura, 60 centmetros de largura e 30 centmetros de comprimento, montados na forma da letra U. Uma leitora de cartes
perfurados e uma perfuradora de cartes eram usados para entrada e sada de
dados.
Os tempos de execuo do ENIAC so mostrados na Tabela 1.2. Compare
estes tempos com os tempos dos computadores atuais que esto na ordem de
nano segundos, ou 109 segundos.
Em 1939 John Vincent Atanasoff e Clifford E. Berry, na Universidade Estadual de Iowa construram um prottipo de computador digital eletrnico, que
usa aritmtica binria. Em 19 de outubro de 1973, o juiz federal Earl R. Larson
19

Operao
soma
multiplicao
diviso

Tempo
200 s
2,8 ms
6,0 ms

Tabela 1.2: Tempo de execuo das instrues aritmticas no ENIAC

assinou uma deciso, em seguida a uma longa batalha judicial, que declarava
a patente do ENIAC de Mauchly e Eckert invlida e atribua a Atanasoff a
inveno computador eletrnico digital, o ABC ou Atanasoff-Berry Computer.
Na Inglaterra
Jnos von Neumann, emigrante hngaro que vivia nos EUA, sugeriu que a
memria do computador deveria ser usada para armazenar as instrues do
computador de maneira codificada, o conceito de programa armazenado. Esta
idia foi fundamental para o progresso da computao. Os primeiros computadores, como o ENIAC, eram programados por fios que os cientistas usavam para
conectar as diversas partes. Quando um programa terminava, estes cientistas
trocavam os fios de posio de acordo com a nova tarefa a ser executada. Com o
programa armazenado na memria, juntamente com os dados, no era mais necessrio interromper as atividades. Carregava-se o programa na memria, uma
tarefa extremamente rpida, junto com os dados e dava-se partida no programa.
Ao trmino da execuo do programa passava-se imediatamente para a prxima
tarefa sem interrupes para troca de fios.
Em 1949, na Inglaterra, dois computadores que usavam a memria para
armazenar tanto programas como dados foram lanados. Na Universidade de
Cambridge foi lanado o EDSAC, (Electronic Delay Storage Automatic Calculator) e em Manchester o computador chamado de Manchester Mark I. O EDSAC
considerado o primeiro computador de programa armazenado a ser lanado.
Curiosamente, a Universidade de Manchester reivindica que o primeiro computador de programa armazenado foi o chamado Baby, um prottipo do Mark I,
que comeou a operar onze meses antes do EDSAC.
Outro fato curioso em relao Inglaterra e que foi divulgado recentemente
relata que um computador chamado COLOSSUS entrou em operao secretamente na Inglaterra em 1943. Este computador foi usado para auxiliar na
quebra dos cdigos de criptografia alemes durante a segunda grande guerra.

1.2.4 As Geraes
Costumava-se dividir os projetos de computadores em geraes. Hoje em dia
como a taxa de evoluo muito grande no se usa mais este tipo de terminologia. No entanto interessante mencionar estas divises.
Primeira Gerao: Os computadores construdos com rels e vlvulas so os
da primeira gerao. Estes computadores consumiam muita energia e
espao.
20

Segunda Gerao: Os computadores da segunda gerao foram construdos


com transistores, os quais tinham a vantagem de serem mais compactos e
consumirem muito menos energia. Por gerarem menos calor eram mquinas mais confiveis.
Terceira Gerao: Com o advento dos circuitos integrados, que so componentes em que vrios transistores so construdos em uma mesma base
de semicondutor, chegamos aos computadores de terceira gerao. Com
a integrao o tamanho dos computadores e seu consumo diminuiu ainda
mais e aumentou a capacidade de processamento.
Quarta Gerao: Os computadores de quarta gerao utilizavam circuitos
com a tecnologia (Very Large Scale Integration), que permitia uma escala
de integrao de transistores muito grande.

1.3 O Hardware
O hardware corresponde aos circuitos eletrnicos e componentes mecnicos que
compem o computador. Um tpico diagrama em blocos de um computador
digital monoprocessado esta mostrado na Figura 1.7. A Unidade Central
de Processamento (UCP), em ingls Central Processing Unit (CPU), como o
prprio nome diz, a unidade onde os dados so processados, ou seja alterados,
no computador. Ou seja, dentro das UCPs os dados so somados, subtrados
etc. A UCP tambm controla a movimentao dos dados dentro de todo o
sistema. Os mdulos que constituem a UCP so os seguintes:
Unidade de Controle (UC): comanda a operao do computador. Esta unidade l da memria tanto as instrues como os dados e comanda todos
os circuitos para executar cada instruo lida da memria. Atualmente as
unidades de controle so capazes de executar mais de uma instruo por
ciclo de mquina, o que caracteriza o processamento paralelo. A tcnica
mais comum para conseguir este paralelismo conhecida como pipelining,
que ser detalhada mais adiante.
Unidade Aritmtica e Lgica (UAL): local onde as transformaes sobre
os dados acontecem. Atualmente esta unidade bastante sofisticada e
diversos mtodos so empregadas para acelerar a execuo das instrues.
Alguns processadores duplicam circuitos para permitir que mais de uma
operao aritmtica seja executada por vez. muito comum, por exemplo, a existncia de uma unidade aritmtica para executar instrues que
operam sobre nmeros inteiros e outra sobre nmeros reais, chamada de
unidade de ponto flutuante. As vezes a UCP conta com mais de uma de
cada uma destas unidades.
Unidade de Entrada e Sada (UES): controla a comunicao com os usurios do computador e os equipamentos perifricos tais como discos e impressoras. Em alguns computadores mais simples esta unidade no existe
independentemente, sendo distribuda pela Unidade Central de Processamento. Em computadores mais poderosos ao contrrio as Unidades de
Entrada e Sada so computadores completos que foram programados para
controlar a comunicao com os perifricos.
21

Unidade
de
Controle

Unidade
de
Entrada
e
Sada
Memria

Unidade
Arimtica

Discos

Vdeo

Unidade
Central
de
Processamento

Figura 1.7: Diagrama Bsico de um Computador Digital


O termo pipelining que mencionamos acima se refere a um dos modos de
como o processador pode paralelizar a execuo de instrues. Este termo pode
ser traduzido por linha de montagem, porque exatamente isto que a tcnica
faz, uma linha de montagem de instrues. Por exemplo, em uma linha de
montagem de uma fbrica de automveis, mais de um automvel montado
ao mesmo tempo. No incio da linha o carro no existe. Em cada estgio da
linha de montagem os operrios vo adicionando partes e ao fim da linha sai
um carro novo. Se voc olhar a linha poder ver carros em diversos estgios da
montagem. Repare que a linha no pra, e a montagem de um carro no espera
que o que comeou a ser montado antes dele esteja terminado. Nas linhas de
montagem muitos carros so montados ao mesmo tempo. O efeito final que
cada carro continua levando bastante tempo para ser montado, mas como vrios
vo sendo montados ao mesmo tempo, algum que se colocasse no final da linha
de montagem teria a impresso que cada carro leva muito pouco tempo para
ser montado. Isto porque no final da linha de montagem sai um carro a cada
poucos minutos. O mesmo acontece com a linha de montagem de instrues.

1.3.1 Mi ro omputadores
Uma UCP integrada em um nico circuito (chip) comumente chamada de
microprocessador . Os microprocessadores atuais incluem outros circuitos que
normalmente ficavam fora da UCP, tais como processadores de ponto flutuante
e memrias cache. Alguns exemplos de microprocessadores so mostrados na
Tabela 1.3
Usualmente se chama de computador, o processador mais os seus perifricos
e os sistemas para controlar estes perifricos, ou seja todo o sistema de processamento de dados. Os perifricos so os dispositivos usados para fazer a entrada
e sada dos dados que sero processados.
Os microcomputadores so computadores baseados em microprocessadores. As assim chamadas placas me dos microprocessadores atuais incluem
diversos componentes que formam o microcomputador. Por exemplo, uma placa
me pode incluir o microprocessador e seus circuitos de suporte, que, no conjunto so conhecidos como o chipset. Alm disso a placa me pode incluir tambm a memria principal e as placas de controle de perifricos, como a placa de
22

Microprocessador
Arquitetura Intel X86
PowerPC
Power
MIPS
ARM
SPARC

Empresa
Intel, AMD
Consrcio Apple/IBM/Motorola
IBM
MIPS Technologies
ARM Technologies
SUN

Tabela 1.3: Exemplos de Microprocessadores

vdeo, e os conectores para os perifricos, enfim, quase todo o sistema.

1.3.2 Memrias
Os dados no computador podem ser armazenados em diversos nveis de memria
semicondutoras ou em perifricos (discos, fitas, etc). Quanto mais rpida a
memria, usualmente mais cara ela . A idia por traz da separao em nveis
colocar mais perto do processador, em memrias rpidas e mais caras, os
dados que o processador ir precisar mais freqentemente. A medida que vamos
nos afastando do processador as memrias vo, ao mesmo tempo, ficando mais
baratas, aumentando de capacidade e diminuindo de velocidade. A Figura 1.8
ilustra esta hierarquia.

PROCESSADOR

MEMRIA

DISCO

CACHE
REGISTRADORES

Figura 1.8: Nveis de hierarquia da memria de um computador.


No nvel mais prximo do processador esto os registradores , que, na verdade, ficam internamente ao processador. So poucos e extremamente rpidos
e, portanto, no podem armazenar grandes quantidades de dados. Somente os
dados que so necessrios ao processador com rapidez extraordinria devem ser
colocados nos registradores.
Durante o processamento normal, na memria principal onde o processador busca instrues e dados de um programa para executar. Alm da memria
principal esto os discos. Devido a sua velocidade menor que a da memria
principal e a sua grande capacidade, os discos so considerados dispositivos de
armazenamento secundrio. Os discos tambm so memrias de armazenamento
permanente, isto , quando os computadores so desligados o seu contedo se
mantm. Ao contrrio, a memria principal e os registradores so memrias
semicondutoras e perdem seus contedos quando a energia eltrica desligada.
23

Em alguns computadores os discos esto sendo substitudos por memrias semicondutoras.


Para acelerar o acesso aos dados freqentemente usados, os computadores
dispem de memrias mais rpidas, porm de menor capacidade, que ficam entre os registradores e a memria principal. Estas funcionam como as bolsas ou
carteiras em que carregamos documentos e outros itens que precisamos freqentemente. Este tipo de memria conhecido como memria cache. O cache
opera de forma invisvel para o processador. Ao pedir um dado para memria,
circuitos especiais verificam se este dado est no cache, caso esteja, ele repassado para o processador. Para o processador o que aconteceu que a memria
entregou o dado com uma rapidez maior do que o normal.
Uma memria como se fosse uma srie de cofres numerados capazes de
armazenar os dados, como est ilustrado na Figura 2.3. Os dados e instrues
na memria so apontados ou referenciados por estes nmeros, conhecidos como
endereos. Ou seja, para ler um dado da memria necessrio fornecer um
endereo para que a memria possa encontrar e devolver o contedo pedido. Isto
similar ao o que ocorre quando enviamos uma carta, o endereo faz com que o
carteiro saiba onde ele deve entregar a correspondncia. Em operao normal,
toda vez que o processador precisa de um dado ele envia um pedido de leitura
memria junto com o endereo da memria onde o dado est. Nas escritas
o processador envia o endereo, o dado e pedido de escrita. Normalmente a
memria somente pode atender um pedido de cada vez. Portanto, para ler 1000
nmeros o processador ter de fazer 1000 acessos seqencialmente.
Os dois tipos bsicos de memria mais comuns so ROM e RAM. Estas
siglas tm diversas variaes (PROM, EPROM, DRAM, etc), mas os princpios
bsicos so os mesmos. Estas siglas indicam os dois tipos bsicos de memria
que so usadas em computadores. A sigla bsica ROM significa Read Only
Memory, ou seja, memria de somente de leitura. A outra sigla RAM (Random
Access Memory) significa memria de acesso randmico, portanto, memria que
se pode ler em qualquer endereo.
A sigla RAM muito confusa porque em uma memria ROM tambm se
pode ler em qualquer endereo. A diferena real que nas RAMs se pode ler e
escrever com a mesma velocidade em qualquer endereo, enquanto que na ROM,
o acesso rpido somente para leituras, a escrita uma histria mais complicada.
A ROM normalmente contm dados que no podem ser modificados durante o
funcionamento do computador. Outro tipo de dados armazenados em ROMs so
os que no devem ser perdidos quando o computador desligado. Exemplos de
uso de ROM so as memrias que armazenam os programas que so executados
quando os computadores so ligados, os famosos BIOS (Basic Input Output
System). Um computador ao ser ligado deve ter um programa mnimo capaz
de iniciar o seu funcionamento normal, caso contrrio seria como uma pessoa
que perdeu totalmente a memria. Para isto so escritos programas simples que
fazem acesso aos perifricos em busca do Sistema Operacional da mquina.
As primeiras memrias do tipo ROM eram gravadas nas fbricas e nunca
mais eram modificadas. Isto trazia algumas dificuldades, por exemplo, quando
um programa precisava ser atualizado. Para resolver este tipo de problemas
surgiram as PROMs, que so ROMs programveis. Ou seja possvel desgravar
o contedo antigo e gravar novos programas nesta memria. Antigamente este
24

era um processo complicado e exigia que a memria fosse retirada fisicamente


do circuito e colocada em dispositivos especiais capazes de apagar o contedo
antigo. Em seguida um circuito programador de PROMs era usado para gravar
o novo contedo e somente aps tudo isto a memria era recolocada no local.
O computador ficava literalmente sem a memria dos programas iniciais. Hoje
em dia existem PROMs que podem ser apagadas e regravadas muito facilmente.
Por exemplo, as EEPROMs (Eletricaly Erasable PROMs), que so memrias
que podem ser apagadas eletricamente sem a necessidade de serem retiradas
dos circuitos. Flash memory uma forma de memria no voltil que pode
ser apagada e reprogramada eletricamente. Diferentemente das EEPROMs, ela
deve ser apagada em blocos de endereos. Este tipo de memria custa menos
do que EEPROMs e portanto so preferidas quando necessrio usar memria
no voltil em forma de circuitos integrados.
As memrias RAMs so as memrias onde os nossos programas comuns
rodam. Elas so modificveis e de acesso rpido tanto na leitura quanto na
gravao. Muitas siglas aparecem e desaparecem quando falamos de memrias
RAM. Existem as DRAM, memrias EDO, SIMM, etc. Tudo isto ou se refere ao
mtodo de acesso dos dados na memria ou a tecnologia de construo ou a outra
caracterstica acessria. O certo que todas elas tem como caracterstica bsica
o fato dos acessos de leitura e escrita poderem ser feitos na mesma velocidade.

1.3.3 Bits e Bytes


A memria do computador composta de bits, a menor unidade de informao
que o computador armazena. Um bit pode conter o valor 0 ou 1, que so os
dgitos usados na base dois, a base usada nos computadores. Um conjunto de
8 bits forma o byte. Uma palavra de memria um conjunto de bytes.
Atualmente a maioria dos computadores tem palavras de memria 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 memria e no do tamanho dos


dados que o computador pode processar. Considere que este tamanho relacionado com a quantidade mxima de algarismos que um nmero pode ter para ser
processado. Um computador pode ter capacidade de processar 64 bits de cada
vez. Caso sua memria tenha palavras de 32 bits o processador dever, ento,
ler duas palavras da memria para poder processar um nmero. Lembre-se que
25

as duas leituras so atendidas uma de cada vez. Da mesma forma o computador


pode processar 32 bits de cada vez e a memria ter largura 64 bits. Isto pode
acelerar o processamento, j que o processador est se adiantando e recebendo
o que poder ser o prximo dado a ser processado, ou seja economizando uma
leitura.
Devido a base 2 o fator kilo tem um significado diferente em computao.
Por exemplo 1 Kbyte de memria corresponde a 2 elevado a 10 (210 ), ou seja
1024 bytes. Da mesma forma 1 Megabyte corresponde a 1024 x 1024 bytes e 1
Gigabyte igual a 1024 x 1024 x 1024 bytes. Na Tabela 1.4 esto mostradas as
diversas abreviaes usadas quando se fazem referncias s memrias.
Nome
Kilobyte
Megabyte
Gigabyte
Terabyte
Petabyte
Exabyte

Smbolo
Kb
MB
GB
TB
PB
EB

Multiplicador
210 = 1024
220
230
240
250
260

Tabela 1.4: Abreviaes usadas em referncias s memrias.

1.3.4 Perifri os
Como j mencionamos antes, os dados no ficam guardados somente na memria, h tambm os perifricos . H perifricos de entrada, outros de sada
e alguns que servem tanto para entrada como sada de dados. Perifricos no
servem somente para armazenar dados. H perifricos que so usados para permitir a interao entre os usurios e o computador. A tabela 1.5 ilustra alguns
destes perifricos.
Entrada
Teclados
Mouse
CD-ROM
Scanner

Sada
Impressoras
Vdeo
Plotter
Alto-falantes

Ambos
Discos Rgidos
Fitas Magnticas
Disquetes
Discos Zip

Tabela 1.5: Exemplos de perifricos

1.4 O Software
Tudo isto que sobre o que acabamos de escrever constitui o hardware do computador, o que se v e o que se toca. A partir de agora falaremos brevemente
no software, o que no se v nem se toca, mas tambm est l.

26

Para que um computador execute alguma tarefa primeiro se desenvolve um


algoritmo , que uma espcie de receita que diz precisamente, ao computador,
como o problema deve ser resolvido. Esta definio informal de algoritmo
enganosamente simples, e a chave para entender o engano est nas palavras
dizer precisamente ao computador. Por exemplo, uma receita em gastronomia
normalmente no um algoritmo. Receitas so entendidas pela comunidade de
cozinheiros, que as seguem facilmente durante o preparo do prato. No entanto,
receitas esto cheias de expresses como, por exemplo, mexer at ficar no ponto
e colocar sal a gosto. Fora da comunidade de cozinheiros estas expresses so
passveis de vrias interpretaes. Para escrever algoritmos precisamos de uma
linguagem matematicamente precisa e sem ambigidades.
A escrita de um algoritmo consta de uma definio 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, alm de definir os passos, so
necessrias regras que definam se aps a execuo de um passo do algoritmo o
novo estado do problema vlido. As regras do xadrez definem o estado inicial
do tabuleiro, os movimentos possveis de cada pea e se aps um movimento
de uma pea a configurao atingida vlida. Ou seja precisamos verificar em
cada instante qual dos movimentos (instrues) 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 nmero finito de passos;
trabalhar em todos os exemplos da classe de problemas que o algoritmo
se prope 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 incio da computao eletrnica com programas armazenados, estes eram
escritos diretamente em linguagem de mquina que a linguagem que o computador realmente entende. Estas instrues so conjuntos de bits indicando
a operao que deve ser executada e, caso necessrio, onde como achar os dados
que sero operados. Por esta razo tambm costuma-se dizer que so programas
escritos em binrio.
Com a evoluo da computao os programas passaram a ser escritos em
assembly , que uma representao em mnemnicos das instrues de mquina.
Deste modo era mais fcil escrever os algoritmos. Por exemplo, um fragmento
de um programa escrito em assembly do processador PowerPC :
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 contedos de r3 (4) e r4 (8)
* e armazene o resultado em r5
Este pequeno trecho de programa armazena os nmeros 4 e 5 em registradores internos do processador em seguida os soma e armazena o resultado em um
27

terceiro registrador. As informaes aps os asteriscos so comentrios usados


para explicar o que o programa est fazendo naquela instruo.
O PowerPC um microprocessador criado em 1991 por um consrcio formado pela IBM, Apple e Motorola Os microprocessadores PowerPC podem ser
usados para equipar desde sistemas embutidos at computadores de alto desempenho. A Apple usou este microprocessador para equipar suas mquinas at
2006.
Um programa escrito em assembly deve ser traduzido para a representao
binria, tarefa que normalmente se chama de montar o programa. A palavra
assembler frequentemente usada erradamente para significar a linguagem e
no o programa que traduz o programa de assembly para linguagem binria de
mquina. Este tipo de programao pode levar a se escrever programas muito
eficientes, devido ao controle quase que total do programador sobre a mquina.
No entanto devido ao fato de ser uma linguagem prxima do computador e afastada da maneira de raciocinar do ser humano mais difcil de ser usada. Alm
deste fato h outros problemas tais como: dificuldade de leitura por humanos,
dificuldade de manuteno dos programas, maior tempo de desenvolvimento etc.
Para evitar estes problemas foram desenvolvidas as linguagens de programao chamadas de linguagens de alto nvel, por estarem mais prximas da
linguagem natural empregada pelos serem humanos. Alguns exemplos de linguagens de programao so:
Fortran: Usada em programao cientfica e engenharia;
Pascal: Usada em ensino de linguagens e desenvolvimento de sistemas;
COBOL: Usada em ambientes comerciais;
Basic: O nome diz tudo, bsica;
C: Mesmas caractersticas do Pascal com facilidades que permitem mais controle
do computador;
C++: Linguagem originria do C com metodologia de orientao objetos;
Java: Linguagem tambm baseada na sintaxe do C e tambm seguindo o modelo de orientao objetos.
Delphi: Linguagem originria do Pascal com metodologia de orientao objetos;
Lisp e Prolog: Linguagens usadas para desenvolver programas de Inteligncia
Artificial.
Aplicativos importantes para os programadores so os compiladores. Estes programas traduzem programas escritos em linguagens de alto nvel para
a linguagem de mquina, de modo que o computador possa execut-los. De
maneira geral um compilador um programa que traduz um programa de uma
linguagem para outra.
Podemos resumir os passos necessrios para criar um programa em uma
linguagem de programao, por exemplo C, nos passos descritos a seguir. A
Figura 1.10 ilustra a ordem em que se desenvolvem estes passos.
28

Criao do Algoritmo: neste passo criado o algoritmo que ir resolver o


problema. As diversas maneiras de descrever um algoritmo sero apresentadas no prximo captulo.
Codificao do Algoritmo: O algoritmo preparado no passo anterior escrito em uma linguagem de programao. Neste passo o programador
conta, normalmente, com a ajuda de um editor de textos (no processador de textos). Para esta edio qualquer editor pode ser usado. Hoje
em dia muitos ambientes de desenvolvimento integram todas as ferramentas necessrias para criar um programa, inclusive o editor, em um nico
aplicativo.
Compilao do Programa: O arquivo texto contendo o programa passa por
um programa especial chamado compilador que gera, caso no hajam erros, uma sada que quase o programa executvel, ou seja o programa
em cdigo binrio do processador em que ser executado. Os erros mais
comuns nesta etapa so erros de uso correto da linguagem de programao. Estes erros so chamados de erros de compilao. As linguagens de
programao so baseadas em regras gramaticais muito rgidas e qualquer
violao destas regras pode implicar em erro. No caso de erros serem
encontrados o programador deve voltar ao passo de codificao para a
correo dos erros.
Ligao: Em ingls este passo conhecido por link edition. Um programa
completo composto por vrios mdulos que podem ter sido criados pelo
prprio programador ou por outras programadores. Por exemplo, em C
os trechos de programa que interagem com os usurios, os comandos de
entrada e sada de dados, normalmente vm com o programa compilador.
Estes trechos podem estar guardados em bibliotecas de programas e so
ligados ao programa do usurio para completar o programa.
Depurao e Testes: Nesta etapa o programa ser testado para a retirada
dos possveis erros de lgica que o programador cometeu. Caso algum
erro de execuo seja encontrado o programador deve reelaborar o que
estiver errado no algoritmo e em seguida ir para a etapa de codificao do
algoritmo. Este ciclo pode repetir-se inmeras vezes at que o desenvolvedor acredite que os erros foram corrigidos.
Uso do Programa: O programa foi entregue aos seus usurios para ser usado. Durante o uso, erros que no foram encontrados durante o desenvolvimento do programa podem ser descobertos e precisam ser corrigidos. A
correo pode ser feita pelos mesmos programadores que desenvolveram o
programa ou por outro grupo devidamente treinado. Costuma-se chamar
esta correo de manuteno do programa.
Algumas linguagens de programao no so compiladas e sim interpretadas.
Isto significa que o programa para ser executado no precisa ser traduzido diretamente para linguagem de mquina, gerando um arquivo executvel. Este arquivo final, se torna independente do programa fonte. Para executar o programa
podemos usar somente o arquivo executvel. Em um programa interpretado um
aplicativo l o programa instruo por instruo, diretamente na prpria linguagem de alto nvel, traduz cada uma destas instrues para linguagem de
29

Incio
Ligao

Criao de
Algoritmo

Depurao e
Testes

Sim

Codificao do
Algoritmo

Erros de
Execuo?
No

Compilacao do
Programa

Uso do programa

Sim

Sim

Erros de
Compilao?

Erros de
Execuo?

No

Figura 1.10: Ciclo de desenvolvimento de um programa.

mquina e as executa. No h, portanto, o processo de traduo antecipada


do programa. A interpretao de um programa funciona como o processo de
traduo simultnea do discurso de um orador. A medida que ele pronuncia seu
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 uma linguagem interpretada. Em Java ocorre um
processo um pouco diferente. Um programa em Java traduzido para uma linguagem intermediria e depois interpretado por meio de uma chamada mquina
virtual. No h efetivamente uma compilao para linguagem de mquina. A
execuo de um programa escrito em uma linguagem interpretada mais lenta,
j que o processo de interpretao e execuo ao mesmo tempo mais lento do
que a simples execuo de um programa traduzido antecipadamente.
Hoje em dia a maior parte dos usurios de computadores no so programadores e sim pessoas que usam programas para resolver seus problemas do dia
a dia. Aplicativos tpicos que rodam nos computadores so: editores de texto,
processadores de texto, planilhas eletrnicas, 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 usurio normalmente
utiliza partilharo o processador do computador. Um usurio pode estar ouvindo msica, digitando um texto e imprimindo um outro documento ao mesmo
tempo. Portanto, os computadores so capazes de executar um nmero de tarefas muito maior do que o nmero de processadores disponveis. Atualmente
a maior parte dos computadores possui somente um processador. O Sistema
Operacional controla a alocao de recursos tais como: comunicao com os

30

usurios, espao em discos, uso de memria, tempo que cada programa pode rodar etc. Alguns dos sistemas operacionais conhecidos so os baseados no padro
UNIX, por exemplo o LINUX. Outros sistemas muito usados so os da famlia
Windows.
Compilando Programas Simples em C
Para resolver os exerccios deste livro voc ir precisar de um compilador para a
linguagem C e de um editor de textos simples (no processador como o Word).
O editor pode ser to simples quanto o Notepad, na verdade recomendamos
fortemente que o editor seja simples para que voc possa ter contato com todas
as etapas do processo de desenvolvimento de um programa. Para compilar
empregaremos o compilador gcc que gratuito e pode ser obtido na Internet
como veremos adiante. No ser necessrio nenhum ambiente mais complexo,
tal como um Integrated Development Environment (IDE).
A coleo de compiladores da GNU (GNU Compiler Collection) usualmente
abreviada por gcc, uma coleo de compiladores produzidos pelo projeto GNU.
A abreviao gcc, originalmente, significava GNU C Compiler. Este aplicativo
distribudo gratuitamente pela Free Software Foundation (FSF) sob a licena
GNU GPL e GNU LGPL. Este o compilador padro para os sistemas operacionais livres do tipo Unix, como o LINUX, e diversos sistemas operacionais
proprietrios 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
executvel 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 sufixo .c no nome do programa normalmente usado para indicar
que o arquivo de um programa C. Este comando deve ser digitado no diretrio
onde est o arquivo fonte teste.c. O arquivo executvel ser armazenado no
mesmo diretrio.
Nos sistemas Unix normalmente o gcc faz parte da distribuio padro e
nada precisa ser feito. No Windows uma maneira fcil de obter uma verso
do gcc instalar o MinGW (Minimalist GNU for Windows). MinGW uma
coleo de arquivos e bibliotecas distribudas 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 dispe
de um programa instalador que facilita enormemente o processo. Este programa
pode ser obtido no stio oficial do MinGW. Caso aps a instalao, o comando
indicado no funcione uma das razes para a falha pode ser que o sistema operacional no sabe onde se encontra o compilador gcc. Suponha que o programa
gcc foi instalado no diretrio C:\MinGW\bin. Uma soluo digitar o caminho
completo do compilador. Neste caso o comando se torna
C:\MinGW\bin\gcc -o teste teste.c -Wall
Para que no seja necessrio digitar o caminho completo, preciso adicionar este caminho varivel PATH do Windows. Consulte o manual para obter
informaes de como fazer este passo no seu sistema Windows.

31

1.5 Um programa em C
Vamos terminar este captulo mostrando um exemplo simples de programa escrito em C(Listagem 1.1). A nica coisa que este programa faz imprimir Alo
Mundo! e terminar [Kernighan e Ritchie 1978, Schildt 1997, Oliveira 2008].
A primeira linha do programa avisa ao compilador que ir usar funes de
entrada e sada de dados guardadas na biblioteca stdio. Neste caso a funo
usada printf. A segunda linha o incio real do programa. A linha indica que
esta a funo main que todo programa C deve conter, pois nesta funo que
o programa obrigatoriamente comea sua execuo. A funo vai retornar um
valor inteiro (int) ao final de sua execuo e no vai precisar receber nenhum
argumento para sua execuo (void). As chaves ({ e }) marcam o incio e o
fim da funo. Para imprimir o texto Alo Mundo! o programa usa a funo
printf. O incio e o fim do texto a ser impresso so marcados pelo caractere ".
A funo termina com o comando return 0, que avisa ao sistema operacional,
que foi quem iniciou a execuo do programa, que o programa terminou sem
problemas. Este programa simples ilustra alguns das estruturas bsicas que
sero usadas nos programas C que sero apresentados neste livro.

Listagem 1.1: Exemplo de Programa em C.

#in lude
int main
{
}

< stdio .h >


( void )

printf ( " Alo Mundo !\ n " ) ;


0;

return

32

Exer ios
1.1: O que o hardware do computador?
1.2: Quais os principais componentes de um computador?
1.3: Quais as diferenas entre um microprocessador e o microcomputador?
1.4: D exemplos de microprocessadores e de microcomputadores.
1.5: Qual o nmero exato de bytes em 64 Kbytes?
1.6: Se voc j usa computadores, liste alguns aplicativos que voc normalmente
usa.
1.7: Defina Sistema Operacional.
1.8: Qual a diferena bsica entre memrias ROM e RAM?
1.9: Procure em manuais, internet e outras fontes quais so os tempos de acesso
das memrias RAMs atuais.
1.10: Faa trs listas, uma de perifricos de entrada, outra de perifricos de
sada e finalmente uma de perifricos de entrada e sada.
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 so erros de compilao e de execuo.
1.14: Procure nomes de linguagens de programao no listadas no texto e diga
quais so as suas caractersticas principais.
1.15: Segundo a Wikipedia, a norma ABNT NBR 14724:2011, sugere que uma
pgina de texto pode conter mais de 3000 caracteres. Nesta questo considere
que uma pgina de texto sempre contm 3000 caracteres e que cada caractere
ocupa 32 bits. Precisamos armazenar 1000 livros e cada um deles contm 200
pginas de texto. Marque o MENOR dos tamanhos de memria abaixo capaz
de conter todos os 1000 livros, ou seja, se mais de um tamanho puder conter os
livros escolha o menor.
(a) 1 Kilo bytes
(b) 1 Mega bytes
(c) 1 Giga bytes
(d) 1 Tera bytes
(e) Nenhuma das respostas anteriores
1.16: Responda as seguintes questes:

33

(a) Um anncio de computadores informa que a velocidade do processador igual a 3.5 Gigahertz. Qual a quantidade exata de Hertz do
processador anunciado?
(b) H duas maneiras de calcular a capacidade de armazenamento de
discos rgidos em termos de 1 Gigabyte de memria. Uma alternativa
usa a base 10 e outra a base 2. Qual a quantidade exata de 1
Gigabyte nas duas maneiras?
1.17: BIOS um software que vem junto com os PCs e o primeiro cdigo executado pelo computador quando ele ligado. A sua principal funo carregar
na memria do computador o sistema operacional e dar incio a sua execuo.
Discuta porque o BIOS fica armazenado em uma memria conhecida como flash,
e que basicamente funciona como uma memria EPROM, enquanto que os programas comuns ficam armazenados na memria principal que composta de
memrias RAM.
1.18: Computadores internamente executam operaes aritmticas na base 2 e
no na base 10 como a que normalmente usamos. Uma representao binria,
muito comum, para nmeros inteiros usa 32 bits ou 4 bytes. Por exemplo, o
nmero inteiro 25 quando convertido para binrio representado por 32 bits
com o seguinte cdigo
00000000000000000000000000011001
No entanto, quando processando texto computadores usam cdigos binrios
diferentes. Por exemplo, o cdigo ASCII muito popular para representar
caracteres que devem ser armazenados na memria. Neste cdigo cada caractere
representado por um cdigo binrio com 8 bits. Encontre uma referncia que
contenha a tabela ASCII e responda como seriam representados os caracteres
2 e 5 usando os cdigos desta tabela.
1.19: Qual a diferena entre um endereo de memria e o contedo de memria?
Explique o conceito de contedo de memria e o de endereo de memria. Se
possvel mostre com figuras ou diagramas.

34

Captulo 2

Algoritmos
2.1 Introduo
O objetivo deste captulo fazer uma breve introduo ao conceito de algoritmos e apresentar algumas formas mais comuns de representar algoritmos para
facilitar o entendimento dos demais captulos deste livro. Iremos apresentar as
construes mais comuns empregadas no desenvolvimento de algoritmos e apresentaremos exemplos bsicos de algoritmos usando algumas destas formas de
representao e construes.
Para resolver um problema no computador necessrio que seja primeiramente encontrada uma maneira de descrever este problema de uma forma clara
e precisa. preciso que encontremos uma seqncia de passos que permitam
que o problema possa ser resolvido de maneira automtica e repetitiva. Alm
disto preciso definir como os dados que sero processados sero armazenados no computador. Portanto, a soluo de um problema por computador
baseada em dois pontos: a seqncia de passos e a forma como os dados sero
armazenados no computador. Esta seqncia de passos chamada de algoritmo.
Usamos algoritmos em diversas atividades que realizamos diariamente. Uma
grande parte destas atividades no esto relacionadas com computao. Um
exemplo simples e prosaico, de como um problema pode ser resolvido caso forneamos uma seqncia de passos que mostrem a maneira de obter a soluo,
uma receita para preparar um bolo.
Uma vez que foi criado um algoritmo para resolver um determinado problema usando computadores passamos para a prxima fase que a escrita deste
algoritmo em alguma linguagem de programao.
A noo de algoritmo central para toda a computao. A criao de algoritmos para resolver os problemas uma das maiores dificuldades dos iniciantes
em programao em computadores. Isto porque no existe um conjunto de regras, ou seja um algoritmo, que nos permita criar algoritmos. Caso isto fosse
possvel a funo de criador de algoritmos desapareceria. Claro que existem
linhas mestras e estruturas bsicas, a partir das quais podemos criar algoritmos, mas a soluo completa depende em grande parte do criador do algoritmo.

35

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 [Knuth 1973]
apresenta uma verso para a origem desta palavra. Ela seria derivada do nome
de um famoso matemtico persa chamado Abu Jafar Maom ibn Ms alKhowrism (825) que traduzido literalmente quer dizer Pai de Jafar, Maom,
filho de Moiss, de Khowrizm. Khowrizm hoje a cidade de Khiva, na ex
Unio Sovitica. Este autor escreveu um livro chamado Kitab al jabr walmuqabala (Regras de Restaurao e Reduo). O ttulo do livro deu origem
tambm a palavra lgebra.
O significado da palavra muito similar ao de uma receita, procedimento,
tcnica, rotina. Um algoritmo um conjunto finito de regras que fornece uma seqncia de operaes para resolver um problema especfico. Segundo o dicionrio do prof. Aurlio Buarque de Holanda um algoritmo
um:
Processo de clculo, ou de resoluo de um grupo de problemas semelhantes, em que se estipulam, com generalidade e sem restries,
regras formais para a obteno de resultado ou de soluo de problema.
Um algoritmo opera sobre um conjunto de entradas (no caso do bolo, farinha
ovos, fermento, etc.) de modo a gerar uma sada que seja til (ou agradvel)
para o usurio (o bolo pronto).
Um algoritmo computacional tem cinco caractersticas importantes:
Finitude: Um algoritmo deve sempre terminar aps um nmero finito de passos.
Definio: Cada passo de um algoritmo deve ser precisamente definido. As
aes devem ser definidas rigorosamente e sem ambiguidades.
Entradas: Um algoritmo deve ter zero ou mais entradas. Entradas so as
quantidades que so lhe so fornecidas para processamento.
Sadas: Um algoritmo deve ter uma ou mais sadas, isto quantidades que tem
uma relao especfica com as entradas.
Efetividade: Um algoritmo deve ser efetivo. Isto significa que todas as operaes devem ser suficientemente bsicas de modo que possam ser, em princpio, executadas com preciso em um tempo finito por um humano usando
papel e lpis.

2.2 Primeiros Passos


claro que todos ns sabemos construir algoritmos. Se isto no fosse verdade,
no conseguiramos sair de casa pela manh, ir ao trabalho, decidir qual o melhor
caminho para chegar a um lugar, voltar para casa, etc. Para que tudo isto seja
feito necessrio uma srie de entradas do tipo: a que hora acordar, que hora
36

sair de casa, qual o melhor meio de transporte etc. Um fator importante


que pode haver mais de um algoritmo para resolver um determinado problema.
Por exemplo, para ir de casa at o trabalho, posso escolher diversos meios de
transporte em funo do preo, conforto, rapidez, etc. A escolha ser feita em
funo do critrio que melhor se adequar as nossas necessidades. Um exemplo
de algoritmo pode ser as instrues que um professor passa aos seus alunos em
uma academia de ginstica, mostrado no Algoritmo 2.1. Observar que nesta
representao do algoritmo cada linha contm uma instruo.
Algoritmo 2.1: Exemplo de Algoritmo.
inicio
enquanto no fez 10 vezes faa
Levantar e abaixar brao direito
Levantar e abaixar brao esquerdo
Levantar e abaixar perna esquerda
Levantar e abaixar perna direita
fim enqto
fin
Computadores so mquinas muito eficientes na resoluo de problemas matemticos ou que envolvam nmeros. Como exemplo de um algoritmo matemtico, vamos considerar o problema de resolver uma equao do primeiro grau da
forma
ax + b = 0
A soluo desta equao
x = b/a
se o valor de a for diferente de 0. Caso a seja igual a 0, a equao no possui
soluo, j que no possvel dividir por 0. Este algoritmo escrito (Algoritmo
2.2) em uma pseudo-linguagem de programao ficaria da seguinte maneira:
Algoritmo 2.2: Algoritmo para resolver uma equao do primeiro grau.
Entrada: Coeficientes a e b da equao ax + b = 0
Sada: Resultado x da Equao
inicio
ler a
ler b
se a = 0 ento
imprimir A equao nao tem soluo
seno
x b/a
imprimir A raiz da equao vale , x
fim se
fin
As instrues do algoritmo so executadas passo a passo e uma instruo
somente executada quando a anterior terminou sua tarefa. Os dois primeiros
37

passos do algoritmo servem para o algoritmo obter os valores dos coeficientes a e


b. Os valores podem, por exemplo, serem digitados em um teclado pelo usurio
que est usando o algoritmo. O valor digitado vai para uma posio da memria
do computador, que para facilitar o manuseio do dado, recebe um nome. Neste
exemplo demos os nomes a, b e x as posies de memria usadas pelo programa
para armazenar dados. Aps os dois primeiros passos o algoritmo executa uma
instruo de teste para verificar se o valor de a diferente de 0. Neste caso
podemos ter duas respostas e o computador ir escolher entre dois caminhos
independentes e exclusivos. Caso a seja igual a zero, o algoritmo executa as
instrues entre a palavra ento e seno, e portanto, imprime uma mensagem
de aviso para o usurio e termina. Esta mensagem normalmente aparece em
um monitor de vdeo. No caso de a ser diferente de zero, o algoritmo executa as
instrues entre seno e fim se. Isto significa calcular o resultado da equao
e atribuir este resultado x. O ltimo passo, desta opo a impresso do
resultado da equao.

2.3 Representao
As formas mais comuns de representao de algoritmos so as seguintes:
Linguagem Natural: Os algoritmos so expressos diretamente em linguagem
natural, como nos exemplos anteriores.
Fluxograma Convencional: Esta um representao grfica que emprega
formas geomtricas padronizadas para indicar as diversas aes e decises
que devem ser executadas para resolver o problema.
Pseudo-linguagem: Emprega uma linguagem intermediria entre a linguagem
natural e uma linguagem de programao para descrever os algoritmos.
No existe consenso entre os especialistas sobre qual seria a melhor maneira de representar um algoritmo. Atualmente a maneira mais comum de
representar-se algoritmos atravs de uma pseudo-linguagem ou pseudo-cdigo.
Esta forma de representao tem a vantagem de fazer com que o algoritmo seja
escrito de uma forma que est mais prxima de uma linguagem de programao
de computadores.

2.3.1 Linguagem Natural


A representao em linguagem natural tem a desvantagem de colocar uma
grande distncia entre a soluo encontrada e o resultado final do processo
que um programa em linguagem de programao. O Algoritmo 2.3 mostra
um algoritmo, escrito em linguagem natural, para calcular a mdia de um aluno
que faz trs provas e precisa de obter mdia acima de 5.0 para ser aprovado.

2.3.2 Fluxogramas
Esta forma de representao de algoritmos emprega vrias formas geomtricas
para descrever cada uma das possveis aes durante a execuo do algoritmos.
38

Algoritmo 2.3: Algoritmo para calcular a mdia das notas de um aluno.


Entrada: Notas n1 , n2 e n3 .
Sada: Resultado media do aluno e se ele foi aprovado ou no.
inicio
Obter as notas n1 , n2 e n3
Calcular mdia. Usar a frmula ((n1 + n2 + n3 )/3.0).
Se a mdia for maior que 5.0 imprimir que o aluno foi aprovado
Caso contrrio imprimir que o aluno foi reprovado.
Imprimir a mdia.
fin

Existem algumas formas geomtricas que usualmente so empregadas neste mtodo. Estas formas esto mostradas na Figura 2.1. Cada uma destas formas se
aplica a uma determinada ao como est indicado na figura. Estas formas so
apenas alguns exemplos, existindo outras, no entanto, nesta apostila estas sero
suficientes para os exemplos que sero mostrados.
Incio e Fim de Fluxograma

Processamento

Ponto de Deciso

Entrada de Dados Manual

Impresso de Resultados

Conector para mesma pgina

Figura 2.1: Smbolos mais comumente usados em fluxogramas.


Como exemplo de um algoritmo escrito em forma de fluxograma, vamos
considerar o algoritmo 2.2 para resolver uma equao do primeiro grau da forma
ax + b = 0. A Figura 2.2 mostra um fluxograma para resolver este problema.
Os dois primeiros passos do algoritmo lem os valores dos coeficientes a e
b da equao. Em seguida h um teste para descobrir se o valor de a igual
a zero. Se o valor de a for igual a zero o algoritmo manda que seja impressa
uma mensagem informando que a equao no tem soluo. Caso o valor de
a seja diferente os prximos passos calculam o valor da soluo e em seguida
imprimem este resultado

2.3.3 Pseudo-Linguagem
Este modo de representar algoritmos procura empregar uma linguagem que esteja o mais prximo possvel de uma linguagem de programao de computadores de alto nvel, mas evitando de definir regras de construo gramatical muito
rgidas. A idia usar as vantagens do emprego da linguagem natural, mas
restringindo o escopo da linguagem. Normalmente estas linguagens so verses
ultra reduzidas de linguagens de alto nvel do tipo Pascal ou C. O algoritmo 2.2
foi escrito em uma pseudo-linguagem. A maioria destas linguagens so muito
39

Incio

Obter a

Obter b

Sim
a =0
No
No h razes
reais

x=-b/a

Imprime x

Fim

Figura 2.2: Fluxograma para resolver uma equao do primeiro grau.

parecidas e tm a vantagem de serem facilmente entendidas. Vamos apresentar


agora um outro exemplo (Algoritmo 2.4) escrito em pseudo-linguagem. Este
algoritmo serve para descobrir qual a maior nota de um grupo de trs notas
de um aluno. O algoritmo inicialmente l a primeira nota e guarda esta nota
como a maior nota. Em seguida, l 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 so usadas para facilitar o entendimento entre os programadores.
Vamos detalhar algumas delas. As palavras incio e fim indicam onde comea
e termina o algoritmo. As palavras em negrito indicam instrues que devem
ser executadas pelo computador onde o algoritmo ser rodado. Por exemplo,
ler notaAluno uma instruo do algoritmo que ordena ao computador para
obter a nota de um aluno para ser processada. Em algoritmos esta nota normalmente ser obtida de um perifrico de entrada de dados, sendo mais comum
o teclado. As palavras em itlico so normalmente chamadas de variveis e
representam locais na memria do computador onde os valores a serem usados
durante o processamento esto armazenados. Os programadores podem incluir
nos algoritmos explicaes que facilitem o entendimento do seu funcionamento.
Estes comentrios no so executados pelos computadores e somente so lidos
pelos programadores. Existem diversas maneiras de indicar que o texto no algoritmo apenas um comentrio. Neste exemplo usamos dois caracteres para
indicar que o restante da linha apenas um comentrio. Mais adiante outras
explicaes sero apresentadas.
40

Algoritmo 2.4: Algoritmo para calcular a maior nota de um grupo de


notas.
Entrada: Trs notas de um aluno, (notaAluno).
Sada: Maior das notas do aluno, (maiorN ota)
inicio
L primeira nota
ler notaAluno
maiorN ota notaAluno
L segunda nota
ler notaAluno
se notaAluno > maiorN ota ento
maiorN ota notaAluno
fim se
L terceira nota
ler notaAluno
se notaAluno > maiorN ota ento
maiorN ota notaAluno
fim se
imprimir A maior nota das notas , maiorN ota
fin

2.4 Modelo de von Neumann


Algoritmos para computadores se baseiam em alguns conceitos bsicos e em um
modelo de computador, os quais devem ser bem entendidos para que se possa
criar algoritmos eficientes. Este modelo foi proposto pelo matemtico hngaro
Neumann Jnos Lajos Margittai. Em hngaro o nome de famlia aparece antes.
Assim em portugus o seu nome seria Jnos Lajos Margittai Neumann. O seu
pai, que era rico, comprou um ttulo de nobreza e ele passou a se chamar Jnos
Lajos Margittai von Neumann. No modelo de computador proposto por von
Neumann as instrues e os dados ficam juntos na memria. O processador
busca na memria e executa uma instruo de cada vez.
Para ilustrar como este modelo funciona vamos analisar passo a passo a
execuo de um algoritmo simples. Na Figura 2.3 mostramos nos endereos 0, 1
e 2, de uma memria, um grupo de instrues formando parte de um algoritmo.
As instrues tambm podem ser acompanhadas no Algoritmo 2.5. Vamos
assumir que o computador inicie executando o algoritmo a partir da instruo
que est no endereo 0. O procedimento normal a Unidade de Controle (UC)
do computador continuar buscando e executando uma instruo de cada vez
nos endereos seguintes, a no ser que haja uma ordem para desviar o fluxo das
instrues. importante observar que o computador executa uma instruo de
cada vez, e como veremos adiante, tambm um dado buscado de cada vez.
Portanto, as transferncias entre a memria e o processador so feitas passo a
passo. O ciclo normal da execuo de um programa ento:
1. Busca instruo;
2. Decodifica instruo;
41

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

2.5 Estruturas Bsi as de Algoritmos


Com a finalidade de ilustrar como criar algoritmos para computadores usando
este modelo, vamos discutir alguns tipos bsicos de estruturas usados nesta tarefa. Para isto, iremos usar a representao que for apropriada no momento.
No iremos neste livro discutir em detalhes estes tpicos, nem apresentar de
uma maneira formal qualquer uma destas formas. O interesse apenas apresentar e discutir algumas estruturas bsicas para ilustrar o pensamento usado pelos
programadores quando criam um algoritmo para resolver um problema especfico. Estas estruturas so importantes e sero reapresentadas quando formos
apresentar a linguagem C. Para o programador iniciante esta discusso serve
como introduo.
42

a<-2

b<-8

12

13

14

15

c<-a+b
9

10

11

10

16

17

18

19

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 memria

2.5.1 Comandos de leitura


Estes comandos servem para obter dados do mundo exterior, normalmente digitados por um usurio em um teclado. Outros exemplos de lugares de onde
podem ser obtidos dados so os arquivos em discos rgidos, disquetes e fitas
magnticas. Estes dados so lidos e guardados na memria para posterior uso.
Normalmente os lugares para onde vo estes dados recebem um nome para
facilitar o seu manuseio durante a execuo do algoritmo.
Por exemplo, o comando
ler a
significa que o algoritmo ir obter um dado do teclado e ir armazen-lo em uma
posio de memria que passar a ser conhecida pelo nome a. Estas posies
so conhecidas por variveis em computao. Costuma-se dizer ento que a
uma varivel do algoritmo. Apesar de a no algoritmo 2.2 representar uma das
constantes da equao do primeiro grau no algoritmo ela uma das variveis.
Observe que cada vez que o algoritmo executado a pode assumir um valor
diferente, portanto varia de acordo com a execuo do algoritmo.
O comando pode ser seguido por uma lista de nomes separados por vrgulas.
Por exemplo o comando
ler a, b
l dois valores do teclado e os atribui as variveis a e b. Observe que a ordem em
que os valores foram digitados determina como os valores sero atribudos. O
primeiro valor lido atribudo a primeira varivel, no caso a. O segundo valor
lido atribudo a segunda varivel (b). Os valores normalmente so digitados
separados por um ou mais espaos em branco ou em linhas diferentes.

2.5.2 Comandos de es rita


Aps a obteno dos resultados do algoritmo, estes devem ser apresentados ao
usurio, e para isto usamos os comandos de escrita. Por exemplo o comando
43

imprimir x
imprime o valor atual que est na memria representada pelo nome x.
Da mesma forma que nos comandos de leitura possvel colocar uma lista
de nomes de variveis aps o comando. Por exemplo, o comando
imprimir x1, x2
imprime os valores das variveis x1 e x2. O meio de apresentao dos resultados,
normalmente, um monitor de vdeo.
O comando imprimir pode ser usado para mandar mensagens de texto
para o usurio do algoritmo das formas mais variadas. Alguns exemplos de
comandos de impresso so os seguintes:

imprimir Entre com o valor do coeficiente


imprimir O valor de x , x
imprimir O valor de x1 , x1, e o de x2 , x2
Notar que os textos entre aspas indicam um texto que deve ser impresso no
perifrico de sada sem nenhuma modificao. Vamos considerar que as variveis
destes exemplos valem x = 10, x1 = 5 e x2 = 8. Os trs comandos mostrariam
no perifrico de sada os seguintes resultados:
Entre com o valor do coeficiente.
O valor de x 10
O valor de x1 5 e o de x2 8

2.5.3 Expresses
Expresses so usadas para definir os clculos requeridos pelo algoritmo, por
exemplo b/a. Iremos discutir dois tipos bsicos de expresses: expresses aritmticas e expresses lgicas.
Expresses manipulam dados dentro dos algoritmos. Uma pergunta importante neste momento : que tipo de dados poderemos manipular? As linguagens
de programao normalmente estabelecem regras precisas para definir que tipos
de dados elas iro manipular. Nesta discusso vamos estabelecer, ainda que
informalmente, algumas regras que limitam os conjuntos de dados existentes na
Matemtica e estabelecem que dados podero ser manipulados pelos algoritmos.
Isto ocorre porque os computadores possuem limitaes 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 representaes. Existem trs tipos bsicos de
dados que iremos discutir:
Dados numricos: como o nome indica so os nmeros que sero operados.
Dados alfa-numricos: so os dados representados por caracteres. Como caracteres podem ser letras, algarismos e sinais diversos estes dados recebem
este nome.
44

Dados Lgicos: estes dados podem assumir dois valores verdadeiro e falso.
Estes dados resultam de expresses do tipo x > 0.
Os dados numricos que os algoritmos que iremos construir podem manipular
so de dois tipos: inteiros e reais. So exemplos de nmeros inteiros:
+3
3
-324
-50
So exemplos de nmeros reais:
+0.5
0.5
-8.175
2.0
Dados alfa-numricos servem para tratamento de textos e normalmente so
compostos por uma seqncia de caracteres contendo letras, algarismos e caracteres de pontuao. Nos algoritmos so normalmente representados por uma
seqncia de caracteres entre aspas, por exemplo:
Linguagem de programao
Qual o seu nome?
12345
Dados lgicos so intensamente aplicados durante o processo de tomada
de decises que o computador frequentemente obrigado a fazer. Em muitos
textos este tipo de dados tambm chamado de tipo de dados booleanos, devido
a George Boole, matemtico que deu ao nome lgebra (lgebra booleana) que
manipula este tipo de dados. Os dados deste tipo somente podem assumir
dois valores: verdadeiro e falso. Computadores tomam decises, durante o
processamento de um algoritmo, baseados nestes dois valores. Por exemplo,
considere a deciso abaixo:

se a = 0 ento
imprimir A equao nao tem soluo
seno
x b/a
imprimir A raiz da equao vale , x
fim se
Neste algoritmo aparece a expresso a = 0, que procura descobrir se o valor
de raiz igual a 0. Esta expresso somente pode ter como resultado os valores:
verdadeiro ou falso. Nos nossos algoritmos estes valores sero representados por
verdadeiro e falso.

45

Expresses Aritmticas
Para os nossos exemplos iniciais iremos adotar os operadores aritmticos binrios mostrados na Tabela 2.1. A coluna prioridade indica a prioridade relativa
dos operandos. O menor nmero indica a maior prioridade. Quando temos
dois operandos de mesma prioridade o computador ir executar primeiro a operao mais esquerda. Em computao, as expresses devem ser escritas em
linhas e para alterar a prioridade deve-se usar parnteses. Maiores detalhes
sobre expresses sero apresentados no Captulo 5. No momento, estamos apenas apresentando alguns conceitos bsicos para facilitar a discusso de alguns
algoritmos.
Operador
/
*
%
+
-

Descrio
Diviso
Multiplicao
Mdulo (resto da diviso de
operandos inteiros)
Soma
Subtrao

Prioridade
0
0
0
1
1

Tabela 2.1: Operadores Aritmticos.


Para ilustrar o uso de operadores aritmticos vamos considerar alguns exemplos de expresses. Os exemplos a seguir mostram como converter uma expresso matemtica para a forma que usaremos em pseudo-linguagem. Observer o
uso de parnteses para alterar a prioridade das operaes.
Expresso
Matemtica
a
b+c
a+b
c+d
2

b 4ac
1
1
1+ a+b

Expresso 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 atribuio


Servem para atribuir valores posies de memria. Normalmente estes valores
podem ser constantes ou resultados de expresses dos diversos tipos. Exemplos
de comandos de atribuio so 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
expresso a direita da seta armazenado na varivel que est no lado esquerdo
46

da seta. A direo da seta no pode ser alterada. No caso da ltima expresso temos que o valor atual de i incrementado e depois substitui este valor,
portanto, se ele valia 10, ao final da instruo ele vale 11.

2.5.5 Comandos de ontrole


So usados para controlar o fluxo de execuo das instrues. Nas linguagens
de programao existem diversos tipos de comandos de controle. Para estes
exemplos iniciais vamos mostrar somente o comando mais bsico que serve para o
computador escolher entre dois possveis caminhos qual o algoritmo deve seguir.
Este comando, representado em fluxograma, 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 ...

ento ...

seno.

Algoritmo 2.6: Comando se em pseudo-linguagem


se Condio sendo testada ento
Faa isto
seno
Faa aquilo
fim se
Um exemplo de uso desta construo, 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 contrrio irei praia. Observe que para
ir para a praia basta apenas que no esteja chovendo, nenhum outro teste foi
47

feito. Esta deciso em forma de pseudo-linguagem fica da maneira mostrada no


Algoritmo 2.7.
Algoritmo 2.7: Algoritmo para decidir o que fazer no domingo.
se est chovendo ento
vou ao cinema
seno
vou praia
fim se
Nem sempre nos algoritmos precisamos de duas alternativas. As vezes precisamos somente de decidir se devemos fazer algo ou no Por exemplo, vamos
assumir que decidimos ir ao cinema no domingo chova ou faa sol. No entanto,
preciso decidir se levo um guarda-chuva. O algoritmo para este caso est mostrado no Algoritmo 2.8. Observe que no caso de no estar chovendo nada precisa
ser feito. A Figura 2.5 mostra esta deciso em forma de fluxograma.
Algoritmo 2.8: Algoritmo para decidir se deve levar um guarda-chuva.
Vestir para ir ao cinena
se est chovendo ento
pego guarda-chuva
fim se
Vou ao cinema

2.5.6 Comandos de repetio


As linguagens de programao normalmente possuem diversos comandos que
permitem que um trecho de algoritmo seja repetido um nmero de vezes. Para
estes exemplos iniciais iremos apresentar um comando de repetio que suficientemente 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 condio verdadeira. Caso seja verdade executar o bloco
de comandos situados entre o incio do comando e o final do comando. O
final do comando enquanto normalmente marcado de alguma forma. Em
nossa pseudo-linguagem marcaremos o fim pelas palavras fim enquanto
ou fim eqto.
Passo 2: Executar o bloco de comandos at o fim do enquanto. Quando chegar
ao fim retornar automaticamente para o incio do comando e refazer o
passo 1.
Como exemplo consideremos o caso em que precisamos ler um conjunto de 10
nmeros e imprimir se cada um dos nmeros lidos par ou no. Para descobrir
se o nmero par vamos dividi-lo por 2 e testar o resto. Para simplificar,
48

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.

vamos considerar que caso o resto da diviso seja igual a zero o nmero par.
Neste algoritmo sabemos a quantidade de nmeros a serem lidos e portanto o
nmero de repeties pr-determinado. O Algoritmo 2.9 mostra como seria
implementada uma soluo para este problema.
Vamos mostrar um exemplo onde o nmero de repeties no conhecido.
Considere no exemplo anterior que o total de nmeros a ser lido no conhecido.
Mas ento, como o algoritmo ir terminar de ler nmeros? Usaremos o que
costuma-se chamar de sentinela em computao. O algoritmo ir se manter
lendo nmeros enquanto os nmeros forem positivos. No momento que for
lido um nmero negativo o algoritmo pra. A sentinela que indica o final da
lista de nmeros um nmero negativo. O Algoritmo 2.10 mostra como fica
em pseudo-linguagem o algoritmo modificado. Observe que neste algoritmo o
primeiro nmero tem de ser lido antes do comando enquanto. Isto porque
assumimos que o primeiro nmero que for digitado pode ser negativo e portanto
a lista de nmeros no tem nenhum nmero.

2.6 Exemplos de Algoritmos


Nesta seo iremos apresentar uma srie de algoritmos escritos na pseudolinguagem que acabamos de apresentar.
Exemplo 2.1: Este algoritmo serve para descobrir qual 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
49

Algoritmo 2.9: Algoritmo para ler 10 nmeros e imprimir se so pares


ou no.
Entrada: 10 nmeros, (numero).
Sada: Se o nmero par ou no
inicio
totalN umeros 10
enquanto totalN umeros > 0 faa
ler numero
se numero%2 = 0 ento
imprimir numero, par
seno
imprimir numero, impar
fim se
totalN umeros totalN umeros 1
fim enqto
fin

Algoritmo 2.10: Algoritmo para ler nmeros e imprimir se so pares ou


no. A quantidade de nmeros a ser lida desconhecida.
Entrada: nmeros, (numero). O algoritmo para quando um nmero
negativo lido
Sada: Se o nmero par ou no
inicio
ler numero
enquanto numero > 0 faa
se numero % 2 = 0 ento
imprimir numero, par
seno
imprimir numero, impar
fim se
ler numero
fim enqto
fin

50

Algoritmando

Falso
Testa
Condio

Verdadeiro

Bloco de comandos
do enquanto

Continuo
algoritmando

Figura 2.6: Fluxograma do comando enquanto.

caso ela seja maior substitui o valor anterior pelo novo valor. Observar que
criamos uma varivel para armazenar a quantidade de alunos. Voc poderia
perguntar porque no usar o nmero 25 toda vez que for necessrio. A razo
simples. Suponha que voc gostaria de usar este algoritmo para calcular a maior
nota de uma turma de 40 alunos. Neste algoritmo bastaria substituir o nmero
25 por 40. No entanto, existe uma soluo mais geral ainda que permite que
o algoritmo possa ser usado para qualquer tamanho de turma. Este problema
est apresentado na lista de exerccios deste captulo.
Exemplo 2.2: Vamos mostrar outro exemplo de algoritmo muito usado. Precisamos ler as notas de uma turma de alunos e calcular a mdia destas notas.
Vamos assumir que a turma tem 25 alunos e as notas esto entre 0 e 10. O
algoritmo est mostrado em Algoritmo 2.12.
Exemplo 2.3: Neste exemplo considere o seguinte problema. Um escritrio de
previso do tempo armazena diariamente a temperatura mdia de uma determinada regio. A tarefa descobrir qual a maior temperatura do ano passado.
Assuma que foram armazenadas 365 temperaturas, uma para cada dia do ano.
Neste caso no podemos aplicar o algoritmo 2.11 usado para descobrir a maior
nota da turma. Antes de continuar procure encontrar a razo. Como dica,
considere que estamos no plo sul e portanto todas as temperaturas lidas so
negativas.
Uma soluo possvel para este exemplo est mostrada no algoritmo 2.13.
Este algoritmo faz o seguinte. Pega a primeira temperatura e a anota como a
maior j encontrada. A partir da o algoritmo fica repetidamente lendo tem51

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).
Sada: Maior das notas dos alunos, (maiorN ota)
inicio
totalAlunos 25
maiorN ota 0.0
enquanto totalAlunos > 0 faa
ler notaAluno
se notaAluno > maiorN ota ento
maiorN ota notaAluno
fim se
totalAlunos totalAlunos 1
fim enqto
imprimir A maior nota das notas , maiorN ota
fin

Algoritmo 2.12: Algoritmo para calcular a nota mdia de uma turma de


25 alunos.
Entrada: Nota de cada um dos dos 25 alunos da turma, (notaAluno).
Sada: Mdia das notas dos alunos, (mediaN otas)
inicio
totalAlunos 25
i0
somaN otas 0.0
enquanto i < totalAlunos faa
ler notaAluno
somaN otas somaN otas + notaAluno
ii+1
fim enqto
mediaN otas somaN otas/totalAlunos
imprimir A mdia das notas , mediaN otas
fin

52

peraturas dos registros do escritrio comparando com a temperatura que no


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 no houver mais
temperaturas para ler a que estiver anotada como a maior a maior verdadeiramente.
Algoritmo 2.13: Algoritmo para calcular a maior temperatura do ano.
Entrada: Temperaturas registradas em ano, (temperatura).
Sada: Maior das temperaturas, (maiorT emperatura)
inicio
totalT emperaturas 365
ler temperatura
J li uma temperatura
totalT emperaturas totalT emperaturas 1
A primeira temperatura a maior temperatura
maiorT emperatura temperatura
enquanto totalT emperaturas > 0 faa
ler temperatura
se temperatura > maiorT emperatura ento
maiorT emperatura temperatura
fim se
totalT emperaturas totalT emperaturas 1
fim enqto
imprimir A maior nota das temperaturas , maiorT emperatura
fin

53

Exer ios
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 salrio
anual deste trabalhador.
2.2: Assuma que o trabalhador do exerccio anterior deve pagar 10% de imposto
se o seu salrio anual for menor ou igual a R$ 12000.00. Caso o salrio seja maior
que este valor o imposto devido 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 usurio.
2.4: Modifique o algoritmo anterior de modo que ele imprima tambm quantas
vezes a maior nota aparece.
2.5: Nos exerccios anteriores assumimos que os usurios sempre digitam uma
nota entre 0 e 10. Vamos assumir agora que o usurio sempre digita um nmero,
mas este nmero pode estar fora do intervalo 0 a 10. Ou seja, poderemos ter
uma nota menor que zero ou maior que 10. Modifique o algoritmo anterior
para que ele verifique a nota digitada e, caso o aluno tenha digitado uma nota
invlida, uma mensagem avisando o usurio seja impressa e uma nova nota seja
pedida. O algoritmo deve insistir at que o usurio digite um valor vlido.
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 trs nmeros e os imprima em ordem crescente.
2.8: Escreva um algoritmo que leia um nmero inteiro entre 100 e 999 e imprima
na sada cada um dos algarismos que compem o nmero. Observe que o nmero
lido com um valor inteiro, e, portanto, ele tem de ser decomposto em trs
nmeros: 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, ms e ano e imprima
a data mais recente.
2.11: Um aluno est escrevendo um programa que l uma nota no intervalo
entre 0 e 100, inclusive. Foi pedido ao aluno que o programa aceite as notas
vlidas e rejeite as invlidas. Marque a letra que mostra a expresso que falta
no trecho pontilhado do algoritmo mostrado em 2.14.
(a) (nota < 0) e (nota > 100)
(b) (nota <= 0) e (nota >= 100)
54

(c) (nota < 0) ou (nota > 100)


(d) (nota <= 0) ou (nota >= 100)
(e) (nota >= 0) e (nota <= 100)
Algoritmo 2.14: Algoritmo do exerccio 11.
inicio
imprimir Entre com a nota
ler nota
se .............. ento
imprimir Nota invlida
seno
imprimir Nota vlida
fim se
fin
2.11: Considere que os valores -3, -4 e -5, nesta ordem, foram fornecidos ao
algoritmo 2.15:
Algoritmo 2.15: Algoritmo do exerccio 11.
Dados: t1, t2, t3, maior
inicio
ler (t1, t2, t3)
maior 0
se t1 > maior ento
maior t1
fim se
se t2 > maior ento
maior t2
fim se
se t3 > maior ento
maior t3
fim se
imprimir (maior)
fin
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.

55

Captulo 3

Tipos de Dados, Constantes e


Variveis
3.1 Introduo
Variveis e constantes so os elementos bsicos que um programa manipula.
Uma varivel corresponde a um espao reservado na memria do computador
para armazenar um determinado tipo de dado. Variveis devem receber nomes para poderem ser mais facilmente referenciadas e modificadas sempre que
necessrio. Muitas linguagens de programao exigem que os programas declarem todas as variveis antes que elas possam ser usadas. Estas declaraes
especificam de que tipo so as variveis usadas pelos programas e as vezes um
valor inicial. Tipos podem ser por exemplo: inteiros, reais, caracteres, etc. As
expresses combinam variveis e constantes para calcular novos valores.

3.2 Tipos de Dados


3.2.1 Tipos Bsi os
Os dados em C podem assumir cinco tipos bsicos que so os seguintes:
char: O valor armazenado um caractere. Caracteres geralmente so armazenados em cdigos (usualmente o cdigo ASCII). A Tabela A.1 mostra
este cdigo. Caracteres so armazenados em um byte.
int: O valor armazenado um nmero inteiro e o tamanho do subconjunto que
pode ser representado pelo computador normalmente depende da mquina
em que o programa est rodando. Atualmente em C os nmeros inteiros
so armazenados em 32 bits.
float: Nmero em ponto flutuante de preciso simples, normalmente 32 bits.
So conhecidos como nmeros reais, no entanto, os computadores somente
podem armazenar e trabalhar com uma pequena parte do conjunto dos
nmeros reais.
56

double: Nmero em ponto flutuante de preciso dupla, com isto a preciso e


as vezes a excurso dos nmeros aumenta. Este tipo armazenado em 64
bits.
void: Este tipo serve para indicar que um resultado no tem um tipo definido. Uma das aplicaes deste tipo em C criar um tipo vazio que pode
posteriormente ser modificado para um dos tipos anteriores.

3.2.2 Modi adores de tipos


Modificadores podem ser aplicados a estes tipos. Estes modificadores so palavras que alteram o tamanho do conjunto de valores que o tipo pode representar.
Por exemplo, um modificador permite que possam ser usados mais bits para armazenar nmeros inteiros. Um outro modificador obriga que s nmeros inteiros
sem sinal possam ser armazenados pela varivel. Deste modo no necessrio
guardar o bit de sinal do nmero e somente nmeros positivos so armazenados.
O resultado prtico que o conjunto praticamente dobra de tamanho.
Os modificadores de tipos so os seguintes:
unsigned: Este modificador pode ser aplicado aos tipos int e char e faz com
que o bit de sinal no seja usado, ou seja o tipo passa a ter um bit a mais.
signed: Este modificador tambm pode ser aplicado aos tipos int e char. O
uso de signed com int redundante.
long: Modificador que pode ser aplicado aos tipos int e double aumentando o
nmero de bytes reservado para armazenamento de dados.
possvel combinar estes modificadores de diversas maneiras como est mostrado na Tabela 3.1 que lista os tipos bsicos definidos no padro ANSI e a sua
excurso.

3.3 Constantes Numri as


Constantes so valores que o programa no pode modificar durante a execuo
de um programa. Elas so usadas em expresses para representar vrios tipos de
valores. Em C existem regras rgidas para determinar como devem ser escritos
estes valores. A seguir iremos mostrar estas regras.
Para escrever constantes numricas vamos usar as seguintes definies:
dgito: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
dgito_sem_zero: 1, 2, 3, 4, 5, 6, 7, 8, 9
dgito_octal: 0, 1, 2, 3, 4, 5, 6, 7
dgito_hexa: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, A, b, B, c, C, d, D,
e, E, f, F
sinal: +, 57

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
float
double
long double

Bytes
1
1
1
4
4
4
2
2
2
4
4
4

Faixa Mnima
-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

8
4
8
12

0 a 18.446.744.073.709.551.615
oito dgitos de preciso
16 dgitos de preciso
16 dgitos de preciso

Tabela 3.1: Tipos de dados definidos pelo Padro ANSI C.

ponto_decimal: .
sufixo: sufixo_sem_sinal, sufixo_longo
sufixo_sem_sinal: u, U
sufixo_longo: l, L
sufixo_flutuante: f, F, l, L
O uso destas caracteres ser mostrado com exemplos nas sees seguintes.

3.3.1 Constantes Inteiras na base 10


So valores numricos sem ponto decimal, precedidos ou no por um sinal. No
possvel separar, por espaos em branco, o sinal do valor numrico. Podemos
descrever este formato com uma notao simplificada da seguinte maneira:
[sinal]dgito_sem_zero{dgito}[sufixo_sem_sinal|sufixo_longo]
Esta notao deve ser entendida da seguinte maneira. Colchetes indicam
opo, portanto, o fato de sinal (+ ou -) estar entre colchetes significa que um
nmero inteiro pode ou no ter sinal, isto o sinal opcional. Em seguida temos
58

um dgito_sem_zero que obrigatrio. Isto dados inteiros devem comear


por, pelo menos, um algarismo entre 1 e 9. A seguir temos a palavra dgito
entre chaves. As chaves indicam que o fator entre elas pode ser repetido zero ou
mais vezes. Portanto, um nmero inteiro, aps o algarismo inicial obrigatrio,
pode ser seguido por uma seqncia de zero ou mais algarismos. Como sufixo
podemos ter opcionalmente as letras u (U) ou l (L) ou uma mistura, em qualquer
ordem, das duas. Para constantes inteiras o sufixo U (u) representa o modificador
unsigned. O sufixo L (l) representa o modificador long. Um par de Ls (ls)
indica que a constante do tipo long long. A tabela 3.2 mostra exemplos de
nmeros inteiros:
Tipo
int
unsigned int
long int
unsigned long int
long long
unsigned long long

1997
1997U
1234L
1997UL
134LL
1997ULL

Constantes
-3
+5
45u 12345U
1997L
-3l
45Lu
23Ul
1997Ll
-3ll
45LLu
23Ull

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

Tabela 3.2: Constantes Inteiras na Base 10

Alguns exemplos de erros na escrita de constantes inteiras so:


1.0 (No possvel usar ponto decimal.)
- 345 (No possvel colocar um espao entre o sinal e o valor numrico.)
23 (No possvel usar notao de expoentes.)
Nos compiladores modernos o nmero de bytes usados para armazenar os
valores inteiros o mesmo tanto para tipos inteiros (int) quanto para tipos
inteiros longos (long int), como est mostrado na Tabela 3.1. Por esta razo,
a diferena entre estes dois tipos de constantes perdeu a razo de ser. Alguns
exemplos de constantes inteira longas esto mostrados na Tabela 3.2.

3.3.2 Constantes Inteiras O tais


So constantes representadas na base 8. Normalmente so representadas sem
sinal e devem comear com um 0. Usando a notao apresentada na seo
anterior podemos definir a forma que deve ter uma constante octal como:
0 {dgito_octal}[sufixo_sem_sinal|sufixo_longo]
Na Tabela 3.3 mostramos exemplos de constantes octais e o seu valor na base 10.
Nmeros escritos na base 8 somente podem ser escritos com algarismos entre 0
e 7 inclusive.

59

Base 8
025
077
011
010ul
0175

Base 10
21
63
9
8
125

Tabela 3.3: Constantes octais

3.3.3 Constantes Inteiras Hexade imais


So constantes representadas na base 16. So iniciadas com um 0x ou 0X
. Usando a notao podemos definir uma contante hexadecimal como:
[0x|0X]dgito_hexa{dgito_hexa}[sufixo_sem_sinal|sufixo_longo]
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 Converso entre Bases


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

(3.1)

Esta equao est escrita na base 10. Por exemplo, aplicando a equao 3.1
para converter o nmero 0175 da base 8 para a base 10 ficamos com
(0175)8 = 1 82 + 7 81 + 5 80 = (125)10
60

A frmula para converso da base 8 para a base 10 pode se estendida para


uma base qualquer com a substituio do algarismo 8. Considere uma base
qualquer representada por b. Nesta base os dgitos di ficam no intervalo b 1
di 0. A equao 3.2 mostra a frmula para converter um nmero 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 (3AF )16 . Aplicando a frmula 3.2 temos
(3AF )16 = 3 162 + 10 161 + 15 160 = (943)10
O algoritmo para converter um nmero inteiro da base 10 para uma determinada base b feito por um conjunto de divises sucessivas do nmero pela base
at que o resultado da diviso seja 0. O Algoritmo 3.1 mostra como converter
um nmero (N )10 para uma base b. importante notar que os algarismos na
base b vo sendo impressos na ordem inversa, do menos significativo para o mais
significativo. Por exemplo, caso forneamos para o algoritmo o nmero (943)10
e a base 16, o algoritmo iria imprimir os resultados 15, 10 e 3 nesta ordem. Isto
corresponderia aos seguintes dgitos 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: nmero, (numero) e base b (baseb).
Sada: Dgitos do nmero na base b
inicio
ler numero
ler base
enquanto numero > 0 faa
resto numero % base
numero numero / base
imprimir resto
fim enqto
fin

3.3.5 Constantes em Ponto Flutuante


Constantes em ponto flutuante so usadas para representar nmeros reais. O
nome ponto flutuante devido ao modo como os valores so armazenados pelo
computador. Constantes de ponto flutuante podem ser do tipo oat , double
, long ou long double. Constantes sem nenhum sufixo so consideradas do tipo
double. Caso seja usado o sufixo F ou o f a constante ser considerada como
do tipo oat . O sufixo L ou o l torna a constante long double.
Uma constante em ponto flutuante pode ser definida de duas maneiras. Voc
pode escrever um nmero com ponto decimal (1.5) ou na chamada forma cientfica, em que um expoente usado (0.15E1). Na segunda forma o nmero
61

igual a 0.15 101 . possvel omitir ou os dgitos antes do ponto (a parte


inteira) ou aps (a parte fracionria), mas nunca os dois grupos. possvel
escrever um nmero em ponto flutuante sem ponto, desde que um expoente seja
usado. Portanto, os nmeros .8, 1234., 1E1 so nmeros de ponto flutuante.
Para mostrar mais formalmente como se deve escrever as constantes de ponto
flutuante vamos usar a mesma notao usada at aqui, mas usando uma hierarquia de definies para facilitar o entendimento. Primeiro damos uma definio
mais geral que vai sendo mais detalhada a medida que avanamos. Lembrar
que termos entre chaves podem ser repetidos 0 ou mais vezes e termos entre
colchetes so opcionais.
Portanto, usando a forma hierrquica, uma constante de ponto flutuante
(CPF) pode ser definida das seguintes maneiras:
CPF = [sinal]frao[expoente][sufixo_flutuante]
CPF = [sinal]seq_dgitos expoente[sufixo_flutuante]
A seguir definimos cada um dos componentes. Uma frao definida como:
frao = [seq_digitos] ponto_decimal seq_dgitos ou
frao = seq_dgitos ponto_decimal
O expoente e a seqencia de dgitos so definidos como:
expoente = [e | E][sinal]seq_dgitos
seq_dgitos = dgito{dgito}
A Tabela 3.5 mostra exemplos de constantes em ponto flutuante.
Descrio
sinal frao expoente
frao
frao expoente
frao sufixo
seq_dgitos ponto_decimal

Nmero
+23.45e-10
123.45
123.45E+10
123.45F
123.

Tabela 3.5: Constantes em ponto flutuante

3.4 Constantes Cara teres


Uma constante caractere um nico caractere escrito entre , como em a. Alm
disso, uma constante de tamanho igual a um byte pode ser usada para definir um
caractere, escrevendo-se, por exemplo, \ddd, onde ddd uma constante com
entre um e trs dgitos octais. Em C, caracteres podem participar normalmente
de expresses aritmticas. O valor que entra na expresso o do cdigo usado
para representar o caractere. Exemplos de constantes do tipo caractere so
mostrados na Tabela 3.6.
Certos caracteres que no so visveis podem ser representados antepondo-se
o caractere \ (barra invertida), como no exemplo nova linha da Tabela 3.6.
Este caractere tambm conhecido como caractere de escape. Exemplos so
mostrados na Tabela 3.7.
62

Caractere
a
A
\0141
(
9
\n

Significado
caractere a
caractere A
Constante octal correspondente ao caractere a
caractere abre parnteses
algarismo 9
Nova linha, posiciona o cursor no incio da nova linha.
Tabela 3.6: Exemplos de constantes caractere

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

Significado
Passa para uma nova linha.
Tabulao horizontal, move o cursor
para a prxima parada de tabulao.
Retorna um caractere.
Salta uma pgina.
Carriage return, posiciona o cursor
no incio 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 invisveis.

3.4.1 Constantes Cadeias de Cara teres


Neste livro vamos usar em alguns casos a palavra cadeia para significar cadeia
de caracteres (string em ingls). Uma constante do tipo cadeia de caracteres
uma seqncia de qualquer nmero de caracteres entre " como no exemplo:
"alo mundo!!!".
importante notar que a linguagem C insere automaticamente ao final de
uma cadeia de caracteres um caractere null (\0). Este caractere ser usado
em diversos algoritmos como sinal de fim de cadeia. Os caracteres \ (caractere
escape) e " (incio e fim de cadeia) tm significados 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 so \" (aspas) dentro de cadeias."
As aspas no meio da cadeia no indicam o fim, j que elas esto precedidas
do caractere de escape.

63

3.5 Variveis
Variveis so nomes dados para posies de memria a fim de facilitar o manuseio dos dados durante a criao dos programas. Os dados podem ser de
qualquer dos tipos definidos para a linguagem C.

3.5.1 Nomes das Variveis


Existem algumas regras bsicas que regulam o batismo de variveis. Estas regras
so as seguintes:
Nomes de varivel s podem conter letras, dgitos e o caractere _;
Todo primeiro caractere deve ser sempre uma letra ou o caractere _;
Letras maisculas e minsculas so consideradas caracteres diferentes, isto
, C diferencia a caixa das letras;
Palavras reservadas no podem ser usadas como nome de variveis. Palavras reservadas so palavras usadas para indicar os comandos da linguagem, tipos de dados ou outras funes. O Anexo B mostra as palavras
reservadas da linguagem C.
boa poltica escolher nomes que indiquem a funo da varivel. Por exemplo:
soma
mediaNotas

total
salarioMensal

nome
taxa_imposto

raio
_inicio

Em C nomes como raio, Raio e RAIO referem-se a diferentes variveis. No


entanto, para afastar confuses, evite diferenciar nomes de variveis por letras
maisculas e minsculas. Normalmente, os programadores usam letras maisculas para representar constantes.
Observe que em alguns nomes combinamos duas palavras para melhor indicar o dado armazenado na varivel. Note tambm que o caractere espao no
pode ser usado em nomes de variveis. Os programadores ao longo do tempo
desenvolveram algumas regras informais para fazer esta combinao. Por exemplo, usa-se o caractere _ para separar as palavras que compem o nome, como
em taxa_imposto. Outra maneira usar letras maisculas para indicar quando
comea uma palavra, como em mediaNotas. Alguns programadores usam a conveno de no comear nomes de variveis por letras maisculas. No existem
regras formais para definir como nomes devem ser criados. O melhor analisar
as regras que programadores mais experientes usam ou os padres que empresas
adotam, para ento escolher o que mais lhe agrada e segui-lo. Uma vez adotado
um padro ele deve ser seguido para evitar incoerncias.

3.5.2 De larao de variveis


Para serem usadas, as variveis precisam ser declaradas de modo que o compilador possa reservar espao na memria para o valor a ser armazenado. A forma
geral de uma declarao :
64

tipo lista_de_variveis;
onde uma lista_de_variveis uma lista de nomes de variveis separadas
por vrgulas. Por exemplo:

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

mes , ano ;

3.5.3 Atribuio de valores


Aps ser declarada, uma varivel pode receber valores. O operador de atribuio
= indica que o resultado da expresso direita do operador ser atribudo
varivel. Nada se pode afirmar sobre o contedo de uma uma varivel que j
foi declarada mas ainda no recebeu um valor.
A seguir so mostrados exemplos de atribuies de valores s variveis durante as declaraes.

int i = 0 , j = 10;
f l o a t raio = 2.54;
har = 'd ';
double pre isao = 0.00001 L ;
A seguir mostramos um trecho de programa com exemplos de atribuio de
valores aps a definio das variveis.

int i , j ;
f l o a t raio ;
har ;

i = 0;
j = 10;
raio = 2.54;
= 'd ';

65

Exer ios
3.1: Indique os nomes de variveis que so vlidos. Justifique os nomes invlidos.
(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 contm pelo menos um nome de varivel invlido.
(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 nmeros abaixo so constantes inteiras (longas ou no)
vlidas. Justifique 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 nmeros inteiros em 32 bits.


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

66

Descrio
total de alunos em uma sala
a nota de aluno em Computao I
Primeira letra de um nome
pontos de um jogador de voleibol ao final do ano;
o raio de um crculo.
Tabela 3.8: Tabela do exercicio 6

67

Tipo da varivel

Captulo 4

Entrada e Sada pelo Console


4.1 Introduo
Neste captulo vamos apresentar conceitos bsicos de entrada e sada de dados
para que os exemplos e exerccios iniciais possam ser construdos. Um programa
que no fornece resultados nem pede valores para operar no deve ter grande
utilidade. A entrada de dados ser feita pelo teclado e a sada poder ser vista
na tela do computador. Em C, quando um programa se inicia, normalmente trs
fluxos (arquivos) de dados so abertos para operaes de entrada e sada: um
para entrada, um para sada e um para imprimir mensagens de erro ou diagnstico. Normalmente o fluxo de entrada est conectado ao teclado, enquanto que
o fluxo de sada e o de mensagens de erro, para serem visualizados, esto conectados ao monitor. Estas configuraes podem ser alteradas de acordo com as
necessidades dos usurios e estas operaes so chamadas de redirecionamento.
O fluxo de entrada chamado de entrada padro (standard input); o fluxo de
sada chamado de sada padro (standard output) e o fluxo de erros chamado
de sada padro de erros (standard error output). Estes termos so substitudos
pelas suas formas abreviadas: stdin, stdout e stderr.

4.2 Bibliote a Padro


Na linguagem C no existem comandos de entrada e sada. As operaes de
entrada e sada so executadas com auxlio de variveis, macros e funes especiais. Para termos acesso biblioteca que contm estas ferramentas o programa
deve conter a declarao

#in lude

<stdio.h>

no incio do programa.
A diretiva #in lude instrui o compilador a ler o arquivo indicado entre <
e >, e process-lo como se ele fosse parte do arquivo original e seu contedo
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 procurado em
um diretrio especfico de localizao pr-definida, onde esto os arquivos de
68

incluso. Quando se usa aspas o arquivo procurado de maneira definida pela


implementao, isso pode significar procurar no diretrio de trabalho atual,
ou em um diretrio indicado no comando usado para compilar o programa.
Normalmente os programadores usam maior e menor para incluir os arquivos
de cabealho padro e aspas para a incluso de arquivos do prprio projeto.

4.3 Sada - A Funo printf


A funo printf faz com que dados sejam escritos na sada padro, que normalmente a tela do computador. O prottipo da funo :

int

printf( ontrole, arg1, arg2, ...);

onde os argumentos arg1, arg2, ... so impressos de acordo com o formato


indicado pela cadeia de caracteres que compe controle. O formato ao mesmo
tempo de uso simples e bastante flexvel, permitindo que os resultados possam
ser apresentados de diversas maneiras. A funo retorna o nmero de caracteres
impressos, no incluindo o nulo em vetores de caracteres. No caso de um erro
de sada um valor negativo retornado.
Um exemplo simples pode tornar a explicao mais clara. O programa 4.1
imprime o valor da varivel ano.

Listagem 4.1: Exemplo de impresso de resultados

#in lude < stdio .h >


int main ( void ) {
int ano = 1997;

/* Imprime o valor do ano */


printf ( " Estamos no ano % d " , ano ) ;
return 0;

Este programa ir imprimir na tela do computador:


Estamos no ano 1997
Como controle uma cadeia ele aparece entre " ". Ele define como sero
impressos os valores representados pelos argumentos. No controle podem existir dois tipos de informaes: caracteres comuns e cdigos de formatao. Os
caracteres comuns, como no exemplo o texto Estamos no ano, so escritos na
tela sem nenhuma modificao. Os cdigos de formatao, aparecem precedidos
por um caractere% e so aplicados aos argumentos na ordem em que aparecem. Deve haver um cdigo de formatao para cada argumento. O cdigo
%d indica que o valor armazenado em ano deve ser impresso na notao inteiro
decimal. importante notar que o campo de controle aparece somente uma
vez na funo printf e sempre no incio.

69

4.3.1 Cdigos de Converso


Os cdigos de converso esto mostrados na tabela 4.1.
Cdigo
%c
%d
%i
%E
%e
%f
%G
%g
%o
%s
%u
%x
%X
%p
%%

Comentrio
Caracter simples
Inteiro decimal com sinal
Inteiro decimal com sinal
Real em notao cientfica com E
Real em notao cientfica com e
Real em ponto flutuante
%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 minsculas)
Inteiro em base hexadecimal (letras maisculas)
Endereo de memria
Imprime o caractere %

Tabela 4.1: Cdigos de Converso para escrita de dados.


Entre o caractere % e o cdigo de converso podem ser inseridos caracteres
que alteram o formato. A seguir so mostrados a ordem de insero destes
caracteres e o seu significado:
%[modificadores][largura][.preciso][comprimento]cdigo
modificadores: Usados logo aps o caractere %.
- Um sinal de menos serve para especificar que o argumento deve ser
justificado esquerda no seu campo de impresso. Caso nenhum
sinal seja usado o argumento ser ajustado direita. O programa
4.2 ilustra os dois tipos de justificao.
+ Fora que o resultado seja precedido por sinal de menos ou de mais,
mesmo para nmeros positivos. O padro que somente negativos
sejam precedidos por sinal de menos.
espao Caso nenhum sinal v ser escrito, um espao 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, fora
que a sada contenha um ponto decimal mesmo que no haja parte
fracionria. Por padro, se no h parte fracionria o ponto decimal
no escrito. Usado com g ou G o resultado o mesmo que com e
ou E, mas os zeros finais no so retirados.

70

0 Completa o campo, pela esquerda, com zeros (0) ao invs de espaos,


sempre que a opo para completar seja especificada (ver especificador de largura do campo).
largura: Caso seja usado um nmero inteiro, este especifica o tamanho mnimo
do campo onde o argumento ser impresso. Na listagem 4.2 o nmero
especifica que 8 espaos so reservados para imprimir o resultado. Os
espaos livres sero completados com espaos em branco. Se o argumento
precisar de mais espao que o especificado ele ser escrito normalmente e
o tamanho mnimo ignorado.
.preciso Este nmero tem diferentes significados dependendo do cdigo usado.
caracteres: No caso de impresso de cadeia de caracteres (s), este nmero especifica o nmero mximo de caracteres de uma cadeia de
caracteres a serem impressos.
ponto flutuante: No caso de formato (e, E, f) o nmero de dgitos a
serem impressos a direita do ponto, ou seja o nmero de casas decimais. Para o formato g ou G o nmero mximo dgitos significativos.
inteiros: No formatos inteiros (d, i, o, u, x, X) a preciso especificou o nmero mximo de dgitos a serem impressos. Se o nmero de
caracteres a serem impressos menor que este o resultado completado com brancos. O valor no truncado
comprimento: Modifica os formatos da seguinte maneira:
l Aplicado aos formatos de tipo d, i, o, u, x e X indicando que o dado
do tipo long int e no int.
h Modifica 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 modificado para long double.
O programa 4.2 ir imprimir o seguinte resultado:
Justificado para direita Ano =
1997
Justificado para esquerda Ano = 1997

Listagem 4.2: Exemplo de justificao de resultados.

#in lude < stdio .h >


int main ( void ) {
int ano = 1997;
printf ( " Justifi ado para direita Ano = %8 d \ n " , ano ) ;
printf ( " Justifi ado para esquerda Ano = % -8 d \ n " , ano ) ;
}

return

0;

O programa exemplo 4.3 imprimir o seguinte resultado:


71

Listagem 4.3: Exemplo de uso de especificador de preciso.

#in lude < stdio .h >


int main () {
f l o a t r = 1.0/3.0;
har s [ = " Alo Mundo " ;
printf ( " O resultado e = %9.3 f \ n " , r ) ;
printf ( " %9.3 s \ n " , s ) ;
}

return

0;

O resultado e = 0.333
.
Alo
Nos exemplos anteriores verifique que \n no impresso. A barra inclinada
chamada de seqencia de escape, indicando que o prximo caractere no para
ser impresso mas representa caracteres invisveis ou caracteres que no esto
representados no teclado. Esta seqncia de escape indica que o programa deve
passar a imprimir na prxima linha.

4.4 Entrada - A Funo s anf


A funo s anf pode ser utilizada para entrada de dados a partir do teclado e
seu prottipo :
s anf( ontrole, arg1, arg2, ...);

Uma diferena fundamental que existe entre esta funo e a funo printf
est nos argumentos que vm depois do controle. No caso de s anf os argumentos so os endereos das variveis que iro receber os valores lidos e no,
como em printf, as prprias variveis. A indicao que estamos referenciando
um endereo e no a varivel se faz pelo operador &. Por exemplo, o comando
s anf("%d %d", &a, &b);

espera que dois valores inteiros sejam digitados no teclado. O primeiro armazenado na varivel a e o segundo em b. Os valores sero armazenados diretamente
nos endereos indicados por &a e &b respectivamente.
Um outro exemplo incluindo variveis reais :

int i ;
float x;

s anf ( " % d % f " , &i , & x ) ;

Assumindo que a linha de entrada no teclado fosse


34 56.43

72

a execuo do exemplo iria terminar com o valor inteiro 34 sendo armazenado


na varivel i e o valor real 56.43 em x.
Usualmente o campo de controle s contm especificaes de converso, como
os listados na Tabela 4.1, que so utilizadas para interpretar os dados que sero
lidos, no entanto, como em printf, outros caracteres podem aparecer. O campo
de controle pode conter:
Caracteres branco: A funo l e ignora todos os caracteres branco e/ou
<enter> e/ou tab que aparecerem antes de qualquer caractere diferente
destes.
Caracteres comuns: (no %) que devem casar com o prximo caractere diferente de branco da entrada. Isto significa que qualquer caractere que no
for igual a branco e/ou <enter> e/ou tab ou parte de um especificador de
formato faz com que a funo leia o prximo caractere da entrada (stdin)
e se for igual a este ele descartado. Caso os caracteres sejam diferentes
a funo falha e retorna deixando os caracteres seguintes no lidos.
Especificaes de converso: Um especificador de converso de formato seguindo um modelo similar ao da funo printf.
O modelo o seguinte:
%{*}{largura}{modificadores}tipo
O caracteres entre chaves so opcionais. O asterisco indica que o dado ser lido
de stdin mas ignorado. A largura especifica o nmero mximo de caracteres a
serem lidos.
Os modificadores alteram o tamanho do especificadores de tipo que vm logo
a seguir. Existem os seguintes modificadores:
h: Os tipos d, i e n, que so int passam a ser short int e os tipos o, u e x,
tambm 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 vrgulas, o
comando deveria ser escrito da seguinte maneira:
s anf("%d, %f", &i, &x);

Observar que deve haver uma correspondncia exata entre os caracteres no


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 funo s anf.
O resultado da execuo deste programa :

73

Listagem 4.4: Exemplo de uso de scanf.

#in lude < stdio .h >


int main () {
har ;
int num1 , num2 ;

printf ( " Entre om um ara tere qualquer .\ n " ) ;


s anf ( " % " , & ) ;
printf ( " Codigo ASCII do ara tere % vale % d .\ n " , ,
);
printf ( " Agora dois inteiros separados por espa o .\ n " ) ;
s anf ( " % d % d " , & num1 , & num2 ) ;
printf ( " A soma destes numeros vale % d .\ n " , num1 + num2 ) ;
return 0;

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 funo s anf retorna o nmero de itens lidos com sucesso. Este nmero
pode ser usado para verificar se todos os valores pedidos foram lidos. No caso
de ocorrer uma falha antes da leitura se iniciar a constante EOF retornada.

4.5 Lendo e Imprimindo Cara teres


4.5.1 Funes get har e put har
Para ler e escrever caracteres do teclado as funes de entrada e sada mais
simples so get har e put har, que esto na biblioteca stdio.h e cujos prottipos
so os seguintes:

int
int

get har ( void ) ;


put har ( int ) ;

Apesar da funo get har retornar um parmetro inteiro possvel atribuir


este valor a uma varivel do tipo har porque o cdigo do caractere est armazenado no byte ordem mais baixa. O mesmo acontece com a funo put har que
recebe um inteiro, mas somente o byte de ordem mais baixa passado para a
tela do computador. A funo put har retorna o caractere que foi escrito e EOF
em caso de erro. O programa da listagem 4.5 mostra exemplos de uso destas
funes, e o seu resultado :

74

Entre com um algarismo entre 0 e 9.


7
O caractere lido foi o 7

Listagem 4.5: Exemplo de uso de getchar e putchar.

#in lude < stdio .h >


int main ( void ) {
har ;
printf ( " Entre om um algarismo entre 0 e 9.\ n " ) ;
= get har () ;
printf ( " O ara tere lido foi o " ) ;
put har ( ) ;
}

return

0;

Observar que, normalmente, quando algum dado fornecido pelo teclado


termina-se a digitao com a tecla <enter>. No entanto, o <enter> um
caractere tambm, e isto pode causar problemas. Vamos analisar o que acontece
quando antes do comando get har, se l um dado do tipo inteiro, por exemplo.
O comando s anf l o nmero inteiro mas no o <enter> digitado. Deste modo,
quando logo em seguida o programa executar a funo get har, o que ser lido
o <enter> digitado ao final do nmero. A listagem 4.6 um exemplo de
programa onde isto pode ocorrer. Considere que o usurio digitou 35<enter>
como resposta ao comando s anf. O comando get har ir ler o <enter> e em
seguida o programa ir imprimir o nmero 35, lido no s anf, e apenas uma linha
em branco correspondente ao caractere <enter>, lido pelo get har, como est
indicado a seguir. Mais adiante mostraremos como resolver este problema.
Entre com um numero inteiro.
35
Agora um caractere.
Numero lido 35
Caractere lido

4.5.2 Lendo e Imprimindo Cadeias de Cara teres


Uma cadeia de caracteres (string) em C um vetor de caracteres. Vetores, que
sero vistos mais adiante no Captulo 7, so conjuntos de caracteres em que
cada um deles pode ser acessado independentemente dos outros por meio de
um endereo. Nesta etapa iremos apresentar rapidamente alguns conceitos que
nos permitiro criar alguns exemplos simples com cadeias de caracteres. Para
usar cadeias preciso primeiro definir um espao para armazen-las. Para isto
preciso declarar o nome, o tamanho e o tipo do vetor. Considere que precisamos armazenar uma cadeia de caracteres chamada nome com 40 caracteres. A
definio desta cadeia ficaria da seguinte maneira:
75

Listagem 4.6: Exemplo de uso de getchar e putchar.

#in lude < stdio .h >


int main ( void ) {
har ;
int i ;
printf ( " Entre om um numero inteiro .\ n " ) ;
s anf ( " % d " , & i ) ;
printf ( " Agora um ara tere .\ n " ) ;
= get har () ;
printf ( " Numero lido % d \ n " , i ) ;
printf ( " Cara tere lido % \ n " , ) ;
return 0;

har

nome [41;

Quando definir o tamanho do vetor de caracteres, observar que toda cadeia


em C termina com o caractere NULL (\0), que automaticamente inserido
pelo compilador. Portanto o vetor nome deve ser definido com um espao a
mais. Aps este passo, o vetor nome pode ser usado durante a execuo do
programa.

4.5.3 Lendo e Imprimindo adeias om s anf e printf


O programa 4.7 mostra como ler e imprimir um cadeia usando os comandos
scanf e printf respectivamente.

Listagem 4.7: Exemplo de uso de printf e scanf na leitura de cadeias.

#define DIM 40
#in lude < stdio .h >
int main ( void ) {
har nome [ DIM ;

/* linha de ara teres lidos */

/* Entrada de dados do vetor */


printf ( " Por favor , qual o seu nome ?\ n " ) ;
s anf ( " % s " , nome ) ;
printf ( " Sou um omputador . Posso ajuda - lo % s ?\ n " , nome
);
return 0;

76

Considere que este programa se chama util. Uma possvel interao entre
este programa e um usurio poderia ser da seguinte maneira.
$ util
Por favor, qual o seu nome?
Ze Sa
Sou um computador. Posso ajuda-lo Ze?
O smbolo $ o prompt tpico dos sistemas Unix. Aparentemente o computador se tornou ntimo do usurio Ze Sa e o tratou apenas pelo primeiro nome. A
explicao para esta intimidade est no modo de leitura. Quando se usa scanf
para ler uma cadeia deve-se empregar o cdigo de converso %s. Este comando
no l o nome todo, mas encerra a leitura dos caracteres quando encontra um
caractere espao (ou branco), ou seja o separador de cadeias no comando s anf
o caractere espao. Mas como ler para um vetor um nome inteiro, ou um
cadeia que contenha brancos? Para isto deve-se usar a funo gets que ser
nosso prximo assunto.

4.5.4 Lendo e Imprimindo adeias om gets e puts


Diferentemente do comando scanf a funo gets l toda a cadeia at que a tecla
<enter> seja digitada. No vetor so colocados todos os cdigos dos caracteres
lidos excetuando-se o da tecla <enter>, que no armazenado sendo substitudo
pelo cdigo NULL. Caso a funo s anf do exemplo anterior fosse substituda pela
gets o programa imprimiria
Posso ajuda-lo Ze Sa?
O comando que substitui o scanf gets(nome). O prottipo da funo gets
o seguinte:

#in lude < stdio .h >


har * gets ( har * str ) ;
A funo gets retorna str caso nenhum erro ocorra. Caso o final do arquivo seja encontrado antes de qualquer caractere ser lido, o vetor permanece
inalterado e um ponteiro nulo retornado. Caso um erro ocorra durante a leitura, o contedo do array fica indeterminado e novamente um ponteiro nulo
retornado.
A funo puts tem o seguinte prottipo:

#in lude < stdio .h >


int puts ( onst har

* str ) ;

Ela imprime a cadeia apontado por str. O programa 4.8 semelhante ao


exemplo anterior com as funes printf substitudas por puts. Observe que a
impresso sempre termina e passa para a prxima linha. A funo puts retorna
um valor positivo caso nenhum erro ocorra. Em caso de erro retornado um
valor negativo.

77

Entre com o seu nome, por favor.


Ze Sa
Alo
Ze Sa
Eu sou um computador, em que posso ajuda-lo?

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

#define DIM 41
#in lude < stdio .h >
int main ( void ) {
har nome [ DIM ;

/* linha de ara teres lidos */


/* Entrada de dados do vetor */
puts ( " Entre om o seu nome , por favor . " ) ;
gets ( nome ) ;
puts ( " Alo " ) ;
puts ( nome ) ;
puts ( " Eu sou um omputador , em que posso ajuda - lo ? " );
return 0;

4.5.5 A Funo fgets


A funo gets pode abrir porta para invases de computadores pelo fato dela
no controlar o nmero de caracteres lido de stdin. Apesar do usurio definir
um tamanho mximo para o vetor que ir armazenar os caracteres a funo
ignora o limite e continua lendo valores at que o usurio digite o caractere
<enter>.
Para evitar este problema recomenda-se o emprego da funo fgets cujo
prottipo

#in lude < stdio .h >


int * fgets ( onst har

* str ,

int

tam , FILE * fluxo ) ;

A funo fgets l no mximo um caractere a menos que o nmero de caracteres especificado no parmetro tam a partir do fluxo de entrada de dados
definido por fluxo. No caso de leitura do teclado, como temos feito, fluxo
igual a stdin. A leitura interrompida quando um caractere <enter> encontrado ou o final do arquivo foi atingido. Diferentemente do que ocorre na
funo gets, aqui o caractere <enter> armazenado no vetor onde os demais
caracteres esto sendo guardados. O caractere nulo adicionado aps o ltimo
caractere lido.
A funo retorna str caso seja bem sucedida. Se o final do arquivo for
atingido e nenhum caractere tiver sido lido, o vetor str permanece inalterado
e um ponteiro nulo retornado. Caso ocorra um erro de leitura o contedo do
vetor fica indeterminado e um ponteiro nulo retornado.
78

Exer ios
4.1: Escreva um programa que declare variveis do tipo int, char e float,
inicialize-as, e imprima os seus valores.
4.2: Escreva um programa que defina variveis do tipo int e armazene nelas
constantes octais e hexadecimais e imprima o seu contedo no formato original
e em formato decimal.
4.3: Faa 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 Sada:
Entre com o valor:
10
Hexadecimal: A
Octal: 12
4.4: Faa um programa capaz de ler um valor real e escrev-lo com apenas uma
casa decimal.
4.5: Faa um programa que leia trs palavras de at 10 letras e reescreva estas
palavras alinhadas direita da tela.
4.6: Sabendo que os argumentos da funo printf podem ser expresses (a+b,
a/b, a*b, 3*a...), e no somente argumentos, faa um programa capaz de ler
um valor inteiro e escrever seu triplo, seu quadrado, e a sua metade.
Exemplo de Entrada e Sada:
Valor:
6
Triplo: 18
Quadrado: 36
Meio: 3
4.7: Escreva um programa que leia 3 nmeros reais e imprima a mdia aritmtica destes nmeros.
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: Faa um programa que pea ao usurio a quilometragem atual, a quilometragem anterior, os litros consumidos e informe a taxa de consumo (quilmetros
por litro) de um automvel.
4.10: Escreva um programa que converta uma temperatura de Farenheit para
Celsius.
4.11: Escreva um programa que, dado o permetro de um crculo, calcule sua
rea.
4.12: Faa um programa que utilize a funo gets para ler duas cadeias de
tamanho at 20 e em seguia s reescreva na linha de baixo, uma ao lado da
outra e separadas por "/-/ ";
79

Captulo 5

Operadores e Expresses
5.1 Introduo
O objetivo deste captulo apresentar os operadores existentes na linguagem
C e a forma correta de construir expresses que envolvam estes operadores,
constantes e variveis.

5.2 Operador de Atribuio


Este o operador usado para transferir o resultado de uma expresso para uma
varivel. Em C este operador o sinal de igual (=). Esta escolha do sinal de
igual para servir de operador de atribuio pode causar problemas. Isto porque
este sinal no est representando que o resultado da expresso do lado direito
igual ao resultado do lado esquerdo e sim uma atribuio. Observe que o
comando de atribuio termina em ponto e vrgula. Isto faz parte das regras da
linguagem C, que determina que comandos terminam com este caractere. Por
exemplo:
soma = a + b;
pi = 3.1415;
possvel fazer-se vrias atribuies em uma nica linha, como no exemplo
a seguir:
a = b = c = 1.0;
as trs variveis recebem o mesmo valor. As atribuies so feitas na seguinte
ordem:
1. c = 1.0; c recebe o valor 1.0.
2. b recebe o resultado da expresso sua direita, que o valor atribudo
c, ou seja 1.0.
3. a recebe o resultado da expresso sua direita, que o valor atribudo
b, ou seja 1.0.
80

5.3 Operadores Aritmti os


A Tabela 5.1 mostra os operadores aritmticos e as suas ordens de precedncia.
Operador
+
++

*
/
%
+
-

Descrio
Mais unrio
Menos unrio
Incremento
Decremento
Multiplicao
Diviso
Resto da diviso
Soma
Subtrao

Prioridade
0
0
1
1
2
2
2
3
3

Tabela 5.1: Operadores aritmticos.


Os smbolos mostrados na Tabela 5.1 so os nicos que podem ser usados
para representar as operaes acima listadas. Expresses aritmticas em C devem ser escritas no formato linear para facilitar a digitao dos programas e
tambm porque alguns smbolos usados em Matemtica no existem nos teclados. O exemplo mais comum deste formato a operao de diviso que deve
ser escrita a/b.
Parnteses tm um papel importante nas expresses e permitem que a ordem
das operaes seja alterada. Expresses entre parnteses so calculadas em
primeiro lugar, portanto eles conferem o maior grau de prioridade as expresses
que eles envolvem. Podemos ter pares de parnteses envolvendo outros pares.
Dizemos que os parnteses esto aninhados. Neste caso as expresses dentro
dos parnteses mais internos so avaliadas primeiro.
Outro ponto importante so as regras de precedncia que determinam que
operao deve ser executada primeiro. Na tabela os operadores esto listados
em ordem decrescente de prioridade. Para os operadores aritmticos a operao
de mais alta precedncia o - unrio, vindo em seguida ++, com a mesma
prioridade. Os operadores de multiplicao, diviso e mdulo tem a mesma
prioridade. O operador menos unrio multiplica seu operador por -1. Quando
duas operaes de mesmo nvel de prioridade tm de ser avaliadas, a operao
mais esquerda ser avaliada primeiro.
Um ponto importante que deve ser sempre levado em considerao quando
uma expresso for calculada so os tipos das variveis, porque eles alteram radicalmente os resultados das expresses. Por exemplo, a diviso entre operandos
do tipo inteiro tem como resultado um valor inteiro. Portanto, se o resultado
possuir uma parte fracionria ela ser truncada. No possvel aplicar a operao de mdulo a operandos do tipo float e double. Algumas regras de
converso simples existem e sero discutidas em detalhes mais adiante. Por
exemplo a operao 1/3 em C fornece como resultado o valor 0, enquanto que
1 % 3 igual a 1.
A seguir mostramos alguns exemplos de expresses aritmticas escritas na
81

notao da linguagem C. Observe o uso de parnteses para evitar ambigidades


que poderiam fazer com que a expresso fosse calculada erradamente.
Exemplo 5.4:
1. a +

b
b+c

= a + b/(b+c)

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

x
a+ cb

= x/(a+b/c)

5.4 Operadores Rela ionais e Lgi os


5.4.1 Operadores Rela ionais
Os operadores relacionais esto mostrados na Tabela 5.2. Nesta tabela mostramos somente a ordem de precedncia destes operadores. A ordem de precedncia
que inclui todos os operadores est mostrada na Tabela 5.9.
Operador
>=
>
<=
<
==
!=

Descrio
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 <= tm a mesma precedncia e esto acima de ==
e !=. Estes operadores tm precedncia menor que os aritmticos, portanto
expresses como ( i < limite - 1) e i < (limite -1) tm o mesmo significado.

5.4.2 Operadores Lgi os


Os operadores lgicos definem as maneiras como as relaes acima podem ser
conectadas. Por exemplo podemos querer testar se ao mesmo tempo uma nota
maior ou igual a 5.0 e a taxa de presena maior que 75%.
Para simplificar a apresentao destes operadores sero usadas variveis para
substituir as relaes. Neste caso a expresso acima seria representada como
p e q, onde p est representando nota maior ou igual a 5.0 e q taxa de presena maior que 75%. Estas expresses podem ter dois resultados verdadeiro
e falso. Observar que, assim como em operaes aritmticas, podemos ter
combinaes de mais de duas relaes em uma nica expresso. Por exemplo,
podemos ter a seguinte combinao: ano maior que 2000 e ms menor que 6
e dia maior que 15. Nas linguagens de programao os valores verdadeiro e
falso podem ser representados de diversas maneiras. Uma das maneiras mais
82

comum representar verdadeiro por true e falso por false. Em C o valor


falso representado por 0 e verdadeiro por qualquer valor diferente de 0. A
seguir iremos mostrar os operadores lgicos existentes na linguagem C.
E lgico
O smbolo usado para representar o operador E lgico &&. A Tabela 5.3
mostra a tabela verdade do operador. O resultado da expresso verdadeiro
se e somente se todas as variveis forem iguais a verdadeiro. Por exemplo,
considere o seguinte trecho de programa:

int i = 3 , j =
f l o a t z = 3.0;
int resultado ;

-5;

resultado = (10 > 5) && ( i > -5) && ( z != 0) ;


printf ( " O resultado e vale % d . " , resultado ) ;

O resultado deste trecho a impresso de um valor diferente de 0, ou seja o


valor correspondente a verdadeiro. Isto porque 10 maior que 5 E i maior
que -5 E z diferente de 0.
p
0
0
1
1

q
0
1
0
1

p && q
0
0
0
1

Tabela 5.3: Operador Lgico E.

OU lgico
O smbolo usado para representar o operador OU lgico ||. A Tabela 5.4
mostra a tabela verdade do operador. Para que o resultado da expresso seja
verdade basta que uma das variveis seja verdade. Por exemplo, considere o
seguinte trecho de programa:

f l o a t x = 3.0;
int n = 55 , i =
int resultado ;

0;

resultado = ( i != 0) || ( x == 0) || ( n < 100) ;


printf ( " O resultado e % d " , resultado ) ;

O resultado deste trecho a impresso do valor 1. Isto porque, apesar de i


no ser diferente de 0 e x no ser diferente de zero, temos que n menor que
100. Como basta um dos testes ser verdade para o resultado ser verdade ser
impresso um valor diferente de 0.
83

p
0
0
1
1

q
0
1
0
1

p || q
0
1
1
1

Tabela 5.4: Operador Lgico OU.

No lgico
O smbolo usado para representar o operador NO lgico !. A Tabela 5.5
mostra a tabela verdade do operador. Este operador unrio e quando aplicado
uma varivel ele troca seu valor. Por exemplo, considere o seguinte trecho de
programa:

int
int

dia = 25 , ano = 1959;


resultado ;

resultado = ! ( ( dia < 30) && ( ano > 1950) )


printf ( " O resultado vale \% d . " , resultado ) ;

Este trecho de programa imprime 0 (falso), porque dia menor que 30 E


ano maior que 1950. Portanto, o resultado do parnteses vale 1 (verdadeiro).
No entanto, o operador ! nega este valor que vira 0.
p
0
1

!p
1
0

Tabela 5.5: Operador Lgico NO.


A tabela 5.6 mostra, em ordem decrescente, a precedncia dos operadores
lgicos e relacionais.
Operador
!
>, >=, <, <=
==, !=
&&
||

Prioridade
0
1
2
3
4

Tabela 5.6: Precedncia dos operadores lgicos e relacionais.

84

5.5 Operadores om Bits


Para operaes com bits, a linguagem C dispe de alguns operadores que podem
ser usados nos tipos char, int, long e long long mas no podem ser usados
em float, double, long double e void. A diferena entre estes operadores
e os lgicos que estes operam em pares de bits enquanto que os operadores
lgicos anteriores consideram a palavra toda. Por exemplo, para um valor int
ser falso necessrio que todos os 32 bits sejam iguais a zero. Os operadores
em bits esto mostrados na Tabela 5.7.
[fragile]Operadores com bits
Operador

~
&
^
|

Descrio
Desloca para direita
Desloca para esquerda
No
E
Ou exclusivo
OU

Prioridade
0
0
1
2
3
4

Tabela 5.7: Operadores com bits.

Os operadores &, | e ~ tm a mesma tabela verdade que os operadores &&, ||


e ! respectivamente. O operador ^ (OU Exclusivo) est descrito pela Tabela
5.8. O resultado da operao verdadeiro se e somente se os dois operandos
so diferentes.
p
0
0
1
1

q
0
1
0
1

p ^ q
0
1
1
0

Tabela 5.8: Operador Lgico OU.

Os operandos de deslocamento tm os seguintes modos de operao:


operando vezes: o operando deslocado vezes bits para a direita.
operando vezes: o operando deslocado vezes bits para a esquerda.
Observaes:
Nos deslocamentos direita em variveis unsigned e nos deslocamentos
esquerda, os bits que entram so zeros;
Nos deslocamentos direita em variveis signed, os bits que entram correspondem ao sinal do nmero (1= sinal negativo, 0 = sinal positivo).
85

Um deslocamento para a direita equivalente a uma diviso por 2. Deslocamento para a esquerda equivalente a uma multiplicao por 2. Assim
a = a * 2; e a = a 1; so equivalentes.
O exemplo 5.1 ilustra o uso dos operandos de deslocamento:

Listagem 5.1: Exemplo de operadores de deslocamento.

#in lude < stdio .h >


int main ( void ) {
unsigned int
int d = -7;

= 7;

= < <1; printf ( " %3 d = %08 X \ n " , , ) ;


= > >1; printf ( " %3 d = %08 X \ n " , , ) ;
d = d < <1; printf ( " %3 d = %08 X \ n " , d , d ) ;
d = d > >1; printf ( " %3 d = %08 X \ n " , d , d ) ;

return

0;

Este programa teria como resposta os seguintes resultados.


14
7
-14
-7

=
=
=
=

0000000E
00000007
FFFFFFF2
FFFFFFF9

Os resultados mostram que o nmero 7 aps o primeiro deslocamento de 1


bit para a esquerda ficou igual a 14, portanto um 0 entrou no nmero. Quando
o nmero foi deslocado para direita 1 bit, ele retornou ao valor original. Observe
que quando o nmero -14 foi deslocado para a direita entrou um bit 1, que
igual ao sinal negativo.

5.6 Operadores de Atribuio Composta


Em C qualquer expresso da forma:
variavel = variavel operador expressao
pode ser escrita como:
variavel operador= expressao
Por exemplo:
ano = ano + 10;
equivalente a
ano += 10;
Outros exemplos so:
86

raiz = raiz * 4;
raiz *= 4;
soma = soma / ( a + b);
soma /= (a + b);
a = a 1;
a = 1;
i = i % 2;
i %= 2;

5.7 Operador vrgula


O operador vrgula (,) usado para separar duas ou mais expresses que so
escritas onde somente uma esperada. Quando o conjunto de expresses tem
de ser reduzido a somente um valor, somente a expresso mais direita considerada. Por exemplo, considere o seguinte trecho de cdigo:
y = ( x =5 , x +2) ;

A expresso comea a ser avaliada da esquerda para a direita. Portanto,


primeiro seria atribudo o valor 5 a varivel x. Em seguida atribui x+2 para a
varivel y. Ao final a varivel x contm o valor 5 e y o valor 7.

5.8 Operador sizeof()


O operador sizeof() um operador unrio que retorna o tamanho em bytes
da expresso ou tipo fornecido entre parnteses. Por exemplo, suponha que o
tipo float tenha quatro bytes ento o operador sizeof(float) retorna o valor
4. Para se calcular o tamanho de bytes de uma expresso no necessrio o uso
de parnteses. No exemplo 5.2 ilustramos alguns exemplos de uso do operador
sizeof().
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

5.9 Converso de Tipos


Quando operandos de tipos diferentes aparecem em expresses so convertidos
para um tipo comum, que permita o clculo da expresso da forma mais eficiente.
Por exemplo, uma operao que envolva um tipo int e um float, o valor int
convertido para float.

87

Listagem 5.2: Exemplo do operador sizeof.

#define DIM 10
#in lude < stdio .h >
#in lude < onio .h >
int main () {
int i =0;
f l o a t f =3.0;
har = 'a ';
int 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 har % d \ n " , s i z e o f ) ;
printf ( " Tamanho do vetor de % d inteiros % d \ n " ,
DIM , s i z e o f ( v ) ) ;
return 0;

Observar que converses ocorrem somente quando necessrio. Por exemplo,


em uma diviso de inteiros o resultado do tipo inteiro. Isto pode causar
surpresas desagradveis para programadores iniciantes. A expresso 1/3*3 tem
como resultado o valor inteiro 0. J que a primeira expresso executada 1/3
tem como resultado 0.
Operandos do tipo char e int podem ser livremente misturados em expresses aritmticas. Os tipos char so convertidos para int. Caso o conjunto de
caracteres esteja codificado segundo a tabela ASCII, esta facilidade permite a
realizao de algumas transformaes interessantes. Por exemplo, a converso
de uma letra maiscula para minscula pode ser facilmente implementada com
o comando:
l = l - A + a;
A letra maiscula armazenada na varivel l subtrada do cdigo da letra
maiscula A, fornecendo a posio desta letra no alfabeto. Em seguida este
valor somado ao cdigo da letra minscula a, resultando da converso para
minscula.
Portanto, converses aritmticas ocorrem de maneira quase que natural. Em
operaes binrias as seguintes converses ocorrem quando diferentes tipos esto
envolvidos:
char convertido para int;
float convertido para double.
Ento, se algum dos operandos double o outro convertido para double
e o resultado double. Caso contrrio, se algum dos operandos long, o
88

outro convertido para long e o resultado long. Caso contrrio, se algum


dos operandos unsigned, o outro convertido para unsigned e o resultado
deste tipo. Caso contrrio os operandos so int e o resultado int. Note que
todos os floats em uma expresso so convertidos para double e a expresso
avaliada em double.
O resultado de uma expresso convertido para o tipo da varivel onde o resultado ser armazenado. Um resultado float ao ser carregado em uma varivel
do tipo int causa o truncamento da parte fracionria, porventura existente.
A converso de inteiro para caractere bem comportada, mas o contrrio
nem sempre ocorre convenientemente. A linguagem no especifica se o tipo
char um tipo com sinal ou no. Quando um caractere armazenado em uma
varivel do tipo inteiro podem ocorrer problemas com caracteres que tm o bit
mais esquerda igual a 1. Isto porque algumas arquiteturas podem estender
este bit e outras no.

5.10

Regras de Pre edn ia

A Tabela 5.9 mostra, em ordem decrescente de prioridade, as regras de precedncia dos operadores em C. Os operadores que esto na mesma linha da tabela
e com a mesma ordem tm a mesma prioridade. Alguns dos operadores listados
na Tabela somente sero mostrados nos captulos seguintes.
Pri
0
1
1
2
3
4
5
6
7
8
9
10
11
12
13
13
14

Operador
() [] -> .
! ++ * &
(tipo) sizeof()
* / %
+
< <= >= >
== !=
&
^
|
&&
||
? () : ()
= += -= *= /= %=
= = &= |=
,

Descrio
Agrupamento; acesso vetor; acesso membro
Unrias lgicas, aritmticas e com ponteiros;
Conformao de tipo; tamanho
Multiplicao, diviso e mdulo
soma e subtrao
Deslocamento de bits direita e esquerda
Operadores relacionais
Igualdade e diferena
E bit a bit
Ou exclusivo bit a bit
Ou bit a bit
E
Ou
Ternrio
Atribuies
Atribuies
Separador de expresses

Tabela 5.9: Precedncia dos operadores.

89

Exer ios
5.1: Escreva as expresses C abaixo na sua forma matemtica 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 expresses matemticas na linguagem C.
1. b2 4 b c
2.
3.

1
1+

1+

1
1
1+x

a+b
c+d

4. a

x
c+d

5.3: Diga a ordem de clculo e o resultado das expresses 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 funo ou exclusivo.
5.5: Escreva um programa que calcule o produto entre um valor x e 2n , onde
n e x so inteiros. Utilize operadores binrios.
5.6: Escreva um programa que leia um ngulo em segundos e imprima quantos
graus, minutos e segundos h neste ngulo.
5.7: Escreva um programa que leia um tempo em segundos e imprima quantas
horas, minutos e segundos h neste tempo.
5.8: Escreva um programa que leia um comprimento em centmetros e imprima
quantos metros, decmetros e centmetros h neste comprimento.
5.9: Uma empresa est selecionando entre seus empregados os que iro fazer um
treinamento especial. O funcionrio selecionado deve satisfazer a dois critrios.
O primeiro critrio para que um funcionrio seja pr-selecionado que ele deve
ter um salrio menor ou igual a R$ 400,00 ou maior ou igual a R$ 1.000,00.
O segundo critrio leva em conta o tempo de trabalho e o funcionrio deve ter
mais de 5 anos na empresa. Marque a resposta que indica a expresso lgica
que representa este critrio. Considere que existem as seguintes variveis.
90

Listagem 5.3: Variveis da questo 9.

f l o a t salario ;
int 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)

91

Captulo 6

Comandos de Controle
6.1 Introduo
Este captulo tem por objetivo apresentar os comandos de controle da linguagem
C. Estes comandos servem para controlar o fluxo de execuo das instrues
de um programa. Estes comandos permitem que o computador tome decises
independentemente do usurio que est rodando o programa.

6.2 Blo os de Comandos


Blocos de comando so grupos de comandos que devem ser tratados como uma
unidade lgica. O incio de um bloco em C marcado por uma chave de abertura
({) e o trmino 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
qualquer trecho de programa onde se pode usar um comando C. interessante
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
mostrado a seguir.
/* blo o_de_ o ma nd o 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 execuo do programa, independentemente do usurio. Estes testes
92

so baseados em estados internos disponveis ao processador. Estes estados


podem ser resultantes de uma operao aritmtica anterior, de uma operao
anterior etc.

6.3.1 Comando if
O comando if utilizado quando for necessrio escolher entre dois caminhos.
A forma geral do comando if a seguinte:

if

( expresso )
blo o_de_ o ma n do s 1 ;

else

blo o_de_ o ma n do s 2 ;

Neste comando a expresso avaliada, e caso o resultado seja verdadeiro


(qualquer resultado diferente de zero) o bloco_de_comandos1 executado, caso
contrrio o bloco_de_comandos2 executado. Pela definio do comando a expresso deve ter como resultado um valor diferente de zero para ser considerada
verdade. Observar que somente um dos dois blocos ser executado. Como a
clusula else opcional a forma abaixo do comando if perfeitamente vlida.

if

( expresso )
blo o_de_ om a nd o s ;

Lembrar que os blocos de comandos devem ser delimitados pelas chaves,


a no ser quando o bloco composto por 0 ou 1 comando. Na listagem 6.1
mostramos alguns exemplos de uso de comando if.
Uma construo que pode aparecer so os comandos ifs em escada, cuja
forma geral a seguinte:

if

( expresso )
blo o_de_ o ma nd o s
e l s e i f ( expresso1 )
blo o_de_ o m an d os 1
e l s e i f ( expresso2 )
blo o_de_ o ma nd o s2
...

else

blo o_de_ o ma nd o sn

O programa 6.2 mostra um exemplo com ifs em escada e aninhados. Um


exemplo de uso deste programa o seguinte:

93

Listagem 6.1: Exemplo de comandos if.


s anf ( " % d " , & dia ) ;
i f ( dia > 31 || dia < 1 )
printf ( " Dia invalido \ n " ) ;
s anf ( " % d " , & numero ) ;
i f ( numero > 0 )
printf ( " Numero positivo \ n " ) ;

else

printf ( " Numero negativo \ n " ) ;

s anf ( " % 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;
}

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:

if

( expresso )
blo o_de_ om a nd o s ;
e l s e i f ( expresso )
blo o_de_ om a nd o s ;
e l s e i f ( expresso )
blo o_de_ om a nd o s ;
...
e l s e blo o_de_ o ma n do s ;

6.3.2 Comando swit h


O comando if, em todas suas formas, suficiente resolver problemas de seleo
de comandos. Porm em alguns casos, como no exemplo 6.2 o programa se
torna mais trabalhoso para ser escrito e entendido. O comando switch facilita

94

Listagem 6.2: Programas com ifs em escada e aninhados.

#in lude < stdio .h >


int main ( void ) {
f l o a t num1 ,
har

/* primeiro operando */
num2 ,
/* segundo operando */
res ; /* resultado da opera ao */
oper ;
/* ara tere que define a opera ao */

printf ( " \ nPrograma que simula al uladora simples .\ n " )


;
printf ( " Entre om os dois operandos .\ n " ) ;
s anf ( " % f % f " , & num1 , & num2 ) ; get har () ; /* tirar o r
*/
printf ( " Qual a opera ao ? \ n " ) ;
oper = get har () ;
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 ( " Opera ao de divisao por 0 invalida !\
n");
return 1;
}
e l s e res = num1 / num2 ;
}
else {
printf ( " Opera ao invalida !\ n " ) ;
return 1;
}
printf ( " O resultado da % vale % f .\ n " , oper , res ) ;
return 0;

95

a escrita de trechos de programa em que a seleo deve ser feita entre vrias
alternativas.
A forma geral do comando switch a seguinte:

swit h ( expresso ) {
ase onstante1 :

seqn ia_ d e _ o ma n d os ;

ase

break ;

onstante2 :
seqn ia_ d e _ o ma n d os ;
break ;
ase onstante3 :
seqn ia_ d e _ o ma n d os ;
break ;
...
default :
seqn ia_ d e_ om a n do s ;

Uma seqncia de comandos diferente de um bloco de comandos. Um


bloco de comandos inicia com uma chave e termina com uma chave, enquanto
que uma seqncia apenas uma srie de comandos. Por exemplo, uma vez que
um bloco de comandos foi selecionado por um comando if ele ser executado
at a ltima instruo do bloco, a menos que haja um comando de desvio. Uma
srie de comandos so apenas comandos colocados um aps outro. A execuo
do comando switch segue os seguintes passos:
1. A expresso avaliada;
2. O resultado da expresso comparado com os valores das constantes que
aparecem nos comandos case;
3. Quando o resultado da expresso for igual a uma das constantes, a execuo se inicia a partir do comando associado com esta constante. A
execuo continua at o fim do comando switch, ou at que um comando
break seja encontrado;
4. Caso no ocorra nenhuma coincidncia os comandos associados ao comando default so executados. O comando default opcional, e se ele
no aparecer nenhum comando ser executado.
O comando break um dos comandos de desvio da linguagem C. O break
usado dentro do comando switch para interromper a execuo da seqncia
de comandos e pular para o comando seguinte ao comando switch.
H alguns pontos importantes que devem ser mencionados sobre o comando
switch.
O resultado da expresso deve ser um tipo enumervel, por exemplo o
tipo int. Tambm podem ser usados tipos compatveis com int, isto ,
expresses com resultados tipo char podem ser usadas;
96

Notar que caso no aparea um comando de desvio, todas as instrues


seguintes ao teste case que teve sucesso sero executadas, mesmo as que
estejam relacionadas com outros testes case;
O comando switch s pode testar igualdade;
No podem aparecer duas constantes iguais em um case;
O programa 6.3 mostra um exemplo de uso de comandos switch.

6.3.3 Comando Ternrio


O comando ternrio tem este nome porque necessita de trs operandos para ser
avaliado. O comando ternrio tem a seguinte forma:
expresso1 ?

expresso2 :

expresso3

Para avaliar o resultado total da expresso, primeiro a expresso1 avaliada. Caso este resultado seja correspondente ao valor verdadeiro ento o
resultado da expresso ser igual ao resultado da expresso2. Caso contrrio
a expresso3 avaliada e se torna o resultado. O programa 6.4 mostra um
exemplo de uso de comando ternrio.

6.4 Laos de Repetio


Estes comandos permitem que trechos de programa sejam repetidos um certo
nmero de vezes controlado pelo programa. O nmero de vezes que um lao
ser executado pode ser fixo ou depender de condies que mudam durante a
execuo do lao.

6.4.1 Comando for


Este comando aparece em vrias linguagens de programao, mas na linguagem
C ele apresenta um grau maior de flexibilidade. A idia bsica do comando for
a seguinte. Uma varivel de controle, geralmente um contador, recebe um valor
inicial. O trecho de programa que pertence ao lao executado e ao final a
varivel de controle incrementada ou decrementada e comparada com o valor
final que ela deve alcanar. Caso a condio de trmino tenha sido atingida o
lao interrompido. A forma geral do comando for a seguinte:

for

( expresso1 ; expresso2 ; expresso3 )


blo ode oman do s ;

As trs expresses geralmente tm os seguintes significados:


1. A expresso1 utilizada para inicializar a varivel de controle do lao;
2. A expresso2 um teste que controla o fim do lao;

97

Listagem 6.3: Exemplo de switch.

#in lude < stdio .h >


int main ( void ) {
float
num1 ,
num2 ,
res ;
har oper ;
*/

/* primeiro operando */
/* segundo operando */
/* resultado da opera ao */
/* ara ter que define a opera ao

printf ( " \ nEste programa simula uma al uladora simples


.\ n " ) ;
printf ( " Por favor entre om os dois operandos .\ n " ) ;
s anf ( " % f % f " , & num1 , & num2 ) ; get har () ;
printf ( " Qual a opera ao \ n " ) ;
oper = get har () ;
printf ( " A opera ao e % \ n " , oper ) ;
swit h ( oper ) {
ase '+ ':
res = num1 + num2 ;
break ;
ase ' - ':
res = num1 - num2 ;
break ;
ase '* ':
res = num1 * num2 ;
break ;
ase '/ ':
i f ( num2 == 0.0) {
printf ( " Divisao por zero e uma op ao
invalida .\ n " ) ;
return 1;
}
else {
res = num1 / num2 ;
break ;
}
default :
printf ( " Opera ao invalida !\ n " ) ;
return 2;
}
printf ( " O resultado da % vale % f .\ n " , oper , res ) ;
return 0;

98

Listagem 6.4: Exemplo de comando ternrio.

#in lude < stdio .h >


int main ( void ) {
float
num1 ,
num2 ,
max ;

/* primeiro operando */
/* segundo operando */
/* resultado da opera ao */

printf ( " Imprime o maior valor de dois numeros .\ n " ) ;


printf ( " Por favor entre om os dois mumeros .\ n " ) ;
s anf ( " % f % f " , & num1 , & num2 ) ;
max = ( num1 > num2 ) ? num1 : num2 ;
printf ( " O maior dos numeros lidos e % f .\ n " , max ) ;
return 0;

3. A expresso3 normalmente faz um incremento ou decremento da varivel


de controle.
A execuo do comando for segue os seguintes passos:
1. A expresso1 avaliada;
2. A expresso2 avaliada para determinar se o comando deve ser executado;
3. Se o resultado da expresso2 for verdadeiro o bloco de comandos
executado, caso contrrio o lao terminado;
4. A expresso3 avaliada;
5. Voltar para o passo 2.
O trecho a seguir imprime todos os nmeros entre 1 e 100.

for
}

( i = 1; i <= 100; i ++) {


printf ( " Numero % d \ n " , i ) ;

O programa 6.5 mostra como se pode calcular o fatorial de um nmero


usando-se o comando for.
Laos for com mais de um comando por expresso
Outra possibilidade que o comando for em C permite a incluso de vrios
comandos, separados por vrgulas, nas expresses. O trecho de programa a
seguir mostra um exemplo de uso de comando for com vrios comandos nas
expresses.

99

Listagem 6.5: Exemplo de comando for.

#in lude < stdio .h >


#in lude < stdlib .h >
int

main () {
int numero , fat =1 , i ;
printf ( " \ nEntre om um numero positivo . " ) ;
s anf ( " % d " , & numero ) ;
for ( i = numero ; i >1; i - -) fat = fat * i ;
printf ( " O fatorial de % u vale % u . " , numero , fat ) ;
return 0;

int
for
}

i,j;
( i =1 , j = 10; i <= 10; i ++ , j += 10) {
printf ( " i = %d , j = % d \ n " , i , j ) ;

Laos for com testes usando outras variveis


A expresso de controle no precisa necessariamente envolver somente um teste
com a varivel que controla o lao. O teste de final do lao pode ser qualquer
expresso relacional ou lgica. No programa 6.6 o lao pode terminar porque
a varivel de controle j chegou ao seu valor limite ou foi batida a tecla *, e
neste caso o lao termina antecipadamente.

Listagem 6.6: Exemplo de comando for com testes sobre outras variveis.

#in lude < stdio .h >


int main () {
har = ' ';
int i ;
for ( i =0 ; (i <5)
}
}

&& ( != '* ') ; i ++ ) {


printf ( " % \ n " , ) ;
= get har () ;

return

0;

Laos for com expresses faltando


Um outro ponto importante do for que nem todas as expresses precisam estar
presentes. No exemplo 6.7 a varivel de controle no incrementada. A nica
100

maneira do programa terminar o usurio bater o nmero -1.

Listagem 6.7: Exemplo de comando for sem alterao da varivel de controle.

#in lude < stdio .h >


int main () {
int i ;
for ( i =0 ; i
}

!= -1 ; ) {
printf ( " % d \ n " ,i ) ;
s anf ( " % d " , & i ) ;

return

0;

possvel omitir qualquer uma das expresses. Por exemplo, se a expresso2


for omitida o programa assume que ela sempre verdade de modo que o lao
s termina com um comando de desvio como o break. O programa do exemplo
6.8 pra quando o valor da varivel de controle for igual a 5. Neste caso o teste
ser verdade o lao termina por meio do break.

Listagem 6.8: Exemplo de comando for sem teste de fim.

#in lude < stdio .h >


int main () {
int i ;
for ( i = 0; ;
}
}

i ++) {
printf ( " numero % d \ n " , i ) ;
i f ( i == 5) break ;

return

0;

Lao infinito
Uma construo muito utilizada o lao infinito. No lao infinito o programa
pra quando se executa o comando break. O trecho de programa a seguir
somente pra quando for digitada a tecla s ou S .

for

( ; ; ) {
printf ( " \ nVo e quer parar ?\ n " ) ;
= get har () ;
i f ( == 'S ' || == 's ') break ;

101

Laos for aninhados


Uma importante construo aparece quando colocamos como comando a ser repetido um outro comando for. Esta construo pode aparecer quando estamos
trabalhando com matrizes. O exemplo 6.9 mostra um programa que imprime
uma tabuada.

Listagem 6.9: Comando for aninhados.

#in lude < stdio .h >


int main ( void ) {
int i , j ;
printf ( " Imprime tabuada de multipli a ao .\ n " ) ;
for ( i =1 ; i <10 ; i ++) {
printf ( " Tabuada de % d \ n " , i ) ;
for ( 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

( expresso )
blo o_de_ o ma nd o s

A expresso pode assumir o valor falso (igual a 0) ou verdade (diferente


de 0). Os passos para execuo do comando so os seguintes:
1. A expresso avaliada;
2. Se o resultado for verdadeiro ento o bloco de comandos executado,
caso contrrio a execuo do bloco terminada;
3. Voltar para o passo 1.
Uma caracterstica do comando while, como pode ser visto dos passos acima,
que o bloco de comandos pode no ser executado caso a condio seja igual a
falso logo no primeiro teste.
O trecho de abaixo imprime os 100 primeiros nmeros usando um comando
while.

102

i = 1;

while

( i <= 100) {
printf ( " Numero % d \ n " , i ) ;
i ++;

A expresso do comando pode incluir chamadas de funo. Lembrar que


qualquer atribuio entre parnteses considerada como uma expresso que
tem como resultado o valor da atribuio sendo feita. Por exemplo, o programa
6.10 repete um bloco de comandos enquanto o usurio usar a tecla c para
continuar, qualquer outra tecla o bloco interrompido.

Listagem 6.10: Comando while com uma funo.

#in lude < stdio .h >


int main ( void ) {
int ;
puts ( " Te le para ontinuar .\ n " ) ;
(( = get har () ) == ' ') {
puts ( " Nao A abou .\ n " ) ;
get har () ; /* tira o enter */
}
puts ( " A abou .\ n " ) ;
return 0;

while

6.4.3 Comando do-while


A forma genrica do comando a seguinte:

do

blo o_de_ o ma nd o s
( expresso ) ;

while

Observar que neste comando a expresso de teste est aps a execuo do


comando, portanto o bloco de comandos executado pelo menos uma vez. A
execuo do comando segue os seguintes passos:
1. Executa o comando;
2. Avalia a expresso;
3. Se o resultado da expresso for verdadeiro ento volta para o passo 1,
caso contrrio interrompe o do-while
O exemplo de comando for para imprimir os 100 primeiros nmeros escrito
com comando do-while fica da seguinte maneira:
103

i = 1;
{
printf ( " Numero % d \ n " , i ) ;
i ++;
} while ( i <= 100) ;

do

6.5 Comandos de Desvio


6.5.1 Comando break
O comando break pode ser tanto usado para terminar um teste case dentro
de um comando switch quanto interromper a execuo de um lao. Quando o
comando utilizado dentro de um comando for o lao imediatamente interrompido e o programa continua a execuo no comando seguinte ao comando
for. No trecho de programa abaixo o comando for deve ler 100 nmeros inteiros
positivos. No entanto, se for digitado um nmero negativo o comando for
interrompido imediatamente sem que o nmero seja impresso.

for

( i = 0; i < 100; i ++) {


s anf ( " % d " , & num ) ;
i f ( num < 0) break ;
printf ( " % d \ n " , num ) ;

6.5.2 Comando ontinue


O comando continue parecido com o comando break. A diferena que o
comando continue simplesmente interrompe a execuo da iterao corrente
passando para a prxima iterao do lao, se houver uma. No comando for o
controle passa a execuo da expresso3. Nos comandos while e do-while o
controle passa para a fase de testes.
No trecho de programa abaixo o lao l 100 nmeros inteiros, caso o nmero
seja negativo, um novo nmero lido.

for

( i = 0; i < 100; i ++) {


s anf ( " % d " , & num ) ;
i f ( num < 0) ontinue ;
printf ( " % d \ n " , num ) ;

6.5.3 Comando goto


O comando goto causa um desvio incondicional para um outro ponto da funo
em que o comando est sendo usado. O comando para onde deve ser feito o
104

desvio indicado por um rtulo, que um identificador vlido em C seguido por


dois pontos. importante notar que o comando goto e o ponto para onde ser
feito o desvio pode estar em qualquer ponto dentro da mesma funo. A forma
geral deste comando :
goto rtulo;
...
rtulo:
Este comando durante muito tempo foi associado a programas ilegveis. O
argumento para esta afirmao se baseia no fato de que programas com comandos goto perdem a organizao e estrutura porque o fluxo de execuo pode
ficar saltando erraticamente de um ponto para outro. Atualmente as restries
ao uso do comando tem diminudo e seu uso pode ser admitido em alguns casos.

6.5.4 Funo exit()


A funo exit provoca a terminao de um programa, retornando o controle ao
sistema operacional. O prottipo da funo a seguinte:
void exit (int codigo);
Observar que esta funo interrompe o programa como um todo. O cdigo
usado para indicar qual condio causou a interrupo 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 usado para interromper a execuo de uma funo e retornar um valor ao programa que chamou esta funo. Caso haja algum valor
associado ao comando return este devolvido para a funo, caso contrrio um
valor qualquer retornado. A forma geral do comando :
return expresso;
Notar que a expresso opcional. A chave que termina uma funo equivalente a um comando return sem a expresso correspondente. possvel haver
mais de um comando return dentro de uma funo. O primeiro que for encontrado durante a execuo causar o fim da execuo. Uma funo declarada
como do tipo void no pode ter um comando return que retorne um valor.
Isto no faz sentido, j que funes deste tipo no podem retornar valores.

105

Exer ios
6.1: Escreva um programa que calcule x elevado a n. Assuma que n um valor
inteiro.
6.2: Escreva um programa que exiba as opes
1-multiplicar e 2-somar
de um menu, leia a opo desejada, leia dois valores, execute a operao (utilizando o comando if) e exiba o resultado.
6.3: Utilizando ifs em escada, inclua, no programa do exerccio anterior, as
opes 3-Subtrair e 4-Dividir.
6.4: Simplifique os programas anteriores da seguinte forma:
Reescreva o programa do exerccio 1 substituindo o comando if pelo comando ternrio.
Reescreva o programa do exerccio 2 substituindo os ifs em escada pelo
comando switch.
6.5: Utilizando um lao for dentro de outro, escreva um programa que exiba
as tabuadas de multiplicao dos nmeros de 1 9.
6.6: Escreva um programa com menu de 5 opes que utilize o comando de
desvio goto para executar a opo desejada e s saia do programa caso a opo
5-Sair seja selecionada.
6.7:Escreva um programa que tenha um nmero (inteiro) como entrada do
usurio e escreva como sada a seqencia de bits que forma esse numero. Por
exemplo, aps digitado o nmero 10, a sada 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 espao entre os nmeros.
6.9: Escreva um programa que leia 10 nmeros. O programa deve imprimir a
media, o maior e o menor deles.
Obs: Os nmeros devem ser entre 0 e 10.
6.10: Escreva um programa que leia 10 nmeros. O programa deve imprimir a
media, o maior e o menor deles.
Obs: Considere agora que os nmeros podem ser quaisquer.
6.11: Escreva um programa que exibe a tabela ascii.
6.12: Crie um programa para verificar se um nmero dado 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 seqncia
987654321876543217654321654321543214321321211

106

No use nenhuma constante, use apenas variveis. Em outra linha imprima


as letras maisculas de A at Z (ABCD...).
6.15: Escreva um programa que conte de 100 a 999 (inclusive) e exiba, um
por linha, o produto dos trs dgitos dos nmeros. Por exemplo, inicialmente o
programa ir 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
Faa seu programa dar uma pausa a cada 20 linhas para que seja possvel
ver todos os nmeros pouco a pouco. Solicite que seja pressionada alguma tecla
para ver a prxima seqncia de nmeros.
6.16:
Escreva um programa que imprima uma figura como a mostrada abaixo. O
nmero de linhas da figura deve ser pedido ao usurio.
******
*****
****
***
**
*

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

107

Listagem 6.11: Programa do exercicio 17.

#in lude < stdio .h >


int main ( void ) {
int i , j , m ;
for ( i = 0; i

}
}

< 6; i ++) {
s anf ( " % d " , & m ) ;
i f ( m % 2) {
for ( j = 0; j < m ; j ++) {
printf ( " # " ) ;
}
}
else {
for ( j = m ; j > 0; j - -) {
printf ( " * " ) ;
}
}
printf ( " \ n " ) ;

return

0;

108

Captulo 7

Vetores e Cadeias de
Cara teres
7.1 Introduo
Vetores so usados para tratamento de conjuntos de dados que possuem as
mesmas caractersticas. Uma das vantagens de usar vetores que o conjunto
recebe um nome comum e elementos deste conjunto so referenciados atravs
de ndices. Pelo nome vetor estaremos referenciando estruturas que podem
ter mais de uma dimenso, como por exemplo matrizes de duas dimenses.
Neste captulo estaremos mostrando vetores de tamanhos fixos. Somente aps
apresentarmos ponteiros iremos abordar alocao de memria para vetores.

7.2 De larao de Vetores Unidimensionais


A forma geral da declarao de vetores de uma dimenso :
tipo nome [tamanho;

onde tipo um tipo qualquer de dados, nome o nome pelo qual o vetor vai
ser referenciado e tamanho o nmero de elementos que o vetor vai conter.
Observar que em C o primeiro elemento tem ndice 0 e o ltimo tamanho - 1.
Exemplos de declaraes de vetores so:

int numeros [1000;


f l o a t notas [65;
har nome [40;

/* vetor de 1000 inteiros */


/* onjunto de 65 numeros reais */
/* onjunto de 40 ara teres */

O espao de memria, em bytes, ocupado por um vetor de tipo qualquer


igual a:
espao = tamanho *

sizeof(tipo)

importante notar que em C no h verificao de limites em vetores. Isto


significa que possvel ultrapassar o fim de um vetor e escrever em outras
109

variveis, ou mesmo em trechos de cdigo. tarefa do programador fazer com


que os ndices dos vetores estejam sempre dentro dos limites estabelecidos pela
declarao do vetor.
O programa 7.1 ilustra como se declara um vetor, inicializa seus valores
e imprime o contedo. Notar o uso da diretiva #define DIM 5 para definir
uma constante, que posteriormente foi usada para estabelecer o tamanho do
vetor. Esta constante passa a ser usada nas referncias ao vetor, por exemplo no comando de gerao do conjunto de dados armazenado no vetor. Caso
seja necessrio trocar o tamanho do vetor basta alterar o valor da constante e
recompilar o programa.

Listagem 7.1: Exemplo de vetores.

#define DIM 5
#in lude < stdio .h >
int main ( void ) {
int vetor [ DIM ;
unsigned int i ,

num ;

puts ( " Este programa gera um vetor de inteiros .\ n " ) ;


puts ( " Entre om o numero ini ial do onjunto . " ) ;
s anf ( " % d " , & num ) ;
/* Gera ao do onjunto */
for ( i = 0 ; i < DIM ; i ++) vetor [ i = num ++;
/* Impressao do onjunto */
for ( 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 endereo & antes
do nome de cada elemento.
O programa 7.3 ilustra o mtodo da bolha para ordenao em ordem crescente de um vetor de inteiros. Neste mtodo a cada etapa o maior elemento
movido para a sua posio. A cada iterao os elementos do vetor so comparados dois a dois, sendo trocados caso seja necessrio. Ao trmino da primeira
passada pelo vetor, o maior elemento levado para a sua posio, no final do
vetor. Portanto, ele no precisa ser mais considerado, da o valor da varivel
que aponta para o final do vetor (fim) diminuda de 1. O processo repetido
at que todos os elementos sejam levados para as suas posies ou que nenhuma
troca seja realizada. Quando nenhuma troca realizada o vetor est ordenado.
A Tabela 7.1 mostra os passos executados pelo algoritmo at ordenar o vetor.

110

Listagem 7.2: Produto escalar de dois vetores.

#define DIM 5
#in lude < stdio .h >
int

main ( void ) {
int vetor1 [ DIM , vetor2 [ DIM , i , prod =0;
printf ( " Entre om um vetor de % d elementos \ n " , DIM ) ;
for ( i = 0; i < DIM ; i ++) {
printf ( " Elemento % d " , i ) ;
s anf ( " % d " , & vetor1 [ i ) ;
}
printf ( " Entre om outro vetor de % d elementos \ n " , DIM )
;
for ( i = 0; i < DIM ; i ++) {
printf ( " Elemento % d " , i ) ;
s anf ( " % d " , & vetor2 [ i ) ;
}
for ( i = 0; i < DIM ; i ++)
prod += vetor1 [ i * vetor2 [ i ;
printf ( " O produto vale % d " , prod ) ;

return

0;

111

Operao
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]

v[1]

v[2]

v[3]

v[4]

20
15
15
15
15
15
15
15

15
20
20
8
8
8
8
8

8
8
8
20
20
12
12
12

12
12
12
12
12
20
20
5

5
5
5
5
5
5
5
20

v[3]

15
8
8
8
8
8

8
15
15
12
12
12

12
12
12
15
15
5

5
5
5
5
5
15

20
20
20
20
20
20

v[2]

8
8
8

12
12
5

5
5
12

15
15
15

20
20
20

v[1]?

8
5

5
8

12
12

15
15

20
20

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

v[1]
v[2]

Tabela 7.1: Passos executados durante o algoritmo da bolha.

112

Listagem 7.3: Ordenao pelo mtodo da bolha.

#define
#define
#define

DIM 5
FALSO 0
VERDADE 1

#in lude
int main
int
int

< stdio .h >


( void ) {
vetor [ DIM , i ;
tro ou = FALSO , fim = DIM , temp ;

printf ( " Entre om um vetor de % d elementos \ n " , DIM ) ;


for ( i = 0; i < DIM ; i ++) {
printf ( " Elemento % d " , i ) ;
s anf ( " % d " , & vetor [ i ) ;
}

do

tro ou = FALSO ;
for ( 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 ;
tro ou = VERDADE ;
}
}
fim - -;
} while ( tro ou ) ;

for
}

( i =0; i < DIM ; i ++) printf ( " % d \ n " , vetor [ i ) ;

return

0;

113

7.3 Cadeias de Cara teres


Um cadeia de caracteres (string) um conjunto de caracteres terminado por um
caractere nulo, que representado como \0. Para especificar um vetor para
armazenar um cadeia deve-se sempre reservar um espao para este caractere.
Por exemplo, para armazenar um cadeia de 40 caracteres deve-se reservar um
vetor de 41 de caracteres. Em C possvel haver constantes cadeia, que so
definidas como uma lista de caracteres entre aspas. Por exemplo,
"programando em C"
No necessrio a colocao do caractere nulo ao final da cadeia. Em C
no h o tipo cadeia (string) e, portanto, conjuntos de caracteres teriam de
ser tratados como conjuntos de nmeros inteiros, por exemplo. Para facilitar a
programao foram criadas algumas funes para manipular cadeias. Algumas
das funes mais comuns esto resumidamente descritas a seguir:
Nas definies a seguir, size_t o tipo inteiro sem sinal que volta como
resultado do operador sizeof.
har *str at( har *dest, onst har *orig): Concatena cadeia orig ao
final de dest. O primeiro caractere de orig substitui o caractere nulo de
dest. A funo retorna o valor de dest.
har *strn at ( har *dest, onst har *orig, size_t n): Concatena cadeia orig ao final de dest, usando no mximo n caracteres de orig. O
primeiro caractere de orig substitui o caractere nulo de dest. A funo
retorna o valor de dest.
har *str mp ( onst har * ad1, onst har * ad2): Compara lexicograficamente as duas cadeias. Retorna zero se as cadeias so iguais, menor
que 0 se ad1 < ad2, maior que 0 se ad1 > ad2.
har *strn mp ( onst har * ad1, onst har * ad2, size_t n): Compara lexicograficamente at n caracteres das duas cadeias. Retorna zero se
as cadeias so iguais, menor que 0 se ad1 < ad2, maior que 0 se ad1
> ad2.
size_t strlen( onst har * ad): Calcula o comprimento da cadeia sem
contar o caraca ter nulo. O comprimento da cadeia determinado pelo
caractere nulo. No confundir o tamanho da cadeia com o tamanho do
vetor que armazena a cadeia.
har *str py( har *dest, onst har *orig): Copia cadeia orig para
dest. A cadeia destino deve ter espao suficiente para armazenar orig.
O valor de dest retornado.
Estas funes esto na biblioteca string.h. O programa 7.4 mostra exemplos de uso de algumas das funes de cadeia. Neste exemplo, o programa
primeiro l um nome e em seguida um sobrenome. O programa ir ento concatenar as duas cadeias. Observe que sempre colocado um branco ao final
do nome para separ-lo do sobrenome. Este branco inserido usando a funo

114

strcat, e esta razo das aspas, ou seja, uma cadeia de um caractere apenas.
A seguir mostramos um resultado da execuo 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

Listagem 7.4: Exemplos de funes para cadeias.

#in lude < string .h >


#in lude < stdio .h >
int

void ) {
har , nome [81 ,
int i ;

main (

sobrenome [41;

printf ( " Entre om um nome " ) ;


fgets ( nome , 41 , stdin ) ;
nome [ strlen ( nome ) -1 = ' \0 '; /* tira r do fim */
puts ( nome ) ;
printf ( " Entre om um sobrenome " ) ;
fgets ( sobrenome , 41 , stdin ) ;
sobrenome [ strlen ( sobrenome ) -1 = ' \0 ';
puts ( sobrenome ) ;
str at ( nome , " " ) ;
str at ( nome , sobrenome ) ;
puts ( nome ) ;
printf ( " Qual ara ter ? " ) ;
= get har () ;

for

}
}

( i =0; i < strlen ( nome ) ; i ++) {


i f ( == nome [ i ) {
printf ( " O ara tere apare e na posi ao % d \ n "
, i);
}

return

0;

115

7.4 De larao de Vetores Multidimensionais


Em C existe a possibilidade de declararmos vetores de mais de uma dimenso.
A forma geral da declarao a seguinte:
tipo nome [dim1][dim2][dim3]...[dimN];
onde dimI o tamanho da dimenso I. Deve-se tomar cuidado com armazenamento de matrizes multidimensionais, por que a memria necessria para
guardar estes dados igual a

sizeof(tipo)*dim1*dim2*dim3*...*dimN
Por exemplo a declarao

int

matriz[10[20;

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


= 2 * matriz[3[8;

armazena o dobro do elemento que est na quarta linha e nona coluna na varivel
c. Observar que o primeiro ndice indica a linha e o segundo a coluna. Lembrar
que o nmero da primeira linha (coluna) igual a 0. O programa 7.5 l uma
matriz de trs linhas e cinco colunas e imprime os valores lidos.

Listagem 7.5: Leitura de uma matriz.

#define DIML 3
#define DIMC 5
#in lude < stdio .h >
int main ( void ) {
int i , j ;
int matriz [ DIML [ DIMC ;
for

( i =0; i < DIML ; i ++)


for ( j =0; j < DIMC ; j ++)
s anf ( " % d " , & matriz [ i [ j ) ;

for

( i =0; i < DIML ; i ++) {


for ( j =0; j < DIMC ; j ++)
printf ( " %4 d " , matriz [ i [ j ) ;
printf ( " \ n " ) ;

}
}

return

0;

A matriz armazenada na memria linha a linha e a Figura 7.1 ilustra esta


idia com uma matriz de nmeros inteiros de trs por trs. Estamos assumindo
que cada nmero inteiro ocupa quatro bytes, o endereo aponta um byte e a
matriz est armazenada a partir do endereo 1000.
Uma operao muito comum em matemtica a multiplicao de matrizes.
Considere a matriz M 1 com L1 linhas e C1 colunas e a matriz M 2 com L2
linhas e C2 colunas. O nmero de colunas C1 de M 1 deve ser igual ao nmero
116

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 memria de uma matriz.

de linhas L2 de M 2. O elemento M Rij da matriz resultado M R do produto


destas matrizes definido pela equao 7.1. O programa 7.6 multiplica duas
matrizes de acordo com a frmula.

M Rij =

C1
X

M 1ik M 2kj

(7.1)

k=1

7.5 Vetores de Cadeias de Cara teres


A declarao 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 uma matriz de nomes e imprime
os seus contedos. importante notar que para ler um nome o programa no
l um caracter de cada vez mas usa a funo fgets. Como cada linha da matriz
uma cadeia de caracteres, o programa l o nome que est na linha i como
fgets(nomes[i], DIMC-1, stdin).

117

Listagem 7.6: Multiplicao de duas matrizes.

#in lude < stdio .h >


#define
#define
#define
#define
int

3
3
3
3

void ) {
f l o a t m1 [ L1 [ C1 ,
f l o a t mr [ L1 [ C2 ,
int i , j , k ;

main (

for

for

for

for

}
}

L1
L2
C1
C2

m2 [ L2 [ C2 ;
m;

( i =0; i < L1 ; i ++) {


for ( j =0; j < C1 ; j ++) {
printf ( " %d , % d " , i , j ) ;
s anf ( " % f " , & m1 [ i [ j ) ;
}
( i =0; i < L2 ; i ++) {
for ( j =0; j < C2 ; j ++) {
printf ( " %d , % d " , i , j ) ;
s anf ( " % f " , & m2 [ i [ j ) ;
}
( i =0; i < L1 ; i ++) {
for ( j =0; j < C2 ; j ++) {
m = 0;
for ( k =0; k < C1 ; k ++) {
m += m1 [ i [ k * m2 [ k [ j ;
}
mr [ i [ j = m ;
}
( i =0; i < L1 ; i ++ ) {
for ( j =0; j < C2 ; j ++) {
printf ( " %.3 f " , mr [ i [ j ) ;
}
printf ( " \ n " ) ;

return

0;

118

Listagem 7.7: Leitura de um vetor de nomes.

#define DIML 5
#define DIMC 41
#in lude < stdio .h >
#in lude < string .h >
int main ( void ) {
int i ;
har nomes [ DIML [ DIMC ;
for

for
}
}

( i =0; i < DIML ; i ++) {


printf ( " Entre om a linha % d " , i ) ;
fgets ( nomes [ i , DIMC -1 , stdin ) ;
nomes [ i [ strlen ( nomes [ i ) -1 = ' \0 ';
( i =0; i < DIML ; i ++) {
printf ( " O nome % d e " , i ) ;
puts ( nomes [ i ) ;

return

0;

7.6 Ini ializao de Vetores e Matrizes


Em C possvel inicializar vetores da mesma forma que variveis, isto , no
momento em que so declarados. A forma de fazer isto a seguinte:
tipo nome[dim] = {lista_de_valores};
onde lista_de_valores um conjunto de valores separados por vrgulas. Por
exemplo, a declarao abaixo inicializa um vetor inteiro de cinco posies.
int vetor[5] = { 10, 15, 20, 25, 30 };
Observe que nesta declarao necessrio que o tamanho do conjunto seja
conhecido antecipadamente. No entanto, tambm possvel inicializar vetores
em que no se conhece o seu tamanho. Neste caso, ento, importante que o
programador preveja um modo de indicar o fim do vetor.
O Programa 7.8 mostra os casos ilustrados acima. No primeiro exemplo o
tamanho do vetor conhecido e foi definido pela constante DIM. Para descobrir o
como parar de processar o vetor, quando desconhecemos seu tamanho, apresentamos duas solues possveis. No primeiro caso a condio de fim do vetor o
nmero negativo -1. Neste caso uma posio do vetor perdida para armazenar
esta condio. No segundo caso usado o operador sizeof para descobrir o
tamanho do vetor. Observe que sizeof calcula o tamanho do vetor em bytes e
por esta razo necessrio uma diviso pelo tamanho em bytes do tipo de cada
elemento.
possvel inicializar matrizes multidimensionais e neste caso necessrio
especificar todas as dimenses menos a primeira, para que o compilador possa
119

Listagem 7.8: Exemplos de tratamento de vetores.

#define DIM 5
#in lude < stdio .h >
int

main () {
int vetor [ DIM = {10 , 15 , 20 , 25 , 30};
int vetor1 [ = {10 , 20 , 30 , 40 , 50 , 60 , -1};
int vetor2 [ = {3 , 6 , 9 , 12 , 15 , 18 , 21 , 24};
unsigned int i , tam ;
printf ( " Este programa imprime vetores " ) ;
printf ( " ontendo numeros inteiros e \ n " ) ;
printf ( " que foram ini ializado s durante " ) ;
printf ( " a sua de lara ao .\ n " ) ;
/* Impressao dos onjuntos */
printf ( " \ nVetor om tamanho pre - definido \ n " ) ;
for ( i =0; i < DIM ; i ++)
printf ( " Elemento % d = % d \ n " , i , vetor [ i ) ;
printf ( " \ nVetor terminando por -1\ n " ) ;
for ( i =0; vetor1 [ i >0; i ++)
printf ( " Elemento % d = % d \ n " , i , vetor1 [ i ) ;
tam = s i z e o f ( vetor2 )
printf ( " \ nDes obrindo
for ( i =0; i < tam ;
printf ( " Elemento

return

/ s i z e o f ( int ) ;
o tamanho do Vetor \ n " ) ;
i ++)
% d = % d \ n " , i , vetor2 [ i ) ;

0;

120

reservar memria de maneira adequada. A primeira dimenso somente especifica


quantos elementos o vetor ir armazenar e isto lendo a inicializao o compilador
pode descobrir.
A declarao a seguir ilustra como declarar e inicializar uma matriz de trs
linhas por quatro colunas de nmeros reais.

float

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 definio de um vetor de cadeia de caracteres, que


nada mais do que uma matriz de caracteres. Note que as cadeias so separadas
uma das outras por vrgulas.

Listagem 7.9: Exemplos de tratamento de vetores.

#define DIM 5
#in lude < stdio .h >
int

main (

har

};

int

void

) {
dis iplinas [[40 = {
" dis 0: Computa ao para Informati a " ,
" dis 1: Ban o de Dados I " ,
" dis 2: Ban o de Dados II " ,
" dis 3: Arquitetura de Computadores I "

i;

printf ( " Qual a dis iplina ? " ) ; s anf ( " % d " , & i ) ;
puts ( dis iplinas [ i ) ;
}

return

0;

121

Exer ios
7.1: Escreva um programa que leia uma linha de at 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, tambm fornecido pelo teclado, aparece nesta linha.
O programa tambm deve imprimir em que posies 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
posies o par foi encontrado. Obs. No use funes 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 mximo da linha deve ser 40 caracteres.
7.5: O imperador romano Csar usava um sistema simples para codificar as
mensagens que enviava aos seus generais. Neste sistema cada letra era substituda por trs letras frente no alfabeto. A sua misso mais simples ainda,
escrever um programa que converta cada letra, e somente as letras, de uma
mensagem de at 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 espaos em branco.
7.7: Escreva um programa que leia uma linha de caracteres do teclado de
tamanho 80. A linha somente contm 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 trs letras adiante e assim at a quinta. Os espaos em branco
devem ser retirados da frase. Considere o seguinte exemplo.
1. Frase lida:
EVA VIU A UVA
2. Retirada dos espaos em branco:
EVAVIUAUVA
3. Diviso em blocos de 5 (blocos indicados por tipos diferentes):
EVAVIUAUVA
4. Criptografia:
FYDANVCYAF
Portanto, o que ser impresso pelo programa :
FYDANVCYAF
7.8: Escreva um programa que leia uma matriz de 3x3 que contm 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.
122

7.9: Escreva um programa que leia uma linha de caracteres do teclado e converta
o primeiro caractere de cada palavra para maisculas. Assuma que as palavras
so sempre separadas por um branco.
7.10: Escreva um programa que leia para um vetor um conjunto de nmeros
inteiros. Assuma que o conjunto de nmeros lidos menor que o tamanho do
vetor. O programa deve inserir no vetor, em uma posio especificada pelo
usurio, um nmero lido do teclado. Assuma que a posio especificada pelo
usurio corresponde ao ndice do vetor.
7.11: Faa um programa que inverta uma cadeia de caracteres. O programa
deve ler a cadeia com gets e armazen-la invertida em outra cadeia. Use o
comando for para varrer a cadeia at o seu final.
7.12: Escreva um programa que leia um conjunto de nomes para uma matriz
e imprima estes nomes em ordem alfabtica. Assuma que os nomes sero lidos
somente em letras maisculas. Assuma tambm que os nomes tm no mximo
40 caracteres e sero lidos 10 nomes ao todo.
7.13: Escreva um programa que leia um conjunto N (1 N 1000000000) de
nmeros inteiros e imprima os seguintes resultados:
media dos nmeros;
maior dos nmeros;
menor dos nmeros;
produto de todos os nmeros.
7.14: Considere que voc digitou o seu nome para o programa mostrado na
listagem 7.10. O que ser impresso? Indique o que voc digitou. Justifique
sua resposta com detalhes.

123

Listagem 7.10: Programa do exercicio 14.

#in lude < stdio .h >


#in lude < string .h >
#define MAX 50
int main ( void ) {
har texto [ MAX +2 ,
int tam , i ;

temp ;

gets ( texto ) ;
tam = strlen ( texto ) ;
for ( i = 0; i < tam ; i ++) {
temp = texto [ i ;
texto [ i = texto [ tam -1 - i ;
texto [ strlen ( texto ) -1 - i = temp ;
}
puts ( texto ) ;
return 0;

124

Captulo 8

Funes
8.1 Introduo
Em C, diferentemente de outras linguagens como Pascal, todas as aes ocorrem
dentro de funes. Na linguagem C no h conceito de um programa principal, o
que existe uma funo chamada main que sempre a primeira a ser executada.
Um programa pode ser escrito apenas com a funo main e mais as funes
existentes nas bibliotecas da linguagem C. No entanto o uso de funes pode
facilitar o desenvolvimento de programas de diversas maneiras.
Em primeiro lugar temos as vantagens do reuso de cdigo desenvolvido por
outros programadores. As funes de entrada e sada so o exemplo mais direto
deste reuso. Em C no existem estes tipos de comandos como na maioria das
linguagens. Programas escritos em C usam funes de entrada e sada escritas
e testadas por outros programadores. Este reuso de cdigo apresenta vrias
vantagens. Primeiro, diminui o tempo de desenvolvimento do programas. Em
segundo lugar, como estas funes foram testadas por diversos usurios, a quantidade de erros bastante reduzida. Estes fatores contribuem para a reduo
dos custos de desenvolvimento dos projetos.
Uma outra vantagem do uso de funes e a maior facilidade na diviso do
trabalho necessrio para construir um aplicativo. Funes podem ser desenvolvidas por programadores trabalhando independentemente. Para isto basta que
alguns acordos sejam feitos entre os programadores que iro programar a funo
e os que iro us-las. Estes acordos precisam definir que parmetros a funo
ir receber, que resultados ir fornecer e que operaes ela deve realizar sobre
estes parmetros para obter os resultados necessrios. Esta diviso do trabalho
concorre para acelerar o desenvolvimento dos programas e na reduo dos custos
deste desenvolvimento.
A diviso de um programa em funes tambm permite que os testes do
sistema completo sejam feitos mais facilmente e com mais garantia de correo.
Os programadores podem testar suas funes separadamente em testes menos
complexos, j que as funes normalmente so simples e tm 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.
125

Mesmo quando um programa desenvolvido por um nico programador a


sua diviso em funes 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 funo em C a seguinte:
tipo nome ( tipo nome1 , tipo nome2 , ... , tipo nomeN ) {
de larao das variveis
orpo da funo
}

Uma funo recebe uma lista de argumentos (nome1, nome2, ..., nomeN),
executa comandos com estes argumentos e pode retornar ou no um resultado
para a funo que chamou esta funo. A lista de argumentos, tambm chamados de parmetros, uma lista, separada por vrgulas, de variveis com seus
tipos associados. No possvel usar uma nica definio de tipo para vrias
variveis. A lista de argumentos pode ser vazia, ou seja, a funo no recebe
nenhum argumento. O nome da funo pode ser qualquer identificador vlido.
O tipo que aparece antes do nome da funo especifica o tipo do resultado que
ser devolvido ao final da execuo da funo. Caso nenhum tipo seja especificado o compilador assume que um tipo inteiro retornado. O tipo void pode
ser usado para declarar funes que no retornam valor algum.
H basicamente duas maneiras de terminar a execuo de uma funo. Normalmente usa-se o comando return para retornar o resultado da funo. Portanto, quando o comando

return

expresso;

for executado, o valor da expresso devolvido para a funo que chamou.


Quando no h valor para retornar o comando return no precisa ser usado e
a funo termina quando a chave que indica o trmino do corpo da funo
atingido.
Os parmetros so valores que a funo recebe para realizar as tarefas para
as quais foi programada. Por exemplo, uma funo que calcule a raiz quadrada
de um nmero do tipo oat , deve declarar como parmetro uma varivel deste
tipo para receber o valor.
importante notar que diferentemente de declaraes de variveis onde
podemos associar vrios nomes de variveis a uma declarao como em

int

a, dia, mes, i;

na lista de parmetros necessrio associar um tipo a cada varivel como


no exemplo a seguir:

oat

media (oat n1,

oat

n2,

oat

n3);

Neste exemplo, uma funo chamada media que do tipo oat , isto retorna
um resultado oat , recebe trs argumentos (n1, n2, n3) tambm do tipo oat .
126

Um ponto importante como usar a funo. Suponha que uma determinada


funo, A, deseje usar uma outra funo, B. A funo A deve colocar no local
desejado o nome da funo (B) e a lista de valores que deseja passar. Por
exemplo, um programador que deseje usar a funo media em seu programa
para calcular a mdia de trs valores, nota1, nota2 e nota3, deve escrever no
local onde quer que a mdia seja calculada o seguinte comando:
resultado = media(nota1, nota2, nota3);

onde resultado a varivel que vai receber a mdia calculada.


importante notar que o nome da funo pode aparecer em qualquer lugar
onde o nome de uma varivel apareceria. Alm disso os tipos e o nmero de
parmetros que aparecem na declarao da funo e na sua chamada devem
estar na mesma ordem e ser tipos equivalentes. Se os tipos so incompatveis,
o compilador no gera um erro, mas podem ser gerados avisos na compilao e
resultados estranhos.
Outro ponto importante a ser notado e que ser detalhado mais adiante
que os nomes das variveis nos programas que usam a funo media podem ser
diferentes dos nomes usados na definio da funo.

8.3 Prottipos de Funes


O padro ANSI estendeu a declarao da funo para permitir que o compilador
faa uma verificao mais rgida da compatibilidade entre os tipos que a funo
espera receber e queles que so fornecidos. Prottipos de funes ajudam a
detectar erros antes que eles ocorram, impedindo que funes sejam chamadas
com argumentos inconsistentes. A forma geral de definio de um prottipo
a seguinte:
tipo nome (tipo nome1, tipo nome2, ..., tipo nomeN);

O exemplo 8.1 mostra a declarao de uma funo e seu prottipo.


Tambm possvel declarar um prottipo sem dar os nomes das variveis
somente os tipos das funes. No exemplo 8.1 o prottipo da funo soma pode
ser declarada da seguinte maneira

int

soma (int,

int)

8.4 Es opo de Variveis


Variveis podem ser definidas para serem usadas somente dentro de uma funo
particular, ou pode ocorrer que variveis precisem ser acessveis diversas funes diferentes. Por esta razo, temos que apresentar os locais onde as variveis
de um programa podem ser definidas e a partir destes locais podermos inferir
onde elas estaro disponveis. As variveis podem ser declaradas basicamente
em trs lugares:
dentro de funes,
fora de todas as funes,
127

Listagem 8.1: Exemplo de prottipos.

#in lude < stdio .h >


/* Prototipo da fun ao */
int soma ( int a , int b ) ;
/* Fun ao Prin ipal */
int main () {
int a =5 , b =9;
printf ( " % d \ n " , soma (a , b ) ) ;
return 0;
}
/* Defini ao da fun ao */
int soma ( int a , int b ) {
return a + b ;
}

na lista de parmetros das funes.


As variveis definidas dentro das funes so chamadas de variveis locais, as
que aparecem fora de todas as funes chamamos de variveis globais e aquelas
que aparecem na lista de parmetros so os parmetros formais. importante
notar que em C todas as funes esto no mesmo nvel, por esta razo no
possvel definir uma funo dentro de outra funo.

8.4.1 Variveis Lo ais


As variveis locais so aquelas declaradas dentro de uma funo ou um bloco
de comandos. Elas passam a existir quando do incio da execuo do bloco de
comandos ou funo onde foram definidas e so destrudas ao final da execuo
do bloco. Uma varivel local s pode ser referenciada, ou seja usada, dentro
da funo (ou bloco) onde foi declarada. Outro ponto muito importante que
como as variveis locais deixam de existir ao final da execuo da funo (ou
bloco), elas so invisveis para outras funes do mesmo programa. O cdigo
que define uma funo e os seus dados so particulares da funo (do bloco).
No programa 8.2 podemos ver o uso de variveis locais. A varivel i definida
em cada uma das funes do programa (pares, impares). Os valores da varivel
no podem ser acessados a partir de nenhuma outra funo e as modificaes
feitas dentro da funo somente valem enquanto a funo est sendo executada.
Alguns autores usam o termo variveis automticas para se referir as variveis locais. Em C existe a palavra chave auto que pode ser usada para declarar
que variveis pertencem classe de armazenamento padro. No entanto, como
todas as variveis locais so por definio automticas raramente se usa esta
palavra chave.

128

Listagem 8.2: Exemplos de variveis locais.

#in lude
void

pares ( void ) {
int i ;
for ( i = 2; i <= 10; i += 2) {
printf ( " % d : " , i ) ;
}

void

int

< stdio .h >

impares ( void ) {
int i ;
for ( i = 3; i <= 11; i += 2) {
printf ( " % d : " , i ) ;
}
main ( int arg ,
pares () ;
printf ( " \ n " ) ;
impares () ;

return

har

* argv [) {

0;

Observe que um bloco de comandos se inicia em um { e termina em um


}. O bloco de comandos, dentro do qual mais comumente se define uma varivel a funo. Todas as variveis que sero usadas dentro de um bloco de
comandos precisam ser declaradas antes do primeiro comando do bloco. Declaraes de variveis, incluindo sua inicializao, podem vir logo aps o abre
chaves que inicia um bloco de comandos, no somente o que comea uma funo.
O programa 8.3 ilustra este tipo de declarao.

Listagem 8.3: Definio de varivel dentro de um bloco.

#in lude < stdio .h >


int main () {
int i ;
for ( i =0; i <10;
int t = 2;
}
}

i ++) {

printf ( " % d \ n " , i * t ) ;

return

0;

Existem algumas vantagens em se declarar variveis dentro de blocos. Como


as variveis somente existem durante a execuo do bloco, o programa pode
ocupar menos espao de memria. Por exemplo, se a execuo do bloco for
condicional a varivel pode nem ser alocada. Outra vantagem que como a
129

varivel somente existe dentro do bloco, pode-se controlar melhor o uso da


varivel, evitando erros de uso indevido da varivel.

8.4.2 Variveis Globais


As variveis globais so definidas fora de qualquer funo e so portanto disponveis para qualquer funo. Este tipo de varivel pode servir como uma canal
de comunicao entre funes, uma maneira de transferir valores entre elas. Por
exemplo, se duas funes tem de partilhar dados, mais uma no chama a outra,
uma varivel global tem de ser usada.
O programa 8.4 ilustra este tipo de declarao. O resultado da execuo
deste programa o seguinte:
Funcao soma1: i = 1
Funcao sub1: i = 9
Funcao main: i = 1
Observe que a varivel global i recebe o valor 0 no incio da funo main. A
funo soma1 ao executar um comando que aumenta o valor de i em uma unidade
est aumentando a varivel global. Em seguida vemos que a funo sub1 define
uma varivel local tambm chamada i e, portanto, a alterao feita por esta
funo somente modifica esta varivel. Finalmente, a funo main imprime o
valor final da varivel global.

Listagem 8.4: Definio de varivel global.

#in lude
int
void
}

void

int

< stdio .h >

i;
soma1 ( void ) {
i += 1;
printf ( " Fun ao soma1 : i = % d \ n " , i ) ;
sub1 ( void ) {
int i = 10;
i -= 1;
printf ( " Fun ao sub1 : i = % d \ n " , i ) ;
main ( int arg , har * argv [) {
i = 0;
soma1 () ;
sub1 () ;
printf ( " Fun ao main : i = % d \ n " , i ) ;
return 0;

130

8.5 Parmetros Formais


As variveis que aparecem na lista de parmetros da funo so chamadas de
parmetros formais da funo. Eles so criados no incio da execuo da funo
e destrudos no final. Parmetros so valores que as funes recebem da funo
que a chamou. Portanto, os parmetros permitem que uma funo passe valores
para outra. Normalmente os parmetros so inicializados durante a chamada da
funo, pois para isto foram criados. No entanto, as variveis que atuam como
parmetros so iguais a todas as outras e podem ser modificadas, operadas, etc,
sem nenhuma restrio. Parmetros podem ser passados para funes de duas
maneiras: passagem por valor ou passagem por referncia.

8.5.1 Passagem de Parmetros por Valor


Na passagem por valor uma cpia do valor do argumento passado para a
funo. Neste caso a funo que recebe este valor, ao fazer modificaes no
parmetro, no estar alterando o valor original que somente existe na funo
que chamou.
O exemplo 8.5 mostra o uso de passagem de parmetros por valor. Observe
que as funo Eleva recebe dois parmetros (a,b) e opera usando os valores
recebidos. O resultado da funo retornado por meio da varivel local res.

Listagem 8.5: Exemplo de passagem por valor.

#in lude < stdio .h >


#in lude < stdlib .h >
float

int

Eleva ( f l o a t a , int b ) {
res = 1.0;

float

for ( ; b >0;
return res ;

b - -) res *= a ;

main () {
f l o a t numero ;
int poten ia ;
har linha [80;
puts ( " Entre om um numero " ) ;
gets ( linha ) ; numero = atof ( linha ) ;
puts ( " Entre om a poten ia " ) ;
gets ( linha ) ; poten ia = atoi ( linha ) ;
printf ( " \ n % f Elevado a % d e igual a % f \ n " ,
numero , poten ia , Eleva ( numero , poten ia ) ) ;

return

0;

131

Para ilustrar o fato de que somente o valor passado vamos usar o exemplo
8.6. Neste programa as variveis a e b recebem os valores 10 e 20 respectivamente. Na funo tro ar estes valores so recebidos e so trocados localmente.
Aps o retorno da funo, o programa imprime os valores originais das variveis,
j que estes no sofreram nenhuma alterao. O resultado da execuo deste
programa o seguinte:
a = 10, b = 20

Listagem 8.6: Uso indevido de variveis locais.

#in lude < stdio .h >


void tro ar ( int a , int
int temp ;
}

int

b) {

temp = a ; a = b ; b = temp ;

main ( int arg , har * argv [) {


int a = 10 , b = 20;
tro ar (a , b ) ;
printf ( " a = %d , b = % d \ n " , a , b ) ;

return

0;

8.5.2 Passagem de Parmetros por Refern ia


Na passagem por referncia o que passado para a funo o endereo do
parmetro e, portanto, a funo que recebe pode, atravs do endereo, modificar
o valor do argumento diretamente na funo que chamou. Para a passagem de
parmetros por referncia necessrio o uso de ponteiros. Este assunto ser
discutido no prximo captulo e portanto, por agora, usaremos somente funes
com passagem por valor.

8.5.3 Passagem de Vetores e Matrizes


Matrizes so um caso especial e exceo a regra que parmetros so passados
sempre por valor. Como veremos mais adiante, o nome de um vetor corresponde
ao endereo do primeiro elemento do array, Quando um vetor passado como
parmetro, apenas o endereo do primeiro elemento passado.
Existem basicamente trs maneiras de declarar um vetor como um parmetro
de uma funo. Na primeira ele declarado como tem sido apresentado em todos
os exemplos at agora. O exemplo 8.7 mostra um programa que usa uma funo
para descobrir quantas vezes um caractere ocorre em um vetor. Observe que na
definio da funo a dimenso do vetor foi declarada explicitamente.
Uma outra maneira, leva em conta que apenas o endereo do vetor passado.
Neste modo o parmetro declarado como um vetor sem dimenso. Isto
132

Listagem 8.7: Passagem de vetor com dimenses.

#in lude < stdio .h >


#in lude < onio .h >
#define DIM 80
har
int

har

onta ( har v [ ,

har

);

main () {
har , linha [ DIM ;
int maius ulas [26 , minus ulas [26;
puts ( " Entre om uma linha " ) ;
gets ( linha ) ;
for ( = 'a '; <= 'z '; ++)
minus ulas [ - 'a ' = onta ( linha , ) ;
for ( = 'A '; <= 'Z '; ++)
maius ulas [ - 'A ' = onta ( linha , ) ;
for ( = 'a '; <= 'z '; ++)
i f ( minus ulas [ - 'a ' )
printf ( " % apare eu % d vezes \ n " , , minus ulas [
- 'a ' ) ;
for ( = 'A '; <= 'Z '; ++)
i f ( maius ulas [ - 'A ' )
printf ( " % apare eu % d vezes \ n " , , maius ulas [
- 'A ' ) ;
return 0;
onta ( har v [ DIM ,
int i =0 , vezes =0;

har

) {

while
}

( v [ i != ' \0 ' )
i f ( v [ i ++ == ) vezes ++;
return vezes ;

133

perfeitamente possvel porque a funo somente precisa receber o endereo onde


se encontra o vetor. Alm disso C no confere limites de vetores e portanto a
funo precisa do endereo inicial do vetor e uma maneira de descobrir o final
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 contedo de um vetor.
A terceira maneira de passagem de parmetros implica no uso de ponteiros,
o que somente iremos ver no prximo captulo.

8.6 O Comando return


O comando return usado para retornar o valor calculado para a funo que
chamou. Qualquer expresso pode aparecer no comando, que tem a a seguinte
forma geral:

return

expresso

A funo que chamou livre para ignorar o valor retornado. Alm disso a
funo pode no conter o comando e portanto nenhum valor retornado e neste
caso a funo termina quando o ltimo comando da funo executado. Quando
o comando return no existe o valor de retorno considerado indefinido. As
funes que no retornam valores devem ser declaradas como do tipo void.
importante observar que funes que so declaradas com um tipo vlido podem
ser includas em qualquer expresso vlida em C.

8.7 Re urso
Funes em C podem ser usadas recursivamente, isto uma funo pode chamar
a si mesmo. como se procurssemos no dicionrio a definio da palavra
recurso e encontrssemos o seguinte texto:
recurso: s.f. Veja a definio em recurso
Um exemplo simples de funo que pode ser escrita com chamadas recursivas
o fatorial de um nmero inteiro. O fatorial de um nmero, sem recurso,
definido como
n! = n (n 1) (n 2) 2 1
A partir desta definio podemos escrever a funo fatorial como mostrado
na listagem 8.9.
Alternativamente, o fatorial pode ser definido como o produto deste nmero
pelo fatorial de seu predecessor, ou seja
n! = n (n 1)!
Deste modo podemos escrever uma funo recursiva em que cada chamada
da funo que calcula o fatorial chama a prpria funo fatorial. O exemplo,
mostrado na listagem 8.10 ilustra como a funo pode ser escrita recursivamente.
134

Listagem 8.8: Passagem de vetores sem dimenses.

#in lude < stdio .h >


#in lude < onio .h >
#define DIM 6
void Le_vetor ( int
void Imprime_vetor
void Inverte_vetor
int

void

main () {
int v [ DIM ;
Le_vetor (v , DIM ) ;
Imprime_vetor (v , DIM ) ;
Inverte_vetor (v , DIM ) ;
Imprime_vetor (v , DIM ) ;
return 0;
Le_vetor ( int v [ ,
int i ;

for

void

tam ) {

( i = 0; i < tam ; i ++) {


printf ( " % d = ? " , i ) ;
s anf ( " % d " , & v [ i ) ;

int

tam ) {

( i = 0; i < tam ; i ++)


printf ( " % d = % d \ n " , i , v [ i ) ;

Inverte_vetor ( int v [ ,
int i , temp ;

for

int

Imprime_vetor ( int v [ ,
int i ;

for
void

v [ , int tam ) ;
( int v [ , int tam ) ;
( int v [ , int tam ) ;

int

( i = 0; i < tam /2; i ++) {


temp = v [ i ;
v [ i = v [ tam -i -1;
v [ tam -i -1 = temp ;

135

tam ) {

Listagem 8.9: Fatorial calculado no recursivamente.

unsigned long int fat


unsigned long int
for
}

( unsigned long
fato =1 , i ;

int

num ) {

( i = num ; i >1; i - -) fato = fato * i ;

return

fato ;

Listagem 8.10: Fatorial calculado recursivamente.

unsigned long int fat ( unsigned long int


i f ( num == 0)
return 1;
else
return num * fat ( num -1) ;

num ) {

Quando a funo fatorial recursiva chamada, primeiro verificado se o


nmero recebido como parmetro vale 0 e neste caso a funo retorna o valor 1.
No caso contrrio ela devolve o valor da expresso num * fat(num-1), ou seja o
produto do nmero pelo valor do fatorial do nmero predecessor. Ou seja para
retornar um valor a funo precisa chamar ela mesma passando como parmetro
o valor do nmero menos 1. Este processo continua se repetindo at que o valor
passado igual a 0, o que indica o final da recurso. Neste ponto o processo se
reverte e as chamadas comeam a ser respondidas.
Um ponto importante que toda funo recursiva deve prever cuidadosamente como o processo de recurso deve ser interrompido. No caso da funo
fat o processo interrompido quando o valor do nmero passado como parmetro vale 0. Se este teste no tivesse sido includo na funo as chamadas
continuariam indefinidamente com valores negativos cada vez menores sendo
passados como parmetro.
Quando uma funo chama a si mesmo recursivamente ela recebe um conjunto novo de variveis na pilha que usada para transferncia de valores entre
funes. importante notar que recurso no traz obrigatoriamente economia
de memria porque os valores sendo processados tem de ser mantidos em pilhas.
Nem ser mais rpido, e as vezes pode ser at mais lento porque temos o custo
de chamada as funes. As principais vantagens da recurso so cdigos mais
compactos e provavelmente mais fceis de serem lidos.
Uma funo recursiva se ela chama a si mesmo, podendo ser diretamente
(listagem 8.11) ou indiretamente (listagem 8.12).
Um outro exemplo simples de funo que pode ser resolvida por recurso
xn , assumindo que n 0. Esta funo pode escrita na sua forma recursiva

136

Listagem 8.11: Chamada recursiva direta.

void

f () {
/* ... */
f ()
/* ... */

Listagem 8.12: Chamada recursiva indireta.

void

f () {
/* ... */
g ()
/* ... */

void

g () {
... f () ...

como

xn = x x(n1)

que nos leva a escrever a funo da maneira mostrada no exemplo 8.13. Na


funo consideramos que x do tipo oat .

Listagem 8.13: Funo recursiva para calcular xn .

float

Elevar ( f l o a t x ,
( n <= 1) {
return x ;

if
}

else

return

int

n) {

x * Elevar (x , b -1) ;

Para facilitar pode-se pensar que quando uma chamada recursiva feita, a
funo faz uma cpia de si mesmo, das variveis locais, com seus valores iniciais,
e dos parmetros.
Cada cpia da funo inclui uma marcao indicando o ponto atual onde a
funo est sendo executada. Quando uma chamada recursiva feita, o marcador na funo que chamou fica logo aps a chamada. O marcador na funo
chamada vai para o incio da funo.
Quando a funo retorna, a cpia some, e a funo que chamou continua aps
a chamada, posio indicada pela marcao. As cpias anteriores continuam
sabendo de onde continuar porque as marcaes esto em suas posies.
137

Funes podem ser recursivas com cauda ou no. Em uma funo recursiva
com cauda, nenhuma das chamadas recursivas executam algo aps a chamada
recursiva completar, exceto para retornar o valor da funo.
A listagem 8.14 mostra o return de uma tpica funo recursiva com cauda e
a listagem 8.15 mostra uma sem cauda. A chamada sem cauda caracterizada
porque primeiro f feita e depois soma 5, portanto, algo executado aps a
chamada.

Listagem 8.14: Chamada recursiva com cauda.

int
}

f ( int x , int y ) {
return f (x , y ) ;

Listagem 8.15: Chamada recursiva sem cauda.

int
}

f ( int x , int y ) {
return f (x , y ) + 5;

8.7.1 Como pensar re ursivamente?


Primeiro escreva o prottipo da funo. Defina o que a funo recursiva deve
fazer em portugus. Considere o seguinte exemplo.
/* Soma os primeiros n elementos de um vetor */
int soma ( int vetor [ , int n ) ;

Quando a chamada soma( vetor, 10 ); for executada sabemos que os primeiros 10 elementos do vetor vetor sero somados.
Em seguida, repita vrias vezes para si mesmo o seguinte raciocnio:
recurso resolve um grande problema (de tamanho n, por
exemplo), resolvendo um ou mais problemas de tamanho
menor, e usando as solues destes pequenos problemas
para resolver o grande problema.
Caso bsico
Portanto, recurso um processo que quebra um problema em problemas
menores que sero quebrados em problemas menores at que chegamos no menor
problema possvel e na sua soluo (caso bsico) e retornamos esta soluo.
Uma vez que voc escreveu o prottipo, pense em como resolver o prximo
problema menor. Ento se a chamada
138

soma(vetor, n),

o prximo caso menor


soma(vetor, n-1)

Suponha que algum lhe daria a resposta para esta segunda soma. O que
voc teria? Voc teria a soma dos n1 primeiros elementos do vetor. Agora que
voc tem esta soluo (por hiptese), o que falta para resolver todo o problema?
Achar a soluo do caso base, que o menor problema. Neste exemplo seria:
sum(vetor, 1 );

Quanto falta apenas um elemento a soma a ser calculada o prprio elemento. Deste modo a soluo para este problema fica como mostrado na listagem 8.16.

Listagem 8.16: Soma de vetor recursiva.

int

soma (

vetor [ ,

int menor ;
i f ( n == 1 )
return v [0

else

int

int

n )

{ /* aso base */
/* sem hamada re ursiva */

{
menor = soma ( vetor , n - 1 ) ; /* resolve problema
menor */
/* usa solu ao do menor para resolver o maior */
return menor + vetor [ n - 1 ;

Os passos para escrever uma funo recursiva so:


1. Escreva um prottipo da funo recursiva.
2. Escreva um comentrio que descreve o que a funo deve fazer.
3. Determine o caso base (pode haver mais que um) e sua soluo.
4. Determine qual o problema menor a resolver. Se facilitar use variveis
para armazenar o resultado em variveis locais.
5. Use a soluo do problema menor para resolver o problema maior.

8.7.2 O que faz re urso trabalhar?


Recurso somente funciona quando um problema tem uma estrutura recursiva.
Isto significa que a soluo do problema a mesma para diferentes tamanhos.
Caso reduzir o tamanho do problema faz com que a soluo seja diferente
ento recurso no a soluo. Do mesmo modo, voc deve ser capaz de usar
os problemas menores para resolver o problema maior.
139

Todavia, pela mesma razo, deve ser difcil resolver usar laos para resolver
o problema. Laos tambm dependem de fazer a mesma coisa diversas vezes,
em diferentes ndices.
Se voc conseguir resolver um problema por meio de um lao, deve ser possvel resolve-lo por meio de recurso.

8.8 Argumentos - arg e argv


A funo main como todas as funes podem ter parmetros. Como a funo
main sempre a primeira a ser executada, os parmetros que ela recebe so
fornecidos pela linha de comando ou pelo programa que iniciou a sua execuo.
No caso da funo main so usados dois argumentos especiais int arg e har
**argv.
O primeiro argumento, arg , uma varivel inteira que indica quantos argumentos foram fornecidos para a funo. Observar que arg vale sempre pelo
menos 1, porque o nome do programa sempre o primeiro argumento fornecido
ao programa. A partir do segundo argumento em diante que aparecem os
outros argumentos.
O outro parmetro um vetor de cadeias de caracteres, e portanto, caso
sejam fornecidos nmeros, estes devem ser convertidos para o formato requerido.
Cada um dos argumentos do programa um elemento deste vetor. A primeira
linha da funo main pode ter a seguinte forma

void

main (int arg ,

har

*argv[)

O programa exemplo 8.17 calcula o fatorial dos nmeros fornecidos como


argumentos.
Os nomes arg e argv so comumente usados mas o programador livre para
escolher os nomes mais apropriados.

140

Listagem 8.17: Uso de argc e argv.

#in lude < stdio .h >


#in lude < stdlib .h >
unsigned long int fat ( unsigned long int
i f ( num == 0)
return 1;
else
return num * fat ( num -1) ;
}

int

main ( int arg ,

har * argv [) {
unsigned long int numero , fatorial ,
if

for

}
}

num ) {

i;

( arg < 2) {
printf ( " Para rodar : % s num1 num2 ... .\ n " , argv
[0) ;
return 1;
( i =1; i < arg ; i ++) {
numero = ( unsigned long int ) ( atoi ( argv [ i ) ) ;
fatorial = fat ( numero ) ;
printf ( " O fatorial de % lu vale % lu .\ n " , numero ,
fatorial ) ;

return

0;

141

Exer ios
8.1: Escrever um programa que declare, inicialize e imprima um vetor de 10
inteiros. O vetor deve conter os 10 primeiros mltiplos de 5. A inicializao do
vetor e a sua impresso devem ser feitas por funes.
8.2: Escreva um programa para declarar um vetor de caracteres de tamanho 26 e
imprimir o seu contedo. O vetor deve ser inicializado com as letras minsculas
do alfabeto. A inicializao do vetor e a sua impresso devem ser feitas por
funes.
8.3: Escreva um programa que armazene em uma matriz trs nomes de pessoas
e em seguida os imprima. Assuma que o tamanho mximo de cada nome 40
caracteres. Neste programa a leitura dos nomes dever ser feita por uma funo
e a impresso dos nomes por outra.
8.4: Escreva um programa que imprima o cdigo ASCII de todos os caracteres,
das seguintes maneiras:
1. caractere a caractere, a escolha do usurio;
2. a tabela inteira, a partir de um determinado valor decimal.
Cada item deste exerccio deve corresponder a uma funo.
8.5: Escreva um programa que crie uma tabela de temperaturas Celsius - Fahrenheit. O programa deve usar uma funo 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 funes, que gere um vetor a partir de uma
matriz. Cada elemento do vetor 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 seqncia do
Fibonacci. A seqncia de Fibonacci definida como:
f (0) =
f (1) =

0
1

f (n) =

f (n 1) + f (n 2)

O programa deve ler um numero e exibir o valor dele na seqncia de Fibonacci.


Exemplos de entrada e sada do programa so 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
142

Entre com um numero inteiro:


Fibonacci (6) = 8

8.8: O que o programa mostrado na listagem 8.18 imprime, caso sejam fornecidos os valores 48 e 256. Justifique a sua resposta.

Listagem 8.18: Programa do exerccio 8.

#in lude < stdio .h >


#define MAX 1000
int

int

ab ( int x , int y ) {
printf ( " % d % d \ n " , x , y ) ;
i f ( y == 0) {
return x ;
}
else {
return ab (y , x % y ) ;
}
main ( void ) {
int a , b ;
s anf ( " % d % d " , &a , & b ) ;
printf ( " % d \ n " , ab (a , b ) ) ;
return 0;

8.9: O programa mostrado na listagem 8.19 converte cadeias de caracteres


contendo nmeros na base 16 para a base 10. Neste programa est faltando um
trecho. A sua tarefa e completar o trecho que est faltando.

143

Listagem 8.19: Programa do problema 9.

#in lude < stdio .h >


#in lude < string .h >
#in lude < stdlib .h >
int fromHexatoD e im a l ( har
int toNumero ( har ) ;
har toLower ( har ) ;
int

[) ;

main ( void ) {
har numeroC [80;
fgets ( numeroC , 80 , stdin ) ;
{
numeroC [ strlen ( numeroC ) -1 = ' \0 ';
printf ( " % s = % d \ n " , numeroC , fromHexatoD e i ma l (
numeroC ) ) ;
fgets ( numeroC , 80 , stdin ) ;
}
return 0;

while (! feof ( stdin ) )

int fromHexatoD e im a l ( har numeroC [)


{ /* Aqui falta odigo */ }
har

int

toLower ( har ) {
i f ( >= 'A ' && <= 'Z ') {
= - 'A ' + 'a ';
}
return ;
toNumero ( har ) {
int resultado ;

if
}

( >= '0 ' && <= '9 ') {


resultado = - '0 ';

else i f

}
}

( toLower ( ) >= 'a ' && toLower ( ) <= 'f ') {


resultado = toLower ( ) - 'a ' + 10;

return

resultado ;

144

Captulo 9

Ponteiros
9.1 Introduo
Ponteiros so usados em situaes em que necessrio conhecer o endereo
onde est armazenada a varivel e no o seu contedo. Um ponteiro uma
varivel que contm um endereo de uma posio de memria e no o contedo
da posio. A memria de um computador pode ser vista como uma seqncia
de bytes cada um com seu prprio e nico endereo. No h dois bytes com
o mesmo endereo. O primeiro endereo sempre 0 e o ltimo geralmente
uma potncia de 2. Por exemplo um computador com memria igual a 512
Mbytes tem 512x1024x1024 bytes. A Figura 9.1 mostra o mapa de um trecho
de memria que contm duas variveis inteiras (num, res) ocupando 4 bytes
cada uma e mais um ponteiro (pint), que tambm ocupa 4 bytes. Observar que
os endereos esto pulando de quatro em quatro bytes devido ao espao que
cada um destas variveis ocupa.
0
4

10

num

120

res
*pint

12
16

Figura 9.1: Mapa de memria com duas variveis e ponteiro.


Ponteiros so importantes, por exemplo, quando se deseja que uma funo
retorne mais de um valor. Neste caso uma soluo a funo receber como
argumentos no os valores dos parmetros mas sim ponteiros que apontem para
seus endereos. Assim esta funo pode modificar diretamente os contedos
145

destas variveis, que aps o fim da funo estaro disponveis para a funo que
chamou. Neste caso os argumentos podem funcionar como entrada e sada de
dados da funo.
Uma outra aplicao importante de ponteiros apontar para reas de memria que devem ser gerenciadas durante a execuo do programa. Com ponteiros,
possvel reservar as posies de memria necessrias para armazenamento
destas reas somente quando for necessrio e no quando as variveis so declaradas. Neste esquema o programador pode reservar o nmero exato de posies
que o programa requer. A Figura 9.2 ilustra como um ponteiro faz referncia
para uma rea de memria. Na figura a varivel ponteiro pi aponta para a rea
de memria que contm um vetor de 10 inteiros. Com ponteiros, o programador
precisa, no incio, definir a varivel ponteiro e seu tipo. Durante a execuo do
programa, aps descobrir o tamanho do vetor, reserva a rea necessria para
guardar os dados. Observe a diferena do que ocorre quando se usa vetores de
tamanho fixo. Neste caso a definio do tamanho do vetor dada na declarao
do vetor e mantida at o final da execuo do programa.
0
pi ponteiro
para vetor

1000

4
8

120

1000

Vetor de
10 inteiros
1036

97

Figura 9.2: Ponteiro apontando para rea de memria contendo vetor.

9.2 Operaes om Ponteiros


9.2.1 De larao de Ponteiros
Antes de serem usados os ponteiros, como as variveis, precisam ser declarados.
A forma geral da declarao de um ponteiro a seguinte:
tipo *nome;
Onde tipo qualquer tipo vlido em C e nome o nome da varivel ponteiro.
Por exemplo:

146

int * res ; /* ponteiro para inteiro


f l o a t * div ; /* ponteiro para ponto

*/
flutuante */

Como as variveis, os ponteiros devem ser inicializados antes de serem usados. Esta inicializao pode ser feita na declarao ou atravs de uma atribuio.
Aps a declarao o que temos um espao na memria reservado para armazenamento de endereos. O valor inicial da memria indefinido como acontece
com variveis. A Figura 9.3 ilustra esta situao. Um ponteiro pode ser inicializado com um endereo ou com o valor NULL. O valor NULL, que equivalente a
0, uma constante definida no arquivo <stdio.h> e significa que o ponteiro no
aponta para lugar nenhum. A atribuio de inteiros a ponteiros no faz sentido a no ser em aplicaes muito especiais e o nico valor inteiro que se pode
atribuir a um ponteiro o 0. Este tipo de atribuio no faz sentido porque na
maioria das aplicaes o sistema operacional que aloca e gerencia a posio
dos programas na memria e, portanto, o usurio no tem controle sobre estes
endereos.
996

1000

endereo indefinido

*res

1004

endereo indefinido

*div

Figura 9.3: Declarao de ponteiros.

9.2.2 Os Operadores Espe iais para Ponteiros


Existem dois operadores especiais para ponteiros: * e &. Os dois operadores
so unrios, isto requerem somente um operando. O operador & devolve o
endereo de memria do seu operando. Considere a Figura 9.1. Aps a execuo
da instruo
pint = &num; /*o endere o de num e arregado em pint */

a varivel ponteiro pint termina com o valor 4, como est mostrado na Figura
9.4. Lembre-se que o valor 4 no tem sentido prtico na maioria das aplicaes.
O fato importante que o ponteiro pint passou a apontar para a varivel num.
O operador * o complemento de &. O operador * devolve o valor da varivel
localizada no endereo apontado pelo ponteiro. Por exemplo, considere que o

147

0
4

10

num

120

12

res
*pint

16

Figura 9.4: Atribuio de endereo de uma varivel a um ponteiro.

comando res = *pint; foi executado logo aps pint = &num;. Isto significa que
a varivel res recebe o valor apontado por pint, ou seja a varivel res recebe o
valor 10, como est mostrado na Figura 9.5.
0
4

10

120 10

12

num
res = *pint
*pint

16

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


Estes operadores no devem ser confundidos com os j estudados em captulos anteriores. O operador * para ponteiros no tem nada a ver com o operador
multiplicao *. O operador ponteiro * unrio e, como o operador &, tem
precedncia maior que do que todos os operadores aritmticos.

9.2.3 Atribuio de Ponteiros


Da mesma maneira que ocorre com uma varivel comum, o contedo de um
ponteiro pode ser passado para outro ponteiro do mesmo tipo. Por exemplo,
uma varivel ponteiro declarada como apontador de dados inteiros deve sempre
apontar para dados deste tipo. Observar que em C possvel atribuir qualquer
endereo a uma varivel ponteiro. Deste modo possvel atribuir o endereo de
uma varivel do tipo oat a um ponteiro do tipo int. No entanto, o programa
no ir funcionar da maneira correta. O programa 9.1 mostra exemplos de
atribuies de ponteiros. Neste exemplo o endereo do terceiro elemento do
vetor v carregado em p1 e o endereo da varivel i carregado em p2. A
148

Figura 9.6 a situao da memria aps estas operaes. Alm disso no final o
endereo apontado por p1 carregado em p2. Os comandos printf imprimem os
valores apontados pelos ponteiros respectivos, mostrando os seguintes valores:
30
100
30

Listagem 9.1: Exemplo de atribuio de ponteiros.

#in lude < stdio .h >


int main ( void ) {
int vetor [ =
int
int

{ 10 , 20 , 30 , 40 , 50 };

* p1 , * p2 ;
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

10

v[0]

20

v[1]

12

30

v[2]

16

40

v[3]

20

50

v[4]

24

12

*p1

28

32
100

*p2

32

p1 = &v[2];

p2 = &i;
i

Figura 9.6: Exemplos de atribuies de ponteiros.

149

9.2.4 In rementando e De rementando Ponteiros


O exemplo 9.2 mostra que operaes de incremento e decremento podem ser
aplicadas em operandos. O primeiro printf imprime 30, que o elemento de
ndice igual a 2 no vetor vetor. Aps o incremento do ponteiro o segundo
printf imprime 40 e o mesmo acontece com o terceiro printf que imprime 50.

Listagem 9.2: Exemplos de operaes com ponteiros.

int

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

Pode parecer estranho que um ponteiro para um nmero inteiro, que armazenado em quatro bytes, seja incrementado por um e passe para apontar para
o prximo nmero inteiro. A primeira vista, para que passasse a apontar para
o prximo endereo, seria necessrio aumentar o endereo em quatro. Ou seja,
sempre que um ponteiro incrementado (decrementado) ele passa a apontar
para a posio do elemento seguinte (anterior). O compilador interpreta o comando p1++ como: passe a apontar para o prximo nmero inteiro e, portanto,
aumenta o endereo do nmero de bytes correto. Este ajuste feito de acordo
com o tipo do operando que o ponteiro est apontando. Do mesmo modo, somar
trs a um ponteiro faz com que ele passe apontar para o terceiro elemento aps o
atual. Portanto, um incremento em um ponteiro que aponta para um valor que
armazenado em n bytes faz que n seja somado ao endereo. ento possvel
somar-se e subtrair-se inteiros de ponteiros. A operao abaixo faz com que o
ponteiro p passe a apontar para o terceiro elemento aps o atual.
p = p + 3;

Tambm possvel usar-se o seguinte comando


*(p+1)=10;

Este comando armazena o valor 10 na posio seguinte quela apontada por


p. A operao realizada nos seguintes passos:

1. A expresso p+1 calculada e o seu resultado aponta para o prximo


endereo de dado inteiro;
2. A expresso do lado direito do sinal de atribuio, calculada e fornece
como resultado o valor 10;
3. Este resultado atribudo ao endereo calculado no primeiro passo.
150

A diferena entre ponteiros fornece quantos elementos do tipo do ponteiro


existem entre os dois ponteiros. No exemplo 9.3 impresso o valor 2.

Listagem 9.3: Exemplo de subtrao de ponteiros.

#in lude < stdio .h >


int main ( void ) {
f l o a t vetor [ =
f l o a t * p1 , * p2 ;

{ 1.0 , 2.0 , 3.0 , 4.0 , 5.0 };

p1 = & vetor [2; /* endere o do ter eiro elemento */


p2 = vetor ;
/* endere o do primeiro elemento
*/
printf ( " Diferen a entre ponteiros % d \ n " , p1 - p2 ) ;
return 0;

No possvel multiplicar ou dividir ponteiros, e no se pode adicionar ou


subtrair o tipo oat ou o tipo double a ponteiros.

9.2.5 Comparao de Ponteiros


possvel comparar ponteiros em uma expresso relacional. No entanto, s
possvel comparar ponteiros de mesmo tipo. O Programa 9.4 ilustra um exemplo
deste tipo de operao.

Listagem 9.4: Exemplo de comparao de ponteiros.

#in lude < stdio .h >


int main ( void ) {
har * , *v ,

a, b;

s anf ( " % % " , &a , & b ) ;


= &a;
v = &b;

if

( == v )
printf ( " As variveis estao na mesma posi ao . " ) ;

else

printf ( " As variaveis nao estao na mesma posi ao . "


);

return

0;

151

9.3 Ponteiros e Vetores


Ponteiros e Vetores esto fortemente relacionados na linguagem C. O nome de
um vetor um ponteiro que aponta para a primeira posio do vetor. A declarao int vetor[100 cria um vetor de inteiros de 100 posies e permite que
algumas operaes com ponteiros possam ser realizadas com a varivel vetor.
No entanto, existe uma diferena fundamental entre declarar um conjunto
de dados como um vetor ou atravs de um ponteiro. Na declarao de vetor,
o compilador automaticamente reserva um bloco de memria para que o vetor
seja armazenado. Quando apenas um ponteiro declarado a nica coisa que
o compilador faz alocar um ponteiro para apontar para a memria, sem que
espao seja reservado. O nome de um vetor chamado de ponteiro constante
e, portanto, no pode ter o seu valor alterado. O nome de um ponteiro constante no pode aparecer em expresses no lado esquerdo do sinal de igual, ou
seja, no pode receber valores diferentes do valor inicial atribudo na declarao
da varivel. Assim, os comandos que alteram o ponteiro list, mostrados no
exemplo 9.5, no so vlidos:

Listagem 9.5: Exemplo de alteraes invlidas sobre ponteiros.

int

list [5 , i ;

/* O ponteiro list nao pode ser modifi ado


re ebendo o endere o de i */
list = & i
/* O ponteiro list nao pode ser in rementado */
list ++;

O contedo de vetores pode ser acessado usando-se o operador * para obter


o contedo do vetor. O Programa 9.6 mostra a notao que usa ndices para
buscar o elemento de um vetor e o uso do operador * de ponteiros. Neste
programa o contedo do vetor impresso usando-se estas duas notaes.

Listagem 9.6: Exemplo de notaes de vetores.

#in lude < stdio .h >


int main ( void ) {
f l o a t v [ = {1.0 , 2.0 , 3.0 ,
int i ;
for ( i = 0; i < 7; i ++)

4.0 , 5.0 , 6.0 , 7.0};

printf ( " %.1 f " , v [ i ) ;


printf ( " \ n " ) ;
for ( i = 0; i < 7; i ++)
printf ( " %.1 f " , *( v + i ) ) ;
return 0;

152

Para percorrer um vetor alm da maneira mostrada no programa 9.6 possvel usar um ponteiro varivel como ilustrado no Programa 9.7. Observe como
o ponteiro p recebe seu valor inicial e a maneira como ele incrementado.

Listagem 9.7: Exemplo de ponteiro varivel.

#in lude < stdio .h >


int main ( void ) {
f l o a t v [ = {1.0 ,
int i ;
float *p;

2.0 , 3.0 , 4.0 , 5.0 , 6.0 , 7.0};

for ( i = 0; i < 7; i ++) printf ( " %.1 f " , v [ i ) ;


printf ( " \ n " ) ;
for ( i = 0; i < 7; i ++) printf ( " %.1 f " , *( v + i ) ) ;
printf ( " \ n " ) ;
for ( i = 0 , p = v ; i < 7; i ++ , p ++) printf ( " %.1 f " , * p
);
return 0;

9.4 Ponteiros e Cadeias de Cara teres


Uma cadeia de caracteres constante escrita como no exemplo:
"Esta e uma adeia de ara teres."

At agora um dos usos mais comuns de cadeias de caracteres constantes tem


sido na funo printf, como no exemplo abaixo
printf("A abou o programa.\n");

Quando uma cadeia de caracteres como esta enviada para a funo, o que
passado o ponteiro para a cadeia. possvel ento carregar o endereo da
cadeia em um ponteiro do tipo har, como no exemplo 9.8. Neste programa
contado o nmero de caracteres de uma cadeia. Observe o ponteiro *(s+tam++)
apontando caractere a caractere.
Um outro exemplo (Programa 9.9) mostra uma funo que copia um cadeia
de caracteres para outra.

9.5 Alo ao Dinmi a de Memria


O uso de ponteiros e vetores exige que aps a definio da varivel ponteiro uma
rea de memria deve ser reservada para armazenar os dados do vetor. Para
obter esta rea o programa deve usar funes existentes na biblioteca stdlib.
Estas funes pedem ao sistema operacional para separar pedaos da memria
e devolvem ao programa que pediu o endereo inicial deste local. As funes
bsicas de alocao de memria que iremos discutir so:
153

Listagem 9.8: Exemplo de ponteiro para cadeia de caracteres.

#in lude < stdio .h >


int main ( void ) {
har *s , * lista = " 1234567890 " ;
int tam =0;

s = lista ;
while (*( s + tam ++) != ' \0 ') ;
tam - -;
printf ( " O tamanho do string \"% s \" e % d ara teres .\ n "
,
lista , tam ) ;
return 0;

Listagem 9.9: Exemplo de cpia de cadeias de caracteres.

#in lude < stdio .h >


int str op ( har *d , har * o ) ;
int main ( void ) {
har destino [20;
har * origem = " adeia de ara tere

int

str op ( destino , origem ) ;


printf ( " % s \ n " , origem ) ;
printf ( " % s \ n " , destino ) ;
return 0;

de origem " ;

str op ( har *d , har * o ) {


while ((* d ++ = * o ++) != ' \0 ') ;
return 0;

void *mallo (size_t size); Reserva espao na memria para algum item
de um programa. O tamanho em bytes reservado definido pela varivel size.
O valor armazenado no espao indefinido. A funo retorna um ponteiro de
tipo void para o espao reservado ou NULL no caso de algum erro ocorrer.
void * allo (size_t num, size_t size); Reserva espao na memria para
um vetor de num itens do programa. Cada item tem tamanho size e todos os
bits do espao so inicializados com 0. A funo retorna um ponteiro de tipo
void para o espao reservado ou NULL no caso de algum erro ocorrer.
void free(void *pont); O espao apontado por pont devolvido ao sistema
para uso. Caso pont seja um ponteiro nulo nenhuma ao executada. No caso
do ponteiro no ter sido resultado de uma reserva feita por meio de uma das
funes allo , reallo ou mallo o resultado indefinido.
void reallo (void *pont, size_t size); A funo altera o tamanho do objeto na memria apontado por pont para o tamanho especificado por size. O
154

contedo do objeto ser mantido at um tamanho igual ao menor dos dois tamanhos, novo e antigo. Se o novo tamanho requerer movimento, o espao reservado
anteriormente liberado. Caso o novo tamanho for maior, o contedo da poro de memria reservada a mais ficar com um valor sem especificao. Se o
tamanho size for igual a 0 e pont no um ponteiro nulo o objeto previamente
reservado liberado.
Estas funes podem ser encontradas na biblioteca stdlib.h. O Programa
9.10 ilustra o uso das funo allo e free.

Listagem 9.10: Exemplo de uso de allo e free.

#in lude < stdio .h >


#in lude < stdlib .h >
int main ( void ) {
float *v;
int i , tam ;

printf ( " Qual o tamanho do vetor ? " ) ;


s anf ( " % d " , & tam ) ;
v = allo ( tam , s i z e o f ( f l o a t ) ) ;
i f (! v ) {
printf ( " Nao onsegui alo ar memoria . " ) ;
return 1;
}
for ( i =0; i < tam ; i ++) {
printf ( " Elemento % d ? " , i ) ;
s anf ( " % f " , v + i ) ;
printf ( " Li valor % f \ n " , *( v + i ) ) ;
}
free ( v ) ;
return 0;

Um outro exemplo, agora empregando a funo mallo () est mostrado no


Programa 9.11. Observe que neste programa tambm mostramos exemplos onde
um endereo de varivel foi passado para uma funo de modo que a funo
main possa receber um valor (vezes).

9.6 Ponteiros e Matrizes


Um ponteiro aponta para uma rea de memria que endereada de maneira
linear. Portanto, vetores podem ser facilmente manipulados com ponteiros. No
entanto, quando usamos estruturas de dados com maior dimensionalidade, como
matrizes, por exemplo, que so arranjos bidimensionais de dados, necessrio
mapear o espao bidimensional (ou de maior ordem) para uma dimenso. No
caso das matrizes necessrio mapear o endereo de cada elemento na matriz,
que definido por um par (linha, coluna) em um endereo 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
155

Listagem 9.11: Exemplo de uso de mallo .

#in lude < stdio .h >


#in lude < stdlib .h >
void LeVetor ( f l o a t *v , int tam ) ;
f l o a t Pro uraMaior ( f l o a t *v , int
int main ( void ) {
f l o a t *v , maior ;
int i , tam , vezes ;

void

float

tam ,

int

* vezes ) ;

printf ( " Qual o tamanho do vetor ? " ) ;


s anf ( " % d " , & tam ) ;
v = ( f l o a t *) mallo ( tam * s i z e o f ( f l o a t ) ) ;
i f (v) {
LeVetor (v , tam ) ;
maior = Pro uraMaior (v , tam , & vezes ) ;
printf ( " Maior = % f e apare e % d vezes .\ n . " ,
maior , vezes ) ;
free ( v ) ;
}
else {
printf ( " Nao onsegui alo ar memoria . " ) ;
return 1;
}
return 0;
LeVetor ( f l o a t *v , int tam ) {
int i ;
for ( i =0; i < tam ; i ++) {
printf ( " Elemento % d ? " , i ) ;
s anf ( " % f " , v + i ) ;
printf ( " Li valor % f \ n " , *( v + i ) ) ;
}
Pro uraMaior ( f l o a t *v ,

int i ;
f l o a t maior ;

int

tam ,

int

* vezes ) {

maior = v [0; * vezes = 1;


for ( i =1; i < tam ; i ++) {
i f ( v [ i & gt ; maior ) {
maior = v [ i ;
* vezes = 1;
}
e l s e i f ( maior == v [ i ) * vezes =* vezes +1;
}
return maior ;

156

programa listado em 9.12. Caso o programa utilizasse ponteiros ao invs de


notao de matrizes, poderamos usar uma soluo que mapeasse a matriz que
um objeto de duas dimenses em um vetor que tem apenas uma. Neste caso
o programa deve fazer a translao de endereos toda vez que precisar ler ou
escrever na matriz. O trecho de programa ficaria como mostrado no exemplo
9.13. A expresso matriz+(i*COL+j) calcula a posio do elemento matriz
[i[j a partir do primeiro elemento da matriz que est no endereo inicial
matriz.

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

#define
#define

LIN 3
COL 4

int matriz [ LIN [ COL ;


for ( i =0; i < LIN ; i ++) {
for ( j =0; j < COL ; j ++)
}

{
printf ( " Elemento % d % d = " , i , j ) ;
s anf ( " % d " , & matriz [ i [ j ) ;

Listagem 9.13: Exemplo de matriz mapeada em um vetor.

#define
#define
int
int

LIN 3
COL 4
* matriz ;
i, j;

matriz = mallo ( LIN * COL * s i z e o f ( int ) ) ;


i f (! matriz ) {
printf ( " Erro .\ n " ) ;
return 1;
}
for ( i = 0; i < LIN ; i ++) {
for ( j = 0; j < COL ; j ++)
{
printf ( " Elemento % d % d = " , i , j ) ;
s anf ( " % d " , matriz +( i * COL + j ) ) ;
}

No entanto, esta soluo ainda no a melhor j que o usurio necessita


escrever diretamente uma expresso para mapear o endereo bidimensional da
matriz matriz[i[j em um endereo linear. O ideal usar uma notao que
use somente ponteiros. Esta notao ser discutida nas sees seguintes.

157

9.7 Vetores de Ponteiros


Uma possibilidade mais interessante utilizar vetores de ponteiros. Esta no
a notao ideal, mas um passo na direo da notao mais efetiva. Neste caso
cada linha da matriz corresponde a um vetor que apontado por um ponteiro
armazenado no vetor de ponteiros. Como ponteiros tambm so variveis
possvel ento criar vetores de ponteiros e utiliz-los. O exemplo mostrado em
9.14 mostra um programa onde utilizado um vetor de ponteiros para vrias
linhas de caracteres. Observe na funo main a declarao har *linha[LINHAS
; que define um vetor de tamanho LINHAS. Este vetor contem ponteiros e no
valores. At este momento do programa temos apenas posies reservadas para
armazenar ponteiros. A alocao de espao e a inicializao dos ponteiros feito
no primeiro comando for. Como cada elemento do vetor linha um ponteiro
temos que o endereo retornado pela funo mallo armazenado em cada
um dos elementos deste vetor. A leitura das linhas de caracteres feita pela
funo gets(linha[i) que passa o elemento do vetor onde os caracteres sero
armazenados.

Listagem 9.14: Exemplo de uso de vetor de ponteiros.

#in lude < stdio .h >


#in lude < stdlib .h >
#define LINHAS 10
#define COLUNAS 60
int

main ( void ) {
har * linha [ LINHAS ;
int i ;

for

for
}

for
}
}

( i = 0; i < LINHAS ; i ++) {


i f (!( linha [ i = mallo ( COLUNAS * s i z e o f ( har ) ) ) ) {
printf ( " Sem memria para vetor % d .\ n " , i ) ;
return i ;
}
( i = 0; i < LINHAS ; i ++) {
printf ( " Entre om a linha % d .\ n " , i ) ;
gets ( linha [ i ) ;
( i = 0; i < LINHAS ; i ++) {
printf ( " Linha % d % s .\ n " , i , linha [ i ) ;

return

0;

158

9.8 Ponteiros para Ponteiros


No exemplo anterior podemos observar que o nmero de linhas da matriz
fixa, e portanto, h uma mistura de notao de ponteiros com matrizes. Vamos considerar um exemplo onde tanto o nmero de linhas como o de colunas
desconhecido. Neste exemplo iremos criar um vetor de ponteiros que ir armazenar o endereo inicial de cada linha. Portanto, para obter um elemento da
matriz primeiro devemos descobrir onde est a linha no vetor que armazena os
endereos das linhas, em seguida procuramos na linha o elemento. A Figura 9.7
ilustra como ser feito o armazenamento desta matriz.
Vetor de ponteiros
**matriz

linha 0

*(matriz+0)
*(matriz+1)

linha 1

*(matriz+2)
linha 2

*(matriz+n)
linha n

Figura 9.7: Armazenamento de matrizes com vetores de ponteiros.

O Programa 9.15, listado a seguir, ir pedir ao usurio que digite o nmero


de linhas e colunas da matriz. Em seguida ler todos os elementos da matriz e
por ltimo ir trocar duas linhas da matriz de posio. Observe que agora foi
criado um ponteiro para ponteiro chamado de **matriz. O programa primeiro
pergunta o nmero de linhas da matriz para poder alocar espao para armazenar
os ponteiros para cada uma das linhas. Em seguida alocado espao para
armazenar cada uma das linhas. O comando
matriz = (int **)mallo (lin *

sizeof(int

*));

foi usado pelo programa para reservar espao para armazenar lin linhas de
ponteiros para ponteiros. Observe que o comando sizeof(int *) calcula o espao
para armazenar um ponteiro na memria. Note tambm que o valor retornado
pela funo mallo foi conformado ao tipo ponteiro para ponteiro pela operao
(int **). O interessante do programa que a troca de linhas da matriz envolve
simplesmente a troca de dois ponteiros e no a troca de todos os elementos das
linhas. Esta soluo muito mais rpida do que trocar elemento a elemento,
especialmente para matrizes grandes.
A seguir mostramos o programa nas listagens 9.16 e 9.17 que o exemplo
anterior modificado para utilizar funes. O propsito mostrar como ficam as
chamadas e as definies das funes que utilizam ponteiros para ponteiros.
159

Listagem 9.15: Exemplo de uso de ponteiros para ponteiros.

#in lude < stdio .h >


#in lude < stdlib .h >
int main ( void ) {
int ** matriz ; /* ponteiro para os ponteiros */
int lin , ol ; /* nmero de linhas e olunas */
int i , j ;
int linha1 , linha2 ; /* linhas que serao tro adas */
har linha [80; /* linha de ara teres om os dados
int * temp ;

*/

puts ( " Qual o numero de linhas ? " ) ;


gets ( linha ) ; lin = atoi ( linha ) ;
matriz = ( int **) mallo ( lin * s i z e o f ( int *) ) ;
i f (! matriz ) {
puts ( " Nao h espao para alo ar memria " ) ;
return 1;
}
puts ( " Qual o numero de olunas ? " ) ;
gets ( linha ) ; ol = atoi ( linha ) ;
for ( i =0; i < lin ; i ++) {
*( matriz + i ) = ( int *) mallo ( ol * s i z e o f ( int ) )
;
i f (! *( matriz + i ) ) {
printf ( " Sem espao para alo ar a linha % d " ,
i);
return 1;
}
}
puts ( " Entre om os dados " ) ;}
for ( i =0; i < lin ; i ++) {
printf ( " Entre om a linha % d \ n " , i ) ;
for ( j =0; j < ol ; j ++) {
printf ( " Elemento % d % d \ n " , i , j ) ;
s anf ( " % d " , *( matriz + i ) + j ) ;
}
}
puts ( " Qual a primeira linha a ser tro ada ? " ) ;
gets ( linha ) ; linha1 = atoi ( linha ) ;
puts ( " Qual a segunda linha a ser tro ada ? " ) ;
gets ( linha ) ; linha2 = atoi ( linha ) ;
temp = *( matriz + linha1 ) ;
*( matriz + linha1 ) = *( matriz + linha2 ) ;
*( matriz + linha2 ) = temp ;
puts ( " Dados tro ados . " ) ;
for ( i =0; i < lin ; i ++) {
for ( j =0; j < ol ; j ++) {
printf ( " %7 d " , *(*( matriz + i ) + j ) ) ;
}
printf ( " \ n " ) ;
}
return 0;

160

Listagem 9.16: Exemplo de uso de ponteiros para ponteiros usando funes.

#in lude < stdio .h >


#in lude < stdlib .h >}
int ** alo a_linhas ( int ) ;
void alo a_ olunas ( int ** , int , int ) ;
void le_dados ( int ** , int , int ) ;
void imprime_matri z ( int ** , int , int ) ;
void tro a_linhas ( int ** , int , int ) ;
int main ( void ) {
int ** matriz ;
int lin , ol ;& nbsp ;& nbsp ;
int linha1 , linha2 ;
har linha [80;
puts ( " Qual o numero de linhas ? " ) ;
gets ( linha ) ; lin = atoi ( linha ) ;
matriz = alo a_linhas ( lin ) ;
puts ( " Qual o numero de olunas ? " ) ;
gets ( linha ) ; ol = atoi ( linha ) ;

int

void

printf ( " Alo ando espao para linhas .\ n " ) ;


alo a_ olunas ( matriz , lin , ol ) ;
le_dados ( matriz , lin , ol ) ;
imprime_matri z ( matriz , lin , ol ) ;
puts ( " Qual a primeira linha a ser tro ada ? " ) ;
gets ( linha ) ; linha1 = atoi ( linha ) ;
puts ( " Qual a segunda linha a ser tro ada ? " ) ;
gets ( linha ) ; linha2 = atoi ( linha ) ;
tro a_linhas ( matriz , linha1 , linha2 ) ;
imprime_matri z ( matriz , lin , ol ) ;
return 0;
** alo a_linhas ( int lin ) {
int ** m ;
m = ( int **) mallo ( lin * s i z e o f ( int *) ) ;
i f (! m ) {
puts ( " Sem espao para alo ar memria " ) ;
return 1;
}
return m ;
alo a_ olunas ( int ** matriz , int lin , int ol ) {
int i ;
for ( i =0; i < lin ; i ++) {
*( matriz + i ) = ( int *) mallo ( ol * s i z e o f ( int ) )
;
i f (! *( matriz + i ) ) {
printf ( " Sem espao para linha % d " , i ) ;
return 1;
}
}

161

Listagem 9.17: Continuao do exemplo 9.16.

void

void

void

le_dados ( int ** matriz , int lin , int ol ) {


int i , j ;
puts ( " Entre om os dados " ) ;
for ( i =0; i < lin ; i ++) {
printf ( " Entre om a linha % d \ n " , i ) ;
for ( j =0; j < ol ; j ++) {
printf ( " Elemento % d % d \ n " , i , j ) ;
s anf ( " % d " , *( matriz + i ) + j ) ;
}
}
imprime_matri z ( int ** matriz , int lin , int ol ) {
int i , j ;
for ( i =0; i < lin ; i ++) {
for ( j =0; j < ol ; j ++) {
printf ( " %7 d " , *(*( matriz + i ) + j ) ) ;
}
printf ( " \ n " ) ;
}
tro a_linhas ( int ** matriz , int linha1 ,
int * temp ;
temp = *( matriz + linha1 ) ;
*( matriz + linha1 ) = *( matriz + linha2 ) ;
*( matriz + linha2 ) = temp ;

162

int

linha2 ) {

Exer ios
9.1: Escreva um programa que gere um vetor de trs dimenses (X, Y e Z) em
que cada posio guarda a soma de suas coordenadas. As dimenses da matriz
devero ser determinadas em tempo de execuo e o programa dever informar
os valores gerados.
9.2: Escreva um programa que leia uma frase de at 80 caracteres do teclado
e imprima a freqncia com que aparece cada uma das letras do alfabeto na
frase.
9.3: Escreva um programa que leia uma frase de at 80 caracteres e a imprima
em ordem reversa convertendo todos os caracteres minsculos para maisculos.
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 posio. Os nmeros 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 operaes na pilha:
Inserir
Remover
Listar
9.6: Escreva uma funo que receba um ponteiro para uma cadeia de caractere
e troque todo o caracter aps um branco pelo seu equivalente maisculo.
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 o nmero 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 funo posi ao que tem
o seguinte prottipo:

int

posi ao( har *substr,

har

*str);

Esta funo deve verificar se a cadeia apontada por substr est presente na
cadeia apontada por str e retornar a posio 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 dimenses da matriz
devem ser pedidas ao usurio.
9.10: Escreva um programa que leia duas cadeias de caracteres e concatene a
segunda cadeia ao final da primeira.
163

Listagem 9.18: Programa do exercicio 11.

#in lude < string .h >


#in lude < stdio .h >
#define
void
int

MAX 80

misterio ( har * p1 ,

har

* p2 ) ;

main ( void ) {
har palavra1 [ MAX ;
har 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

void

misterio ( har * p1 , har * p2 ) {


(* p1 != ' \0 ' && * p2 != ' \0 ') {
put har (* p1 ) ;
put har (* p2 ) ;
p1 = p1 + 1;
p2 = p2 + 1;
}

while

if

if

0;

(* p1 != ' \0 ') {
(* p1 != ' \0 ') {
put har (* p1 ) ;
p1 = p1 + 1;
}

while

(* p2 != ' \0 ') {
(* p2 != ' \0 ') {
put har (* p2 ) ;
p2 = p2 + 1;
}

while

164

9.11: O que ser impresso pelo programa mostrado na listagem 9.18 caso a
primeira palavra fornecida seja o seu primeiro nome e a segunda o seu ltimo
sobrenome.
9.12: O que ser impresso pelo programa mostrado na listagem 9.19 caso a
primeira palavra fornecida seja o seu primeiro nome e a segunda o seu ltimo
sobrenome. Indique os nomes que usou e justifique a sua resposta.

Listagem 9.19: Programa do exercicio 12.

#in lude < string .h >


#in lude < stdio .h >
#define
void

MAX 80

nMisterio ( har * p1 ,
(* p1 != ' \0 ') {
p1 = p1 + 1;

while
}

har

* p2 ) {

while

(* p2 != ' \0 ') {
* p1 = * p2 ;
p1 = p1 + 1;
p2 = p2 + 1;

int

}
* p1 = ' \0 ';

main ( void ) {
palavra1 [ MAX ;
palavra2 [ MAX ;

har
har

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 impresso pelo programa 9.20. Justifique sua resposta.
9.14: O que ser impresso pelo programa mostrado na listagem 9.21. Justifique
sua resposta.

165

Listagem 9.20: Listagem do exerccio 13.

#in lude < stdio .h >


#in lude < string .h >
int main ( void ) {
har * frase = " Otimo teste " ;
har *p , misterio [80;
int i = 0;
int j = 0;

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;

166

Listagem 9.21: Programa do exerccio 14.

#in lude < stdio .h >


void
}

void

int

int

f1 ( int v ) {
v = v + 1;
printf ( " f1 = % d \ n " , v ) ;
f2 ( int * v ) {
* v = * v + 1;
printf ( " f2 = % d \ n " , * v ) ;
f3 ( int v ) {
v = v + 1;
printf ( " f3 = % d \ n " , v ) ;
return v ;
main ( void ) {
int v = 1;
f1 ( v ) ;
f2 (& v ) ;
v = f3 ( v ) ;
printf ( " main = % d \ n " , v ) ;
return 0;

167

Captulo 10

Estruturas
10.1 Introduo
Uma estrutura um conjunto de uma ou mais variveis, que podem ser de tipos diferentes, agrupadas sob um nico nome. O fato de variveis agrupadas
em uma estrutura poderem ser referenciadas por um nico nome facilita a manipulao dos dados armazenados nestas estruturas. Um exemplo poderia ser
uma estrutura que armazenasse as diversas informaes sobre os alunos de uma
Universidade. Nesta estrutura estariam armazenadas, sob o mesmo nome, informaes do tipo: nome, registro, data de nascimento, data de ingresso, CPF,
etc. Uma estrutura pode incluir outras estruturas alm de variveis simples.
As estruturas facilitam manipular estes agrupamentos complexos de dados. Por
exemplo, considere o problema de ordenar as informaes sobre os alunos da
Universidade exemplo. A ordenao pode ser efetuada como se todos os dados
que compem a estrutura fossem uma entidade nica.

10.2 Denies Bsi as


Uma estrutura, ento, uma coleo de variveis, de tipos diversos ou no,
agrupadas sob um nico nome. As variveis que compem a estrutura so os
seus membros, elementos ou campos. Normalmente os elementos da estrutura
tem alguma relao semntica. Por exemplo: alunos de uma universidade, discos
de uma coleo, elementos de uma figura geomtrica, etc. Vamos considerar o
exemplo do aluno e assumir que estaremos armazenando o seu nome, registro,
ano de entrada e curso. Para este fim podemos criar uma estrutura como a
descrita no trecho de programa 10.1.
A palavra chave stru t inicia a declarao da estrutura, em seguida pode
aparecer um identificador (ALUNO), que subseqentemente pode ser usado como
abreviao da definio da estrutura. A declarao continua com a lista de
declaraes entre chaves e termina com um ;. Um membro da estrutura e
uma varivel no membro da estrutura podem ter o mesmo nome, j que
possvel distingui-las por contexto.

168

Listagem 10.1: Definio de uma estrutura.

stru t ALUNO {
har nome [40;
int registro ;
int ano_entrada ;
har urso [20;

};

A declarao acima ainda no alocou espao de memria j que nenhuma


varivel foi realmente definida. Esta declarao apenas um modelo de como
estruturas do tipo ALUNO devem ser construdas. Para definir estruturas deste
tipo podemos usar a seguinte declarao.

stru t

ALUNO paulo, arlos, ana;

Nesta declarao trs estruturas do tipo ALUNO foram criadas. Esta declarao alocou espao para armazenar os dados dos trs alunos. A declarao acima
idntica, na forma, a declarao de variveis de um tipo pr-definido, como
por exemplo:

int

a, b, ;

possvel declarar ao mesmo tempo o modelo da estrutura e as variveis do


programa. Por exemplo,

stru t ALUNO {
har nome [40;
int registro ;
int ano_entrada ;
har urso [20;

} paulo , arlos , ana ;

Para referenciar um elemento da estrutura usa-se o nome da varivel 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. urso);

Estruturas podem conter outras estruturas como membros. Por exemplo,


vamos definir uma estrutura para armazenar uma data com a seguinte definio:

stru t DATA {
int dia ,

};

mes , ano ;

Agora vamos modificar a estrutura aluno de modo que ela inclua a data de
nascimento do aluno. A estrutura fica com a seguinte definio:
169

stru t aluno {
har nome [40;
int registro ;
int ano_entrada ;
har urso [20;
stru t DATA data_nas im en to ;

};

Para se referir ao ms de nascimento de uma varivel paulo do tipo estrutura

aluno usamos a declarao

paulo.data_nas imento.mes

Note que o operador ponto (.) associa da esquerda para a direita.


Uma forma mais conveniente de definio de estruturas possvel com o
uso do comando typedef. Este comando permite dar a um tipo de dados um
novo nome. A inteno aumentar a legibilidade do programa. Por exemplo,
possvel usar o seguinte cdigo

typedef int
typedef int
typedef int

ores ;
laranja ;
manga ;

...
laranja lima ;
manga espada ;
ores = AMARELO ;
...
espada ++;

Ao mesmo tempo que typedef tem a vantagem de tornar mais claro a finalidade de cada varivel ele pode trazer problemas na medida em que esconde o
real tipo da varivel.
comum o uso de typedef em conjunto com stru t. Considere a definio
de uma estrutura para guardar tempos gastos em tarefas. Esta estrutura deve
guardar horas, minutos e segundos. Usando esta combinao, a definio
usualmente feita da seguinte maneira:

stru t _TEMPO {
int hora , minuto ,

};

typedef stru t
...
TEMPO t1 ;

segundo ;

_TEMPO TEMPO ;

Uma forma ainda mais abreviada, junta as duas definies, ficando a definio da estrutura da seguinte maneira:

typedef stru t
int hora ,

} TEMPO ;

_TEMPO {
minuto , segundo ;

170

...
TEMPO t1 ;

possvel dispensar o nome da estrutura (_TEMPO) e a definio fica ainda


mais simples, com a seguinte forma:

typedef stru t
int hora ,

} TEMPO ;
...
TEMPO t1 ;

{
minuto , segundo ;

10.3 Atribuio de Estruturas


possvel atribuir o contedo de uma estrutura a outra estrutura do mesmo
tipo, no sendo necessrio atribuir elemento por elemento da estrutura. Esta
uma das grandes vantagens de estruturas j que o tamanho do cdigo 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.

Listagem 10.2: Atribuio de Estruturas.

#in lude < stdio .h >


typedef stru t _EMPREGADO
har nome [40;
f l o a t salario ;

} EMPREGADO ;

int

main () {
EMPREGADO temp , emp1 ;
puts ( " Entre om nome . " ) ;
gets ( emp1 . nome ) ;
puts ( " Qual o salario ? " ) ; s anf ( " % 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 freqentemente na forma de matrizes. Por exemplo, a
declarao stru t ALUNO turma[100; define uma matriz de 100 estruturas do
171

tipo stru t ALUNO.


O exemplo 10.3 mostra atribuies entre estruturas e operaes aritmticas
envolvendo membros de estruturas. O programa coloca um vetor de estruturas em ordem crescente usando como chave de ordenao um dos membros da
estrutura (media).

10.5 Estruturas e Funes


Primeiro vamos considerar o caso de passar elementos da estrutura para funes.
Caso os elementos da estrutura sejam variveis de um dos tipos j vistos, a
passagem efetuada da maneira normal. O exemplo 10.4 mostra como passar
um elemento ( .raio) de uma estrutura para uma funo.
A funo que recebe este parmetro est preparada para receber uma varivel
de ponto flutuante simples. Caso seja necessrio passar o endereo 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 crculos 1 e 2 usaramos chamadas da seguinte forma.
tro a_x (& 1 .x , & 2 . x ) ;

Para trabalhar com endereos necessrio usar ponteiros dentro da funo


tro a_x, mas isto veremos no prximo item. Antes vamos verificar como

possvel passar uma estrutura inteira para uma funo.


Estruturas, quando passadas para funes, se comportam da mesma maneira
que as variveis dos tipos que j estudamos. Ao passar uma estrutura para uma
funo estaremos passando os valores armazenados nos membros da estrutura.
Como este tipo de passagem feito por valor, alteraes nos membros da estrutura no modificam os valores da estrutura na funo que chamou. A passagem
de estruturas para funes ilustrada no exemplo 10.5 onde o comprimento da
reta que liga dois pontos p1 e p2 calculado e impresso.
Para ilustrar a passagem de vetores de estruturas para funes considere o
programa 10.3. Neste programa iremos substituir o trecho que ordena o vetor de
alunos por uma funo, cujo cdigo mostrado na listagem 10.6. No programa
o trecho que chama a funo tem a seguinte forma
Ordena(turma, 4);

10.6 Ponteiros para Estruturas


Para definir ponteiros para estruturas a declarao similar a declarao de um
ponteiro normal. O exemplo abaixo mostra a definio de um ponteiro chamado
maria para uma estrutura chamada aluno.

stru t aluno {
har nome [40;
172

Listagem 10.3: Ordenao de Estruturas.

#in lude
#in lude

< stdio .h >


< string .h >

typedef stru t _ALUNO {


har nome [40;
f l o a t n1 , n2 , media ;

} ALUNO ;

int

main ( void ) {
ALUNO turma [4 , temp ;
int jaOrdenados = 0 , foraOrdem , i ;

for

do

( i = 0; i < 4; i ++) {
gets ( turma [ i . nome ) ;
s anf ( " % f " , & turma [ i . n1 ) ;
do {} while ( get har () != '\ n ') ;
s anf ( " % f " , & turma [ i . n2 ) ;
do {} while ( get har () != '\ n ') ;
turma [ i . media =( turma [ i . n1 + turma [ i . n2 ) /2.0;
{

foraOrdem = 0;
for ( 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 ) ;
for ( 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;

173

Listagem 10.4: Passando elementos para funes.

#in lude < stdio .h >


typedef stru t _CIRCULO
f l o a t x , y , raio ;

} CIRCULO ;

float
}

int

Area ( f l o a t r ) {
3.141516 * r * r ;

return

main ( void ) {
CIRCULO ;
. x = . y = . raio = 1.0;
printf ( " % f \ n " , Area ( . raio ) ) ;
return 0;

Listagem 10.5: Passagem de estruturas para funes.

#in lude < stdio .h >


#in lude < math .h >
typedef stru t _PONTO
float x, y;

} PONTO ;
f l o a t omp ( PONTO p1 , PONTO p2 ) {
return sqrt ( pow ( p2 .x - p1 .x ,2) + pow ( p2 .y - p1 .y ,2) ) ;
}
int main ( void ) {
PONTO p1 , p2 ;

puts ( " Coordenadas do ponto 1 " ) ;


printf ( " x1 = ? " ) ; s anf ( " % f " , & p1 . x ) ;
printf ( " y1 = ? " ) ; s anf ( " % f " , & p1 . y ) ;
puts ( " Coordenadas do ponto 2 " ) ;
printf ( " x2 = ? " ) ; s anf ( " % f " , & p2 . x ) ;
printf ( " y2 = ? " ) ; s anf ( " % f " , & p2 . y ) ;
printf ( " \ nComprimento da reta = % f \ n " , omp ( p1 , p2 ) ) ;
return 0;

174

Listagem 10.6: Funo que ordena estruturas.

void

Ordena ( ALUNO turma [ , int tam ) {


int i , foraOrdem , jaOrdenados = 0;
ALUNO temp ;
do {
foraOrdem = 0;
for ( 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 ) ;

int ano_entrada ;
f l o a t n1 , n2 , media ;

} * maria ;

Ponteiros so uteis quando passamos estruturas para funes. Ao passar


apenas o ponteiro para estrutura economizamos tempo e memria. O espao
de memria, economizado por que se evita passar os dados que compem a
estrutura um por um. O tempo economizado porque no necessrio gastar o
tempo de empilhar e desempilhar todos os elementos da estrutura no processo
de passagem para a funo. Empilhar e desempilhar se referem a pilha de dados
usada para transferir os dados entre funes.
Para acessar elementos da estrutura apontada por um ponteiro usa-se o
chamado operador seta (->). Por exemplo para imprimir a mdia da aluna
maria usaramos o comando
printf ( " A media vale %.1 f " , maria - > media ) ;

Para alocar espao para estruturas apontadas por ponteiros necessrio usar
o operador unrio sizeof, isto porque o tamanho de uma estrutura sempre
igual ou maior que a soma dos tamanhos dos seu componentes. Para explicar
esta fato devemos considerar como os dados so armazenados na memria dos
computadores.
Algumas arquiteturas de computadores endeream os dados na memria por
bytes, isto cada endereo de memria se refere a um byte. No entanto, estas
arquiteturas lem sempre uma palavra inteira da memria. Usualmente, palavras podem ser compostas de dois bytes e comeam em endereos pares, como
est mostrado na figura abaixo. Sabemos que existem variveis que ocupam
mais de um byte, por exemplo inteiros que so compostos de dois bytes.
175

Imagine ento uma estrutura composta de um caractere (1 byte) e um nmero inteiro (4 bytes). Caso a memria do computador fosse organizada em
palavras de 32 bits ou 4 bytes, e os dados fosse alocados sequencialmente byte a
byte, a estrutura acima ocuparia 5 bytes ou duas palavras, conforme esta mostrado na Figura 10.1a. Para ler o nmero inteiro o programa deveria ler duas
palavras. Para facilitar o acesso s variveis, alguns compiladores armazenam as
variveis de acordo com o que est indicado na Figura 10.1b. Observar que agora
a estrutura ocupa oito bytes e trs so perdidos. Neste caso o acesso ao nmero
inteiro ser sempre feito em um passo e portanto ganhou-se em tempo de acesso
ao custo de gasto de memria. Este uma troca constante em computao.
0

char int

int

int

int

char

int

12

12

16

16

(a) Mapa de memria om


ara ter e inteiro e onomizando espao.

int

int

int

(b) Mapa de memria om


ara ter e inteiro e onomizando tempo.

Vimos ento que embora o total de bytes dos elementos da estrutura fosse
trs o compilador pode armazenar a estrutura em quatro bytes, da a necessidade
de sempre usar o operador sizeof quando alocar espao.
O programa 10.7 mostra como alocar espao para uma varivel simples e
como usar esta varivel em diversos tipos de comandos.
O programa 10.8 mostra como utilizar ponteiros para vetores de estruturas
e a forma mais segura de alocar espao para os dados. Observar as notaes
usadas na funo que l os dados dos funcionrios. Notar que ( adastro+i)
->salario o valor da salrio.
fgets (( adastro + i ) -> nome , 39 , stdin ) ;
ss anf ( linha , " % f " , &(( adastro + i ) -> salario ) ) ;

176

Listagem 10.7: Alocao de espao para estruturas.

#in lude < stdio .h >


#in lude < string .h >
#in lude < stdlib .h >
typedef stru t _ALUNO {
har nome [40;
f l o a t n1 , n2 , media ;
} ALUNO ;

int

main ( void ) {
ALUNO * maria ;
maria = ( ALUNO *) mallo ( s i z e o f ( ALUNO ) ) ;
i f (! maria ) exit (1) ;
gets ( maria - > nome ) ;
s anf ( " % 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;

Exer ios
10.1: Considere que uma empresa precisa armazenar os seguintes dados de um
cliente:
Nome completo com no mximo 50 caracteres;
renda mensal do do cliente;
ano de nascimento;
possui ou no carro.
Defina um tipo e uma estrutura para armazenarem estes dados e escreva um
programa que leia estes dados armazene-os em uma varivel e em seguida os
imprima.
10.2: Considerando a mesma estrutura do exerccio anterior, escreva um programa que leia os dados de 100 clientes e imprima:
quantos clientes tm renda mensal acima da mdia;
quantos clientes tm carro;
quantos clientes nasceram entre 1960 (inclusive) e 1980 (exclusive).

177

Listagem 10.8: Alocao de espao para vetores de estruturas.

#in lude < stdio .h >


#in lude < stdlib .h >
typedef stru t _fun
har nome [40;
f l o a t salario ;

} Tfun ;

void

le ( Tfun * adastro , int fun ionarios ) {


int i ;
har linha [40;
for ( i =0; i < fun ionarios ; i ++) {
puts ( " Nome ? " );
fgets (( adastro + i ) -> nome , 39 , stdin ) ;
puts ( " Salario ? " ) ; fgets ( linha , 39 , stdin ) ;
ss anf ( linha , " % f " , &(( adastro + i ) -> salario ) ) ;
}

float

media ( Tfun * adastro ,

f l o a t media =0.0;
int i ;
for
}

int

int

fun ionarios ) {

( i =0; i < fun ionarios ; i ++) {


media += ( adastro + i ) -> salario ;

return

media /= fun ionarios ;

main ( void ) {
Tfun * adastro ;
int fun ionarios ;
har linha [40;
puts ( " Quantos fun ionarios ? " ) ; fgets ( linha , 39 , stdin )
;
ss anf ( linha , " % d " , & fun ionarios ) ;

if

(!( adastro = ( Tfun *) mallo ( fun ionarios *


s i z e o f ( Tfun ) ) ) ) {
exit (1) ;

}
le ( adastro , fun ionarios ) ;
printf ( " Salario medio = %.2 f \ n " ,
media ( adastro , fun ionarios ) ) ;
return 0;

178

Listagem 10.9: Listagem do exercicio 3.

int

main ( void ) {
stru t aluno turma [ MAX ;
le ( turma ) ;
puts ( " Imprimindo dados lidos da turma . " ) ;
puts ( " Digite qualquer oisa para ontinuar . " ) ;
get har () ;
imprime ( turma ) ;

ordena_medias ( turma ) ;
puts ( " Imprimindo dados ordenados da turma . " ) ;
puts ( " Digite qualquer oisa para ontinuar . " ) ;
get har () ;
imprime ( turma ) ;
get har () ;

10.3: Reescreva o programa 10.3 empregando funes para implementar as


diversas tarefas do programa. A funo main deve ficar da maneira indicada na
Listagem 10.9.
10.4: Escrever um programa que utilize stru ts e ponteiro para stru t e imprima o contedo das variveis da stru t.
10.5: Escrever um programa que utilize enumeradores com as matrias do seu
perodo. Inicialize cada matria com um numero. Depois imprime os valores
das variveis enumeradas.
10.6: Escrever um programa que utilize union. Inicialize as variveis com
valores diferentes e imprima o contedo delas.
10.7: Fazer um programa que simule as operaes de uma pilha push e pop,
usando stru ts. 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 informaes num vetor de uma estrutura que contem esses dados (nome e
telefone). O programa deve ter trs opes apenas: uma que adiciona um novo
dado, outra que lista todos os dados atualmente armazenados na memria e
outra que sai do programa. Esse vetor de estrutura deve ter apenas 10 elementos
e fornecer uma mensagem de erro caso o usurio tente adicionar mais pessoas
que este mximo permitido.
179

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 funes str py e str at para strings nesse formato.
10.10: Escreva um programa fazendo o uso de estruturas. Voc dever criar
uma estrutura chamada Ponto, contendo apenas a posio x e y (inteiros) do
ponto. Declare 2 pontos, leia a posio (coordenadas x e y) de cada um e calcule
a distncia entre eles. Apresente no final a distncia entre os dois pontos.
10.11: Crie uma estrutura chamada retngulo, que possua duas estruturas
ponto (o ponto superior esquerdo e o ponto inferior direito). Faa um programa
que receba as informaes acerca de um retngulo (as coordenadas dos dois
pontos), e informe a rea, o comprimento da diagonal e o comprimento de cada
aresta
10.12: Escreva um programa que use as mesmas estruturas do exerccio anterior
para descobrir se um ponto est dentro de um retngulo.
10.13: Considere que foi definida a seguinte estrutura:

typedef stru t _fra {


int numerador , denominador ;

} FRACAO ;

Escreva um programa em C que calcule as quatro operaes usando fraes


definidas com estruturas do tipo FRACAO. O programa deve ler duas fraes e
imprimir o resultado de cada uma das quatro operaes.

180

Captulo 11

Entrada e Sada por Arquivos


11.1 Introduo
Em C no existem instrues especiais de entrada e sada como em outras linguagens de programao. Estas tarefas, em C so executadas por funes especialmente criadas para esta finalidade e armazenadas em bibliotecas especficas.
Por esta razo todos programas em C que precisam de entrada e/ou sada de
dados necessitam incluir a diretiva #in lude<stdio.h> no incio do programa,
para permitir o uso da biblioteca padro stdio de funes de entrada e sada.

11.2 Fluxos de Dados


Para isolar os programadores dos problemas de manipular os vrios tipos de
dispositivos de armazenamento e seus diferentes formatos a linguagem C utiliza
o conceito de fluxo de dados (stream). Todos os diferentes sistemas de arquivos
se comportam da mesma maneira que foi definida como semelhante a um fluxo
contnuo de dados (stream). Dados podem ser manipulados em dois diferentes
tipos de fluxos: fluxos de texto e fluxos binrios.

11.2.1 Fluxos de Texto


Um fluxo de texto (text stream) composto por uma seqncia de caracteres,
que pode ou no ser dividida em linhas terminadas por um caractere de final de
linha. Um detalhe que deve ser considerado ao escrever um programa que na
ltima linha no obrigatrio o caractere de fim de linha.
Nem sempre a traduo entre a representao do caractere no fluxo de texto
e no sistema de arquivos do computador hospedeiro um para um byte. Por
exemplo, entre UNIX e DOS h uma diferena na representao de final de
linha (linefeed ) que causa problemas na impresso de arquivos. Em UNIX um
final de linha representado pelo caractere de alimentao de linha (LF). Em
DOS um final de linha representado pelo par retorno de carro/alimentao de
linha (CR/LF). Deste modo quando um arquivo gerado em UNIX vai para uma
181

impressora que espera final de linha no modo DOS surge o que comumente
chamado de efeito escada. A impresso continua na linha seguinte mas sem
voltar para o incio da linha porque em UNIX o caractere de retorno de carro
no inserido no fluxo de texto.
At agora temos trabalhado com os fluxos de dados padro: stdin, para
entrada de dados e stdout para sada de dados. Ao iniciar todo programa em
C automaticamente associado a estes dois fluxos de dados sem necessitar de
nenhuma interveno do programador. A definio de que perifricos estaro
associados a estes fluxos depende do sistema operacional. Normalmente o fluxo
de entrada (stdin) est associado ao teclado e o fluxo de sada (stdout) ao
monitor.

11.2.2 Fluxo Binrio


Um fluxo binrio composto por uma seqncia de bytes lidos, sem traduo,
diretamente do dispositivo externo. Existe uma correspondncia um para um
entre os dados do dispositivo e os que esto no fluxo que o programa manipula.
A Figura 11.1 ilustra estes dois tipos de fluxos. No fluxo de texto os dados so
armazenados como caracteres sem converso para representao binria. Cada
um dos caracteres ocupa um byte. O numero 12 ocupa dois bytes e o nmero
113 ocupa 3. Um caractere em branco foi inserido entre cada um dos nmeros
para separ-los, de modo que a funo de entrada e sada possa descobrir que
so dois nmeros inteiros (12 e 113) e no o nmero 12113.
No fluxo binrio cada nmero inteiro ocupa 32 bits e armazenado na forma
binria. Os caracteres do exemplo esto armazenados seguindo a tabela ASCII.
Observe que, em arquivos binrios, no h necessidade de separar os nmeros
j que eles sempre ocupam 32 bits.
fluxo de texto
1 2 b 1 1 3 b a b

fluxo binrio
000...01100

32 bits
12

000...01110001 01100001 01100010

32 bits
113

8 bits 8 bits
a
b

Figura 11.1: Fluxos de dados.

11.2.3 Arquivos
Um arquivo pode estar associado qualquer dispositivo de entrada e sada
como, por exemplo: impressora, teclado, disquete, disco rgido etc. No entanto,
os programas vem os arquivos atravs de fluxos. Para que um determinado
182

arquivo em um perifrico seja associado a um fluxo necessrio que o arquivo


seja aberto e somente aps esta operao, o programa pode manipular os
dados. Normalmente a interao entre o programa e os arquivos feita por
meio de buffers que intermediam a transferncia dos dados entre os programas
e os perifricos. Isto serve para facilitar a operao do sistema operacional.
Operaes comuns em arquivos so:
abertura e fechamento de arquivos;
remover um arquivo;
leitura e escrita de um caractere ou byte;
procurar saber se o fim do arquivo foi atingido;
posicionar o arquivo em um ponto determinado.
Obviamente algumas dessas funes no se aplicam a todos os tipos de dispositivos. Por exemplo, para uma impressora pode no ser possvel usar a
funo que reposiciona o arquivo no incio. Um arquivo em disco permite acesso
aleatrio enquanto um teclado no.
Ao final das operaes nos arquivos o programa deve fech-los. Caso o
programador esquea de executar esta operao, ao final do programa todos os
arquivos associados so fechados automaticamente e os contedos dos buffers
so descarregados para o dispositivo externo. Caso o arquivo seja de entrada o
contedo do buffer esvaziado.

11.3 Funes de Entrada e Sada


As funes de Entrada e Sada normalmente utilizadas pelos programadores
esto armazenadas na biblioteca stdio.h. As funes mais comuns esto mostradas na tabela 11.1.
Para ter acesso aos dados em um arquivo necessrio a definio de um
ponteiro do tipo especial FILE. Este tipo tambm est definido na biblioteca
stdio.h. Um ponteiro deste tipo permite que o programa tenha acesso a uma
estrutura que armazena informaes importantes sobre o arquivo. Para definir
uma varivel deste tipo o programa deve conter a seguinte declarao
FILE *arq;

onde arq o ponteiro que ser usado para executar as operaes no arquivo.

11.4 In io e Fim
As operaes mostradas a seguir mostram operaes que devem ser realizadas
antes e depois de usar um arquivo (fopen() e f lose()). As outras duas funes
servem para que o usurio possa detectar o fim de um arquivo ou voltar para
seu incio.
183

Funo
fopen()
f lose()
fput ()
get (), fget ()
fprintf()
ss anf()
fs anf()
fseek()
rewind()
feof()
ferror()
fflush()
fread()
fwrite()

Descrio
Abre um arquivo
Fecha um arquivo
Escreve um caractere em um arquivo
L um caractere de um arquivo
Equivalente a printf()
Equivalente a s anf(). L de uma cadeia de caracteres
Equivalente a s anf()
Posiciona o arquivo em um ponto especfico
Posiciona o arquivo no incio
Retorna verdade se chegou ao fim do arquivo
Verifica a ocorrncia de um erro
Descarrega o buffer associado ao arquivo
Leitura de dados no modo binrio
Escrita de dados no modo binrio

Tabela 11.1: Exemplos de funes de Entrada e Sada.

11.4.1 Abrindo um Arquivo


Antes de qualquer operao ser executada com o arquivo, ele deve ser aberto.
Esta operao associa um fluxo de dados a um arquivo. Um arquivo pode ser
aberto de diversas maneiras, de acordo com as operaes que devero ser executadas: leitura, escrita, leitura/escrita, adio de texto etc. A funo utilizada
para abrir o arquivo chamada fopen() e tem o seguinte prottipo:
FILE *fopen ( onst

har

*parq,

onst har

*modo)

onde parq um ponteiro de arquivo para o arquivo a ser manipulado e modo


um ponteiro para uma cadeia de caracteres que define a maneira como o arquivo
vai ser aberto. Este ponteiro no deve ser modificado e a funo retorna um
ponteiro nulo (NULL) se o arquivo no 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 contedo apagado.
a: Adiciona ao final de um arquivo. O arquivo criado caso ele no exista.
r+: Abre um arquivo para leitura e escrita. O arquivo deve existir ou um
erro ocorre.
w+: Cria um arquivo vazio para leitura e escrita. Se um arquivo com o
mesmo nome existe o contedo apagado.
a+: Abre um arquivo para leitura e adio. Todas as operaes de escrita so
feitas no final do arquivo. possvel reposicionar o ponteiro do arquivo
para qualquer lugar em leituras, mas as escritas movero o ponteiro para
o final do arquivo. O arquivo criado caso no exista.
184

Observar que se um arquivo for aberto com permisso de escrita todo o seu
contedo anterior ser apagado. Caso o arquivo no exista ele ser criado.
O trecho de programa abaixo ilustra os passos necessrios para abrir um
arquivo para escrita. Primeiro declarado o ponteiro pa para o arquivo. Em
seguida a funo fopen chamada para associar o nome externo do programa
(arquivo.txt) no modo escrita ao ponteiro pa. Um teste para ponteiro nulo
feito para verificar se ocorreu algum problema com a operao de abertura do
arquivo.

FILE * pa ; /* de lara ao do ponteiro para arquivo */


/* nome externo asso iado ao interno */
pa = fopen ( " arquivo . txt " , " w " ) ;
i f ( pa == NULL ) { /* verifi a erro na abertura */
printf ( " Arquivo nao pode ser aberto . " ) ;
return 1;
}

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

11.4.2 Fe hando um Arquivo


Um arquivo aberto por meio da funo fopen() deve ser fechado com a funo
f lose() cujo prottipo

int

f lose (FILE *parq);

onde parq um ponteiro de arquivo para o arquivo que deve ser fechado. Todos
os buffers internos associados com o fluxo de dados do arquivo so descarregados. O contedo de qualquer buffer no escrito escrito e dados no lidos
de buffers so perdidos. Este ponto importante de ser considerado porque
em muitos sistemas operacionais uma operao de escrita em um arquivo no
ocorre imediatamente a emisso da ordem de escrita. O sistema operacional
pode executar a ordem no momento que achar mais conveniente. Um valor zero
de retorno significa que a operao foi executada com xito, qualquer outro valor
implica em erro.

11.4.3 Fim de Arquivo


A funo feof() indica que um arquivo chegou ao seu final. A pergunta que
pode surgir a seguinte - Se j existe o valor EOF para indicar o final de arquivo,
por que precisamos de uma funo extra do tipo feof()? O problema que EOF
um valor inteiro e ao ler arquivos binrios este valor pode ser lido como parte
do arquivo e no por ser o final do arquivo. A funo feof() serve para indicar
185

que o final de um arquivo binrio foi encontrado. Naturalmente esta funo


pode ser aplicada tambm a arquivos texto. O prottipo da funo o seguinte:

int

feof(FILE *parq)

Um valor diferente de zero retornado no caso de ter sido atingido o final


do arquivo. O valor zero indica que ainda no se chegou ao final do arquivo.
O exemplo 11.1 mostra um programa que l um caractere do teclado e o
mostra na tela. Neste exemplo a leitura termina quando o usurio digita o
caractere <ctl>+D, que indica final de arquivo pelo teclado em Unix (no outro
sistema <ctl>+Z).

Listagem 11.1: Uso da funo feof().

#in lude < stdio .h >


int main ( void ) {
har ;

= get har () ;
while ( != EOF ) {
put har ( ) ;
= get har () ;
}
return 0;

11.4.4 Volta ao In io
A funo rewind() recoloca o indicador de posio de arquivo no incio do arquivo. Uma operao semelhante ao que fazemos em uma fita cassete de msica
ou vdeo. O prottipo da funo o seguinte:

void

rewind(FILE *parq)

importante observar que o arquivo deve estar aberto em um modo que


permita a execuo das operaes desejadas. Por exemplo, um arquivo aberto
somente para escrita e em seguida reposicionado para o incio, no ir permitir
outra operao que no seja escrita.

11.5 Lendo e Es revendo Cara teres


As operaes mais simples em arquivos so a leitura e escrita de caracteres.
Para ler um caractere de um arquivo, que foi previamente aberto, pode-se usar
as funes get () e fget (), que so equivalentes. Os prottipos destas funes
so os seguintes:
186

int

fget (FILE *parq);

int

get (FILE *parq);

As funes get () e fget () so equivalentes e muitos compiladores implementam get () como uma macro do seguinte modo:

#dene

get (parq)fget (parq)

A funo l o caractere como um unsigned har mas retorna o valor como


um inteiro, onde o byte mais significativo vale zero. O apontador do arquivo
avana um caractere e passa a apontar para o prximo caractere a ser lido.
A funo devolve o cdigo EOF ao chegar ao final do arquivo ou caso um erro
ocorra. O valor EOF tambm um inteiro vlido e portanto ao usar arquivos
binrios necessrio que a funo feof() seja utilizada para verificar o final do
arquivo. A funo ferror() pode ser usada para determinar se um erro ocorreu.
Para escrever caracteres h duas funes definidas put () e fput (). Os
prottipos das funes so os seguintes:

int

put (int h, FILE *parq);

int

fput (int h, FILE *parq)

onde parq um ponteiro de arquivo para o arquivo que foi previamente aberto
por meio da funo fopen() e h 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 escrito no arquivo. O prximo passo a leitura do arquivo que iniciada aps uma chamada
a funo rewind(), fazendo com que o indicador de posio do arquivo volte a
apontar para seu incio.
Uma outra alternativa mostrada em 11.3 mostra um exemplo onde o arquivo criado para escrita em seguida fechado e reaberto para leitura ficando
automaticamente posicionado no incio para a leitura.

11.6 Testando Erros


A funo ferror(FILE *parq) serve para verificar se ocorreu um erro associado
ao fluxo de dados sendo usado. Um valor diferente de zero a indicao do
erro, que ocorre geralmente quando a operao previamente executada no fluxo
falhou. O parmetro parq um ponteiro para o fluxo a ser testado. O programa
11.4 abre um arquivo para leitura, mas tenta escrever um caractere o que provoca
um erro que testado pela funo ferror.

11.7 Lendo e Es revendo Cadeias de Cara teres


As funes fgets() e fputs() servem para ler e escrever cadeias de caracteres
em arquivos. Os prottipos das funes so:

int

fputs( har *str, FILE *parq);

187

Listagem 11.2: Exemplo de leitura e escrita de caracteres.

#in lude < stdio .h >


#in lude < stdlib .h >
int main ( void ) {
int ;

FILE * pa ;
* nome = " texto . txt " ;

har

/* Abre o arquivo para leitura e es rita */


i f (( pa = fopen ( nome , " w + " ) ) == NULL ) {
printf ( " \ n \ nNao foi possivel abrir o arquivo .\ n " )
;
exit (1) ;
}
/* Cada ara tere digitado sera gravado no arquivo */
= get har () ;
while (! feof ( stdin ) ) {
fput ( , pa ) ;
= get har () ;
}
rewind ( pa ) ; /* volta ao ini io do arquivo */
printf ( " \ nTerminei de es rever , agora vou ler .\ n " ) ;
= fget ( pa ) ;
while (! feof ( pa ) ) {
put har ( ) ;
= fget ( pa ) ;
}
f lose ( pa ) ;
}

return

0;

188

Listagem 11.3: Exemplo de leitura e escrita de caracteres.

#in lude < stdio .h >


int main ( void )
int ;

FILE * pa ;
* nome = " texto . txt " ;

har
if

(( pa = fopen ( nome , " w " ) ) == NULL ) {


printf ( " \ n \ nErro ao abrir o arquivo - es rita .\ n "
);
return 1;

}
= get har () ;
while (! feof ( stdin ) ) {
fput ( , pa ) ;
= get har () ;
}
f lose ( pa ) ;
printf ( " \ nTerminei de es rever , agora vou ler .\ n " ) ;
i f (( pa = fopen ( nome , " r " ) ) == NULL ) {
printf ( " \ n \ nErro ao abrir o arquivo - leitura .\ n "
);
exit (1) ;
}
= fget ( pa ) ;
while (! feof ( pa ) ) {
put har ( ) ;
= fget ( pa ) ;
}
f lose ( pa ) ;
return 0;

189

Listagem 11.4: Uso da funo ferror().

#in lude
int main

< stdio .h >


( void ) {
FILE * pArq ;
pArq = fopen ( " MeusDados . txt " ," r " ) ;

if
}

( pArq == NULL ) {
printf ( " Erro abrindo arquivo . " );
return 1;

else

}
}

{
fput ( 'x ' , pArq ) ;
i f ( ferror ( pArq ) ) {
printf ( " Erro es revendo arquivo \ n " ) ;
f lose ( pArq ) ;
return 1;
}

return

0;

int

fgets( har *str,

int

omp, FILE *parq);

A funo fputs() escreve a cadeia de caracteres apontada por str no fluxo


apontado por parq. O cdigo nulo ao final da cadeia no copiado para o fluxo.
O cdigo correspondente EOF ser retornado se ocorrer um erro e um valor no
negativo em caso de sucesso.
A funo fgets() l uma cadeia de caracteres do fluxo especificado por parq
at que um caractere de nova linha seja encontrado ou omp-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 final. O ponteiro str retornado
caso a leitura ocorra sem erro. No caso de erro o ponteiro str recebe o valor
NULL. Se o fim do arquivo for encontrado e nenhum caractere foi lido, o contedo
de str mantido e um NULL retornado. O exemplo 11.5 mostra um exemplo
de uso destas funes para ler e escrever cadeias de caracteres em um arquivo.

11.8 Entrada e Sada Formatada


As funes fprintf() e fs anf() so equivalentes as funes printf() e s anf
() usadas at agora, sendo a nica modificao o fato de que elas trabalham com
fluxos de dados (arquivos). Os prottipos das duas funes so os seguintes:

int fprintf(FILE *parq, onst har *formata ao, ...);


int fs anf(FILE *parq, onst har *formata ao, ...);

190

Listagem 11.5: Exemplo de leitura e escrita de cadeias de caracteres.

#in lude < stdio .h >


#define MAX 80
int main ( void ) {
har linha [ MAX ;

FILE * pa ;
* nome = " texto . txt " ;

har
if

(( 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 ini io do arquivo */
printf ( " \ nTerminei de es rever , agora vou ler .\ n \ n " );
fgets ( linha , MAX , pa ) ;
while (! feof ( pa ) ) {
puts ( linha ) ;
fgets ( linha , MAX , pa ) ;
}
f lose ( pa ) ;
return 0;

191

onde parq um ponteiro de arquivo recebido aps uma chamada a fopen().


Em leituras, a funo retorna o nmero de itens lidos com sucesso. Esta
contagem pode igualar o nmero 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 retornado.
Em escritas, caso a operao de escrita tenha sucesso, o nmero total de
caracteres escrito retornado. Um nmero negativo retornado em caso de
falha.
Embora estas duas funes, por sua semelhana com printf() e s anf()
, sejam maneiras convenientes de escrever e ler dados de arquivos, elas tm a
desvantagem de serem mais lentas do que uso de arquivos binrios. A perda
de tempo devido ao fato dos dados serem gravados em ASCII, o que obriga
a uma converso dos dados a cada operao realizada. Em alguns casos o fato
dos dados serem gravados em ASCII pode ser considerado um vantagem que se
sobrepe a desvantagem da reduo de velocidade. Dados gravados em ASCII
podem ser facilmente verificados pelos usurios, o que no acontece com dados
em binrio. O exemplo 11.6 mostra o uso destas funes para ler e escrever
vrios tipos de dados em um arquivo.

Listagem 11.6: Exemplo de leitura e escrita de dados formatados.

#in lude < stdio .h >


int main ( void ) {
har palavra [20;
int i ; f l o a t f ;
FILE * pa ;

har * nome
i f (( pa =

= " format . txt " ;


fopen ( nome , " w + " ) ) == NULL ) {
printf ( " \ n \ nNao foi possivel abrir o arquivo .\ n " )
;
return 1;

}
puts ( " Entre om uma palavra . " ) ; s anf ( " % s " , palavra )
;
puts ( " Entre om um numero inteiro . " ) ; s anf ( " % d " , & i )
;
puts ( " Entre om um numero flutuante . " ) ; s anf ( " % f " , &
f);
/* Es reve os dados no arquivo */
fprintf ( pa , " % s % d % f " , palavra , i , f ) ;
rewind ( pa ) ; /* volta ao ini io do arquivo */
printf ( " \ nTerminei de es rever , agora vou ler .\ n " ) ;
fs anf ( 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 ) ;
f lose ( pa ) ;
return 0;

192

11.9 Lendo e Es revendo Arquivos Binrios


As funes fread e fwrite so empregadas para leitura e escrita de dados em
modo binrio. Os prottipos das funes so:
size_t fread (void *ptr, size_t size, size_t nmemb, FILE *parq);
size_t fwrite( onst void *ptr, size_t size, size_t nmemb, FILE *parq);

A funo fread l nmemb objetos, cada um com size bytes de comprimento,


do fluxo apontado por stream e os coloca na localizao apontada por ptr. A
funo retorna o nmero de itens que foram lidos com sucesso. Caso ocorra um
erro, ou o fim do arquivo foi atingido o valor de retorno menor do que nmemb
ou zero. Esta funo no distingue entre um fim de arquivo e erro, portanto
aconselhvel o uso de feof() ou ferror() para determinar que erro ocorreu.
A funo fwrite escreve nmemb elementos de dados, cada um com size bytes
de comprimento, para o fluxo apontado por stream obtendo-os da localizao
apontada por ptr. fwrite retorna o nmero de itens que foram lidos com sucesso.
Caso ocorra um erro, ou o fim do arquivo foi atingido o valor de retorno menor
do que nmemb ou zero. O programa 11.7 ilustra como podemos escrever e ler
dados binrios de diferentes tipos em arquivos. Como um dos parmetros da
funo o nmero de bytes do dado a ser lido, recomendado o uso de sizeof.

Listagem 11.7: Exemplo de leitura e escrita na forma binria.

#in lude < stdio .h >


int main ( void ) {
int inum =10; f l o a t fnum =2.5;
double pi =3.141516; har = 'Z ';
FILE * pa ; har * nome = " texto . bin " ;
if

(( pa = fopen ( nome , " w + " ) ) == NULL ) {


perror ( " fopen : " ) ;
return 1;

}
fwrite (& inum , s i z e o f ( int ) , 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 (& , s i z e o f ( har ) , 1 , pa ) ;
rewind ( pa ) ;
fread (& inum , s i z e o f ( int ) , 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 (& , s i z e o f ( har ) , 1 , pa ) ;
printf ( " %d , %f , %f , % \ n " , inum , fnum , pi , ) ;
f lose ( pa ) ;
return 0;

Uma das principais aplicaes destas funes a leitura e escrita de estruturas criadas pelos usurios. A gravao em binrio da estrutura permite que o
193

programador ao escrever ou ler do arquivo se preocupe somente com a estrutura


como um todo e no com cada elemento que a compe. O programa 11.8 mostra
um exemplo onde estruturas so gravadas e lidas de um arquivo. Neste exemplo
usado um lao para gravar uma estrutura de cada vez. No entanto, tambm
possvel gravar todas as estruturas de uma vez mudando o terceiro parmetro
da funo fwrite(). O lao seria substitudo por
fwrite( &turma[i,

sizeof (stru t

pessoa), MAX, pa);

Para testar erro basta verificar o valor retornado pela funo. Caso ela tenha
retornado um valor diferente de MAX ocorreu um erro.

194

Listagem 11.8: Exemplo de leitura e escrita de estruturas.

#in lude < stdio .h >


#in lude < string .h >
typedef stru t _PESSOA {
har nome [40; int ano ;
} PESSOA ;

int

main () {
FILE * pa ;
har nome [40 , linha [80;
PESSOA turma [4 , ba k [4;
int i ;
for ( 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 ) ;
ss anf ( 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;
}
for ( i =0; i <4; i ++) {
i f ( fwrite ( & turma [ i , s i z e o f ( PESSOA ) , 1 , pa ) !=
1)
puts ( " Erro na es rita . " ) ;
}
rewind ( pa ) ;
for ( i =0; i <4; i ++) {
i f ( fread ( & ba k [ i , s i z e o f ( PESSOA ) , 1 , pa ) !=
1) {
i f ( feof ( pa ) ) break ;
puts ( " Erro na leitura . " ) ;
}
}
for ( i =0; i <4; i ++) {
printf ( " Nome = % s \ n " , ba k [ i . nome ) ;
printf ( " Ano = % d \ n \ n " , ba k [ i . ano ) ;
}
return 0;

195

Exer ios
11.1: Escreva um programa que abra um arquivo texto e conte o nmero de
caracteres presentes nele. Imprima o nmero de caracteres na tela.
11.2: Considere um arquivo de dados do tipo texto com o seguinte contedo:
3
ZE SA
8.5
10.0
ANTONIO SANTOS
7.5
8.5
SEBASTIAO OLIVEIRA
5.0
6.0
O arquivo acima um exemplo. Considere ento que nestes arquivos a
primeira linha contm o nmero de alunos no arquivo. As linhas seguintes
contm os seguintes dados:
nome do aluno com no mximo 50 caracteres;
nota da primeira prova;
nota da segunda prova.
Escreva um programa que imprima os nomes de todos os alunos que tm a mdia
das duas notas menor que 7.0
11.3: Escreva um programa que grave os dados lidos no exerccio anterior em
um arquivo do tipo binrio de acesso aleatrio. O nmero que indica quantos
alunos devem ser lidos (primeira linha do arquivo) no deve ser gravado no
arquivo binrio. Nesta questo o programa deve obrigatoriamente usar um
vetor de estruturas do seguinte tipo:

typedef stru t _ALUNO


har 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 usurio, um conjunto de nmeros reais e armazena em um vetor. O tamanho mximo do vetor e dado pela constante TAM_MAX. A quantidade de nmeros
no arquivo varia entre 0 e TAM_MAX. O programa ao final calcula a media dos
nmeros lidos.
11.5: Faa um programa que leia 10 caracteres e armazene em um arquivo 10
cpias de cada um. Exiba o contedo
196

11.6: Crie uma funo que receba duas strings como parmetros, uma com um
endereo de arquivo e outra com um texto qualquer, e adicione o texto no fim
do arquivo.
11.7: Utilizando a funo do exerccio anterior faa um programa que gere 10
arquivos com o nome "Teste"e extenses "01", ..., "10". Cada um contendo o
texto "Texto do arquivo [NMERO DO ARQUIVO]".
11.8: Escreva um programa para armazenar o telefone de 5 amigos. O programa
deve obrigatoriamente usar a estrutura

typedef stru t _PESSOA {


har nome [50;
int idade ;
f l o a t altura ;
har telefone [10;
} PESSOA ;

a ser preenchida pelo usurio antes do armazenamento de cada registro.


11.9: Faa um programa que leia os dados do arquivo gerado no exerccio
anterior e salve-os num novo arquivo utilizando uma sada 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 o nome de um aluno e duas notas. Estes
dados esto separados por ponto e vrgula. Existe um ponto e vrgula ao final
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 mdia das
duas notas e se o aluno foi aprovado ou no (media 5). O formato de sada :
ze sa 10.0 8.0 9.0 aprovado
antonio silva 9.0 7.0 8.0 aprovado
11.11: Faa um programa que receba o nome de um arquivo e gere uma cpia.
11.12: Escreva um programa que compare dois arquivos especificados pelo
usurio e imprima sempre que os caracteres dos dois arquivos coincidirem. Por
exemplo:
arquivo1.c
Ol, pessoal!
arquivo2.c
Oi, como vai?
Neste caso, os caracteres na primeira e dcima primeira posio so iguais
nos dois arquivos. A sada do seu programa deve ser algo como:

197

1 - O
11 - a
indicando que os primeiros caracteres dos arquivos so iguais (O) bem como o
dcimo primeiro (a)
11.13: Um arquivo do tipo texto, chamado numeros.txt contm uma quantidade desconhecida de nmeros reais. Escreva um programa que leia estes nmeros, os coloque em ordem crescente e depois os grave em um arquivo binrio
chamado numeros.bin.
Observaes:
(a) Neste exerccio a quantidade de dados gravados no arquivo do tipo
texto desconhecida, portanto, obrigatrio usar um vetor definido
com ponteiro. A definio de um vetor com um nmero constante
de elementos, mesmo que seja um nmero grande, 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 nmero de
dados armazenados no arquivo desconhecido.

Listagem 11.9: (I) Trecho de programa do problema 14.

while

(1)
fs anf (p , " % d " , & i ) ;
i f ( feof ( p ) ) break ;
printf ( " % d \ n " , i ) ;

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


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

while

Qual das opes abaixo verdadeira?


(a)
(b)
(c)
(d)

Somente o trecho I funciona.


Somente o trecho II funciona.
Os dois trechos funcionam.
Nenhum dos dois trechos funcionam.

198

Captulo 12

Problemas Extras
1a Problema:

Ser que Zeno hega l?


Zeno estava perdido em uma regio desrtica da Terra Mdia, ao norte de
Nrnia e a leste do famoso Castelo de Hogwarts. A cidade mais prxima, Forks,
ficava a vrios dias de caminhada. Sedento e faminto ele j perdia as esperanas,
quando avistou, a 1000 metros de onde estava, uma fonte jorrando gua.
Zeno comeou a correr, mas chocou-se contra uma barreira mgica que
circundava a fonte. No instante em que se chocou contra a barreira ouviu a
seguinte mensagem:
Forasteiro infeliz, para chegar at a fonte voc deve ter muita pacincia e faa o seguinte: a cada 5 minutos caminhe metade da distncia que ainda falta para chegar at a fonte. Desobedea qualquer
uma destas instrues e a morte ser o seu destino.
Tarefa
A sua tarefa descobrir em quantos minutos Zeno ir chegar a uma distncia
da fonte menor do que 103 m.
Entrada
Este programa no tem entradas.
Sada
O seu programa deve imprimir em quantos minutos Zeno ir chegar na distncia desejada.
2a Problema:
Estatsti a?

199

Uma medida importante em Estatstica o desvio padro representado na


equao 12.2 por . Ele d a medida da variabilidade ou disperso de um
conjunto de dados. Alm de ser bastante til muito fcil de ser calculado.
Considere um conjunto de N nmeros S = {x0 , x1 , x2 , . . . , xN 1 } cuja mdia
vale x. Para este conjunto de dados o desvio padro pode ser calculado pela
equao 12.2.

PN 1

xi
N
v
u N 1
u1 X
(xi x)2
= t
N i=0

i=0

(12.1)
(12.2)

Tarefa
A sua tarefa ler um conjunto de dados armazenado em um arquivo do tipo
texto, chamado estatistica.txt e calcular a mdia e depois o desvio padro
deste conjunto. Observe que o tamanho do conjunto desconhecido e s pode
ser descoberto aps a leitura de todos os dados.
Neste exerccio obrigatrio o uso de ponteiros para armazenar o
vetor.
Sada
A sada deve informar os valores obtidos para a mdia e o desvio padro.
Exemplo de Arquivo de Entrada e da sada
Arquivo estatistica.txt:
1
2
3
4
5
6
7
8
9
10

Sada na tela:
A media vale 5.500000
O desvio padrao vale 2.872281

3a Problema:

Veri ando o CPF


Definies
O CPF o nmero usado pela Receita Federal no Brasil para identificar
os Contribuintes Pessoas Fsicas. O CPF composto por 11 algarismos. Destes 11 algarismos os dois ltimos so usados para verificar se os primeiros 9
foram digitados corretamente. Eles so chamados de algarismos verificadores.
Por exemplo, considere o CPF exemplo 12345678909. Este CPF na realidade
200

123456789, os algarismos 09 servem para que os programas da Receita Federal


verifiquem se os 9 primeiros esto corretos e so gerados automaticamente pelos
computadores da Receita quando algum se inscreve. O algoritmo de gerao
dos dois ltimos algarismos descrito a seguir.
Para o primeiro dgito verificador (v1 ), o 0, no nosso exemplo, o algoritmo
o seguinte: multiplique o primeiro algarismo por 10, o segundo por 9, e assim
sucessivamente at o nono algarismo do cdigo e some todos estes resultados.
Neste exemplo teramos
soma1 = (1 10) + (2 9) + (3 8) + + (9 2)
Calcule o valor do mdulo 11 de soma1 . Se este valor for 0 ou 1 ento o algarismo
v1 0, caso contrrio o algarismo v1 o resultado da subtrao 11soma1 % 11.
Para o segundo dgito verificador (v2 ), no nosso caso o 9, o algoritmo o
seguinte: multiplique o primeiro algarismo por 11, o segundo por 10, e assim
sucessivamente at o nono algarismo do cdigo e some todos estes resultados.
Neste exemplo teramos
soma2 = (1 11) + (2 10) + (3 9) + + (9 3)
Some este resultado ao dobro do primeiro dgito verificador (soma2 = soma2 +
2 v1 ). Calcule o valor do mdulo 11 desta nova soma2 . Se este valor for 0
ou 1 ento o algarismo v2 0, caso contrrio o algarismo v2 o resultado da
subtrao 11 soma2 % 11.
Tarefa
O programa mostrado na listagem 12.1 faz a verificao de um CPF fornecido
pelo usurio. Complete as partes que faltam do programa. Observe que o
CPF lido como um vetor de caracteres. Um exemplo de interao do
programa com um usurio o seguinte:
Entre com o cpf.
12345678909
CPF lido: 12345678909
CPF valido.
4a Problema:
Mais perto, mais longe

Tarefa
Z S est planejando a sua prxima viagem por Pindorama. No momento
ele gostaria de saber qual so as cidades mais distante e as mais perto da sua.
Para fazer estes clculos ele dispe de um arquivo com as coordenadas de sua
cidade e das vrias cidades que ele ir visitar
Entrada
A entrada ser feita a partir de um arquivo texto chamado cidades.txt.
A primeira linha deste arquivo um nmero inteiro n dizendo quantas cidades
h no arquivo. Considere que o nmero mximo de cidades igual a 50. As n
201

Listagem 12.1: Processando o CPF.

#in lude
#in lude
#in lude
#define
#define
#define
int
int
int
int
int

< stdio .h >


< stdlib .h >
< string .h >
TAMCPF 11
CERTO 1
ERRADO 0

pfs ( har *) ;
verifi aCPF ( har *) ;
digito1 ( har *) ;
digito2 ( har * , int ) ;
leCPF ( har *) ;

int main ( int arg , har


har pfs [ TAMCPF +1;
int tam ;

* argv [) {

tam = leCPF ( pfs ) ;


i f ( tam != TAMCPF ) {
puts ( " CPF deve ter 11 digitos . " ) ;
return 1;
}
else {
i f ( verifi aCPF ( pfs ) ) {
puts ( " CPF valido . " ) ;
return 0;
}
else {
puts ( " CPF invalido . " ) ;
return 1;
}
}
return 0;

int

leCPF ( har * pfs ) {


puts ( " Entre om o pf . " ) ;
fgets ( pfs , TAMCPF +2 , stdin ) ;
pfs [ strlen ( pfs ) -1 = ' \0 ';
printf ( " CPF lido : % s \ n " , pfs ) ;
return strlen ( pfs ) ;

int

int

int

verifi aCPF ( har * pfs ) {


int dig1 , dig2 ;
dig1 = digito1 ( pfs ) ;
dig2 = digito2 ( pfs , dig1 ) ;
/* AQUI FALTA O FINAL */
digito1 ( har * pfs ) {
/* AQUI FALTA TODA A FUNCAO

*/

digito2 ( har * pfs , int dig1 ) {


/* AQUI TAMBEM FALTA TODA A202FUNCAO */

linhas seguintes contm pares de nmeros com as coordenadas de cada uma das
cidades que Z S ir visitar. O primeiro par de coordenadas pertence a cidade
onde Z S vive.
Sada
A sada composta de trs tipos de linhas e deve ser feita no vdeo. A
primeira linha informa as coordenadas da cidade onde Z S vive. Em seguida
deve(m) vir as coordenadas da(s) cidade(s) que fica(m) mais perto da cidade
de Z S. Aps devem vir a(s) linha(s) que mostra(m) as coordenadas da(s)
cidade(s) que fica(m) mais longe da cidade de Z S. O exemplo abaixo mostra
o formato do arquivo de entrada e o formato da sada na tela.
Exemplo de entrada e sada
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:

Sada 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 Es alar

O produto escalar de dois vetores de n dimenses A = (a1 , a2 , . . . , an ) e

B = (b1 , b2 , . . . , bn ), onde (ai , bi ) dado pela equao 12.3


A B = a1 b 1 + a2 b 2 + + an b n

(12.3)

Tarefa
Escreva um programa que calcule o produto escalar de M pares de vetores,
todos em um espao de n dimenses. Neste problema no preciso saber
vetores em C.
Entrada
A entrada consiste das seguintes linhas de dados:
1. A primeira linha contm um nmero inteiro M que informa o nmero de
pares de vetores a serem lidos.
2. A segunda linha contm um nmero n que indica a dimenso de cada um
dos vetores.
3. As linhas restantes contm 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.

203

As coordenadas de cada par de vetores so fornecidas da seguinte maneira.


Primeiro so fornecidos dois nmeros a1 b1 depois a2 b2 e assim sucessivamente
at an bn .
Sada
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 sada:
32.000000
22.000000

Des onando do sorteio

H pessoas que desconfiam de tudo, como h 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 a Ultrasena, onde os jogadores devem escolher nmeros entre
1 e 60. O jogador que acertar os nmeros sorteados ganha uma frao mnima
do total que o governo arrecadou. Um jogador desconfiado acha que o sorteio
viciado e contratou voc para descobrir se isto verdade ou no.
Voc deve escrever um programa que leia os N ltimos nmeros inteiros
sorteados e conte a frequncia com que cada um dos nmeros foi sorteado.
Entrada:
Primeiro o programa deve ler o valor de N . Em seguida o programa deve
ler a lista de N nmeros inteiros entre 1 e 60.
Sada:
Imprimir a frequncia com que cada um dos nmeros apareceu. Nmeros
com frequncia zero no devem ser impressos.
Exemplos de entrada e sada:

204

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

Sada 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 sequncia de nmeros inteiros na base


10 e imprima o nmero convertido para base 2 e a maior sequncia de bits 1
que o nmero binrio contm.
Considere que o nmero na base 10 menor que 232 1.
Entrada:
A entrada contm vrios casos de teste. Cada linha de um caso de teste
contm um nmero inteiro menor que 232 1 O programa termina quando o
usurio fornecer um nmero negativo.
Sada:
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 nmero do caso de teste comeando em 1. Na segunda linha o
nmero convertido para base 2. Zeros esquerda no devem ser impressos. Na
terceira linha o seu programa deve imprimir a maior sequncia de 1s do nmero
em binrio. A quarta linha deve ser deixada em branco.
Exemplos de entrada e sada:

205

Exemplo de entrada
6
25
123456
14
-1

Sada para o exemplo de entrada


Teste 1
110
2
Teste 2
11001
2
Teste 3
11110001001000000
4
Teste 4
1110
3

8a Problema:

Cal ulando reas


Voc foi contratado para escrever um programa que calcula reas de crculos.
O programa deve imprimir se um crculo tem rea maior que a rea mdia ou
rea menor ou igual a mdia.
O seu programa deve usar a estrutura (12.2) para representar cada crculo.
Listagem 12.2: Estrutura do problema 8.

typedef stru t

_CIRCULO

int x , y , raio ;
} CIRCULO ;
Entrada
Os dados estaro organizados da seguinte maneira. Primeiro, a quantidade
N de crculos, em seguida os dados dos N crculos, na seguinte ordem: coordenada x, coordenada y, raio raio.
Obs. No possvel assumir um valor mximo para N , aloque o espao de
memria necessrio.
Sada
O programa de imprimir se um dado crculo tem rea maior que a mdia
ou rea menor ou igual a mdia. Considerando que o primeiro crculo recebe o
nmero um, o segundo o nmero 2 e assim at o crculo N , o formato de sada
o seguinte: a palavra Circulo seguida do nmero do crculo e se ele tem rea
maior ou menor ou igual.
206

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

Exemplo de Sada:
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:

Lu rando om Aes
Voc foi contratado, pela bolsa de valores de Pindorama, para escrever um
programa que imprima as aes com o melhor e o pior desempenho durante o
ano de 2325.
Entrada
A entrada ser lida de um arquivo texto com o nome de acoes.txt. O
arquivo consiste de uma srie de linhas. Em cada linha h o nome da ao
seguido pelas cotaes no dia 01 de janeiro de 2325 e no do dia 31 de dezembro
de 2325.
Nenhum nome de empresa ter mais de 20 caracteres. Observe que pode
haver mais de uma pior (melhor) ao.
Sada
A sada dever ser um arquivo do tipo texto, com o nome saida.txt. Neste
arquivo voc deve indicar a melhor ao e seu rendimento e a pior ao com sua
perda. Observe que pode haver mais de uma melhor (pior) ao.
Exemplo de Entrada:

Exemplo Sada:

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

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
nmeros reais. O tamanho mximo da matriz 10001000. O nome do arquivo
de entrada matrizin.txt. O seu programa deve calcular a soma de todos
os elementos de cada linha. Em seguida o seu programa deve descobrir qual a
maior soma e que linha tem soma igual a maior soma. O programa deve gravar
207

a maior soma e o(s) nmero(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 contm o tamanho da matriz (1 N 1000). Em seguida o arquivo
contm N N nmeros inteiros em um formato livre, ou seja quantidade de
nmeros por linha do arquivo varivel.
Sada
O arquivo de sada 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

Entrada:
4.0
1.0
0.0
2.0
1.0

Exemplo de Sada:
14.000000
1
2
3

2.0
8.0
11.0
6.0
1.0

11a Problema:

Misturando Dados
Uma tarefa muito comum em computao misturar dois vetores dados j
ordenados para criar um terceiro tambm ordenado.
A sua tarefa escrever um programa que leia os dados de dois vetores e os
misture em um terceiro.
Considere que o tamanho mximo de cada um dos dois vetores originais
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 nmeros reais. Aps estas leituras o programa l o tamanho do segundo
vetor (tam2). Finalmente, o programa l tam2 nmeros reais. Considerar que
os dados do primeiro e do segundo vetor esto em ordem crescente.
Sada
Aps misturar os dois vetores em um terceiro o programa deve imprimir os
tam1 + tam2 nmeros reais armazenados no terceiro vetor. Estes dados devem

208

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 Sada:
1.0
1.0
2.0
4.0
7.0
9.0
10.0
12.0

209

Apndi e A

Tabela ASCII
A tabela ASCII (American Standard for Information Interchange) usada por
grande parte da indstria de computadores para a troca de informaes e armazenamento de caracteres. Cada caractere representado por um cdigo de
8 bits. A Tabela A.1 mostra os cdigos para a tabela ASCII de 7 bits. Existe
uma table estendida para 8 bits que inclui os caracteres acentuados.
Para saber qual o cdigo de um caractere na base 10 junte o dgito da
primeira coluna da tabela com o dgito da primeira linha da tabela. Por exemplo,
o cdigo da letra a minscula 97 na base 10.

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

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

Tabela A.1: Conjunto de caracteres ASCII


Os caracteres de controle listados acima, servem para comunicao com perifricos e controlar a troca de dados entre computadores. Eles tm o significado
mostrado na Tabela A.2.

210

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

Descrio
Caractere nulo
Comeo de texto
Fim de transmisso
Confirmao
Volta um caractere
Passa para prxima linha
Passa para prxima pgina
Shift-out
Data line escape
Controle de dispositivo
Controle de dispositivo
Synchronous idle
Cancela
Substitui
Separador de arquivo
Separador de registro
Espao em branco

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

Descrio
Comeo de cabealho de transmisso
Fim de texto
Interroga
Sinal sonoro
Tabulao horizontal
Tabulao vertical
Passa para incio da linha
Shift-in
Controle de dispositivo
Controle de dispositivo
Negativa de confirmao
Fim de transmisso de um bloco
Fim de meio de transmisso
Escape
Separador de grupo
Separador de unidade

Tabela A.2: Conjunto de cdigos especiais ASCII e seus significados

211

Apndi e B

Palavras Reservadas
Palavras reservadas, tambm as vezes chamadas de palavra chave, servem para
propsitos especiais nas linguagens de programao. Servem para declarar tipos
de dados ou propriedades de um objeto da linguagem, indicar um comando alm
de vrias outras funes. Palavras reservadas no podem ser usadas como nomes
de variveis ou funes.
asm: Indica que cdigo escrito em assembly ser inserido junto comandos C.
auto: Modificador que define a classe de armazenamento padro.
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: Modificados de dados que impede que uma varivel seja modificada.
Esta palavra no existia nas primeiras verses da linguagem C e foi introduzida pelo comit ANSI C. Veja volatile.
continue: Comando que interrompe os comandos de repetio for , while ,
ou do...while e faz que eles passem para a prxima iterao.
default: usado dentro do comando switch para aceitar qualquer valor no
definido previamente com um comando case.
do: Comando de repetio usado em conjunto com o comando while . Pela
definio do comando o lao sempre executado pelo menos uma vez.
double: Tipo de dados usado para armazenar valores de ponto flutuante em
preciso dupla.
else: Comando que indica um bloco de comandos alternativo que deve ser executado quando a condio testada pelo comando if foi avaliada como
FALSA.
212

enum: Tipo definido pelo usurio que permite a definio de variveis que iro
aceitar somente certos valores.
extern: Modificador de dados que indica que uma varivel ir ser declarada em
outra rea do programa.
float: Tipo usado para armazenar valores de ponto flutuante.
for: Comando de repetio que contm inicializao de variveis, incremento e
sees condicionais. Em C o comando for um comando de repetio
extremamente flexvel, permitindo inmeras possibilidades.
goto: Comando que causa um pulo para uma posio do programa marcada
com um rtulo.
if: Comando de testes usado para mudar o fluxo do programa baseada em uma
deciso VERDADEIRO/FALSO.
int: Tipo de dados usado para armazenar valores inteiros.
long: Tipo de dados usado para armazenar valores inteiros com preciso maior
do que o tipo int. Nos computadores modernos o tipo long tem a mesma
preciso que o tipo int e so usados 4 bytes.
register: Especificador de classe de armazenamento que pede que, caso seja
possvel, uma varivel deve ser armazenada nos registradores do processador.
return: Comando que causa o fluxo de instrues do programa abandonar a
funo em execuo e retornar para a funo que chamou. Tambm pode
ser usado para retornar um nico valor.
short: Tipo de dados usado para armazenar valores inteiros em preciso menor
do que o tipo int. Neste tipo 2 bytes so usados para armazenar os dados.
signed: Modificador usado para indicar que uma varivel pode armazenar tanto
valores positivos como negativos.
sizeof: Operador que retorna o tamanho em bytes do item fornecido.
static: Modificador usado para significar que o compilador deve preparar o
cdigo de forma a reter o valor da varivel.
struct: Usado para combinar C variveis de tipos diferentes na mesma estrutura.
switch: Comando de desvio usado para permitir que o fluxo do programa possa
ser mudado para vrias direes diferentes. Usado em conjunto com o
comando case.
typedef: Modificador usado para criar novos nomes para tipos j existentes.
union: Palavra chave usada para permitir mltiplas variveis partilharem o
mesmo espao na memria.

213

unsigned: Modificador usado para significar que uma varivel conter somente
valores positivos.
void: Palavra usada para significar que ou a funo no retorna nada ou que
um ponteiro deve ser considerado genrico ou ser capaz de apontar para
qualquer tipo de dados.
volatile: Modificador que significa que uma varivel pode ser alterada.
while: Comando de teste que executa uma seo de cdigo enquanto uma condio retorna VERDADEIRO.
Em adio a estas as seguintes palavras so 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++ aconselhvel no us-las.

214

Refern ias Bibliogr as


[Kernighan e Ritchie 1978]KERNIGHAN, B. W.; RITCHIE, D. M. The C Programming Language. Englewood Cliffs, NJ, USA: Prentice-Hall, Inc, 1978.
[Knuth 1973]KNUTH, D. E. The Art of Computer Programming: Fundamental
Algorithms - vol. 1. Massachusetts, USA: Addison-Wesley Publishing Company, Inc, 1973.
[Oliveira 2008]OLIVEIRA, U. de. Programando em C: Fundamentos. 1. ed. Brasil: Editora Cincia Moderna, 2008.
[Schildt 1997]SCHILDT, H. C Completo e Total. So Paulo, Brasil: Makron
Books do Brasil Editora, 1997.

215