Você está na página 1de 265

Programao de Computadores I

Fbio Henrique Viduani Martinez

Faculdade de Computao UFMS

2011

S UMRIO

1 Breve histria da computao

1.1

Pr-histria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

Sculo XX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2.1

Computadores Eletromecnicos . . . . . . . . . . . . . . . . . . . . . . . .

1.2.2

Computadores Eletrnicos . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 Introduo computao

21

2.1

Contextualizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

2.2

Arquitetura de von Neumann . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

2.3

Algoritmos e programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

2.3.1

Algoritmos e resoluo de problemas . . . . . . . . . . . . . . . . . . . . .

26

2.3.2

Resoluo de problemas e abstrao . . . . . . . . . . . . . . . . . . . . . .

27

2.3.3

Algoritmos e computadores . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

3 Dicas iniciais

31

3.1

Interface do sistema operacional . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

3.2

Compilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

3.3

Emacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

4 Primeiros programas

41

4.1

Digitando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

4.2

Compilando e executando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

4.3

Olhando o primeiro programa mais de perto . . . . . . . . . . . . . . . . . . . . .

42

4.4

Prximo programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

4.5

Documentao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

4.6

Entrada e sada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

5 Estruturas condicionais

49
i

5.1

Estrutura condicional simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

5.2

Estrutura condicional composta . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

5.2.1

Aplicao: troca de contedos . . . . . . . . . . . . . . . . . . . . . . . . .

51

Reviso de nmeros inteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

5.3.1

56

5.3

Representao de nmeros inteiros . . . . . . . . . . . . . . . . . . . . . . .

6 Estrutura de repetio while

59

6.1

Motivao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

6.2

Estrutura de repetio while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

60

7 Expresses com inteiros

63

7.1

Expresses aritmticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

7.2

Expresses relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

7.3

Expresses lgicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

65

8 Outras estruturas de repetio

73

8.1

Estrutura de repetio for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

8.2

Estrutura de repetio do-while . . . . . . . . . . . . . . . . . . . . . . . . . . . .

75

9 Nmeros com ponto flutuante

79

9.1

Constantes e variveis do tipo ponto flutuante . . . . . . . . . . . . . . . . . . . .

79

9.2

Expresses aritmticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

10 Caracteres

89

10.1 Representao grfica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

10.2 Constantes e variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

91

10.3 Expresses com caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

93

11 Tipos primitivos de dados

95

11.1 Tipos inteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

11.2 Nmeros com ponto flutuante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101


11.3 Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
11.4 Converso de tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
11.5 Tipos de dados definidos pelo programador . . . . . . . . . . . . . . . . . . . . . . 108
11.6 Operador sizeof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
11.7 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
ii

12 Vetores

113

12.1 Motivao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113


12.2 Definio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
12.3 Declarao com inicializao

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

12.4 Exemplo com vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117


12.5 Macros para constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
13 Cadeias de caracteres

125

13.1 Literais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125


13.2 Vetores de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
13.3 Cadeias de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
14 Matrizes

133

14.1 Definio, declarao e uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133


14.2 Declarao e inicializao simultneas . . . . . . . . . . . . . . . . . . . . . . . . . 135
14.3 Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
15 Registros

143

15.1 Definio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143


15.2 Declarao e inicializao simultneas . . . . . . . . . . . . . . . . . . . . . . . . . 146
15.3 Operaes sobre registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
15.4 Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
16 Vetores, matrizes e registros

151

16.1 Variveis compostas homogneas de registros . . . . . . . . . . . . . . . . . . . . 151


16.2 Registros contendo variveis compostas homogneas . . . . . . . . . . . . . . . . 155
16.3 Registros contendo registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
17 Introduo s funes

163

17.1 Noes iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163


17.2 Definio e chamada de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
17.3 Finalizao de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
17.4 Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
17.5 Declarao de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
18 Argumentos e parmetros de funes

181
iii

18.1 Argumentos e parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181


18.2 Escopo de dados e de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
19 Funes e vetores

187

19.1 Vetores como argumentos de funes . . . . . . . . . . . . . . . . . . . . . . . . . . 187


19.2 Vetores so parmetros passados por referncia . . . . . . . . . . . . . . . . . . . . 188
19.3 Vetores como parmetros com dimenses omitidas . . . . . . . . . . . . . . . . . . 189
20 Funes e matrizes

193

20.1 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193


20.2 Matrizes como parmetros com uma dimenso omitida . . . . . . . . . . . . . . . 194
21 Funes e registros

199

21.1 Tipo registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199


21.2 Registros e passagem por cpia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
21.3 Registros e passagem por referncia . . . . . . . . . . . . . . . . . . . . . . . . . . 203
21.4 Funes que devolvem registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
22 Biblioteca padro

209

22.1 Qualificadores de tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209


22.2 Arquivo-cabealho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
22.3 Arquivos-cabealhos da biblioteca padro . . . . . . . . . . . . . . . . . . . . . . . 213
22.3.1 Diagnsticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
22.3.2 Manipulao, teste e converso de caracteres . . . . . . . . . . . . . . . . . 214
22.3.3 Erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
22.3.4 Caractersticas dos tipos com ponto flutuante . . . . . . . . . . . . . . . . . 216
22.3.5 Localizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
22.3.6 Matemtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
22.3.7 Saltos no-locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
22.3.8 Manipulao de sinais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
22.3.9 Nmero varivel de argumentos . . . . . . . . . . . . . . . . . . . . . . . . 222
22.3.10 Definies comuns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
22.3.11 Entrada e sada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
22.3.12 Utilitrios gerais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
22.3.13 Manipulao de cadeias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
22.3.14 Data e hora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
iv

23 Depurao de programas

229

23.1 Depurador GDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229


23.2 Primeiro contato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
23.3 Sintaxe dos comandos do GDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
23.4 Pontos de parada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
23.5 Programa fonte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
23.6 Verificao de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
23.7 Alterao de dados durante a execuo . . . . . . . . . . . . . . . . . . . . . . . . 236
23.8 Resumo dos comandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
23.9 Exemplos de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
24 Pr-processador

249

24.1 Funcionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249


24.2 Diretivas de pr-processamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
24.3 Definies de macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
24.4 Incluso de arquivos-cabealhos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
24.5 Compilao condicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
24.6 Outras diretivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256

AULA

B REVE

HISTRIA DA COMPUTAO

Nesta aula abordaremos uma pequena histria da computao. Sabemos, no entanto, que
esta na verdade uma tentativa e que fatos histricos relevantes podem ter sido excludos involuntariamente. Continuaremos a trabalhar no sentido de produzir um texto cada vez mais
amplo e completo, buscando informaes em outras fontes que, por descuido ou desconhecimento, infelizmente ainda no foram consultadas.
Este texto baseado principalmente nas pginas da Rede Mundial de Computadores [1, 2,
3, 4, 5] e nos livros de Philippe Breton [6] e Russel Shackelford [7].

1.1 Pr-histria
Desde muito tempo, possvel notar que o ser humano vem realizando clculos complexos
para solucionar seus mais diversos problemas. Um dos primeiros e mais notveis exemplos que
temos registro a descoberta do nmero real que representa a relao entre o comprimento da
circunferncia de um crculo e o comprimento de seu raio. A mais antiga evidncia do uso
consciente de uma aproximao precisa para esse nmero, com valor 3 + 17 , foi descoberta nos
projetos das pirmides da poca do Reino Antigo no Egito, datando assim do ano de 2630 a.C. a
2468 a.C. As mais antigas evidncias textuais do clculo de aproximaes desse nmero datam
de 1900 a.C., realizadas pelos gemetras egpcios, babilnios, hindus e gregos. A letra grega
at hoje usada como a representao desse nmero.
Alm disso, a histria do pensamento humano marcada, desde o princpio, pelos registros
de tentativas de sistematizao e estruturao do mesmo. A lgica1 uma cincia filosficomatemtica descrita geralmente por um conjunto de regras que procura sistematizar o pensamento. A lgica enxerga o pensamento como a manifestao do conhecimento, que por sua vez
visto como a busca da verdade, e, para que essa meta seja atingida, estabelece regras a serem
seguidas, chamadas de regras do pensar corretamente. Apesar de muitos povos antigos terem usado sofisticados sistemas de raciocnio, somente na China, ndia e Grcia os mtodos de
raciocnio tiveram um desenvolvimento sustentvel e possvel que a lgica tenha emergido
nesses trs pases por volta do sculo IV a.C. A lgica moderna descende da lgica clssica,
tambm conhecida como lgica aristotlica, desenvolvida por Aristteles2. A lgica moderna
baseada na lgica clssica e usada extensivamente em diversas reas do conhecimento, em
especial na Cincia da Computao. At os dias de hoje, programas e computadores so projetados com base nessa estruturao do pensamento chamada lgica.
1

Do grego clssico o, ou logos, que significa palavra, pensamento, idia, argumento, relato, razo lgica ou
princpio lgico.
2
Aristotles ( a.C. a.C.), nascido na Grcia, filsofo, aluno de Plato, mestre de Alexandre, o Grande.

B REVE

HISTRIA DA COMPUTAO

Do mesmo modo, quando comeou a realizar tarefas mecnicas para sua comodidade e
bem estar, o ser humano predominantemente as mulheres tinha de realizar, hora aps hora,
dia aps dia, todos os clculos repetitivos em tarefas das cincias, do comrcio e da indstria.
Tabelas e mais tabelas eram preenchidas com os resultados desses clculos, para que no fossem sempre refeitos. No entanto, erros nesses clculos eram freqentes devido, em especial, ao
tdio e desconcentrao. Alm disso, esses clculos no eram realizados de forma rpida. Assim, muitos inventores tentaram por centenas de anos construir mquinas que nos ajudassem
a realizar essas tarefas.

Figura 1.1: baco.

O baco3 provavelmente o mais antigo instrumento conhecido de auxlio ao ser humano em clculos matemticos. O baco mais antigo foi descoberto
na Babilnia, hoje conhecida como Iraque, e data do
ano de 300 a.C. Seu valor est baseado especialmente
no fato de auxiliar a memria humana durante as operaes aritmticas mais bsicas. Algum bem treinado
no uso de um baco pode executar adies e subtraes com a mesma velocidade de quem usa uma calculadora eletrnica. No entanto, as duas outras operaes bsicas so realizadas de forma bem mais lenta.
Esse instrumento ainda consideravelmente utilizado
em certos pases do Oriente.

a alNo sculo IX, as contribuies de Muh.ammad ibn Mus


Khwarizm4 para a matemtica, geografia, astronomia e cartografia estabelecem a base para inovaes na lgebra e na trigonometria. A palavra lgebra deriva de seu livro do ano de
830 chamado O Livro Compndio sobre Clculo por Completamento e Equalizao (al-Kitab al-mukhtasar fi hisab al-jabr
wal-muqabala ), onde apresenta um mtodo sistemtico para
soluo de equaes lineares e quadrticas. Por esse trabalho
conhecido como o fundador da lgebra, ttulo que divide
com Diophantus. Seu outro livro Sobre o Clculo com Nmeros Hindus (Ketab fi Istimal al-Adad al-Hindi ), escrito no
ano de 825 e traduzido em seguida para o latim, foi responsvel pelo espalhamento do sistema de numerao hindu pelo
Oriente Mdio e Europa. Esses e outros de seus livros foram
Figura 1.2: Pgina de lgebra.
responsveis por enormes avanos na rea da Matemtica no
mundo ocidental naquela poca. Um outro livro seu chamado
A Imagem da Terra (Kitab surat al-ard ), traduzido como Geografia, apresenta uma reviso do trabalho de Ptolomeu com coordenadas mais precisas especialmente do mar Mediterrneo, sia e frica. Seu nome al-Khwarizm foi traduzido para o latim como Algoritmi, o
que levou o surgimento da palavra algoritmo (algorithm em ingls) e algarismo em portugus.
al-Khwarizm tambm projetou dispositivos mecnicos como o astrolbio e o relgio solar.
3

Abacus uma palavra em latim que tem sua origem nas palavras gregas abax ou abakon, que quer dizer tabela e
que, por sua vez, tem sua origem possivelmente na palavra semtica abq, que significa areia (do livro The Universal
History of Numbers de Georges Ifrah, Wiley Press 2000).
4
a al-Khwarizm ( ), nascido na Prsia, matemtico, astrnomo e
Abu Abdalla Muh.ammad ibn Mus
gegrafo.
FACOM

UFMS

1.1 P R - HISTRIA

Ainda sobre os primeiros dispositivos de auxlio nas atividades humanas, o primeiro relgio de bolso foi criado por Peter Henlein5 por volta de 1504. No ano de 1600, William Gilbert6
ficou conhecido por suas investigaes em magnetismo e eletricidade, tendo cunhado o termo
eletricidade a partir da palavra grega elecktra. John Napier7 , em seu trabalho Mirifici Logarithmorum Canonis Descriptio de 1614, inventou o logaritmo, uma ferramenta que permitia
que multiplicaes fossem realizadas via adies e divises via subtraes. A mgica consistia na consulta do logaritmo de cada operando, obtido de uma tabela impressa. A inveno de
John Napier deu origem rgua de clculo, instrumento de preciso construdo inicialmente na
Inglaterra em 1622 por William Oughtred8 e utilizado nos projetos Mercury, Gemini e Apollo
da NASA, que levaram o homem lua.

Figura 1.3: Rgua de clculo.


Leonardo da Vinci9 e Wilhelm Schickard10 , nos sculos XVI e XVII, respectivamente, foram
os primeiros a projetar mquinas de clculo baseadas em engrenagens. A mquina proposta
por da Vinci nunca saiu do papel, mas a mquina de Schickard conhecida como a primeira
calculadora mecnica automtica ou o primeiro computador no programvel. O sucesso de
uma mquina como essa s foi obtido por Blaise Pascal11 em 1642, que aos 19 anos construiu a
Pascaline para ajudar seu pai, um recolhedor de taxas, a somar quantias. A Pascaline realizava
apenas adies e no era muito precisa. Pouco tempo aps Pascal ter proposto sua mquina
de calcular, o alemo Gottfried Leibniz12 , co-inventor do Clculo juntamente com Isaac Newton13 , planejou construir uma calculadora14 com as quatro operaes bsicas e que, ao invs
de engrenagens, empregava cilindros dentados com 10 dentes, possibilitando seu trabalho no
sistema numrico decimal. O sculo seguinte tem poucas inovaes diretamente relacionadas
aos computadores, como a escala de temperaturas Fahrenheit15 , o telgrafo e a eletricidade,
tambm investigada por Benjamin Franklin16 .
5

Peter Henlein ( ), nascido na Alemanha, serralheiro, arteso e relojoeiro.


William Gilbert ( ), nascido na Inglaterra, fsico e filsofo. lhe atribudo o ttulo de Pai da Engenharia Eltrica ou Pai da Eletricidade e Magnetismo.
7
John Napier ( ), nascido na Esccia, matemtico, fsico, astrnomo e 8o Lorde de Merchistoun.
8
William Oughtred ( ), nascido na Inglaterra, matemtico.
9
Leonardo di ser Piero da Vinci ( ), nascido na Itlia, erudito, arquiteto, anatomista, escultor, engenheiro, inventor, matemtico, msico, cientista e pintor.
10
Wilhelm Schickard ( ), nascido na Alemanha, erudito.
11
Blaise Pascal ( ), nascido na Frana, matemtico, fsico e filsofo.
12
Gottfried Wilhelm Leibniz ( ), nascido na Alemanha, erudito.
13
Sir Isaac Newton ( ), nascido na Inglaterra, fsico, matemtico, astrnomo e filsofo.
14
Ele chamou sua mquina de stepped reckoner.
15
Daniel Gabriel Fahrenheit ( ), nascido na Alemanha, fsico e engenheiro.
16
Benjamin Franklin ( ), nascido nos Estados Unidos, jornalista, editor, autor, filantropo, abolicionista,
funcionrio pblico, cientista, diplomata e inventor. Foi tambm um dos lderes da Revoluo Norte-americana.
6

FACOM

UFMS

B REVE

HISTRIA DA COMPUTAO

Joseph Jacquard17 criou, em 1801, um tear que podia tecer a partir de um padro lido automaticamente de cartes de madeira perfurados e conectados por cordes. Descendentes desses
cartes perfurados so utilizados at hoje em algumas aplicaes. A inveno de Jacquard
incrementou a produtividade de tecidos da poca, mas, em contrapartida, gerou grande desemprego de operrios da indstria txtil.

Figura 1.4: Cartes perfurados da mquina de Jacquard.


A Mquina de Diferenas 18 , projetada por Charles Babbage19 , era uma mquina de calcular
a vapor e foi criada com o objetivo de atender estratgia expansionista do governo ingls, que
tinha a ambio de se tornar o maior imprio do planeta. Esse foi o projeto mais caro financiado
pelo governo da Inglaterra at ento, mas aps dez anos de tentativas infrutferas, o projeto
ruiu e a mquina no foi terminada. Todavia, Babbage no desistiu e projetou uma segunda
mquina chamada Mquina Analtica 20 que seria alimentada por seis mquinas a vapor, teria
o tamanho de uma casa e era uma mquina de propsito mais geral, j que seria programvel
por meio de cartes perfurados. Alm disso, sua inveno tambm permitiria que os cartes
perfurados, agora de papel, fossem empregados como um dispositivo de armazenamento. Essa
mquina teria ainda um dispositivo que a distinguia das calculadoras e a aproximava do que
conhecemos hoje como computadores: uma sentena condicional.
Ada Byron21 tornou-se amiga de Charles Babbage e ficou fascinada com o as idias da Mquina Analtica. Apesar de nunca ter sido construda, Ada escreveu diversos programas para
essa mquina e entrou para a histria como a primeira programadora de um computador. Ada
inventou a sub-rotina e reconheceu a importncia do lao como uma estrutura de programao.
O livro Uma Investigao das Leis do Pensamento sobre as quais so fundadas as Teorias
Matemticas da Lgica e das Probabilidades (An Investigation of the Laws of Thought on
Which are Founded the Mathematical Theories of Logic and Probabilities ), publicado em 1854
por George Boole22 , tornou-se muito influente cerca de 70 anos aps sua publicao, quando
Claude Shannon23 e Victor Shestakov24 independentemente descobriram uma interpretao
para a sua lgebra em circuitos de reles eletromecnicos, demonstrando que a aplicao prtica
17

Joseph Marie Jacquard ( ), nascido na Frana, alfaiate e inventor.


Do ingls Difference Engine.
19
Charles Babbage ( ), nascido na Inglaterra, matemtico, filsofo, engenheiro mecnico e precursor
da Cincia da Computao.
20
Do ingls Analytic Engine.
21
Augusta Ada Byron ( ), nascida na Inglaterra, conhecida como a primeira programadora da histria.
Depois de seu casamento passou a se chamar Augusta Ada King, Condessa de Lovelace.
22
George Boole ( ), nascido na Irlanda, matemtico e filsofo.
23
Claude Elwood Shannon ( ), nascido nos Estados Unidos, engenheiro eletrnico e matemtico, conhecido como o pai da Teoria da Informao. Sua dissertao de mestrado j foi considerada como a mais importante dissertao de mestrado de todos os tempos.
24
Victor Ivanovich Shestakov ( ), nascido nos Rssia, lgico e engenheiro eltrico.
18

FACOM

UFMS

1.2 S CULO XX

em eletricidade da lgebra de Boole poderia construir e resolver qualquer relao numrica e


lgica. A lgebra de Boole, devido as suas aplicaes, ainda hoje ensinada nos cursos introdutrios das reas exatas e tecnolgicas, especialmente na Engenharia Eltrica, Engenharia
Eletrnica e na Cincia da Computao.

Figura 1.5: Mesa de Hollerith.

Em 1890 o governo norte-americano tinha grande urgncia de realizar o censo da populao dos
Estados Unidos e a previso era de que, da maneira como tinha sido realizado o ltimo, o censo
de 1890 levaria cerca de 7 anos e meio at ser finalizado. Um prmio foi ento anunciado para o inventor que ajudasse a automatizar o censo de 1890.
O prmio foi vencido por Herman Hollerith25 , que
props a Mesa de Hollerith26 , uma mquina que
consistia de um leitor de cartes perfurados que
era sensvel a pequenos buracos realizados nesses
cartes, um mecanismo de engrenagens que podia
contar e um grande expositor de indicadores para
mostrar os resultados da computao. Essa mquina foi projetada com sucesso e o censo de 1890
terminou em somente 3 anos. A partir da Hollerith
fundou uma empresa chamada TABULATING M A CHINE C OMPANY . Em 1911 sua empresa se une a
outras duas e se torna a C OMPUTING TABULATING
R ECORDING C ORPORATION CTR. Sob a presidncia de Thomas Watson27 , a empresa foi renomeada
I NTERNATIONAL B USINESS M ACHINES IBM em
1924.

1.2 Sculo XX
A exploso dos computadores ocorreu no sculo XX. At a metade desse sculo, computadores eletromecnicos e os primeiros computadores totalmente eletrnicos foram projetados
com fins militares, para realizar clculos balsticos e decifrar cdigos dos inimigos. Eminentes cientistas, que deram origem a quase tudo do que chamamos de Cincia da Computao,
estiveram envolvidos nesses projetos. A partir da segunda metade do sculo, a exploso dos
computadores eletrnicos se deu, quando o computador pessoal passou a fazer parte de nosso
dia a dia.

1.2.1 Computadores Eletromecnicos


No incio do sculo XX a IBM continuava produzindo calculadoras mecnicas que eram
muito utilizadas em escritrios especialmente para realizar somas. No entanto, a demanda por
25

Herman Hollerith ( ), nascido nos Estados Unidos, estatstico e empresrio.


Do ingls Hollerith desk.
27
Thomas John Watson ( ), nascido nos Estados Unidos, empresrio.

26

FACOM

UFMS

B REVE

HISTRIA DA COMPUTAO

calculadoras mecnicas que realizassem clculos cientficos comeou a crescer, impulsionada


especialmente pelas foras armadas norte-americanas e pelo seu envolvimento nas Primeira e
Segunda Guerras Mundiais.
28 introduziu e popularizou a

Interessante observar que em 1921 o dramaturgo Karel Capek


palavra rob em sua pea RUR Rossumovi Univerzln Roboti.
Konrad Zuse29 props a srie Z de computadores e, destacadamente, em 1941, o primeiro
computador digital binrio programvel por fita, o Z3, de 22 bits de barramento, relgio interno
com velocidade de 5 Hz e 2.000 reles. O Z4, construdo em 1950, o primeiro computador
comercial, alugado pelo Instituto Federal de Tecnologia da Sua (Eidgenssische Technische
Hochschule Zrich ETH Zrich ). Zuse tambm projetou uma linguagem de programao de
alto nvel, a Plankalkl, publicada em 1948. Devido s circunstncias da Segunda Guerra Mundial, seu trabalho ficou conhecido muito posteriormente nos Estados Unidos e na Inglaterra,
em meados dos anos 60.
O primeiro computador programvel construdo nos Estados Unidos foi o Mark I, projetado pela universidade de Harvard e a IBM em 1944. O Mark I era um computador eletromecnico composto por interruptores, reles, engates e embreagens. Pesava cerca de 5 toneladas,
incorporava mais de 800 quilmetros de fios, media 2,5 metros de altura por 15,5 metros de
comprimento e funcionava atravs de um motor de 5 cavalos-vapor. O Mark I podia operar
nmeros de at 23 dgitos. Podia adicionar ou subtrair esses nmeros em 3/10 de segundo,
multiplic-los em 4 segundos e dividi-los em 10 segundos30. Apesar de ser um computador
enorme, com aproximadamente 750 mil componentes, o Mark I podia armazenar apenas 72
nmeros e sua velocidade de armazenamento e recuperao era muito lenta, uma motivao e
um fator preponderante para substituio posterior do computador eletromecnico pelo computador eletrnico. Apesar disso, o Mark I funcionou sem parar por quinze anos.

Figura 1.6: O computador eletromecnico Harvard Mark I.


28

Karel Capek
( ), nascido no Imprio Austro-Hngaro, hoje Repblica Tcheca, escritor.
Konrad Zuse ( ), nascido na Alemanha, engenheiro e pioneiro da computao.
30
espantoso observar que aps 45 anos da fabricao do Mark I, um computador podia realizar uma operao
de adio em 1/109 de segundo.
29

FACOM

UFMS

1.2 S CULO XX

Uma das primeiras pessoas a programar o Mark I foi uma mulher, Grace Hopper31, que em
1953 inventou a primeira linguagem de programao de alto nvel chamada Flow-matic, vindo
a se tornar posteriormente a linguagem COBOL. Uma linguagem de programao de alto nvel projetada com o objetivo de ser mais compreensvel ao ser humano, diferentemente da
linguagem binria, de baixo nvel, compreendida pelo computador. No entanto, uma linguagem de alto nvel necessita de um programa chamado compilador que traduz um programa
em linguagem de alto nvel para um programa em linguagem de baixo nvel, de modo que o
Mark I pudesse execut-lo. Portanto, Grace Hopper tambm construiu o primeiro compilador
conhecido.

1.2.2 Computadores Eletrnicos


No princpio da era eletrnica, logo no comeo do sculo XX, os computadores substituram
os interruptores e as engrenagens eletromecnicas pelas vlvulas. Em seguida, a revoluo da
microeletrnica permitiu que uma quantidade enorme de fiao produzida de forma artesanal
pudesse ser produzida industrialmente como um circuito integrado. A principal vantagem de
um circuito integrado que milhes de transistores podem ser produzidos e interconectados
em um processo industrial de larga escala. Alm disso, os transistores so minsculos comparados s vlvulas, alm de muito mais confiveis.
As contribuies tambm vieram da teoria. A Cincia da Computao no seria a mesma
no fossem as contribuies de um matemtico ingls nascido em 1912, conhecido como Pai
da Cincia da Computao. No incio do sculo XX, Alan Turing32 formalizou o conceito de algoritmo e computao atravs de um modelo terico e formal chamado de mquina de Turing
e formulou a tese que qualquer modelo de computao prtico ou tem capacidades equivalentes s de uma mquina de Turing ou tem um subconjunto delas33 . Seu trabalho, que estabelece
as bases tericas da Cincia da Computao, tem influncias dos trabalhos de David Hilbert34
e Kurt Gdel35 . Turing, assim como os melhores crebros da poca, tambm se envolveu com a
guerra. Na Segunda Guerra Mundial, no centro de criptoanlise de Bletchley Park, Inglaterra,
trabalhou como criptoanalista na decifragem do cdigo produzido pela mquina Enigma da
Alemanha nazista. Em 1947 participou do desenvolvimento de um computador eletrnico
chamado Manchester Mark I na Universidade de Manchester, Inglaterra. Em 1952 foi processado criminalmente por assumir sua homossexualidade, tendo ento aceitado um tratamento
com hormnios femininos e castrao qumica, como uma pena alternativa priso. Turing
morreu em 1952 antes de completar 41 anos por um aparente auto-administrado envenenamento por cianeto. Em 10 de setembro de 2009, o primeiro ministro britnico Gordon Brown
fez um pedido formal pblico de desculpas pelo comportamento do governo britnico nessa
questo (Treatment of Alan Turing was appalling). Diversos eventos celebrando o aniversrio
de 100 anos de seu nascimento esto programados pelo mundo em 2012 (The Alan Turing Year).
31

Grace Murray Hopper ( ), nascida nos Estados Unidos, cientista da computao e oficial da Marinha
dos Estados Unidos.
32
Alan Mathison Turing ( ), nascido na Inglaterra, matemtico, lgico e criptoanalista.
33
Esta afirmao chamada Tese de Church-Turing. Uma linguagem de programao ou um computador abstrato Turing-completo se satisfaz essa tese. Alonzo Church, um influente matemtico e lgico norte-americano,
foi seu orientador de doutorado.
34
David Hilbert ( ), nascido na Alemanha, reconhecido como um dos mais influentes matemticos
dos sculos XIX e XX.
35
Kurt Gdel ( ), nascido no Imprio Austro-Hngaro, lgico, matemtico e filsofo.
FACOM

UFMS

B REVE

HISTRIA DA COMPUTAO

Alguns dispositivos da primeira metade do sculo XX reclamam o


ttulo de primeiro computador digital eletrnico. O Z3 de Konrad Zuse,
como j mencionado, era o primeiro computador eletromecnico de propsito geral. Foi o primeiro computador a usar aritmtica binria, era
Turing-completo e era totalmente programvel por fita perfurada. No
entanto, usava reles em seu funcionamento e, portanto, no era eletrnico. Entre 1937 e 1942 foi concebido o Computador Atanasoff-Berry
(ABC), projetado por John Atanasoff36 e Clifford Berry37 , que continha
elementos importantes da computao moderna como aritmtica binria e vlvulas, mas sua especificidade e impossibilidade de armazenamento de seus programas o distinguem dos computadores modernos.
O Colossus tambm foi um computador construdo para fins militares
entre os anos de 1943 e 1944. Tommy Flowers38 o projetou para auxiliar
criptoanalistas ingleses a decifrar mensagens criptografadas produzidas
pelas mquinas Lorenz SZ 40 e 42 da Alemanha nazista na Segunda
Guerra Mundial. Aps a guerra, Winston Churchill, ento primeiro- Figura 1.7: Vlvula.
ministro britnico, ordenou a destruio desses computadores. Em 1993
deu-se incio no Museu Nacional da Computao em Bletchley Park, Manchester, Inglaterra,
um trabalho de reconstruo de um dos 10 computadores Colossus usados pelos Aliados na
Segunda Guerra Mundial. Esse trabalho ainda no foi concludo devido s enormes dificuldades encontradas pela falta do projeto detalhado da mquina e pela forma em que se deu
tal destruio39 . O Colossus, apesar de utilizar a mais recente tecnologia eletrnica de sua
poca, no era um computador de propsito geral, era programvel de forma limitada e no
era Turing-completo.

De 1940 a 1960
O ttulo de primeiro computador digital de propsito geral e totalmente eletrnico em
geral dado ao ENIAC (Electronic Numerical Integrator and Calculator). Esse computador foi construdo na Universidade da Pensilvnia entre 1943 e 1945 pelos professores John Mauchly40 e
John Eckert41 obtendo financiamento do departamento de guerra com a promessa de construir
uma mquina que substituiria todos os computadores existentes, em particular as mulheres
que calculavam as tabelas balsticas para as armas da artilharia pesada do exrcito. O ENIAC
ocupava uma sala de 6 por 12 metros, pesava 30 toneladas e usava mais de 18 mil tubos a
vcuo, que eram muito pouco confiveis e aqueciam demasiadamente.
Apesar de suas 18 mil vlvulas, o ENIAC podia armazenar apenas 20 nmeros por vez.
No entanto, graas eliminao de engrenagens, era muito mais rpido que o Mark I. Por
exemplo, enquanto uma multiplicao no Mark I levava 6 segundos, no ENIAC levava 2,8
milsimos de segundo. A velocidade do relgio interno do ENIAC era de 100 mil ciclos por
segundo42. Financiado pelo exrcito dos Estados Unidos, o ENIAC tinha como principal tarefa
36
37
38
39
40
41
42

John Vincent Atanasoff ( ), nascido nos Estados Unidos, fsico.


Clifford Edward Berry ( ), nascido nos Estados Unidos, engenheiro eltrico.
Thomas Harold Flowers ( ), nascido na Inglaterra, engenheiro.
Veja mais detalhes em The past is the future at Bletchley Park.
John William Mauchly ( ), nascido nos Estados Unidos, fsico e pioneiro da computao.
John Adam Presper Eckert Jr. ( ), nascido nos Estados Unidos, fsico e pioneiro da computao.
Diramos que o ENIAC era um computador com velocidade de 100 KHz.

FACOM

UFMS

1.2 S CULO XX

Figura 1.8: O primeiro computador eletrnico ENIAC.


verificar a possibilidade da construo da bomba de hidrognio. Aps processar um programa
armazenado em meio milho de cartes perfurados por seis semanas, o ENIAC infelizmente
respondeu que a bomba de hidrognio era vivel.
O ENIAC mostrou-se muito til e vivel economicamente, mas tinha como um de seus
principais defeitos a dificuldade de reprogramao. Isto , um programa para o ENIAC estava
intrinsecamente relacionado a sua parte fsica, em especial a fios e interruptores. O EDVAC
(Electronic Discrete Variable Automatic Computer) foi projetado em 1946 pela equipe de John Mauchly e John Eckert, que agregou o matemtico John von Neumann43 e tinha como principais
caractersticas a possibilidade de armazenar um programa em sua memria e de ser um computador baseado no sistema binrio. John von Neumann publicou um trabalho44 descrevendo
uma arquitetura de computadores em que os dados e o programa so mapeados no mesmo
espao de endereos. Essa arquitetura, conhecida como arquitetura de von Neumann ainda
utilizada nos processadores atuais.
43
Margittai Neumann Jnos Lajos ( ), nascido na ustria-Hungria, matemtico e erudito. John von
Neumann tem muitas contribuies em diversas reas. Como matemtico, foi assistente de David Hilbert. Na Cincia da Computao, alm da arquitetura de von Neumann, props os autmatos celulares. Mas, infelizmente,
tambm foi um dos cientistas a trabalhar no Projeto Manhatan, responsvel pelo desenvolvimento de armas nucleares, tendo sido responsvel pela escolha dos alvos de Hiroshima e Nagazaki no Japo na Segunda Guerra Mundial,
onde explodiriam as primeiras bombas nucleares da histria e pelo clculo da melhor altura de exploso para que
uma maior destruio fosse obtida.
44
First Draft of a Report on the EDVAC.

FACOM

UFMS

10

B REVE

HISTRIA DA COMPUTAO

Figura 1.9: O EDVAC.


Nos anos 50, os computadores eram nada populares e pertenciam a algumas poucas universidades e ao governo norte-americano. No incio da dcada, John Eckert e John Mauchly
deixam a Universidade de Pensilvnia por problemas de patenteamento de suas invenes e
fundam sua prpria empresa de computadores, a E CKERT-M AUCHLY C OMPUTER C ORPORA TION. Em 1951 projetam o UNIVAC, de UNIVersal Automatic Computer, o primeiro computador
eletrnico comercial produzido em larga escala e que utilizava fita magntica. O primeiro UNIVAC foi vendido para o escritrio do censo populacional dos Estados Unidos. Mas devido ao
domnio da IBM, que em 1955 vendia mais computadores que o UNIVAC, a empresa de John
Eckert e John Mauchly passa por muitas dificuldades at ser fechada e vendida.
Em 1955 a B ELL L ABORATORIES, uma empresa de tecnologia fundada em 1925, produz o primeiro computador base
de transistores. Os transistores eram menores, mais rpidos e
aqueciam muito menos que as vlvulas, o que tornava computadores base de transistores muito mais eficientes e confiveis. Em 1957 a IBM anuncia que no usaria mais vlvulas
e produz seu primeiro computador contendo 2.000 transistores. Em 1958, descobertas experimentais que mostravam
que dispositivos semicondutores podiam substituir as vlvulas e a possibilidade de produzir tais dispositivo em larga escala, possibilitaram o surgimento do primeiro circuito integrado, ou microchip, desenvolvido simultaneamente por Jack
FACOM

Figura 1.10: Circuito integrado.

UFMS

1.2 S CULO XX

11

Kilby45 da T EXAS I NSTRUMENTS e por Robert Noyce46 da FAIRCHILD S EMICONDUCTOR. Um


circuito integrado um circuito eletrnico miniaturizado, consistindo de dispositivos semicondutores, produzido na superfcie de um fino substrato de material semicondutor. importante observar que a partir dos anos 50 a IBM praticamente engoliu as empresas concorrentes
e tornou-se a maior empresa de produo de computadores da poca. Devido a esse domnio,
o governo norte-americano aplicou procedimentos antitruste contra a IBM de 1969 a 1982.
De 1960 a 1980
Nos anos 60, as empresas produziam computadores de grande porte ou mainframes. Esses computadores eram usados por grandes organizaes para
aplicaes massivas, tipicamente para processamento
de enormes quantidades de dados tais como censo
populacional, estatsticas industriais ou comerciais e
processamento de transaes financeiras. Faz parte
desse conjunto a srie IBM 1400 da IBM e a srie
UNIVAC 1100 da S PERRY-R AND. Naqueles anos, juntamente com a produo de computadores, dispositivos, perifricos e linguagens de programao foram
Figura 1.11: O primeiro mouse.
tambm desenvolvidos, alm de propostas de padronizao desses novos recursos. Em 1963, Douglas Engelbart47 inventou e patenteou o primeiro mouse de computador. No mesmo ano desenvolvido o
cdigo padro norte-americano para troca de informaes48 para padronizar a troca de dados
entre computadores. Em 1967, a IBM cria o primeiro disco flexvel49 para armazenamento de
dados. Alm disso, as linguagens de programao BASIC, FORTRAN e COBOL foram propostas nessa dcada. Com o desenvolvimento da indstria de computadores fervilhando, Gordon
Moore50 , atravs de observaes empricas, afirma em 1965 que o nmero de transistores em
um circuito integrado duplicaria a cada 24 meses. Essa afirmao fica conhecida depois como
Lei de Moore51 . Em 1968, Gordon Moore e Robert Noyce fundam a I NTEL C ORPORATION,
uma empresa fabricante de processadores. Em 1969, um grupo de ex-executivos da FAIRCHILD
S EMICONDUCTOR funda uma empresa de circuitos integrados chamada A DVANCED M ICRO
D EVICES , I NC ., AMD. Em 1969, a AT&T B ELL L ABORATORIES desenvolve o Unix, um excelente sistema operacional utilizado ainda hoje especialmente em servidores. Entre 1969 e 1970,
a primeira impressora matricial e a primeira impressora laser so produzidas.
Como j comentamos, os computadores dos anos 60 e 70 eram computadores de grande
porte estabelecidos em rgos governamentais, universidades e algumas grandes empresas.
Esses computadores podiam ser programados de duas maneiras distintas. A primeira ma45

Jack St. Clair Kilby ( ), nascido nos Estados Unidos, engenheiro eltrico. Ganhador do Prmio Nobel
de Fsica em 2000 por sua contribuio na inveno do circuito integrado.
46
Robert Noyce ( ), nascido nos Estados Unidos, fsico. Tambm conhecido como o Mestre do Vale
do Silcio.
47
Douglas C. Engelbart (), nascido nos Estados Unidos, engenheiro eltrico e inventor.
48
Do ingls American Standard Code for Information Interchange ASCII.
49
Disquete ou disco flexvel, do ingls floppy disk.
50
Gordon Earle Moore (), nascido nos Estados Unidos, qumico e fsico.
51
A afirmao original de Gordon Moore pode ser encontrada no artigo intitulado Cramming more components
onto integrated circuits da Electronics Magazine, nmero 19, de abril de 1965.
FACOM

UFMS

12

B REVE

HISTRIA DA COMPUTAO

neira conhecida como compartilhamento de tempo52 onde o computador d a cada usurio


uma fatia de tempo de processamento, comportando, naquela poca, 100 usurios ativos simultaneamente. A segunda maneira chamada de modo de processamento em lote53 onde
o computador d ateno total a um programa, mas no h usurios ativos. O programa, no
momento em que o computador se dispe a process-lo, lido a partir de cartes perfurados
que foram previamente preparados em uma mquina perfuradora de cartes.

Figura 1.12: Mquinas perfuradoras de cartes IBM 26.


A dcada de 70 tambm foi muito prolfica no desenvolvimento da computao. Linguagens de programao usadas at hoje foram projetadas nessa poca como Pascal, concebida em
1971 por Niklaus Wirth54 , e C, proposta em 1972 por Dennis Ritchie55 . Avanos no projeto de
dispositivos tambm foram obtidos. Datam dessa poca o CD56 , criado em 1972, o primeiro
leitor de discos flexveis, introduzido pela T OSHIBA em 1974, e o primeiro disco flexvel de 5
1/4 produzido em 1978. Ainda, o ano de 1975 marca o nascimento de uma das maiores e
mais bem sucedidas empresas do mundo, a M ICROSOFT, criada por Bill Gates57 e Paul Allen58 .
No mesmo ano, Steve Wozniak59 e Steve Jobs60 fundam a A PPLE C OMPUTERS, tambm uma
das maiores empresas fabricantes de computadores do mundo.
52
53
54
55
56
57
58
59
60

Do ingls time sharing processing.


Do ingls batch processing.
Niklaus E. Wirth (), nascido na Sua, engenheiro eletrnico e cientista da computao.
Dennis MacAlistair Ritchie (), nascido nos Estados Unidos, fsico e matemtico.
Do ingls compact disk.
William Henry Gates III (), nascido nos Estados Unidos, empresrio.
Paul Gardner Allen (), nascido nos Estados Unidos, empresrio.
Stephan Gary Wozniak (), nascido nos Estados Unidos, engenheiro da computao e filantropo.
Steven Paul Jobs (), nascido nos Estados Unidos, empresrio.

FACOM

UFMS

1.2 S CULO XX

13

Mas nenhum dos avanos dessa poca foi to


significativo como aquele obtido pela fabricante de
microprocessadores I NTEL, que conseguiu colocar
um computador inteiro em uma nica pastilha
de silcio logo no incio da dcada. Em 1970 a I N TEL colocou em produo o microprocessador INTEL 4004, com barramento de 4 bits, velocidade de
108 KHz e 2.300 transistores. A encomenda inicial
partiu da empresa japonesa B USICOM, que tinha a
inteno de utilizar o INTEL 4004 em uma linha
de calculadoras cientficas. Porm, o processador
mais notvel que foi disponibilizado em seguida
pela I NTEL foi o INTEL 8080 em 1974, com barramento de 8 bits e velocidade de processamento
de 2 MHz. A I NTEL vendia esse processador por
360 dlares como uma brincadeira com a IBM, j
que seu computador de grande porte IBM S/360
custava milhes de dlares. Em 1975, o INTEL
8080 foi empregado no Altair 8800 da M ICRO I NS TRUMENTATION AND T ELEMETRY S YSTEMS, considerado o primeiro computador pessoal61 , tinha
1 Kbyte de memria principal e tinha de ser construdo a partir de um kit de peas que chegavam
pelo correio. Bill Gates, que acabara de ingressar
Figura 1.13: Altair 8800.
na Universidade de Harvard, largou seus estudos
para concentrar esforos na escrita de programas para esse computador.
Em 1976, trs computadores pessoais concorrentes so colocados venda. O primeiro computador pessoal que j vinha montado pela fbrica, o Apple I, lanado pela A PPLE C OMPU TERS. Logo em seguida, em 1977, a A PPLE inicia a produo do Apple II, o primeiro computador pessoal com monitor colorido, projetado com o processador 6502 da MOS T ECHNOLOGY,
de 8 bits de barramento, 1 MHz de velocidade, 4 Mbytes de memria principal e interface de
udio-cassete para armazenamento e recuperao de dados em fita cassete. Era o computador
padro empregado na rede de ensino dos Estados Unidos nos anos 80 e 90.
Alm do Apple I, um outro computador pessoal que entrou no mercado de computadores
pessoais a partir de 1976 foi o TRS-80 Model I da TANDY C ORPORATION. Esse computador continha um microprocessador de 8 bits, o Zilog Z80, de 1,77 MHz de velocidade e tinha memria
de 4 Kbytes.
Tambm em 1976, a I NTEL lana o processador INTEL 8086, conhecido como P1, com barramento de 16 bits, velocidade de 5 MHz e 29.000 transistores, que d origem arquitetura de
processadores x86. O INTEL 8088 lanado em 1979 baseado no INTEL 8086, mas tem barramento de dados de 8 bits, permitindo compatibilidade com os processadores anteriores. Esse
processador foi utilizado como o processador padro da linha de computadores pessoais da
IBM, os IBM PCs, a partir de 1981. J em 1980, a IBM contrata Bill Gates e Paul Allen para desenvolver um sistema operacional para o IBM PC, que eles denominaram Disk Operating System
DOS. O DOS, ou MS-DOS, era um sistema operacional com interface de linha de comandos.
61

Do ingls personal computer PC.

FACOM

UFMS

14

B REVE

HISTRIA DA COMPUTAO

Figura 1.14: O computador pessoal Apple I.


Ao mesmo tempo que a indstria dos computadores avanava, progressos notveis tambm foram obtidos nos fundamentos da Computao, em grande parte devido a Donald
Knuth62 , a Stephen Cook63 e a Leonid Levin64 . Knuth autor do livro A Arte da Programao de Computadores (The Art of Computer Programming), uma srie em vrios volumes,
que contribuiu para o desenvolvimento e sistematizao de tcnicas matemticas formais para
a anlise rigorosa da complexidade computacional dos algoritmos e a popularizao da notao assinttica. conhecido, a partir desses trabalhos, como o Pai da Anlise de Algoritmos.
Alm das contribuies fundamentais em Teoria da Computao, Knuth o criador do sistema
processador de textos TEX. Cook e Levin so conhecidos por terem demonstrado formalmente
a existncia do primeiro problema NP-completo: o problema da satisfabilidade de frmulas
booleanas. Isso significa que qualquer problema na classe NP pode ser transformado de maneira eficiente, isto , pode ser reduzido em tempo polinomial por uma mquina de Turing
determinstica, para o problema de determinar se uma frmula booleana satisfatvel. Uma
conseqncia importante do Teorema de Cook-Levin que se existe um algoritmo determinstico eficiente, ou de tempo polinomial, que soluciona o problema da satisfabilidade de frmulas
booleanas, ento existe um algoritmo determinstico de tempo polinomial que soluciona todos
os problemas da classe NP. A contribuio desses dois pesquisadores tem um significado fundamental para toda a rea da Computao e pode ser traduzida informal e simplificadamente
como a necessidade que temos de saber se um problema ou no computvel de forma eficiente em uma mquina geral e abstrata. Esse problema conhecido como o Problema P versus
NP, um dos sete Millenium Problems65 do Clay Mathematics Institute of Cambridge.
62

Donald Ervin Knuth (), nascido nos Estados Unidos, cientista da computao, Professor Emrito de Arte
de Programao de Computadores da Universidade de Stanford.
63
Stephen Arthur Cook (), nascido nos Estados Unidos, matemtico e cientista da computao, University
Professor da Universidade de Toronto.
64
Leonid Anatolievich Levin (), nascido na Ucrnia, cientista da computao.
65
Este problema tem um prmio estabelecido de 1 milho de dlares para o(s) pesquisador(es) que o solucionaFACOM

UFMS

1.2 S CULO XX

15

Figura 1.15: O computador pessoal IBM PC.


De 1980 a 2000
Com o mercado de computadores em contnuo crescimento, os anos 80 tambm foram de
muitas inovaes tecnolgicas na rea. O crescimento do nmero de computadores pessoais
nos Estados Unidos nessa poca revela o significado da palavra exploso dos computadores.
Para se ter uma idia, em 1983 o nmero de computadores pessoais em uso nos Estados Unidos
era de 10 milhes, subindo para 30 milhes em 1986 e chegando a mais de 45 milhes em 1988.
Logo em 1982, a A PPLE C OMPUTERS a primeira empresa fabricante de computadores pessoais
a atingir a marca de 1 bilho de dlares em vendas anuais.
Processadores, e conseqentemente os computadores pessoais, foram atualizados a passos
largos. A E PSON C ORPORATE H EADQUARTERS, em 1982, introduz no mercado o primeiro
computador pessoal porttil66 . Os processadores da famlia x86 286, 386 e 486 foram lanados
gradativamente pela I NTEL na dcada de 80 e foram incorporados em computadores pessoais
de diversas marcas. O INTEL 80486, por exemplo, era um processador de 32 bits, 50 MHz
e 1,2 milhes de transistores. Processadores compatveis com a famlia x86 da I NTEL foram
produzidos por outras empresas como IBM, T EXAS I NSTRUMENTS, AMD, C YRIX e C HIPS AND
T ECHNOLOGIES. Em 1984, a A PPLE lana com sucesso estrondoso o primeiro MacIntosh, o
primeiro computador pessoal a usar uma interface grfica para interao entre o usurio e a
mquina, conhecido como MacOS. O MacIntosh era equipado com o processador 68000 da
M OTOROLA de 8 MHz e 128 Kbytes de memria. Uma atualizao com expanso de memria
de 1 Mbytes foi feita em 1986 no MacIntosh Plus.
Os programas tambm evoluram na dcada de 80. O sistema operacional MS-DOS partiu
gradativamente da verso 1.0 em 1981 e atingiu a verso 4.01 em 1988. Em 1985, o sistema
operacional Windows 1.0 vendido por 100 dlares pela M ICROSOFT em resposta tendncia
crescente de uso das interfaces grficas de usurios popularizadas pelo MacIntosh. Em 1987 o
rem. Veja mais informaes em P vs. NP problem.
66
Tambm conhecido como notebook.
FACOM

UFMS

16

B REVE

HISTRIA DA COMPUTAO

Windows 2.0 disponibilizado. Nessa poca a A PPLE trava uma batalha judicial por cpia de
direitos autorais do sistema operacional do MacIntosh contra a M ICROSOFT, pelo sistema operacional Windows 2.03 de 1988, e a H EWLETT-PACKARD, pelo sistema operacional NewWave
de 1989.
Em 1990 Tim Berners-Lee67 prope um sistema de hipertexto que o primeiro impulso da
Rede Mundial de Computadores68 . O primeiro provedor comercial de linha discada da Internet
torna-se ativo em 1991, quando a WWW disponibilizada para o pblico em geral como uma
ferramenta de busca.
Richard Stallman69 , em 1985, escreve o Manifesto GNU
que apresenta sua motivao para desenvolver o sistema
operacional GNU, o primeiro projeto de software livre proposto. Desde meados dos anos 90, Stallman tem gastado
muito de seu tempo como um ativista poltico defendendo
o software livre, bem como fazendo campanha contra patentes de software e a expanso das leis de direitos autorais. Os mais destacados programas desenvolvidos por
Stallman so o GNU Emacs, o GNU Compiler Collection
(gcc) e o GNU Debugger (gdb). Inspirado pelo Minix, um
sistema operacional baseado no Unix voltado para o ensino,
Linus Torvalds70 projetou em 1991 um sistema operacional
para computadores pessoais chamado Linux. O Linux um
exemplo de destaque do que chamamos de software livre e
de desenvolvimento de cdigo aberto. Seu cdigo fonte, escrito na linguagem C, disponibilizado para qualquer pessoa usar, modificar e redistribuir livremente.

Figura 1.16: O smbolo do Linux.

O sistema operacional MS-DOS teve seu fim na dcada de 90, em sua ltima verso comercial 6.22, tendo sido completamente substitudo pelo bem sucedido Windows. A verso
3.0 do Windows vendeu 3 milhes de cpias em 1990. Em 1992, a verso 3.1 vendeu 1 milho
de cpias em apenas 2 meses depois de seu lanamento. J em 1997, aps o lanamento do
Windows 95 em 1995, Bill Gates reconhecido como o homem mais rico do mundo. Nessa
poca de exploso do uso dos sistemas operacionais da M ICROSOFT, os vrus de computador passaram a infestar cada vez mais computadores e a impor perdas cada vez maiores de
tempo, de recursos e de dinheiro s pessoas e empresas que os utilizavam. Um dos primeiros
e mais famosos vrus de computador o Monkey Virus, um vrus de setor de boot descoberto
no Canad em 1991, que se espalhou muito rapidamente pelos Estados Unidos, Inglaterra e
Austrlia. Seguiu-se ao Windows 95 o Windows 98 em 1998 e o Windows ME em 2000.
A Rede Mundial de Computadores e a Internet tambm mostram um desenvolvimento
destacado nessa poca. O ano de 1993 registra um crescimento espantoso da Internet e 50
servidores WWW j so conhecidos at aquele momento. Em 1994, os estudantes de doutorado em engenharia eltrica da Universidade de Stanford Jerry Yang71 e David Filo72 fundam
a Yahoo!, uma empresa de servios de Internet que engloba um portal de Internet, uma ferra67
68
69
70
71
72

Sir Timothy John Berners-Lee (), nascido na Inglaterra, fsico.


Do ingls World Wide Web WWW.
Richard Matthew Stallman (), nascido nos Estados Unidos, fsico, ativista poltico e ativista de software.
Linus Benedict Torvalds (), nascido na Finlndia, cientista da computao.
Jerry Chih-Yuan Yang (), nascido em Taiwan, engenheiro eltrico e empresrio.
David Filo (?), nascido nos Estados Unidos, engenheiro da computao e empresrio.

FACOM

UFMS

1.2 S CULO XX

17

menta de busca na Internet, servio de e-mail, entre outros. A Yahoo! obtm grande sucesso
entre usurios e em outubro de 2005 sua rede de servios espalhada pelo mundo recebe em
mdia 3,4 bilhes de visitas por dia. Em 1994, o World Wide Web Consortium W3C fundado
por Tim Berners-Lee para auxlio no desenvolvimento de protocolos comuns para avaliao da
Rede Mundial de Computadores. O Wiki foi criado em 1995 pelo Repositrio Padro de Portland, nos Estados Unidos, e um banco de dados aberto edio, permitindo que qualquer
usurio possa atualizar e adicionar informao, criar novas pginas, etc., na Internet. Nesse
mesmo ano, a S UN M ICROSYSTEMS lana a linguagem de programao orientada a objetos
Java, amplamente utilizada hoje em dia para criar aplicaes para a Internet. Os rudimentos
da ferramenta de busca Google so desenvolvidos em 1996 como um projeto de pesquisa dos
alunos de doutorado Larry Page73 e Sergey Brin74 da Universidade de Stanford. Em 1998 a
pgina do Google disponibilizada na Internet e, atualmente, a ferramenta de busca mais
utilizada na rede. A WebTV tambm disponibilizada em 1996 possibilitando aos usurios
navegar pela Internet a partir de sua TV.
Com relao aos dispositivos eletrnicos, o Barramento Serial Universal USB75 padronizado em 1995 pela I NTEL, C OMPAQ, M ICROSOFT, entre outras. O USB um barramento externo
padronizado que permite transferncia de dados e capaz de suportar at 127 dispositivos perifricos. Em 1997 o mercado comea a vender uma nova mdia de armazenamento tico de
dados, o Disco Verstil Digital DVD76 , com as mesmas dimenses do CD, mas codificado
em um formato diferente com densidade muito mais alta, o que permite maior capacidade de
armazenamento. Os DVDs so muito utilizados para armazenar filmes com alta qualidade de
som e vdeo. Em 1998 o primeiro tocador de MP3, chamado de MPMan, vendido no Japo
pela empresa S AEHAN. A dcada de 90 tambm marcada pela unio, compra e venda de diversas empresas de computadores. A indstria de jogos para computadores pessoais tambm
teve seu crescimento acentuado nessa poca.
Os processadores tambm foram vendidos como nunca nos anos 90. A I NTEL lana em 1993 o
sucessor do INTEL 486, conhecido como Pentium,
ou Pentium I, de 32 bits, 60 MHz e 3,1 milhes de
transistores em sua verso bsica. A partir de 1997,
a I NTEL lana seus processadores seguidamente,
ano aps ano. Em 1997 anuncia a venda dos processadores Pentium MMX e Pentium II. O Celeron
produzido a partir de 1998 e em 1999, a I NTEL
anuncia o incio da produo do Pentium III. O
Pentium IV produzido a partir de 2000 e um
processador de 32 bits, 1,4 GHz e 42 milhes de
transistores. A AMD j produzia microprocessadores desde a dcada de 70, mas entrou em forte
concorrncia com a I NTEL a partir dessa poca,
com o lanamento do K5 em 1995, concorrente do
Pentium I, de 32 bits, 75 MHz e 4,3 milhes de transistores em sua primeira verso. Seguiu-se ao K5

Figura 1.17: Processador Pentium.

73

Lawrence Edward Page (), nascido nos Estados Unidos, engenheiro da computao e empresrio.
Sergey Brin (), nascido na Rssia, matemtico, cientista da computao e empresrio.
75
Do ingls Universal Serial Bus.
76
Do ingls Digital Versatile Disc.
74

FACOM

UFMS

18

B REVE

HISTRIA DA COMPUTAO

o K6 em 1997, de 32 bits, 66 MHZ e 8,8 milhes de transistores, e a srie K7 de 1999, que engloba os processadores Athlon e Duron. A partir da dcada de 90, uma fatia considervel das
fbricas produz computadores pessoais com processadores da I NTEL ou da AMD. No incio da
dcada de 90, A PPLE, IBM e M OTOROLA se unem para projetar o processador PowerPC de 32
bits que equipou o PowerMac da A PPLE a partir de 1994. A aceitao desse novo computador
no foi como o esperado e, aps um perodo de baixas, a A PPLE ressurge em 1998 com o iMac,
um computador pessoal com projeto visual arrojado e com a filosofia do tudo-em-um-s. A
dcada de 90 marcada pela facilidade de acesso aos computadores pessoais, j que muitos
deles passam a ser vendidos por menos que 1.000 dlares.

De 2000 at hoje
O ano de 2000 inicia receoso para governos e empresas pelo medo das conseqncias potencialmente desastrosas da virada do sculo nos sistemas computacionais, o que se chamou na
poca de Bug do Milnio. Alm disso, o juiz Thomas Penfield anuncia a diviso do imprio
M ICROSOFT em duas companhias com Bill Gates deixando o cargo de Executivo-Chefe.
A M ICROSOFT lana o Windows XP em 2001, o Windows Vista, em janeiro de 2007 e recentemente o Windows 7 em 2009. A A PPLE disponibiliza o MacOS X 10.0 em 2001 e seguidas novas atualizaes at 2009, com o MAC OS X 10.6. O Linux tem maior penetrao e
aceitao dos usurios de computadores pessoais e diversas distribuies so disponibilizadas
como Ubuntu, Mandriva Linux, Fedora Core e SUSE Linux. Estas distribuies e os projetos
comunitrios Debian e Gentoo, montam e testam os programas antes de disponibilizar sua
distribuio. Atualmente, existem centenas de projetos de distribuio Linux em ativo desenvolvimento, constantemente revisando e melhorando suas respectivas distribuies.
Em 2001 a D ELL passa a ser a maior fabricante de computadores pessoais do mundo. Em
2002, uma empresa de consultoria norte-americana faz uma estimativa que at aquele ano
aproximadamente 1 bilho de computadores pessoais tinham sido vendidos no mundo inteiro
desde sua consolidao.
A I NTEL tem investido mais recentemente sua produo em processadores de 64 bits
com ncleos mltiplos, como por exemplo
o Xeon de 2004, o Pentium D de 2005, o
INTEL Core 2 Duo e o INTEL Core 2 Quad
de 2008. A AMD produz os processadores de
64 bits Duron em 2000 e o Sempron em 2004,
ambos da srie K7, e o Opteron em 2003 da
srie K8, este ltimo um processador de dois
ncleos, para competir com os processadores de mltiplos ncleos, como o Xeon da I N TEL. Em seguida, lana a srie K10 chamada
Phenom, com 2, 3 e 4 ncleos. A A PPLE, que
vinha utilizando o processador PowerPC em
sua linha de iMacs, anuncia que a partir de
2006 comear a usar os processadores da
I NTEL. A verso de 2006 do iMac usa o
processador INTEL Core 2 Duo. Na lista dos
FACOM

Figura 1.18: Phenom X4 da AMD.

UFMS

1.2 S CULO XX

19

500 supercomputadores mais rpidos do mundo, a TOP500, de novembro de 2009, h um amplo domnio de mais de 80% de uso de processadores com ncleos mltiplos da INTEL nesses
computadores. Tambm interessante notar que esses supercomputadores usam alguma distribuio do sistema operacional Linux em mais de 82% deles, sendo que 99% usam um sistema
operacional baseado no Unix, como o Linux, e apenas 1% usam um sistema operacional baseado no Windows.

Figura 1.19: Cray XT5-HE Opteron Six Core 2.6 GHz, o computador mais rpido do mundo
na lista TOP500 de 2009, instalado no Oak Ridge National Laboratory. Usa o processador AMD
x86_64 Opteron Six Core 2600 MHz de 10,4 GFlops e o sistema operacional Linux.
Alguns modelos de computadores experimentais e inovadores tm sido propostos, com tentativas de implementaes. O computador baseado em DNA, tambm conhecido como computador molecular, o computador qumico e o computador quntico so exemplos de propostas recentes e promissoras.

Figura 1.20: Computador quntico.


FACOM

UFMS

20

B REVE

HISTRIA DA COMPUTAO

Exerccios
1.1 Visite a pgina do Computer History Museum, que contm uma enorme quantidade de
informaes sobre esses dispositivos.
1.2 Escolha um ou dois personagens da pr-histria da computao e leia os verbetes sobre
esses personagens na Wikipedia.
1.3 Leia os verbetes associados s duas mulheres que tm papel importante na Histria da
Computao: Augusta Ada Byron e Grace Murray Hopper.
1.4 Leia o verbete sobre Alan Mathison Turing, o Pai da Cincia da Computao, na Wikipedia. Aproveite para ler o pedido formal de desculpas feito em 2009 pelo Primeiroministro da Inglaterra, Gordon Brown, e para vasculhar a pgina com as festividades do
centenrio de seu nascimento em 2012.
1.5 Leia uma apresentao simples e motivadora do problema P versus NP na pgina do Clay
Mathematics Institute.
1.6 Leia o verbete Cook-Levin Theorem na Wikipedia e tente entender informalmente o que ele
realmente quer dizer.
1.7 Visite a pgina GNU Operating System e leia o verbete GNU na Wikipedia e veja como este
sistema vem se desenvolvendo ao longo do tempo.
1.8 Visite as pginas Free Software Foundation, Fundao Software Livre Amrica Latina e o
portal de software livre (Portal: Free Software) da Wikipedia. Procure saber quais projetos
mantidos por esta fundao mais lhe interessou.
1.9 Leia o verbete Linux na Wikipedia, o sistema operacional que usamos na universidade.
1.10 Visite a pgina TOP500 para obter informaes dos computadores mais rpidos hoje existentes.

FACOM

UFMS

AULA

I NTRODUO

COMPUTAO

Na aula 1 vimos um pequeno histrico sobre a Computao. Nesta aula, vamos mencionar
brevemente como essas mquinas so organizadas internamente alm de invertigarmos o conceito de algoritmo e programa. Como veremos, John von Neumann foi o responsvel, em 1945,
pelo desenvolvimento de um modelo1 de computador que sobrevive at hoje.
Este texto baseado principalmente nas referncias [8, 9, 10].

2.1 Contextualizao
As primeiras mquinas computacionais projetadas tinham programas fixos. Assim, realizavam apenas aquelas tarefas para as quais foram concebidas. Modificar o programa de uma
dessas mquinas significava reestruturar toda a mquina internamente. Mesmo para computadores como o ENIAC, programar e reprogramar era um processo geralmente laborioso, com
uma quantidade enorme de rearranjo de fiao e de cabos de conexo. Dessa forma, podemos
destacar que a programao dos computadores que foram projetados antes do EDVAC tinha
uma caracterstica curiosa e comum: a programao por meios externos. Ou seja, os programadores, para que essas mquinas executassem seus programas, deviam usar cartes perfurados,
fitas perfuradas, cabos de conexo, entre outros. A pequena disponibilidade de memria para
armazenamento de dados e resultados intermedirios de processamento tambm representava
uma outra dificuldade complicadora importante.
Em 1936, Alan Turing publicou um trabalho [11]2 que descrevia um computador universal
terico, conhecido hoje como mquina universal de Turing. Esse computador tinha capacidade
infinita de armazenamento, onde se poderia armazenar dados e instrues. O termo usado foi o
de computador com armazenamento de programas3 . Sobre esse mesmo conceito, o engenheiro
alemo Konrad Zuse, que projetou a famlia Z de computadores, escreveu um trabalho [12]4
independentemente em 1936. Tambm de forma independente, John Presper Eckert e John
Mauchly, que projetaram o ENIAC na Universidade da Pensilvnia, propuseram um trabalho
em 1943, conforme meno em [13], sobre o conceito de computadores com armazenamento de
programas. Em 1944, no projeto do novo computador EDVAC, John Eckert deixou registrado
que sua equipe estava propondo uma forma inovadora de armazenamento de dados e programas em um dispositivo de memria enderevel, feito de mercrio, conhecido como linhas de
atraso. John von Neumann, tendo trabalhado com a equipe que construiu o ENIAC, juntou1

Veja o verbete von Neumann architecture na Wikipedia.


Artigo disponvel na seo Bibliografia complementar na pgina da disciplina no Moodle.
3
Do ingls stored-program computer.
4
Veja mais em The Life and Work of Konrad Zuse, especialmente a parte 10.
2

21

22

I NTRODUO

COMPUTAO

se tambm s discusses do projeto desse novo computador e ficou responsvel por redigir o
documento com a descrio dessas idias. Com a publicao desse trabalho [14]5 , divulgado
contendo apenas seu nome, essa organizao interna de um computador passou a ser conhecida como arquitetura de von Neumann, apesar de Turing, Zuse, Eckert e Mauchly terem
contribudo ou j apresentado idias semelhantes. Esse trabalho obteve grande circulao no
meio acadmico e seu sucesso como proposta de implementao de um novo computador foi
imediato. At nossos dias, essa organizao ainda usada nos projetos de computadores mais
conhecidos.

2.2 Arquitetura de von Neumann


As idias publicadas por John von Neumann foram revolucionrias a ponto de estabelecer
um novo paradigma de concepo de computadores para a poca e que permanece vlido at
os nossos dias. Informalmente, a maneira de organizar os componentes que constituem um
computador chamada arquitetura do computador. Assim, como a maioria dos computadores
atuais segue o modelo proposto por von Neumann, veremos aqui uma breve descrio da
assim chamada arquitetura de von Neumann.
Nesse modelo, um computador constitudo por trs componentes principais: (i) a unidade
central de processamento ou UCP6 , (ii) a memria e (iii) os dispositivos de entrada e sada.
A UCP, por sua vez, composta pela unidade lgico-aritmtica ou ULA e pela unidade de
controle ou UC. Esses trs componentes principais esto conectados e se comunicam atravs
de linhas de comunicao conhecidas como barramento do computador.
Podemos ilustrar a arquitetura de von Neumann como na figura 2.1.

1111111111111111
0000000000000000
0000000000000000
1111111111111111
0000000000000000
1111111111111111
0000000000000000
1111111111111111
memria
0000000000000000
1111111111111111
0000000000000000
1111111111111111
0000000000000000
1111111111111111
11111111
00000000
00000000UCP
11111111
00000000
11111111
000
111
00
11
00000000
11111111
000
111
00
11
00000000
11111111
UC
ULA
000
111
00
11
00000000
11111111
000
111
00
11
00000000
11111111
00000000
11111111
00000000
11111111
1111
0000
0000
1111
0000
1111
0000
1111
entrada
0000
1111
0000
1111
0000
1111
0000
1111

11111
00000
00000
11111
00000
11111
00000
11111
sada
00000
11111
00000
11111
00000
11111
00000
11111

Figura 2.1: Arquitetura de von Neumann.


A unidade central de processamento responsvel pela execuo das instrues armazenadas, tambm chamadas de programa. Atualmente, o termo UCP quase um sinnimo de
microprocessador. Um microprocessador a implementao de uma UCP atravs de um nico,
5
6

Artigo disponvel na seo Bibliografia complementar na pgina da disciplina no Moodle.


Do ingls central processing unit CPU.

FACOM

UFMS

2.2 A RQUITETURA

DE VON

N EUMANN

23

ou de muito poucos, circuitos integrados. Diversos fabricantes disponibilizam microprocessadores no mercado, como os Core 2 Duo e Core 2 Quad da Intel e os Phenom X3 triple-core e
Phenom X4 quad-core da AMD.
A unidade central de processamento composta tambm pela unidade lgico-aritmtica
(ULA) e pela unidade de controle (UC). A ULA executa dois tipos de operaes: (i) operaes
aritmticas, como adies e subtraes, e (ii) operaes lgicas ou de comparao, como por
exemplo a verificao se um nmero maior ou igual a outro nmero. A UC coordena as
tarefas da UCP.
A memria de um computador pode ser vista como uma lista linear de compartimentos ou
clulas. Cada compartimento tem um identificador ou endereo numrico e pode armazenar
uma certa quantidade pequena de informao. A informao armazenada em um compartimento de memria pode ser uma instruo de um programa ou um dado, uma informao
que deve ser processada atravs das instrues. H dois tipos distintos de memria: (i) memrias volteis e (ii) memrias no volteis. As memrias do primeiro tipo necessitam de
uma fonte de energia para que seu contedo seja mantido. As memrias que permitem acesso
aleatrio7 aos seus compartimentos so, em geral, memrias volteis. Esses dispositivos permitem acesso rpido informao armazenada, mas so muito mais caros que os dispositivos
no volteis de memria. O que em geral chamamos de memria principal de um computador um dispositivo de memria voltil, pois quando desligamos o computador, todas as
informaes armazenadas em seus compartimentos so perdidas. Os dispositivos de armazenamento de informaes no volteis so aqueles que, ao contrrio dos primeiros, podem reter
a informao armazenada mesmo sem uma fonte de energia conectada. Como exemplo desses
dispositivos, podemos listar os discos rgidos, discos ticos, fitas magnticas, memrias do tipo
flash, memrias hologrficas, entre outros. Pela forma como em geral so implementados, esses
dispositivos no permitem que as informaes sejam acessadas rapidamente em um compartimento qualquer, o que acarreta um tempo maior para busca e recuperao das informaes.
No entanto, o custo de produo de tais dispositivos inferior ao custo dos dispositivos de
memrias volteis.
Se enxergarmos um computador como uma caixa-preta que alimentamos com informaes
e colhemos resultados dessas informaes processadas, podemos associar os seus dispositivos de entrada e sada como aqueles que fazem a comunicao do computador com o mundo
externo. O mundo externo pode ser composto por pessoas ou mesmo outros computadores.
Teclados, mouses, microfones, cmeras, entre outros, so dispositivos comuns de entrada. Monitores e impressoras so dispositivos de sada. Placas de rede so dispositivos tanto de entrada
como de sada de informaes.
Um computador funciona ento como uma mquina que, a cada passo, carrega uma instruo e dados da memria, executa essa instruo sobre esses dados e armazena os resultados
desse processamento em sua memria. Ento o processo se repete, isto , o computador novamente carrega uma prxima instruo e novos dados da memria, executa essa instruo sobre
os dados e grava os resultados desse processamento em sua memria. Enquanto existirem instrues a serem executadas em um programa, esse processo se repete. Todo computador tem
um sinal de relgio8 que marca esse passo mencionado, que mais conhecido como ciclo do relgio. Dessa forma, o sinal de relgio de um computador usado para coordenar e sincronizar
as suas aes.
7
8

Do ingls random acess memory RAM.


Do ingls clock signal.

FACOM

UFMS

24

I NTRODUO

COMPUTAO

Uma outra representao a arquitetura de von Neumann, mais prxima ao que conhecemos
como um computador pessoal, pode ser vista na figura 2.2.
impressora
mouse

1111
0000
0000
1111
0000
1111
portas
0000
1111
0000
1111

teclado

1111
0000
0000
1111
UCP
0000
1111
0000
1111
1111
0000
0000
1111
memria
0000
1111
0000
1111

1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1

1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1

1111
0000
0000
1111
placa
0000
1111
0000
1111
de disco
0000
1111

disco
rgido

DVD-RW

1111
0000
placa
0000
1111
0000
1111
grfica
0000
1111

monitor

1111
0000
placa
0000
1111
0000
1111
de som
0000
1111

caixas
de som

1111
0000
placa
0000
1111
0000
1111
de rede
0000
1111

internet

barramento

Figura 2.2: Uma outra ilustrao da arquitetura de von Neumann.


importante salientar que toda transmisso de dados, manipulao, armazenagem e recuperao realizada de fato por um computador atravs de pulsos eltricos e magnticos
representando seqncias de dgitos binrios, chamadas de bits, isto , seqncias de 0s e 1s.
Cada seqncia, por sua vez, organizada em um ou mais bytes, que so grupos de oito bits.
Neste contexto, as instrues e os dados manipulados pelo computador nada mais so do que
seqncias de bytes que possuem significado para o computador.

2.3 Algoritmos e programas


H uma certa controvrsia sobre como definir de maneira formal um algoritmo. Informalmente, podemos dizer que um algoritmo uma seqncia precisa, sistemtica e finita de passos
ou instrues para soluo de algum problema. Uma tentativa de formalizao do termo teve
incio com a tentativa de soluo do problema Entscheidungsproblem, ou o problema da deciso,
proposto por David Hilbert9 em 1928. O termo algoritmo, como mencionamos na aula 1,
a al-Khwarizm10 . A latinizao de
tem sua origem no cientista persa Muh.ammad ibn Mus
seu nome deu origem ao termo algoritmo e algarismo na lngua portuguesa. Suas principais
contribuies incluem inovaes importantes na matemtica, em especial em lgebra e trigonometria. Um de seus mais importantes livros, Sobre o Clculo com Nmeros Hindus, do ano
de 825, foi responsvel pela disseminao do sistema hindu-arbico de numerao no Oriente
Mdio e na Europa.
9
David Hilbert ( ), nascido na Alemanha, reconhecido como um dos mais influentes matemticos
dos sculos XIX e XX.
10
a al-Khwarizm ( ), nascido na Prsia, matemtico, astrnomo e
Abu Abdalla Muh.ammad ibn Mus
gegrafo.

FACOM

UFMS

2.3 A LGORITMOS

E PROGRAMAS

25

Um algoritmo ento um conjunto de idias abstratas para soluo de um problema. Mais


formalmente, podemos estabelecer que um algoritmo uma seqncia finita de instrues para
resolver um problema, a qual possui as seguintes propriedades:
Garantia de trmino: o problema a ser resolvido possui condies especficas que, quando
satisfeitas, a execuo do algoritmo encerrada e o problema ento tido como resolvido. Alm disso, estas condies devem ser satisfeitas aps uma quantidade finita de
tempo, a ser contado a partir do incio da execuo do algoritmo;
Exatido: a inteno de cada instruo no algoritmo deve ser suficientemente clara, de
forma que no haja ambigidade na interpretao da inteno.
Efetividade: cada instruo deve ser bsica o suficiente para ser executada, pelo menos
em princpio, por qualquer agente usando apenas lpis e papel.
Lidamos com algoritmos desde nossa infncia em diversas situaes. Por exemplo, aprendemos no ensino primrio o algoritmo de Euclides para obteno do mximo divisor comum
entre dois nmeros inteiros. Inicialmente, tomamos dois nmeros inteiros a e b. Se b = 0 ento
o mximo divisor comum entre a e b o nmero a. Caso contrrio, o mximo divisor comum
entre a e b dado pelo mximo divisor comum de b e do resto da diviso de a por b. O processo
ento se repete at que b seja igual a 0 (zero). Esquematicamente, podemos escrever a seguinte
seqncia de instrues para resolver o problema:
PASSO

1 Chame o maior nmero de a e o menor de b

PASSO

2 Divida a por b e chame o resto de r

3 Se r igual a zero ento o mximo divisor comum igual a b e a execuo das instrues encerra aqui. Caso contrrio, siga para a prxima instruo.

PASSO

PASSO

4 Atribua o valor de b a a e o valor de r a b

PASSO

5 Volte para o passo 2

importante destacar que essa seqncia de instrues sempre obtm um valor r = 0


em algum dos passos e, portanto, sempre termina. Alm disso, a seqncia de instrues est
correta, j que sempre produz uma resposta correta para um par de nmeros inteiros fornecidos
como entrada. Dessa forma, acabamos de descrever um algoritmo para soluo do problema
do mximo divisor comum, o algoritmo de Euclides.
Como era de se esperar, nem toda seqncia de instrues para resolver um determinado
problema pode ser considerada um algoritmo. Por exemplo, se a instruo Divida x por y
se todo nmero inteiro par maior que 2 a soma de dois nmeros primos estiver presente
na seqncia, ela s poder ser executada se soubermos se a proposio todo nmero inteiro
par maior que 2 a soma de dois nmeros primos verdadeira ou falsa. Entretanto, esta
proposio, conhecida como conjectura de Goldbach11 , foi proposta em 1742 e continua sem
soluo at hoje. Logo, nossa instruo no pode ser executada por qualquer agente hoje em
dia e, portanto, no pode fazer parte de um algoritmo.
11

Veja mais em Goldbachs conjecture.

FACOM

UFMS

26

I NTRODUO

COMPUTAO

Um outro exemplo de instruo que no pode fazer parte de um algoritmo Escreva todos
os nmeros mpares. Neste caso, temos uma instruo que no pode ser executada porque
a execuo nunca terminar, apesar de sabermos exatamente como determinar os nmeros
mpares. Observe que se modificssemos a instruo para Escreva todos os nmeros mpares
menores do que 100, ela poderia, perfeitamente, fazer parte de um algoritmo.
Um problema para o qual existe uma soluo na forma de algoritmo dito um problema
algortmico. O problema de encontrar o mximo divisor comum de dois nmeros naturais
quaisquer , portanto, um problema algortmico. Problemas algortmicos, em geral, possuem
muitas ocorrncias. Por exemplo, para o problema de encontrar o mximo divisor comum de
dois nmeros naturais, cada ocorrncia uma dupla distinta de nmeros naturais cujo mximo
divisor comum queremos encontrar. Um algoritmo dito correto quando ele sempre termina e
produz a resposta correta para todas as ocorrncias de um dado problema.
Algoritmo, ento, pode ser imaginado como a especificao de um processo mecnico
que, quando executado, leva-nos soluo de algum problema. Embora o termo algoritmo
esteja relacionado intimamente com Computao, algoritmos tm sido parte de nossas vidas
desde a primeira vez que uma pessoa explicou para outra como fazer alguma coisa. As pessoas utilizam algoritmos quando seguem receitas culinrias ou instrues para programar um
tocador de msicas. Entretanto, nem todo algoritmo pode ser executado por um computador.
Um computador pode executar apenas aqueles algoritmos cujas instrues envolvam tarefas
que ele possa entender e executar. Este no o caso, por exemplo, de instrues como corte o
fil em cubos e ligue o tocador de msica.
Computadores executam algoritmos que manipulam apenas dados e no coisas fsicas, tais
como fil e tocador de msica. A execuo de um algoritmo por um computador denominada
processamento de dados e consiste de trs partes: uma entrada, um processo ou processamento
e uma sada. A entrada um conjunto de informaes que requisitada para que as instrues
do algoritmo possam ser executadas. O processamento a seqncia de instrues que compe
o algoritmo. E a sada o resultado obtido com a execuo do processo para a entrada fornecida. Por exemplo, a entrada e a sada para uma computao do algoritmo para o problema
de encontrar o mximo divisor comum de dois nmeros naturais so, respectivamente, dois
nmeros naturais e o mximo divisor comum entre eles.
Quando escrevemos algoritmos para serem executados por computador, temos de fazer
algumas suposies sobre o modelo de computao entradaprocessamentosada. A primeira
delas que, a fim de realizar qualquer computao, o algoritmo deve possuir um meio de
obter os dados da entrada. Esta tarefa conhecida como leitura da entrada. A segunda, que o
algoritmo deve possuir um meio de revelar o resultado da computao. Isto conhecido como
escrita dos dados da sada. Todo e qualquer computador possui dispositivos atravs dos quais
a leitura e a escrita de dados so realizadas.

2.3.1 Algoritmos e resoluo de problemas


Todo algoritmo est relacionado com a soluo de um determinado problema. Portanto,
construir um algoritmo para um dado problema significa, antes de mais nada, encontrar uma
soluo para o problema e descrev-la como uma sequncia finita de aes.
A tarefa de encontrar a soluo de um problema qualquer , em geral, realizada de forma
emprica e um tanto quanto desorganizada; ocorrem vrios procedimentos mentais, dos quais
FACOM

UFMS

2.3 A LGORITMOS

E PROGRAMAS

27

raramente tomamos conhecimento. A organizao do procedimento de resoluo de problemas


extremamente desejvel, pois somente assim podemos verificar onde o procedimento no est
eficiente. Identificadas as deficincias, procuramos formas de corrigi-las e, consequentemente,
aumentamos a nossa capacidade de resolver problemas.
A capacidade para resolver problemas pode ser vista como uma habilidade a ser adquirida.
Esta habilidade, como qualquer outra, pode ser obtida pela combinao de duas partes:
Conhecimento: adquirido pelo estudo. Em termos de resoluo de problemas, est relacionado a que tticas, estratgias e planos usar e quando usar;
Destreza: adquirida pela prtica. A experincia no uso do conhecimento nos d mais
agilidade na resoluo de problemas.
Independente do problema a ser resolvido, ao desenvolvermos um algoritmo devemos seguir os seguintes passos:
Anlise preliminar: entender o problema com a maior preciso possvel, identificando os
dados e os resultados desejados;
Soluo: desenvolver um algoritmo para o problema;
Teste de qualidade: executar o algoritmo desenvolvido com uma entrada para a qual o
resultado seja conhecido;
Alterao: se o resultado do teste de qualidade no for satisfatrio, altere o algoritmo e
submeta-o a um novo teste de qualidade;
Produto final: algoritmo concludo e testado, pronto para ser aplicado.

2.3.2 Resoluo de problemas e abstrao


Talvez, o fator mais determinante para o sucesso em resolver um problema seja a abstrao. Abstrao12 alguma coisa independente de qualquer ocorrncia particular ou o processo
de identificar certas propriedades ou caractersticas de uma entidade material e us-las para
especificar uma nova entidade que representa uma simplificao da entidade da qual ela foi
derivada. Esta nova entidade o que chamamos de abstrao.
Para entender o papel da abstrao na resoluo de problemas, considere a seguinte ocorrncia de um problema que lembra nossos tempos de criana:
Maria tinha cinco mas e Joo tinha trs. Quantas mas eles tinham juntos?
Provavelmente, um adulto resolveria este problema fazendo uma abstrao das mas como
se elas fossem os nmeros 5 e 3 e faria a soma de tais nmeros. Uma criana poderia imaginar
as cinco mas de Maria como cinco palitinhos e as trs de Joo como trs palitinhos. Da,
faria uma contagem dos palitinhos para chegar soluo. Em ambos os casos, os elementos
do problema foram substitudos por outros (nmeros e palitinhos) e a soluo foi encontrada
atravs da manipulao dos novos elementos.
12

Segundo o Websters New Dictionary of American Language.

FACOM

UFMS

28

I NTRODUO

COMPUTAO

O processo de abstrao pode ser visto como constando de nveis. Isto diz respeito ao grau
de simplificao de uma abstrao. Por exemplo, se a planta de uma casa entregue a um
experiente mestre-de-obras sem meno de, por exemplo, como fazer uma mistura ideal de
cimento para fundao, provavelmente, isso no ser um problema para ele. Entretanto, se a
mesma planta da casa for entregue a um advogado, ele certamente no saber construir a casa.
Isso quer dizer que a planta da casa dada ao advogado deveria conter maiores detalhes do
processo de construo da casa do que aquela dada para o mestre-de-obras. Aqui, a planta da
casa uma abstrao e o nvel de detalhe da planta proporcional ao nvel de simplificao da
abstrao.
Algoritmos bem projetados so organizados em nveis de abstrao, pois um mesmo algoritmo deve ser entendido por pessoas com diferentes graus de conhecimento. Quando um
algoritmo est assim projetado, as instrues esto organizadas de tal forma que podemos entender o algoritmo sem, contudo, ter de entender os detalhes de todas as instrues de uma s
vez. Para tal, o processo de construo de algoritmos conta com ferramentas, tais como mdulos, que agrupam instrues que realizam uma determinada tarefa no algoritmo, independente
das demais, tal como fazer a leitura da entrada, dispensando-nos de entender o detalhe de cada
instruo separadamente, mas sim fornecendo-nos uma viso da funcionalidade do grupo de
instrues.

2.3.3 Algoritmos e computadores


Aps o desenvolvimento de um algoritmo para soluo de algum problema, o prximo
passo inform-lo a um computador. No entanto, como mencionamos, os computadores no
compreendem, e portanto so incapazes de obedecerem e executarem, instrues em uma linguagem natural como a lngua portuguesa. Dessa forma, precisamos traduzir nosso algoritmo
para um programa em uma linguagem de programao escolhida. Uma linguagem de programao uma linguagem artificial projetada para expressar computaes que podem ser
executadas por um computador. Dessa forma, um programa projetado em uma linguagem de
programao possui uma sintaxe e semntica precisas. Alm disso, um programa escrito em
uma linguagem de programao pode ser facilmente traduzido para um programa em linguagem de mquina, que nada mais que uma seqncia de dgitos binrios (bits) que representam
dados e instrues e que produzem o comportamento desejado do computador, em sua arquitetura especfica. Um programa em linguagem de mquina poderia se parecer com a seguinte
seqncia de bytes:
01000011 00111010 00111011 01000001 00101001 01000100
Como a maioria dos problemas resolvidos por computadores no envolve o conhecimento
dos dispositivos internos do computador, a programao em linguagem de mquina , na maioria das vezes, inadequada, pois o desenvolvedor perde mais tempo com os detalhes da mquina do que com o prprio problema. Entretanto, para programas onde o controle de tais
dispositivos essencial, o uso de linguagem de mquina mais apropriado ou, s vezes, indispensvel.
O prximo passo na evoluo das linguagens de programao foi a criao da linguagem
montadora ou assembly. Nesta linguagem, as instrues da linguagem de mquina recebem
nomes compostos por letras, denominados mnemnicos, que so mais significativos para ns
humanos. Por exemplo, a instruo na linguagem montadora do processador INTEL 8088 que
FACOM

UFMS

2.3 A LGORITMOS

29

E PROGRAMAS

soma o valor no registrador CL com o valor no registrador BH e armazena o resultado em CL


dada por:
ADD CL,BH
Esta instruo equivale a seguinte sequncia de dois bytes na linguagem de mquina do processador INTEL 8088:
00000010 11001111
Para que o computador pudesse executar um programa escrito em linguagem montadora
foi desenvolvido um compilador denominado montador ou assembler, o qual realiza a traduo automtica de um cdigo escrito em linguagem montadora para o seu correspondente em
linguagem de mquina.
O sucesso da linguagem montadora animou os pesquisadores a criarem linguagens em que
a programao fosse realizada atravs de instrues na lngua inglesa, deixando para o prprio computador a tarefa de traduzir o cdigo escrito em tais linguagens para sua linguagem
de mquina. Isto foi possvel devido criao de compiladores mais complexos do que os
montadores.
Em geral, trabalhamos com linguagens de programao chamadas de alto nvel, o que
significa que so linguagens de programao mais facilmente compreensveis para os seres
humanos. As linguagens C, C++, Java, PHP, Lisp, Python, entre outras, so linguagens de
programao de alto nvel. H ainda uma classificao das linguagens de programao de alto
nvel pela forma que diferem nos conceitos e abstraes usados para representar os elementos
de um programa, tais como objetos, funes, variveis, restries, etc, e os passos que compem
uma computao, como por exemplo a atribuio, a avaliao, o fluxo de informaes, etc. A
essa classificao se d o nome de pardigma de programao. Dentre os existentes e mais
comuns, podemos citar o paradigma estruturado, orientado a objetos e funcional.
Infelizmente, programas escritos em uma linguagem programao de alto nvel qualquer
no esto prontos para serem executados por um computador. Ainda h processos de traduo
intermedirios que levam o programa de um ponto compreensvel por um ser humano e incompreensvel para o computador para o outro extremo, isto , basicamente incompreensvel
pelo ser humano e completamente compreensvel pelo computador e sua arquitetura.
Assim, dado um programa em uma linguagem de programao de alto nvel, usamos um
programa especial, chamado compilador, para efetuar a traduo deste programa para um
programa em linguagem assembly, de baixo nvel e associada ao processador do computador
que ir executar as instrues. Um segundo e ltimo processo de traduo ainda realizado,
chamado de montagem, onde h a codificao do programa na linguagem assembly para um
programa em formato binrio, composto por 0s e 1s, e que pode enfim ser executado pela
mquina. Um esquema dos passos desde a concepo de um algoritmo at a obteno de um
programa executvel equivalente em um computador mostrado na figura 2.3.
Modelos conceituais inovadores e alternativos arquitetura de von Neumann tm sido propostos e alguns deles implementados. O computador baseado em DNA ou computador molecular, o computador qumico e o computador quntico so exemplos de propostas recentes e
promissoras.
FACOM

UFMS

30

I NTRODUO

COMPUTAO

111111
000000
000000
111111
000000
111111
000000
111111
algoritmo
000000
111111
000000
111111
000000
111111
0
1
0
1
0
1
0 programao
1
0
1
0
1
000000
111111
programa na
000000
111111
000000
111111
linguagem
000000
111111
X
000000
111111
0
1
000000
111111
0
1
0
1
0
1
0 compilao
1
0
1
0
1
000000
111111
000000
111111
programa
000000
111111
assembly
000000
111111
000000
111111
000000
111111
0
1
0
1
0
1
montagem
0
1
0
1
000000
111111
0
1
000000
111111
programa
em
000000
111111
000000
111111
linguagem
000000
111111
de mquina
000000
111111
000000
111111
Figura 2.3: Passos desde a concepo de um algoritmo at o programa executvel por um
computador.

Exerccios
2.1 Leia o verbete Computer na Wikipedia, que traz muitas informaes sobre essas mquinas.
2.2 Leia o verbete von Neumann architecture na Wikipedia, sobre o modelo de organizao
interna de computadores mais conhecido.
2.3 D uma olhada no trabalho de John von Neumann na referncia [14]13 , sobre a arquitetura de von Neumann.
2.4 D uma olhada no trabalho de Alan Turing na referncia [11]14 com a descrio da mquina de Turing.
2.5 Visite a pgina sobre a vida e o trabalho de Konrad Zuse.
2.6 Sobre a linguagem de programao que adotaremos neste curso, visite as pginas
C History e C Programming Language e leia o verbete C (programming language) na Wikipedia.

13
14

Artigo disponvel na seo Bibliografia complementar na pgina da disciplina no Moodle.


Artigo disponvel na seo Bibliografia complementar na pgina da disciplina no Moodle.

FACOM

UFMS

AULA

D ICAS

INICIAIS

Nesta aula aprenderemos dicas importantes sobre as ferramentas que mais usaremos durante o desenvolvimento da parte prtica da disciplina. Em particular, veremos a definio de
uma interface do sistema operacional (shell ou Unix shell) e aprenderemos a usar alguns dentre
os tantos comandos disponveis para essa interface, aprenderemos alguns comandos e funes
do ambiente de trabalho GNU/Emacs e aprenderemos a usar o compilador da linguagem C da
coleo de compiladores GNU, o GCC .

3.1 Interface do sistema operacional


Podemos definir uma interface de um sistema como um programa que permite a interao entre o sistema e seus usurios. Dessa forma, diversos sistemas contm interfaces desse
tipo. No entanto, esse termo quase que automaticamente associado aos sistemas operacionais, onde uma interface fornecida aos usurios para acesso aos servios do ncleo do sistema operacional. As interfaces dos sistemas operacionais so freqentemente usadas com o
propsito principal de invocar outros programas, mas tambm possuem outras habilidades
adicionais.
H em geral dois tipos de interfaces de sistemas operacionais: as interfaces de linhas de
comando e as interfaces grficas. Neste curso, usaremos as interfaces de linhas de comando
para solicitar servios e executar certos programas nativos do sistema operacional Linux. A
seguir listamos alguns desses comandos.
Antes de mais nada, necessrio saber duas coisas sobre o sistema que temos instalado
em nossos laboratrios. Primeiro, devemos saber que o sistema operacional instalado nesses
computadores o Linux. A distribuio escolhida a Debian, verso Lenny. Essa e uma distribuio no comercial e livre do GNU/Linux, isto , uma verso gratuita e de cdigo fonte
aberto. O nome Debian vem dos nomes dos seus fundadores, Ian Murdock e de sua esposa,
Deb ra. Diversas distribuies comerciais baseiam-se, ou basearam-se, na distribuio Debian,
como Linspire, Xandros, Kurumin, Debian-BR-CDD, Ubuntu e Libranet. A segunda informao importante sobre a interface grfica do Linux usada nos laboratrios. A interface grfica
completa do ambiente de trabalho a plataforma GNOME . Essa plataforma um projeto colaborativo internacional inteiramente baseado em software livre que inclui o desenvolvimento
de arcabouos, de seleo de aplicaes para o ambiente de trabalho e o desenvolvimento de
programas que gerenciam o disparo de aplicaes, manipulao de arquivos, o gerenciamento
de janelas e de tarefas. O GNOME faz parte do Projeto GNU e pode ser usado com diversos
sistemas operacionais do tipo Unix, especialmente aqueles que possuem um ncleo Linux.
31

32

D ICAS

INICIAIS

Isso posto, um dos programas mais comuns disponveis para os usurios do sistema operacional GNU/Linux chamado de terminal, como uma abreviao de terminal de linhas de
comando, que nada mais que uma interface entre o usurio e o sistema operacional. Para
disparar esse programa no gerenciador de janelas GNOME, selecione a opo Aplicaes do
menu principal, depois a opo Acessrios no sub-menu e, em seguida, a opo Terminal.
Um exemplo de uma janela de terminal de linhas de comando do GNOME apresentado na
figura 3.1.

Figura 3.1: Uma interface, ou janela, de linhas de comandos do sistema de janelas GNOME,
chamada no computador Homer pelo usurio fhvm. Esses nomes compem o sinal de pronto
do sistema.
Uma janela de linha de comandos possibilita a interao entre o usurio e o computador,
intermediada pelo sistema operacional, onde o primeiro solicita tarefas diretamente ao outro e,
depois de executadas, recebe seus resultados. Daqui por diante, veremos alguns dos comandos
e utilitrios que sero mais usados durante o decorrer da disciplina. Alguns deles apresentam,
at certo ponto, algum grau de dificuldade de compreenso neste momento. Todavia, importante ressaltar que todos esses comandos e utilitrios sero muito teis a partir de momentos
oportunos, como veremos.
A seguir, apresentamos a tabela 3.1 contendo os principais comandos e utilitrios do sistema operacional, com suas descries breves, os quais mais usaremos no desenvolvimento da
disciplina de Algoritmos e Programao I (e II). Esta tabela apenas um guia de referncia rpida e, apesar da maioria dos comandos e utilitrios serem intuitivos e muito fceis de usar, a
descrio breve contida na tabela infelizmente no nos ensina de fato como fazer uso correto de
cada um deles. Tambm no mostra todas as opes de execuo que em geral todo comando
ou utilitrio possui.
FACOM

UFMS

3.1 I NTERFACE

DO SISTEMA OPERACIONAL

33

Dessa forma, para aprender gradativa e corretamente a usar os comandos e utilitrios apresentados na tabela 3.1 necessrio: (i) fazer os exerccios ao final desta aula; (ii) usar com
freqncia o utilitrio man ou info , que so interfaces para o manual de referncia dos comandos e ferramentas do sistema1 . Por exemplo, podemos digitar:

prompt$ man comando

ou

prompt$ info comando

onde prompt$ o sinal de pronto do sistema, man e info so utilitrios do sistema e


comando o nome do comando/ferramenta do sistema para o qual informaes do manual
sero exibidas; e (iii) usar a opo --help na chamada de um comando/utilitrio. Essa opo
mostra como us-lo corretamente, listando as opes disponveis. Por exemplo,

prompt$ man -help

Para aumentar a flexibilidade e facilidade na especificao de argumentos de comandos do


sistema operacional, podemos usar caracteres especiais de substituio, chamados de coringas.
Como veremos, os coringas so muito usados quando os argumentos dos comandos so nomes
de arquivos.
O caractere * (asterisco) um coringa que substitui zero ou mais caracteres. No comando
apresentado a seguir:

prompt$ ls *.c

prompt$ o sinal de pronto do sistema, ls um comando que permite listar os arquivos


de um diretrio e *.c um argumento desse comando que representa todos os arquivos do
diretrio cujos nomes terminam com os caracteres .c .

O caractere ? (ponto de interrogao) um outro coringa muito usado como parte de


argumentos de comandos, representando exatamente um caractere e que pode ser um caractere
qualquer. Por exemplo, no comando abaixo:

prompt$ ls ???.c

prompt$ o sinal de pronto do sistema, ls um comando que permite listar os arquivos


1

Esses manuais tambm podem ser encontrados em pginas da internet, como Manpages e SS64.com.

FACOM

UFMS

34

D ICAS

INICIAIS

Comando

Descrio

cat arq
cd dir
cmp arq1 arq2
cp arq1 arq2
cp arq(s) dir
date
diff arq1 arq2
echo args
enscript arq
fmt arq
gprof arq
indent arq
info cmd
ls arq(s)
ls dir
man cmd
mkdir dir(s)
mv arq1 arq2
mv arq(s) dir
pwd
pr arq
rm arq(s)
rmdir dir(s)
sort arq(s)
wc arq(s)
who

mostra o contedo de arq ou da entrada padro


troca o diretrio atual para o diretrio dir
compara arq1 e arq2 byte a byte
copia o arq1 para o arq2
copia arq(s) para o diretrio dir
mostra a data e a hora do sistema
compara arq1 e arq2 linha a linha
imprime args
converte arquivos-texto para PostScript, HTML, RTF, ANSI e outros
formata arq
fornece um perfil de execuo do programa arq
faz a indentao correta de um programa na linguagem C em arq
mostra a pgina (mais completa) de manual de cmd
lista arq(s)
lista os arquivos no diretrio dir ou no diretrio atual
mostra a pgina de manual de cmd
cria diretrio(s) dir(s)
move/renomeia o arq1 para o arq2
move arq(s) para o diretrio dir
mostra o nome do diretrio atual
converte arq, do tipo texto, para impresso
remove arq(s)
remove diretrios vazios dir(s)
ordena as linhas de arq(s) ou da entrada padro
conta o nmero de linhas, palavras e caracteres em arq(s) ou na entrada padro
imprime a identificao do usurio do computador

Tabela 3.1: Tabela de comandos e utilitrios mais usados.

de um diretrio e ???.c um argumento desse comando que representa todos os arquivos


do diretrio cujos nomes contm exatamente 3 caracteres iniciais quaisquer seguidos pelos
caracteres .c .
Os colchetes [ ] tambm so caracteres coringas muito usados nos argumentos de comandos e indicam a substituio de um nico caractere especificado no interior dos colchetes. No
exemplo abaixo:

prompt$ ls *[abc]

o argumento *[abc] representa todos os arquivos do diretrio cujos nomes terminam com o
caractere a , b ou c .
Um intervalo de caracteres pode ser obtido no interior dos colchetes se o caractere -
usado. Por exemplo:
FACOM

UFMS

3.1 I NTERFACE

DO SISTEMA OPERACIONAL

35

prompt$ ls *[a-z]

onde o argumento representa os nomes dos arquivos que terminam com uma das 26 letras do
alfabeto.
Por fim, importante destacar que muitos comandos do sistema operacional recebem informaes de entrada a partir do terminal e tambm enviam as informaes resultantes de sada
para o terminal de comandos. Um comando em geral l as informaes de entrada de um local chamado de entrada padro, que pr-definido como o terminal de linha de comandos, e
escreve sua sada em um local chamado de sada padro, que tambm pr-definido como o
terminal de linhas de comando.
Por exemplo, o comando sort pode ordenar nomes fornecidos linha a linha por um usurio no terminal de comandos, ordenar esses nomes lexicograficamente e apresentar o resultado
no terminal de linha de comandos:
prompt$ sort
Zenaide
Carlos
Giovana
Amanda

Ctrl-d
Amanda
Carlos
Giovana
Zenaide
prompt$

Se dispomos os caracteres > arq ao final de qualquer comando ou utilitrio que normalmente envia sua sada para a sada padro, ou seja, para o terminal de linha de comandos,
o sada desse comando ser escrita para o arquivo com nome arq ao invs do terminal. Por
exemplo, a seqncia a seguir:

prompt$ sort > nomes.txt


Zenaide
Carlos
Giovana
Amanda

Ctrl-d
prompt$

faz com que quatro nomes digitados pelo usurio sejam ordenados e, em seguida, armazenados
no arquivo nomes.txt .
Assim como a sada pode ser redirecionada para um arquivo, a entrada tambm pode ser
redirecionada a partir de um arquivo. Se, por exemplo, existe um arquivo temp.txt contendo
diversos nomes apresentados linha a linha, ento o comando a seguir:

FACOM

UFMS

36

D ICAS

INICIAIS

prompt$ sort < temp.txt

faz com que todos os nomes contidos no arquivo temp.txt sejam ordenados lexicograficamente e posteriormente apresentados seguida na sada padro, isto , na janela do terminal de
linha de comandos.
Podemos ainda redirecionar a entrada e a sada de um comando concomitantemente. Por
exemplo, o comando:

prompt$ sort < temp.txt > nomes.txt

recebe, pelo redirecionamento da entrada, os nomes contidos no arquivo temp.txt , ordenaos lexicograficamente e os armazena em um novo arquivo chamado nomes.txt , devido ao
redirecionamento da sada.
Dessa forma, temos que os smbolos < e > so os smbolos de redirecionamento de entrada e sada, respectivamente.

3.2 Compilador
A coleo de compiladores GNU (GCC ) , na verdade, um arcabouo de compiladores para
diversas linguagens de programao. Esse sistema foi desenvolvido pelo Projeto GNU e, por
ter sido adotado como o compilador oficial do sistema operacional GNU, tambm foi adotado
como compilador padro por muitos dos sistemas operacionais derivados do Unix, tais como
o GNU/Linux, a famlia BSD e o Mac OS X. Alm disso, o GCC tem sido traduzido para uma
grande variedade de arquiteturas.
Richard Stallman desenvolveu a primeira verso do GCC em 1987, como uma extenso de
um compilador j existente da linguagem C. Por isso, naquela poca o compilador era conhecido como GNU C Compiler. No mesmo ano, o compilador foi estendido para tambm compilar
programas na linguagem C++. Depois disso, outras extenses foram incorporadas, como Fortran, Pascal, Objective C, Java e Ada, entre outras. A Fundao para o Software Livre distribui
o GCC sob a Licena Geral Pblica (GNU GPL GNU General Public License). O GCC um
software livre.
Um compilador faz o trabalho de traduzir um programa na linguagem C, ou de outra linguagem de alto nvel qualquer, para um programa em uma linguagem intermediria, que ainda
ser traduzido, ou ligado, para um programa em uma linguagem de mquina. Dessa forma,
um argumento bvio que devemos fornecer ao GCC o nome do arquivo que contm um programa na linguagem C. Alm disso, podemos informar ao compilador um nome que ser atribudo ao programa executvel resultante da compilao e ligao. H tambm diversas opes
disponveis para realizar uma compilao personalizada de um programa e que podem ser
informadas no processo de compilao.
Ento, o formato geral de compilao de um programa dado a seguir:
FACOM

UFMS

3.3 E MACS

37

prompt$ gcc programa.c -o executvel -Wall -ansi -pedantic

onde gcc o programa compilador, programa.c um arquivo com extenso .c que contm
um programa fonte na linguagem C, -o uma opo do compilador que permite fornecer um
nome ao programa executvel resultante do processo ( executvel ), -Wall uma opo que
solicita que o compilador mostre qualquer mensagem de erro que ocorra durante a compilao,
-ansi uma opo que fora o programa fonte a estar escrito de acordo com o padro ANSI
da linguagem C e -pedantic uma opo que deixa o compilador muito sensvel a qualquer
possvel erro no programa fonte.
No momento, ainda no escrevemos um programa na linguagem C e, por isso, no conseguimos testar o compilador de forma satisfatria. Esta seo ento apenas um guia de
referncia rpida que ser muito usada daqui por diante.

3.3 Emacs
Em geral, usamos a palavra Emacs para mencionar um editor/processador de textos, mas
Emacs , na verdade, o nome de uma classe de editores/processadores que se caracteriza especialmente pela sua extensibilidade. O Emacs tem mais de 1.000 comandos de edio, mais do
que qualquer outro editor existente, e ainda permite que um usurio combine esses comandos
em macros para automatizao de tarefas. A primeira verso do Emacs foi escrita em 1976
por Richard Stallman. A verso mais popular do Emacs o GNU/Emacs, uma parte do Projeto GNU. O GNU/Emacs um editor extensvel, configurvel, auto-documentado e de tempo
real. A maior parte do editor escrita na linguagem Emacs Lisp, um dialeto da linguagem de
programao funcional Lisp.
O Emacs considerado por muitos especialistas da rea como o editor/processador de
textos mais poderoso existente nos dias de hoje. Sua base em Lisp permite que se torne configurvel a ponto de se transformar em uma ferramenta de trabalho completa para escritores,
analistas e programadores.
Em modo de edio, o Emacs comporta-se como um editor de texto normal, onde o pressionamento de um caractere alfanumrico no teclado provoca a insero do caractere correspondente no texto, as setas movimentam o ponto ou cursor de edio, a tecla Backspace remove
um caractere, a tecla Insert troca o modo de insero para substituio ou vice-versa, etc. Comandos podem ser acionados atravs do pressionamento de uma combinao de teclas, pressionando a tecla Ctrl e/ou o Meta/Alt juntamente com uma tecla normal. Todo comando
de edio de fato uma chamada de uma funo no ambiente Emacs Lisp. Alguns comandos
bsicos so mostrados na tabela 3.2. Observe que a tecla Ctrl representada por C e a tecla
Alt por M . Um manual de referncia rpida est disponvel na bibliografia complementar na
pgina da disciplina.
Para carregar o Emacs, podemos usar o menu principal do GNOME e escolher a opo Aplicaes, escolhendo em seguida a opo Acessrios e ento a opo Emacs. Ou ento, de uma
linha de comandos, podemos usar:

prompt$ emacs &


FACOM

UFMS

38

D ICAS

INICIAIS

Vejamos a tabela 3.2, que contm um certo nmero de comandos2 importantes.


Teclas
C-z
C-x C-c
C-x C-f
C-x C-s
C-x i
C-x C-w
C-h r
C-h t
C-g
C-s
C-r
M-%

Descrio
minimiza a janela do Emacs
finaliza a execuo do Emacs
carrega um arquivo no Emacs
salva o arquivo atual no disco
insere o contedo de um outro arquivo no arquivo atual
salva o contedo do arquivo em um outro arquivo especificado
carrega o manual do Emacs
mostra um tutorial do Emacs
aborta o comando parcialmente informado
busca uma cadeia de caracteres a partir do cursor
busca uma cadeia de caracteres antes do cursor
interativamente, substitui uma cadeia de caracteres

Tabela 3.2: Uma pequena tabela de comandos do Emacs.


importante observar que o Emacs, quando executado em sua interface grfica, tem a
possibilidade de executar muitos de seus comandos atravs de botes do menu ou atravs da
barra de menus. No entanto, usurios avanados preferem usar os atalhos de teclado para esse
tipo de execuo, por terem um acesso mais rpido e mais conveniente depois da memorizao
dessas seqncias de teclas.

Exerccios
3.1 Abra um terminal. A partir de seu diretrio inicial, chamado de home pelo sistema operacional, faa as seguintes tarefas:
crie trs diretrios com os seguintes nomes: algprogi, ftc e temp;

entre no diretrio algprogi;

crie quatro subdiretrios dentro do diretrio algprogi com os seguintes nomes:


teoricas, praticas, trabalhos e provas;
entre no diretrio praticas;

usando o comando cat e o smbolo de redirecionamento de sada > , crie um arquivo com nome agenda.txt, que contm linha a linha, nome e telefone de pessoas.
Adicione pelo menos 10 nomes nesse arquivo;
copie o arquivo agenda.txt para os diretrios algprogi e temp;

verifique o contedo dos diretrios algprogi/praticas, algprogi e temp;

use o comando sort para ordenar o contedo do arquivo agenda.txt. Execute o


comando duas vezes: na primeira, use-o visualizando o resultado na tela do computador. Na segunda, redirecione a sada desse mesmo comando, criando um novo
arquivo com nome agenda-ordenada.txt;
verifique o contedo do diretrio algprogi/praticas;
2

Veja tambm o carto de referncia do Emacs na seo de bibliografia complementar da disciplina no Moodle.

FACOM

UFMS

3.3 E MACS

39

compare os arquivos agenda.txt e agenda-ordenada.txt com os comandos cmp


e diff ;
crie um arquivo com nome frase contendo uma frase qualquer, com pelo menos 20
caracteres. Da mesma forma como antes, use o comandos cat e o smbolo > de
redirecionamento de sada;
conte o nmero de palavras no arquivo frase usando o comando wc ;

neste diretrio, liste todos os arquivos que comeam com a letra a;


neste diretrio, liste todos os arquivos que comeam com a letra f;

neste diretrio, liste todos os arquivos que terminam com a seqncia de caracteres
txt;
repita os trs ltimos comandos, usando no entanto o comando echo ;

liste todos os arquivos contidos neste diretrio, mas redirecione a sada do comando
para um arquivo de nome lista;
execute o comando ls [afl]* e verifique a sada;

execute o comando ls [a-l]* e verifique a sada;


execute o comando ls ?g* e verifique a sada;

execute o comando ls ?[gr]* e verifique a sada;


execute o comando ls ????? e verifique a sada;
execute o comando ls .. e verifique a sada;

execute o comando ls /algprogi e verifique a sada;


execute o comando ls e verifique a sada;

mova os arquivos cujos nomes tm exatamente 5 caracteres neste diretrio para o


diretrio temp;
remova o diretrio temp do seu sistema de arquivos;

remova todos os arquivos criados at aqui, mantendo apenas os diretrios.


3.2 Abra o Emacs. Ento, realize as seguintes tarefas:
digite um texto que resume o que voc aprendeu nas aulas de Algoritmos e Programao I at aqui;
salve o arquivo no diretrio algprogi/teoricas;

busque as palavras computador, Turing, von Neumann, ENIAC, ls, cp e Emacs no


seu texto;
troque a palavra Emacs no seu texto pela palavra GNU/Emacs.

FACOM

UFMS

40

FACOM

D ICAS

INICIAIS

UFMS

AULA

P RIMEIROS

PROGRAMAS

Nesta aula aprenderemos a codificar nossos primeiros programas na linguagem C, tomando


contato com a estrutura seqencial de programao e com funes de entrada e sada.

4.1 Digitando
Abra o seu Emacs, pressione C-x C-f , digite em seguida um nome para seu primeiro
programa, como por exemplo primeiro.c, e ento digite o seguinte cdigo.
Programa 4.1: Primeiro programa.
#include <stdio.h>
int main(void)
{
printf("Programar bacana!\n");
return 0;
}

Depois de ter digitado o programa, pressione as teclas C-x C-s para salv-lo em um diretrio adequado da sua rea de trabalho. Na linguagem C, letras minsculas e maisculas so
diferentes. Alm disso, em programas na linguagem C no h distino de onde voc inicia a
digitao das suas linhas e, assim, usamos essa caracterstica a nosso favor, adicionando espaos em algumas linhas do programa para facilitar sua leitura. Essa adio de espaos em uma
linha chamada indentao ou tabulao. No Emacs, voc pode usar a tecla Tab para adicionar indentaes de forma adequada. Veremos que a indentao uma prtica de programao
muito importante.

4.2 Compilando e executando


Abra um terminal onde possa digitar comandos, solicitando ao sistema operacional que os
execute. Ento, compile o programa 4.1 com o compilador gcc:

prompt$ gcc primeiro.c


prompt$

41

42

P RIMEIROS

PROGRAMAS

Depois disso, o programa executvel a.out estar disponvel para execuo no mesmo
diretrio. Assim, s digitar a.out (ou ./a.out) para ver o resultado da execuo:

prompt$ ./a.out
Programar bacana!
prompt$

O nome a.out um nome padro que o compilador gcc d aos arquivos executveis resultantes de uma compilao. Em geral, atribumos um nome mais significativo a um programa
executvel, como por exemplo o mesmo nome do programa na linguagem C, mas sem a sua
extenso. No exemplo acima, o programa executvel associado tem o nome primeiro. O compilador gcc pode gerar um executvel dessa forma como segue:

prompt$ gcc primeiro.c -o primeiro


prompt$

4.3 Olhando o primeiro programa mais de perto


A primeira linha do nosso primeiro programa

#include <stdio.h>

ser muito provavelmente includa em todo programa que voc far na linguagem C. Essa
linha fornece informaes ao compilador sobre a funo de sada de dados de nome printf ,
que usada depois no programa.
A segunda linha do programa

int main(void)

informa ao compilador onde o programa inicia de fato. Em particular, essa linha indica que
main , do ingls principal, o incio do programa principal e, mais que isso, que esse trecho do
programa na verdade uma funo da linguagem C que no recebe valores de entrada ( void )
e devolve um valor do tipo inteiro ( int ). Esses conceitos de funo, parmetros de uma
funo e valor de sada sero elucidados oportunamente. Por enquanto, devemos memorizar
que essa linha indica o incio de nosso programa.
A prxima linha contm o smbolo abre-chave { que estabelece o incio do corpo do programa. Em seguida, a prxima linha contm uma chamada funo printf :

printf("Programar bacana!\n");
FACOM

UFMS

4.4 P RXIMO

43

PROGRAMA

Passamos um nico argumento funo printf , a seqncia de smbolos ou de caracteres


"Programar bacana!\n" . Note que todos os smbolos dessa seqncia so mostrados na
sada, a menos de " e \n . O caractere \n tem um significado especial quando sua impresso
solicitada por printf : saltar para a prxima linha. A funo printf uma rotina da biblioteca stdio da linguagem C que mostra o seu argumento na sada padro, que geralmente
o monitor. Depois disso, adicionamos a linha

return 0;

que termina a execuo do programa. Finalmente o smbolo fecha-chave } indica o final do


corpo do programa.

4.4 Prximo programa


Vamos digitar um prximo programa.
Programa 4.2: Segundo programa.
#include <stdio.h>
int main(void)
{
int num1, num2, soma;
num1 = 25;
num2 = 30;
soma = num1 + num2;
printf("A soma de %d e %d %d\n", num1, num2, soma);
return 0;
}

Este exemplo ligeiramente diferente do primeiro e introduz algumas novidades. Agora, a


primeira linha aps a linha que contm o nome da funo main apresenta uma declarao de
variveis. Trs variveis do tipo inteiro so declaradas: num1 , num2 e soma . Isso significa
que, durante a execuo desse programa, trs compartimentos de memria so reservados pelo
computador para armazenamento de informaes que, neste caso, so nmeros inteiros. Alm
disso, a cada compartimento associado um nome: num1 , num2 e soma . Esses compartimentos de memria so tambm conhecidos como variveis, j que seu contedo pode variar
durante a execuo de um programa.
Depois disso, na prxima linha do nosso programa temos uma atribuio do valor do tipo
inteiro 25 para a varivel num1 . Observe ento que o operador de atribuio da linguagem C
= . Na linha seguinte, uma outra atribuio realizada, do nmero 30 para a varivel num2 .
Na prxima linha temos uma atribuio para a varivel soma . No entanto, note que no temos
mais um nmero no lado direito da expresso de atribuio, mas sim a expresso aritmtica
num1 + num2 . Neste caso, durante a execuo dessa linha do programa, o computador conFACOM

UFMS

44

P RIMEIROS

PROGRAMAS

sulta o contedo das variveis num1 e num2 , realiza a operao de adio com os dois valores
obtidos dessas variveis e, aps isso, atribui o resultado varivel soma . No nosso exemplo,
o resultado da expresso aritmtica 25 + 30, ou seja, o valor 55, ser atribudo varivel soma .
A linha seguinte contm uma chamada funo printf , mas agora com quatro argumentos:
o primeiro agora uma cadeia de caracteres de formatao, contendo no apenas caracteres a
serem impressos na sada, mas smbolos especiais, iniciados com % , conhecidos como conversores de tipo da linguagem C. Neste caso, os smbolos %d permitem que um nmero inteiro
seja mostrado na sada. Note que trs conversores %d esto contidos na cadeia de caracteres
de formatao e, a cada um deles est associado uma das variveis num1 , num2 e soma , na
ordem em que aparecem. Essas variveis so os argumentos restantes da funo printf .

4.5 Documentao
Uma boa documentao de um programa, conforme [15], significa inserir comentrios apropriados no cdigo de modo a explicar o que cada uma das funes que compem o programa
faz. A documentao de uma funo um pequeno manual que d instrues precisas e completas sobre o uso da funo.
Comentrios so introduzidos em programas com o objetivo de document-los e de incrementar a sua legibilidade. O(a) programador(a) responsvel por manter seus cdigos legveis
e bem documentados para que, no futuro, possa retom-los e compreend-los sem muito esforo e sem desperdcio de tempo. Na linguagem C padro, os comentrios so envolvidos
pelos smbolos /* e */ . Um comentrio completamente ignorado quando encontrado pelo
compilador e, portanto, no faz diferena alguma no programa executvel resultante.
Vejamos o programa 4.3, que nada mais que a codificao do programa 4.2 com uma
documentao do programa principal.
Programa 4.3: Segundo programa.
#include <stdio.h>
/* Este programa faz a adio de dois nmeros inteiros
fixos e mostra o resultado da operao na sada. */
int main(void)
{
int num1, num2, soma;
num1 = 25;
num2 = 30;
soma = num1 + num2;
printf("A soma de %d e %d %d\n", num1, num2, soma);
return 0;
}

Ainda conforme [15], uma boa documentao no se preocupa em explicar como uma funo faz o que faz, mas sim o que ela faz de fato, informando quais so os valores de entrada da
funo, quais so os valores de sada e quais as relaes que esses valores que entram e saem
da funo e as transformaes pela funo realizadas.
FACOM

UFMS

4.6 E NTRADA

45

E SADA

4.6 Entrada e sada


Veremos agora um exemplo de programa na linguagem C que usa pela primeira vez a
funo de leitura de dados scanf . Ento, abra seu Emacs, pressione a seqncia de teclas
C-x C-f , d um nome para seu programa, como por exemplo soma.c , e digite o cdigo
apresentado no programa 4.4 a seguir.
Programa 4.4: Entrada e sada de dados.
#include <stdio.h>
/* Recebe dois nmeros inteiros e imprime sua soma */
int main(void)
{
int num1, num2, soma;
printf("Informe um nmero: ");
scanf("%d", &num1);
printf("Informe outro nmero: ");
scanf("%d", &num2);
soma = num1 + num2;
printf("A soma de %d mais %d %d\n", num1, num2, soma);
return 0;
}

Vamos olhar mais de perto este programa. Observe que, pela primeira vez, usamos a funo
scanf que, como mencionamos acima, uma funo da linguagem C responsvel pela leitura
de dados.
Desconsiderando o esqueleto do programa, a primeira linha a ser notada a declarao de
variveis:
int num1, num2, soma;

Estamos, com esta linha do programa, reservando trs compartimentos de memria que podero ser utilizados para armazenamento de nmeros inteiros, cujos nomes so num1 , num2
e soma . Os contedos desses compartimentos de memria podem variar durante a execuo
do programa. De fato, no momento da declarao, os compartimentos associados aos nomes
num1 , num2 e soma j contm, cada um, algum valor que desconhecido e que referenciamos
como lixo.
Em seguida, h duas chamadas de funes para escrita e leitura:

printf("Informe um nmero: ");


scanf("%d", &num1);
FACOM

UFMS

46

P RIMEIROS

PROGRAMAS

A funo para escrita de dados printf j bem conhecida, vista nesta e nas aulas anteriores. A funo de leitura scanf tem dois argumentos: uma cadeia de caracteres de formatao "%d" e uma varivel num1 correspondente a este formato. Diferentemente da funo
printf , uma varivel do tipo inteiro que um argumento da funo scanf deve sempre vir
precedida com o smbolo & . Na instruo acima, a cadeia de caracteres de formatao "%d"
indica que o valor informado pelo usurio ser convertido para um inteiro. Ainda, este valor
ser ento armazenado na varivel do tipo inteiro num1 . Observe, mais uma vez, que esta
varivel precedida por um & .
A prxima seqncia de instrues equivalente e solicita ao usurio do programa a entrada de um outro nmero, que ser armazenado na varivel num2 :

printf("Informe outro nmero: ");


scanf("%d", &num2);

Depois disso, h uma instruo diferente:

soma = num1 + num2;

Aqui temos uma instruo/comando de atribuio da linguagem C, definida pelo smbolo/operador = . Uma instruo de atribuio tem uma sintaxe bem definida: do lado esquerdo do smbolo de atribuio = h sempre uma varivel; do lado direito h uma constante,
uma varivel ou uma expresso do mesmo tipo da varivel esquerda. Esta instruo funciona da seguinte forma: avalia a expresso do lado direito do smbolo de atribuio e atribui o
resultado desta avaliao para a varivel do lado esquerdo. Em nosso exemplo, o lado direito
uma expresso aritmtica de adio, que soma os contedos das variveis do tipo inteiro num1
e num2 . O resultado da avaliao dessa expresso um nmero inteiro que ser atribudo
varivel soma , do lado esquerdo do smbolo de atribuio. O lado direito de uma instruo
de atribuio pode conter expresses aritmticas to complicadas quanto quiseremos. O lado
esquerdo, ao contrrio, sempre descrito por uma nica varivel.
Por fim, a chamada funo

printf("A soma de %d mais %d %d\n", num1, num2, soma);

mostra, alm dos valores das duas parcelas num1 e num2 , o resultado dessa soma armazenado
na varivel soma .
Veremos agora um segundo exemplo usando as funes de entrada e sada que acabamos
de aprender. Este segundo exemplo muito semelhante ao exemplo anterior. A diferena est
apenas no formato da expresso aritmtica: no primeiro exemplo, uma adio realizada; neste
segundo exemplo, uma multiplicao realizada. O operador aritmtico de multiplicao o
smbolo * . Ento, informe, compile e execute o seguinte programa 4.5.

FACOM

UFMS

4.6 E NTRADA

47

E SADA

Programa 4.5: Segundo exemplo.


#include <stdio.h>
/* A funo main l dois nmeros inteiros e mostra na sada
o resultado da multiplicao desses dois nmeros */
int main(void)
{
int num1, num2, produto;
printf("Informe um nmero: ");
scanf("%d", &num1);
printf("Informe outro nmero: ");
scanf("%d", &num2);
produto = num1 * num2;
printf("O produto de %d por %d %d\n", num1, num2, produto);
return 0;
}

Exerccios
4.1 Escreva uma programa na linguagem C que escreva a seguinte mensagem na sada padro:
a)
b)
c)
d)
e)

Comentrios na linguagem C iniciam com /* e terminam com */


Letras minsculas e maisculas so diferentes na linguagem C
A palavra chave main indica o incio do programa na linguagem C
Os smbolos { e } envolvem um bloco de comandos na linguagem C
Todos os comandos na linguagem C devem terminar com um ponto e vrgula

4.2 Qual a sada esperada para o programa 4.6?


Programa 4.6: Programa do exerccio 4.2.
#include <stdio.h>
int main(void)
{
printf("Al! ");
printf("Al! ");
printf("Tem algum a?");
printf("\n");
return 0;
}

4.3 Escreva um programa na linguagem C que subtraia 14 de 73 e mostre o resultado na sada


padro com uma mensagem apropriada.
4.4 Verifique se o programa 4.7 est correto. Em caso negativo, liste os erros de digitao que
voc encontrou.
FACOM

UFMS

48

P RIMEIROS

PROGRAMAS

Programa 4.7: Programa do exerccio 4.4.


include <stdio.h>
/* computa a soma de dois nmeros
Int main(void)
{
int resultado;
resultado = 13 + 22 - 7
printf("O resultado da operao %d\n"
return 0;
}

resultado);

4.5 Escreva um programa que leia trs nmeros inteiros a, b e c, calcule a b + c e mostre o
resultado na sada padro para o usurio.
4.6 Escreva um programa que leia um nmero inteiro e mostre o seu quadrado e seu cubo.
Por exemplo, se o nmero de entrada 3, a sada deve ser 9 e 27.
4.7 Escreva um programa que leia trs nmeros inteiros e mostre como resultado a soma
desses trs nmeros e tambm a multiplicao desses trs nmeros.
4.8 Escreva um programa que leia um nmero inteiro e mostre o resultado da quociente
(inteiro) da diviso desse nmero por 2 e por 3.

FACOM

UFMS

AULA

E STRUTURAS

CONDICIONAIS

At aqui, implementamos nossos primeiros programas e aprendemos a trabalhar com as


funes de entrada e sada da linguagem C. Dessa forma, at esta aula, fizemos uso constante
da estrutura seqencial de programao. Nessa estrutura, um programa executa uma instruo
aps a outra, em geral linha aps linha, sem que ocorra desvio algum nesse fluxo de execuo.
Nesta aula, veremos estruturas condicionais na linguagem C, tendo oportunidade de
implement-las e de visualizar o funcionamento de programas que as contm. Do mesmo
modo, ressaltamos que uma estrutura condicional uma ferramenta importante que auxilia o
desenvolvedor/programador a decidir que trechos de um programa devem ser executados ou
no, dependendo da avaliao de uma condio expressa.
Esta aula baseada nas referncias [15, 16].

5.1 Estrutura condicional simples


Como vimos na aula 4, nossa linguagem de programao usada para executar uma
seqncia de comandos ou instrues tais como uma leitura de dados, uma impresso de dados e atribuio de valores a variveis. Alm de ter esse poder, os programas tambm podem
ser usados para tomar decises. Na linguagem C, uma deciso tomada com o uso de uma
estrutura condicional simples ou de uma estrutura condicional composta. Uma estrutura condicional simples tem o seguinte formato:
if (condio ) {
instruo1 ;
instruo2 ;
.
.
.
instruon ;
}

para n > 1. Na linguagem C, no caso em que n = 1, isto , se o bloco de instrues da estrutura


condicional contm uma nica instruo, ento os smbolos delimitadores de bloco { e } so
opcionais.
Uma deciso tomada de acordo com a avaliao da condio, que uma expresso lgica: caso o resultado dessa avaliao seja verdadeiro, a instruo, ou o bloco de instrues, ser
executada(o); caso contrrio, ser ignorada(o).
49

50

E STRUTURAS

CONDICIONAIS

Vejamos um pequeno exemplo no programa 5.1.


Programa 5.1: Estrutura condicional if.
/* Recebe um nmero inteiro positivo que representa uma idade
e emite uma mensagem na sada se a idade inferior a 30 */
#include <stdio.h>
int main(void)
{
int idade;
printf("Quantos anos voc tem?");
scanf("%d", &idade);
if (idade < 30)
printf("Puxa! Voc bem jovem!\n");
printf("At breve!\n");
return 0;
}

5.2 Estrutura condicional composta


Uma estrutura condicional composta na linguagem C tem o seguinte formato geral:
if (condio ) {
instruo1 ;
instruo2 ;
.
.
.
instruom ;
}
else {
instruo1 ;
instruo2 ;
.
.
.
instruon ;
}

para m, n > 1. Como nas estruturas condicionais simples, se m = 1 ou n = 1, os smbolos delimitadores de bloco { e } so opcionais. A linguagem C tem como regra sempre envolver um
bloco de instrues com os delimitadores { e } . Exceo se faz quando o bloco de instrues
contm uma nica instruo: neste caso, a incluso dos delimitadores opcional.
Uma deciso tomada de acordo com a avaliao da condio, que uma expresso lgica:
caso o resultado dessa avaliao seja verdadeiro, o primeiro bloco de instrues ser executado
e, ao trmino desse bloco, a instruo da prxima linha aps a estrutura condicional composta
ser executada. Caso contrrio, isto , se o resultado da avaliao da expresso lgica falso,
FACOM

UFMS

5.2 E STRUTURA

51

CONDICIONAL COMPOSTA

o segundo bloco de instrues, logo aps a palavra-chave else , ser executado. Ao final da
execuo das instrues desse bloco, a instruo da prxima linha aps a estrutura condicional
composta ser executada. Veja um exemplo no programa 5.2.
Programa 5.2: Estrutura condicional if-else.
#include <stdio.h>
/* Recebe um nmero inteiro e emite uma mensagem de acordo com esse nmero */
int main(void)
{
int idade;
printf("Quantos anos voc tem? ");
scanf("%d", &idade);
if (idade < 30)
printf("Puxa! Voc bem jovem!\n");
else
printf("Puxa! Voc j velhinho!\n");
printf("At breve!\n");
return 0;
}

5.2.1 Aplicao: troca de contedos


O programa 5.3 recebe dois nmeros inteiros quaisquer e os imprime em ordem crescente.
Programa 5.3: Troca de contedos de variveis.
#include <stdio.h>
/* Recebe dois nmeros inteiros x e y e coloca o menor desses
valores em x e o maior em y, mostrando o resultado na sada */
int main(void)
{
int x, y, aux;
printf("Informe o valor de x: ");
scanf("%d", &x);
printf("Informe o valor de y: ");
scanf("%d", &y);
if (x > y) {
aux = x;
x = y;
y = aux;
}
printf("%d menor ou igual a %d\n", x, y);
return 0;
}

FACOM

UFMS

52

E STRUTURAS

CONDICIONAIS

5.3 Reviso de nmeros inteiros


Como j mencionamos, os primeiros programadores tinham de programar diretamente na
linguagem que o computador compreende, a linguagem de mquina ou linguagem binria,
j que no existia na poca nenhuma linguagem de alto nvel. Isso significa que instrues
em cdigo binrio deviam ser escritas pelos programadores antes que fossem digitadas nesses
computadores. Alm disso, os programadores tinham de referenciar explicitamente um valor
que representasse um endereo de memria para armazenar valores temporrios. Felizmente,
em algoritmos e em as linguagens de programao de alto nvel permitem que um programador se concentre muito mais na soluo do problema que em cdigos especficos da mquina e
em endereos de memria.
Durante a execuo de algoritmos e programas podemos usar compartimentos de memria
para armazenamento de informaes. Como valores podem ser atribudos e sobrescritos nesses compartimentos e, portanto, podem variar durante a execuo do algoritmo ou programa,
esses compartimentos de memria so chamados de variveis. Alm disso, podemos atribuir
um nome simblico a um endereo de um compartimento de memria. Esse nome simblico
conhecido como identificador ou nome da varivel. O identificador de uma varivel pode ser
escolhido pelo(a) desenvolvedor(a)/programador(a) de modo a refletir de alguma forma o seu
contedo. Nas aulas anteriores, temos usado diversas variveis para armazenar valores que
so nmeros inteiros, como num1 , soma e produto , por exemplo. Nos nossos programas,
podemos usar outros tipos de dados alm de inteiros, como j mencionamos e veremos mais
adiante.
H uma regra fundamental sobre variveis em programas: qualquer varivel usada em
um programa deve ser previamente declarada. H tambm regras para um desenvolvedor
determinar os identificadores das variveis. Essas regras so as mesmas vistas na aula terica
e so apresentadas a seguir:
os smbolos vlidos em um identificador de uma varivel so os caracteres alfabticos,
minsculos ou maisculos, os dgitos numricos e o sublinhado1 (_);
o identificador de uma varivel deve iniciar com uma letra do alfabeto ou com um sublinhado (_);
aps o primeiro caractere, o identificador de uma varivel determinado por qualquer
seqncia de letras minsculas ou maisculas, de nmeros ou de sublinhados.
Dessa forma, os seguintes identificadores so nomes vlidos de variveis:

soma
num1
i
soma_total
_sistema
A3x3
frao
1

Do ingls underscore ou underline.

FACOM

UFMS

5.3 R EVISO

DE NMEROS INTEIROS

53

Por outro lado, os identificadores listados a seguir no so nomes vlidos de variveis em


programas:

preo$
soma total
4quant
int

No primeiro caso, o identificador preo$ contm um smbolo no vlido: $. O segundo


identificador tambm tem o mesmo problema, j que um identificador no pode conter um
caractere espao. O terceiro exemplo tem um identificador que inicia com um caracteres no
vlido, um dgito numrico. O ltimo exemplo um identificador no vlido j que int
uma palavra-chave da linguagem C.
Tambm importante destacar que letras minsculas e maisculas na linguagem C so
diferentes. Assim, as variveis soma , Soma e SOMA so todas diferentes.
A declarao de variveis do tipo inteiro pode ser realizada com uma nica instruo int
e mais uma lista de identificadores de variveis, separados por um espao e uma vrgula, finalizada por ponto e vrgula; ou ainda, pode ser realizada uma a uma, com uma instruo int
para cada varivel:

int i, num1, num2, soma, produto, aux;

ou
int
int
int
int
int
int

i;
num1;
num2;
soma;
produto;
aux;

Os identificadores das variveis podem ser to longos quanto se queira. No entanto, um


programa escrito com identificadores de variveis muito longos pode ser difcil de ser escrito e
compreendido. Por exemplo,

TotalDeDinheiroQueTenho = TotalDoDinheiroQueGuardeiAnoPassado +
TotalDeDinheiroQueGuardeiEsteAno - TotalDeImpostosEmReais;

bem menos significativo que

TotalGeral = TotalAno + TotalAnterior - Impostos;

FACOM

UFMS

54

E STRUTURAS

CONDICIONAIS

Em um programa na linguagem C, os nmeros inteiros que ocorrem em algumas expresses so conhecidos como constantes numricas, ou simplesmente constantes. Por exemplo,
o nmero 37 representa um valor inteiro constante. Expresses aritmticas que se constituem
apenas de constantes numricas e de operadores so chamadas de expresses aritmticas constantes. Por exemplo,

781 + 553 - 12 * 44

uma expresso aritmtica constante.


Alm disso, podemos definir uma constante numrica, conhecida na linguagem C como
uma macro, usando a diretiva do pr-processador #define . A definio de uma constante ou
macro na linguagem C tem o seguinte formato geral:

#define identificador constante

onde #define uma diretiva do pr-processador da linguagem C e identificador um


nome associado constante que vem logo a seguir. Observe que, por ser uma diretiva do
pr-processador, a linha contendo uma definio de uma macro inicia com um caractere especial # e no finalizada com o caractere ; . Em geral, a definio de uma macro ocorre logo no
incio do programa, aps as diretivas #include para incluso de cabealhos de bibliotecas de
funes. Alm disso, o identificador de uma macro , preferencial mas no obrigatoriamente,
descrito em letras maisculas.
Exemplos de macros so apresentados a seguir:

#define NUMERADOR 4
#define MIN -10000
#define MAX 100

Quando um programa compilado, o pr-processador troca cada macro definida no cdigo


pelo valor que ela representa. Depois disso, um segundo passo de compilao executado e
ento o programa executvel gerado.
A linguagem C, assim como a linguagem algortmica, possui cinco operadores aritmticos
binrios que podemos usar com nmeros inteiros: + para adio, - para subtrao, * para
multiplicao, / para quociente da diviso e % para resto da diviso. Devemos ressaltar
que todos esses operadores so binrios, isto , necessitam de dois operandos para execuo
da operao aritmtica correspondente. Esses operandos podem ser constantes, variveis ou
expresses aritmticas do tipo inteiro.
O programa 5.4 a seguir um exemplo de programa que usa todos esses operadores em
expresses aritmticas com nmeros inteiros.

FACOM

UFMS

5.3 R EVISO

DE NMEROS INTEIROS

55

Programa 5.4: Operaes aritmticas sobre nmeros inteiros.


/* Realiza operaes aritmticas com nmeros inteiros */
#include <stdio.h>
#define NUM 25
int main(void)
{
int x, y, z, r;
y = 10;
r = NUM + y;
printf("A soma de %d e %d %d\n", NUM, y, r);
x = 38;
r = x - NUM;
printf("A subtrao de %d e %d %d\n", x, NUM, r);
x = 51;
y = 17;
r = x * y;
printf("A multiplicao de %d por %d %d\n", x, y, r);
x = 100;
y = NUM;
r = x / y;
printf("O quociente da diviso de %d por %d %d\n", x, y, r);
x = 17;
y = 3;
r = x % y;
printf("O resto da diviso de %d por %d %d\n", x, y, r);
x = -7;
r = -x;
printf("%d com sinal trocado %d\n", x, r);
x = 10;
y = 4;
z = 15;
r = x + y * z;
printf("A expresso %d+%d*%d %d\n", x, y, z, r);
return 0;
}

H ainda um operador unrio - na linguagem C, que age sobre um nico operando e


que troca o seu sinal, isto , troca o sinal de uma constante, uma varivel ou uma expresso
aritmtica do tipo inteiro. No exemplo acima, as instrues de atribuio x = -7; e r = -x;
fazem com que o valor armazenado na varivel r seja 7 .
Observe finalmente que o resultado da avaliao da expresso aritmtica 10 + 4 * 15
no 14 15 = 210, mas sim 10 + 60 = 70. Os operadores aritmticos na linguagem C
tm precedncias uns sobre os outros. O operador de menos unrio precede todos os outros.
FACOM

UFMS

56

E STRUTURAS

CONDICIONAIS

Multiplicaes, quocientes de divises e restos de divises tm precedncia sobre a adio e


subtrao e, por isso, o resultado da expresso:

x + y * z

dado primeiro pela avaliao da multiplicao e depois pela avaliao da adio. Parnteses
so utilizados para modificar a ordem das operaes. Por exemplo,

(x + y) * z

teria como resultado da avaliao o valor 210.


Segue um resumo das precedncias dos operadores aritmticos binrios sobre nmeros inteiros:
Operador
* / %
+ -

Descrio
Multiplicao, quociente da diviso e resto da diviso
Adio e subtrao

Precedncia
1 (mxima)
2 (mnima)

5.3.1 Representao de nmeros inteiros


Esta seo completamente inspirada no apndice C do livro [15].
A memria do computador uma seqncia de bytes. Um byte consiste em 8 bits, onde bit
significa a menor unidade de informao que pode ser armazenada na memria e pode assumir
apenas dois valores possveis: 0 ou 1. Assim, um byte pode assumir 256 valores possveis:
00000000, 00000001, . . . , 11111111. De fato, o conjunto de todas as seqncias de k bits
representa os nmeros naturais de 0 a 2k 1.
Uma seqncia de bits chamada de um nmero binrio ou nmero na base 2. Por exemplo, 010110 um nmero binrio representado por uma seqncia de 6 bits. Podemos converter um nmero binrio em um nmero decimal, ou nmero na base 10, que nada mais que
um nmero natural. Por exemplo, o nmero binrio 010110 representa o nmero decimal 22,
pois 0 25 + 1 24 + 0 23 + 1 22 + 1 21 + 0 20 = 22.
Na linguagem C, os nmeros inteiros positivos e negativos so conhecidos como inteiros
com sinal. Para declarar uma varivel i do tipo inteiro com sinal, temos de digitar

int i;

Cada varivel do tipo int armazenada em b bytes consecutivos na memria, onde b


dependente da arquitetura do computador. A maioria dos computadores pessoais atuais tm
b = 4 e assim cada varivel do tipo int representada por uma seqncia de 8 4 = 32 bits,
perfazendo um total de 232 valores possveis, contidos no conjunto
231 , . . . , 1, 0, 1, . . . , 231 1
FACOM

UFMS

5.3 R EVISO

57

DE NMEROS INTEIROS

ou
2147483648, . . . , 1, 0, 1, . . . , 2147483647 .
Cada seqncia de 32 bits que comea com 0 representa um int no-negativo em notao
binria. Cada seqncia de 32 bits que comea com 1 representa o inteiro negativo k 232 ,
onde k o valor da seqncia em notao binria. Esta representao de nmeros inteiros
negativos
de complemento-de-dois. Nmeros inteiros que estejam fora do intevalo
 31 31 chamada

2 , 2 1 so representados mdulo 232 .

Ressaltamos ainda que todos os valores acima podem ser obtidos usando frmulas gerais
em funo do nmero de bytes consecutivos usados para representar um int .

Exerccios
5.1 Escreva um programa que receba a temperatura ambiente em graus Clsius e mostre uma
mensagem para o usurio informando se a temperatura est muito quente. Considere
como temperatura limite o valor de 30 graus Clsius.
Programa 5.5: Soluo do exerccio 5.1.
#include <stdio.h>
/* Recebe um nmero inteiro que representa uma
temperatura e imprime uma mensagem de aviso */
int main(void)
{
int temperatura;
printf("Informe uma temperatura (em graus Celsius):"));
scanf("%d", &temperatura);
if (temperatura > 30)
printf("Hoje um dia bem quente!\n");
else
printf("Hoje no um dia to quente.\n");
return 0;
}

5.2 Escreva um programa que receba um nmero inteiro x e avalie o polinmio


p(x) = 3x3 5x2 + 2x 1 .
5.3 Para transformar um nmero inteiro i no menor inteiro m maior que i e mltiplo de um
nmero inteiro j, a seguinte frmula pode ser utilizada:
m = i + j i mod j ,
onde o operador mod o operador de resto de diviso inteira na notao matemtica
usual, que corresponde ao nosso operador % .
FACOM

UFMS

58

E STRUTURAS

CONDICIONAIS

Por exemplo, suponha que usamos i = 256 dias para alguma atividade e queremos saber
qual o total de dias m que devemos ter de forma que esse nmero seja divisvel por j = 7,
para termos uma idia do nmero de semanas que usaremos na atividade. Ento, pela
frmula acima, temos que
m = 256 + 7 256 mod 7
= 256 + 7 4

= 259 .

Escreva um programa que receba dois nmeros inteiros positivos i e j e devolva o menor
inteiro m maior que i e mltiplo de j.
5.4 Escreva um programa que receba um nmero inteiro a e verifique se a par ou mpar.
5.5 Escreva um programa que receba um nmero inteiro a e verifique se a positivo, negativo
ou igual a 0.
5.6 Escreva um programa que receba trs valores, armazenando-os nas variveis x, y e z, e ordene esses valores de modo que, ao final, o menor valor esteja armazenado na varivel x,
o valor intermedirio esteja armazenado na varivel y e o maior valor esteja armazenado
na varivel z.

FACOM

UFMS

AULA

E STRUTURA

DE REPETIO

while

As estruturas de repetio so, juntamente com a estrutura seqencial e as estruturas condicionais que vimos nas aulas passadas, elementos fundamentais em algoritmos e programao.
So essas trs estruturas bsicas que permitem que um(a) desenvolvedor(a)/programador(a)
consiga resolver centenas e centenas de problemas de maneira efetiva. De posse apenas das estruturas seqencial e condicional, um(a) programador(a) fica muito restrito soluo de uma
pequena parcela de problemas. Assim, nesta aula motivaremos o estudo das estruturas de
repetio e apresentaremos a estrutura de repetio while da linguagem C.
Esta aula baseada em [16, 9].

6.1 Motivao
Suponha que algum queira escrever um programa para imprimir os dez primeiros nmeros inteiros positivos. Este problema, apesar de muito simples e pouco til primeira vista,
motiva a introduo das estruturas de repetio, como veremos adiante. Com o que aprendemos at o momento, bem fcil escrever um programa como esse.

#include <stdio.h>
/* Escreve os 10 primeiros nmeros inteiros positivos na sada */
int main(void)
{
printf("1\n");
printf("2\n");
printf("3\n");
printf("4\n");
printf("5\n");
printf("6\n");
printf("7\n");
printf("8\n");
printf("9\n");
printf("10\n");
return 0;
}

59

60

E STRUTURA

DE REPETIO

while

Alm de bem simples, o programa acima est correto, isto , realiza corretamente o propsito de imprimir os dez primeiros nmeros inteiros positivos na sada. Mas e se quisssemos, por exemplo, imprimir os 1000 primeiros nmeros inteiros positivos? Um programa
semelhante ao que acabamos de apresentar ficaria um pouco mais complicado e montono de
escrever, j que teria muitas e muitas linhas de cdigo.
Uma das propriedades fundamentais dos computadores, talvez a que mais nos auxilia,
que eles possuem a capacidade de executar repetitivamente um conjunto de instrues. Essa
capacidade de repetio permite que um(a) desenvolvedor(a)/programador(a) escreva algoritmos e programas mais concisos, contendo processos repetitivos que poderiam necessitar de
centenas ou milhares de linhas se no fossem assim descritos. Na linguagem C podemos ter
trs estruturas de repetio diferentes. A seguir veremos a estrutura de repetio while , mais
simples, mais didtica, mais ilustrativa e provavelmente a mais usada estrutura de repetio
da linguagem C.

6.2 Estrutura de repetio while


O formato geral da estrutura de repetio while apresentado a seguir:

while (condio) {
instruo1 ;
instruo2 ;
.
.
.
instruon ;
}

onde while uma palavra-chave da linguagem C, condio uma expresso lgica envolvida por parnteses que avaliada e possui o valor verdadeiro ou falso, instruo1 a
instruon fazem parte do bloco de instrues da estrutura de repetio while com as chaves { e } delimitando esse bloco de instrues. Do mesmo modo como vimos nas estruturas
condicionais, se o bloco de instrues associado estrutura de repetio while tem uma nica
instruo, esses delimitadores so opcionais.
A estrutura de repetio while funciona da seguinte forma. Quando um programa encontra a palavra-chave while , a expresso descrita na condio avaliada. Se o resultado
da avaliao dessa expresso verdadeiro, o programa desvia seu fluxo de execuo para o
bloco de instrues interno estrutura de repetio. Ento, as instrues so executadas uma
a uma at a ltima delas. Quando o programa atinge o final do bloco de instrues, o fluxo
de execuo desviado para a linha que contm a palavra-chave while e a expresso novamente avaliada. Se o resultado verdadeiro, as instrues so todas executadas novamente e
o processo se repete. Caso contrrio, isto , se o resultado da avaliao da expresso falso, o
fluxo de execuo do programa desviado para a primeira instruo aps o bloco de instrues
envolvido por chaves.
Veja o programa 6.1 para um exemplo de uso da estrutura de repetio while .
FACOM

UFMS

6.2 E STRUTURA

DE REPETIO

while

61

Programa 6.1: Primeiro exemplo usando a estrutura de repetio while .


#include <stdio.h>
/* Mostra os 100 primeiros nmeros inteiros positivos */
int main(void)
{
int numero;
numero = 1;
while (numero <= 100) {
printf("%d\n", numero);
numero = numero + 1;
}
printf("\n");
return 0;
}

Exerccios
6.1 Dado um inteiro positivo n, somar os n primeiros inteiros positivos.
Programa 6.2: Programa para o exerccio 6.1.
#include <stdio.h>
/* Recebe um nmero inteiro n > 0 e mostra a soma dos n primeiros nmeros inteiros positivos */
int main(void)
{
int n, numero, soma;
printf("Informe n: ");
scanf("%d", &n);
soma = 0;
numero = 1;
while (numero <= n) {
soma = soma + numero;
numero = numero + 1;
}
printf("Soma dos %d primeiros inteiros %d\n", n, soma);
return 0;
}

6.2 Dado n, imprimir os n primeiros naturais mpares.


Exemplo:
Para n = 4 a sada dever ser 1, 3, 5, 7.
6.3 Dado um inteiro positivo n, calcular n!.
FACOM

UFMS

62

E STRUTURA

DE REPETIO

while

6.4 Dado n, imprimir as n primeiras potncias de 2.


Exemplo:
Para n = 5 a sada dever ser 1, 2, 4, 8, 16.
6.5 Dados x inteiro e n um natural, calcular xn .
6.6 Dado um inteiro positivo n e uma seqncia de n inteiros, somar esses n nmeros.
6.7 Dado um inteiro positivo n e uma seqncia de n nmeros inteiros, determinar a soma
dos nmeros inteiros positivos da seqncia.
Exemplo:
Se n = 7 e a seqncia de nmeros inteiros 6, 2, 7, 0, 5, 8, 4 a sada deve ser
19.
6.8 Dado um inteiro positivo n e uma seqncia de n inteiros, somar os nmeros pares e os
nmeros mpares.
6.9 Durante os 31 dias do ms de maro foram tomadas as temperaturas mdias dirias de
Campo Grande, MS. Determinar o nmero de dias desse ms com temperaturas abaixo
de zero.
6.10 Dado um inteiro positivo n e uma seqncia de n inteiros, determinar quantos nmeros
da seqncia so positivos e quantos so no-positivos. Um nmero no-positivo se
negativo ou se igual a 0 (zero).
6.11 Dado um inteiro positivo n e uma seqncia de n inteiros, determinar quantos nmeros
da seqncia so pares e quantos so mpares.
6.12 Uma loja de discos anota diariamente durante o ms de abril a quantidade de discos vendidos. Determinar em que dia desse ms ocorreu a maior venda e qual foi a quantidade
de discos vendida nesse dia.
6.13 Dados o nmero n de estudantes de uma turma de Algoritmos e Programao I e suas
notas de primeira prova, determinar a maior e a menor nota obtidas por essa turma, onde
a nota mnima 0 e a nota mxima 100.

FACOM

UFMS

AULA

E XPRESSES

COM INTEIROS

Nesta aula veremos expresses aritmticas, relacionais e lgicas com nmeros inteiros. Em
aulas anteriores j tomamos contato com essas expresses, mas pretendemos formaliz-las
aqui. A compreenso destas expresses com nmeros inteiros fundamental para que possamos escrever programas mais eficientes e poderosos e tambm porque podemos estender
esse entendimento a outros tipos de variveis. Importante destacar que a linguagem C no tem
um tipo lgico primitivo, que ento simulado atravs do tipo inteiro, como veremos.
Esta aula baseada nas referncias [15, 16].

7.1 Expresses aritmticas


Uma expresso aritmtica na linguagem C qualquer seqncia de smbolos formada exclusivamente por constantes numricas, variveis numricas, operadores aritmticos e parnteses.
Como j vimos, uma constante numrica do tipo inteiro qualquer nmero inteiro descrito
em nosso programa, como por exemplo 34 ou 7.
Uma varivel numrica do tipo inteiro aquela que foi declarada com uma instruo int
no incio do programa.

Os operadores aritmticos so divididos em duas classes: operadores aritmticos unrios


e operadores aritmticos binrios. Um operador aritmtico unrio um operador que age sobre um nico nmero inteiro e devolve um resultado. H dois operadores aritmticos unrios
na linguagem C: o operador - , que troca o sinal da expresso aritmtica que o sucede, e o
operador + , que no faz nada alm de enfatizar que uma constante numrica positiva. Os
operadores aritmticos binrios so aqueles que realizam as operaes bsicas sobre dois nmeros inteiros: + para adio, - para subtrao, * para multiplicao, / para quociente da
diviso e % para o resto da diviso.
As expresses aritmticas formadas por operaes binrias envolvendo operandos e operadores tm precedncias umas sobre as outras: as operaes de multiplicao, quociente da
diviso e resto da diviso tm prioridade sobre as operaes de adio e a subtrao. Caso haja
necessidade de modificar a prioridade de uma operao em uma expresso, parnteses devem
ser utilizados. Expresses envolvidas por parnteses tm maior prioridade sobre expresses
que esto fora desses parnteses.
Suponha, por exemplo, que tenhamos declarado as variveis x , y , a , soma e parcela
do tipo inteiro, como abaixo:
63

64

E XPRESSES

COM INTEIROS

int x, y, a, soma, parcela;

Suponha ainda que as seguintes atribuies de valores constantes tenham sido executadas sobre essas variveis:
x = 1;
y = 2;
a = 5;
soma = 100;
parcela = 134;

As sentenas a seguir so exemplos de expresses aritmticas:

2 * x * x + 5 * -x - +4
soma + parcela % 3
4 * 1002 - 4412 % 11 * -2 + a
(((204 / (3 + x)) * y) - ((y % x) + soma))

De acordo com os valores das inicializaes das variveis envolvidas e o resultado da avaliao
das prprias expresses, a avaliao de cada uma das linhas acima tem valores 7, 102, 4037 e
202, respectivamente.
A tabela abaixo, contendo as prioridades dos operadores aritmticos unrios e binrios, j
foi exibida em parte na aula 5.

Operadores
+ * / %
+ -

Tipo
unrios
binrios
binrios

Descrio
constante positiva, troca de sinal
produto, quociente da diviso e resto da diviso
adio e subtrao

Precedncia
1 (mxima)
2
3 (mnima)

7.2 Expresses relacionais


Uma expresso relacional, ou simplesmente uma relao, uma comparao entre dois
valores do mesmo tipo primitivo de dados. Esses valores so representados na relao atravs
de constantes, variveis ou expresses. Essa definio bem abrangente e acomoda outros
tipos de dados alm do tipo int , o nico tipo primitivo de dados que conhecemos at o
momento. Com o tipo int a definio de relao pode ser escrita como uma comparao
entre dois valores, representados por constantes numricas, variveis numricas ou expresses
aritmticas.
Os operadores relacionais da linguagem C, que indicam a comparao a ser realizada entre
os termos da relao, so os seguintes:
FACOM

UFMS

7.3 E XPRESSES

65

LGICAS

Operador
==
!=
<
>
<=
>=

Descrio
igual a
diferente de
menor que
maior que
menor que ou igual a
maior que ou igual a

O resultado da avaliao de uma expresso relacional sempre um valor lgico, isto ,


verdadeiro ou falso. Assim, supondo que temos declarado trs variveis a , b e c do tipo
inteiro como a seguir,

int a, b, c;

e as seguintes atribuies realizadas

a = 2;
b = 3;
c = 4;

ento as expresses relacionais

a
a
b
b

== 2
> b + c
+ c <= 5 - a
!= 3

tm valores verdadeiro, falso, falso e falso, respectivamente.


Uma observao importante neste momento que um tipo lgico ou booleano no existe na
linguagem C. Isso significa que literalmente no existem constantes lgicas e variveis lgicas
na linguagem. O resultado da avaliao de uma expresso relacional ou lgica , na verdade,
um valor numrico do tipo inteiro. Se este um valor diferente de zero, ento o resultado da expresso interpretado como verdadeiro. Caso contrrio, isto , se este valor igual a zero, ento
o resultado da expresso interpretado como falso. Para facilitar, muitas vezes representaremos o valor 1 (um) para a constante lgica com valor verdadeiro e 0 (zero) para a constante
lgica com valor falso. Lembrando apenas que, na verdade, qualquer valor diferente de 0
(zero) avaliado como verdadeiro em uma expresso relacional.

7.3 Expresses lgicas


Uma proposio qualquer sentena que pode ser valorada com o valor verdadeiro ou
falso. Traduzindo essa definio para a linguagem C, uma proposio qualquer sentena que
pode ser valorada com um valor inteiro. Com o que aprendemos at agora, uma proposio
FACOM

UFMS

66

E XPRESSES

COM INTEIROS

uma relao, uma varivel do tipo inteiro ou uma constante do tipo inteiro. Uma expresso
condicional ou lgica, ou ainda booleana formada por uma ou mais proposies. Neste
ltimo caso, relacionamos as proposies atravs de operadores lgicos. Os operadores lgicos
da linguagem C utilizados como conectivos nas expresses lgicas so apresentados a seguir.
Operador
&&
||
!

Descrio
conjuno
disjuno
negao

Duas proposies p e q podem ser combinadas pelo conectivo && para formar uma nica
proposio denominada conjuno das proposies originais: p && q e lemos p e q . O
resultado da avaliao da conjuno de duas proposies verdadeiro se e somente se ambas
as proposies tm valor verdadeiro, como mostra a tabela a seguir.
p

p && q

1
1
0
0

1
0
1
0

1
0
0
0

Duas proposies p e q podem ser combinadas pelo conectivo || para formar uma nica
proposio denominada disjuno das proposies originais: p || q e lemos p ou q ,
com sentido de e/ou. O resultado da avaliao da disjuno de duas proposies verdadeiro
se pelo menos uma das proposies tem valor verdadeiro, como mostra a tabela a seguir.
p

p || q

1
1
0
0

1
0
1
0

1
1
1
0

Dada uma proposio p , uma outra proposio, chamada negao de p , pode ser obtida
atravs da insero do smbolo ! antes da proposio: !p e lemos no p . Se a proposio
p tem valor verdadeiro, ento !p tem valor falso e se p tem valor falso, ento a proposio
!p tem valor verdadeiro, como mostra a tabela a seguir.
p

!p

1
0

0
1

Exemplos de expresses lgicas so mostrados a seguir. Inicialmente, suponha que declaramos as variveis do tipo inteiro a seguir:

int a, b, c, x;

e as seguintes atribuies so realizadas


FACOM

UFMS

7.3 E XPRESSES

a
b
c
x

=
=
=
=

67

LGICAS

2;
3;
4;
1;

ento as expresses lgicas a seguir

5
a
!x
a == 2 && a < b + c
b + c >= 5 - a || b != 3
a + b > c || 2 * x == b && 4 < x

tm valores verdadeiro, verdadeiro, falso, verdadeiro, verdadeiro e falso, respectivamente.


Observe que avaliamos as expresses lgicas em uma ordem: primeiro avaliamos as expresses aritmticas, depois as expresses relacionais e, por fim, as expresses lgicas em si.
Por exemplo,

a == 2 && a + x > b + c
2 == 2 && 3 > 3 + 4
2 == 2 && 3 > 7
1 && 0
1

A tabela abaixo ilustra a prioridade de todos os operadores aritmticos, relacionais e lgicos, unrios e binrios, vistos at aqui.

Operador
+ * / %
+ == != >= <= > <
!
&&
||

Tipo
unrios
binrios
binrios
binrios
unrio
binrio
binrio

Precedncia
1 (mxima)
2
3
4
5
6
7 (mnima)

Observe que o operador de negao ! um operador unrio, ou seja, necessita de apenas


um operando como argumento da operao. Os outros operadores lgicos so todos binrios.
Lembre-se tambm que para modificar a precedncia de alguma expresso necessrio o
uso de parnteses, como j vimos nas expresses aritmticas.
Dessa forma, se considerarmos as mesmas variveis e atribuies acima, a expresso lgica
abaixo seria avaliada da seguinte forma:
FACOM

UFMS

68

E XPRESSES

COM INTEIROS

x + c >= a + b || 2 * x + x < b && a > b + x


1 + 4 >= 2 + 3 || 2 * 1 + 1 < 3 && 2 > 3 + 1
5 >= 5
||
3 < 3 && 2 > 4
1
||
0
&&
0
1
||
0
1

Observe que, como o operador lgico de conjuno && tem prioridade sobre o operador
lgico de disjuno || , o resultado da expresso acima verdadeiro. Se tivssemos realizado a
disjuno primeiramente, como poderamos intuitivamente supor devido ao posicionamento
mais esquerda do operador de disjuno, o resultado da expresso seria diferente.

Exerccios
Alguns exerccios desta aula ensinam um importante truque de programao que , na verdade, o uso de uma varivel que simula um tipo lgico e que indica que algo ocorreu durante
a execuo do programa. Essa varivel chamada de indicadora de passagem.

7.1 Dado p inteiro, verificar se p primo.


Programa 7.1: Soluo para o exerccio 7.1.
#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p primo */
int main(void)
{
int p, divisor;
printf("Informe um nmero: ");
scanf("%d", &p);
divisor = 2;
while (divisor <= p/2) {
if (p % divisor == 0)
divisor = p;
else
divisor = divisor + 1;
}
if (divisor == p/2 + 1)
printf("%d primo\n", p);
else
printf("%d no primo\n", p);
return 0;
}

FACOM

UFMS

7.3 E XPRESSES

69

LGICAS

Programa 7.2: Soluo para o exerccio 7.1 usando uma varivel indicadora de passagem.
#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p primo */
int main(void)
{
int p, divisor, primo;
printf("Informe um nmero: ");
scanf("%d", &p);
divisor = 2;
primo = 1;
while (divisor <= p/2 && primo == 1) {
if (p % divisor == 0)
primo = 0;
else
divisor = divisor + 1;
}
if (primo == 1)
printf("%d primo\n", p);
else
printf("%d no primo\n", p);
return 0;
}

Programa 7.3: Terceira soluo para o exerccio 7.1.


#include <stdio.h>
/* Recebe um inteiro positivo p e verifica se p primo */
int main(void)
{
int p, divisor, primo;
printf("Informe um nmero: ");
scanf("%d", &p);
divisor = 2;
primo = 1;
while (divisor <= p/2 && primo) {
if (! (p % divisor))
primo = 0;
else
divisor = divisor + 1;
}
if (primo)
printf("%d primo\n", p);
else
printf("%d no primo", p);
return 0;
}

FACOM

UFMS

70

E XPRESSES

COM INTEIROS

7.2 Dado um nmero inteiro positivo n e uma seqncia de n nmeros inteiros, verificar se a
seqncia est em ordem crescente.
7.3 Dados um nmero inteiro n > 0 e um dgito d, com 0 6 d 6 9, determinar quantas vezes
o dgito d ocorre no nmero n.
7.4 Dado um nmero inteiro positivo n, verificar se este nmero contm dois dgitos consecutivos iguais.
7.5 Dado um nmero inteiro positivo n, verificar se o primeiro e o ltimo dgito deste nmero
so iguais.
7.6 Dado um nmero inteiro positivo n e dois nmeros naturais no nulos i e j, imprimir em
ordem crescente os n primeiros naturais que so mltiplos de i ou de j ou de ambos.
Exemplo:
Para n = 6, i = 2 e j = 3 a sada dever ser 0, 2, 3, 4, 6, 8.
7.7 Dizemos que um nmero natural triangular se produto de trs nmeros naturais
consecutivos.
Exemplo:
120 triangular, pois 4 5 6 = 120.
Dado n natural, verificar se n triangular.
7.8 Dados dois nmeros inteiros positivos, determinar o mximo divisor comum entre eles
utilizando o algoritmo de Euclides.
Exemplo:
24
9

1
15
6

1
9
3

1
6
0

2
3

= mdc(24,15)

7.9 Dados dois nmeros inteiros positivos a e b, representando a frao a/b, escreva um programa que reduz a/b para uma frao irredutvel.
Exemplo:
Se a entrada 9/12 a sada tem de ser 3/4.
7.10 Dados a quantidade de dias de um ms e o dia da semana em que o ms comea, escreva
um programa que imprima os dias do ms por semana, linha a linha. Considere o dia
da semana 1 como domingo, 2 como segunda-feira, e assim por diante, at o dia 7 como
sbado.
Exemplo:
Se a entrada 31 e 3 ento a sada deve ser
6
13
20
27
FACOM

7
14
21
28

1
8
15
22
29

2
9
16
23
30

3
10
17
24
31

4
11
18
25

5
12
19
26

UFMS

7.3 E XPRESSES

LGICAS

71

7.11 Dados um nmero inteiro n e n seqncias de nmeros inteiros, cada qual terminada por
0, determinar a soma dos nmeros pares de cada seqncia.
7.12 Dados um nmero inteiro n > 0 e uma seqncia de n nmeros inteiros positivos determinar o fatorial de cada nmero da seqncia.
7.13 Dados n nmeros inteiros positivos, calcular a soma dos que so primos.
7.14 Dado um nmero inteiro positivo n, determinar todos os inteiros entre 1 e n que so
comprimento de hipotenusa de um tringulo retngulo com catetos inteiros.
7.15 Dados dois naturais m e n, determinar, entre todos os pares de nmeros naturais (x, y)
tais que x 6 m e y 6 n, um par para o qual o valor da expresso xy x2 + y seja mximo
e calcular tambm esse mximo.
7.16 Sabe-se que um nmero da forma n3 igual soma de n nmeros mpares consecutivos.
Exemplo:
13
23
33
43
..
.

=1
=3+5
= 7 + 9 + 11
= 13 + 15 + 17 + 19

Dado m, determine os mpares consecutivos cuja soma igual a n3 para n assumindo


valores de 1 a m.
7.17 Dado um nmero inteiro positivo, determine a sua decomposio em fatores primos,
calculando tambm a multiplicidade de cada fator.
Exemplo:
Se n = 600 a sada deve ser
fator 2 multiplicidade 3
fator 3 multiplicidade 1
fator 5 multiplicidade 2
7.18 Dados n inteiros positivos, determinar o mximo divisor comum entre eles.

FACOM

UFMS

72

FACOM

E XPRESSES

COM INTEIROS

UFMS

AULA

O UTRAS

ESTRUTURAS DE REPETIO

Duas outras estruturas de repetio esto disponibilizadas na linguagem C. Uma delas


a estrutura de repetio for , que pode ser vista como uma outra forma de apresentao da
estrutura de repetio while . Essas estruturas possuem exepresses lgicas iniciais que controlam o fluxo de execuo de seus respectivos blocos de instrues. Uma outra estrutura
apresentada aqui a estrutura repetio do-while , cuja a expresso lgica de controle posicionada no final de seu bloco de instrues.
Esta aula baseada nas referncias [16, 15].

8.1 Estrutura de repetio for


Retomando o programa 6.1, isto , o primeiro exemplo com uma estrutura de repetio na
linguagem C que vimos at agora, vamos refaz-lo, desta vez usando a estrutura de repetio
for . Vejamos ento o programa 8.1 a seguir.

Programa 8.1: Primeiro exemplo.


#include <stdio.h>
/* Mostra os 100 primeiros nmeros inteiros positivos */
int main(void)
{
int numero;
for (numero = 1; numero <= 100; numero = numero + 1)
printf("%d\n", numero);
printf("\n");
return 0;
}

A novidade neste programa a estrutura de repetio for . O formato geral da estrutura


de repetio for dado a seguir:
73

74

O UTRAS

ESTRUTURAS DE REPETIO

for (inicializao; condio; passo) {


instruo1 ;
.
.
.
instruon ;
}

A estrutura de repetio for dispe a inicializao, a condio e o passo todos na mesma


linha de instruo. O funcionamento desta estrutura dado da seguinte forma. Sempre que
a palavra-chave for encontrada, a inicializao executada. Em seguida, uma condio /expresso avaliada: se o resultado da avaliao verdadeiro, ento o bloco de instrues
delimitado pelas chaves executado. Ao final da execuo do bloco de instrues, o passo
executado e o processo todo se repete. Se, em algum momento, o resultado da avaliao for
falso, o fluxo de execuo do programa desviado para a primeira instruo aps o bloco de
instrues da estrutura de repetio.
No ponto onde nos encontramos talvez seja um bom momento para entrarmos em contato
com outros dois operadores aritmticos da linguagem C. Os operadores unrios de incremento
++ e de decremento -- tm como funo adicionar ou subtrair uma unidade do valor armazenado em seus operandos, respectivamente. De fato, nada mais necessrio compreender
sobre esses operadores simples. No entanto, infelizmente, a compreenso das formas de uso
desses operadores pode ser facilmente confundida. Isso porque, alm de modificar os valores
de seus operandos, ++ e -- podem ser usados como operadores prefixos e tambm como
operadores posfixos. Por exemplo, o trecho de cdigo abaixo:

int cont;
cont = 1;
printf("cont vale %d\n", ++cont);
printf("cont vale %d\n", cont);

imprime cont vale 2 e cont vale 2 em duas linhas consecutivas na sada. Por outro lado,
o trecho de cdigo abaixo:

int cont;
cont = 1;
printf("cont vale %d\n", cont++);
printf("cont vale %d\n", cont);

imprime cont vale 1 e cont vale 2 em duas linhas consecutivas na sada.


Para ajudar em nossa compreenso, podemos pensar que a expresso ++cont significa
incremente cont imediatamente enquanto que a expresso cont++ significa use agora o
valor de cont e depois o incremente. O depois nesse caso depende de algumas questes
tcnicas da linguagem C que ainda no podemos entender, mas seguramente a varivel cont
ser incrementada antes da prxima instruo/sentena ser executada.
FACOM

UFMS

8.2 E STRUTURA

DE REPETIO

do-while

75

O operador de decremento -- tem as mesmas propriedades do operador de incremento


++ , que acabamos de descrever.
importante observar que os operadores de incremento e decremento, se usados como
operadores posfixos, tm maior prioridade que os operadores unrios de constante positiva
+ e de troca de sinal - . Se, ao contrrio, so usados como operadores prefixos, ento os dois
operadores tm a mesma prioridade dos operadores unrios de constante positiva + e de troca
de sinal - .
O programa 8.2 uma outra verso do programa 8.1, que soluciona o problema da soma dos
100 primeiros nmeros inteiros positivos. Desta vez, o programa usa o operador de incremento
na estrutura de repetio for .
Programa 8.2: Soma os 100 primeiros nmeros inteiros positivos.
#include <stdio.h>
/* Mostra os 100 primeiros nmeros inteiros positivos */
int main(void)
{
int numero, soma;
soma = 0;
for (numero = 1; numero <= 100; ++numero)
soma = soma + numero;
printf("A soma dos 100 primeiros inteiros %d\n", soma);
return 0;
}

8.2 Estrutura de repetio do-while


Suponha agora que seja necessrio resolver um problema simples, muito semelhante aos
problemas iniciais que resolvemos usando uma estrutura de repetio. O enunciado do problema o seguinte:
Dada uma seqncia de nmeros inteiros terminada com 0, calcular a soma desses
nmeros.
Com o que aprendemos sobre programao at o momento, este problema parece bem simples de ser resolvido. Observe, antes de tudo, que este problema pode ser facilmente resolvido usando a estrutura de repetio while . E dadas as suas semelhanas, um programa que
soluciona esse problema usando a estrutura de repetio for tambm pode ser facilmente
desenvolvido.
Vejamos agora ento uma soluo um pouco diferente, dada no programa 8.3. Esta soluo contm uma terceira estrutura de repetio da linguagem C, a estrutura de repetio
do-while , que ainda no conhecamos.
FACOM

UFMS

76

O UTRAS

ESTRUTURAS DE REPETIO

Programa 8.3: Exemplo usando a estrutura de repetio do-while.


#include <stdio.h>
/* Recebe uma seqncia de nmeros inteiros finalizada por 0 (zero) e mostra a soma desses nmeros */
int main(void)
{
int numero, soma;
soma = 0;
do {
printf("Informe um nmero: ");
scanf("%d", numero);
soma = soma + numero;
} while (numero != 0);
printf("A soma dos nmeros informados %d\n", soma);
return 0;
}

O programa 8.3 muito semelhante aos demais programas que vimos construindo at o momento. A principal e mais significativa diferena o uso da estrutura de repetio do-while .
Quando o programa encontra essa estrutura pela primeira vez, com uma linha contendo a
palavra-chave do , o fluxo de execuo segue para a primeira instruo do bloco de instrues
dessa estrutura, envolvido por chaves. As instrues desse bloco so ento executados uma a
uma, at o fim do bloco. Logo em seguida, aps o fim do bloco com o caractere } , encontramos
a palavra-chave while e, depois, entre parnteses, uma expresso lgica. Se o resultado da
avaliao dessa expresso lgica for verdadeiro, ento o fluxo de execuo do programa desviado para a primeira instruo do bloco de instrues desta estrutura de repetio e todas as
instrues so executadas novamente. Caso contrrio, se o resultado da avaliao da expresso
lgica falso, o fluxo de execuo desviado para a prxima instruo aps a linha contendo
o final do bloco de execuo desta estrutura de repetio.
Note ainda que o teste de continuidade desta estrutura de repetio realizado sempre no
final, aps todas as instrues de seu bloco interno de instrues terem sido executadas. Isso
significa que esse bloco de instrues ser executado ao menos uma vez. Neste sentido, esta
estrutura de repetio do-while difere das outras estruturas de repetio while e for que
vimos anteriormente, j que nesses dois ltimos casos o resultado da avaliao da expresso
lgica associada a essas estruturas pode fazer com que seus blocos de instrues respectivos
no sejam executados nem mesmo uma nica vez.

Exerccios
8.1 Qualquer nmero natural de quatro algarismos pode ser dividido em duas dezenas formadas pelos seus dois primeiros e dois ltimos dgitos.
Exemplos:
FACOM

UFMS

8.2 E STRUTURA

DE REPETIO

do-while

77

1297: 12 e 97.
5314: 53 e 14.
Escreva um programa que imprima todos os nmeros de quatro algarismos cuja raiz
quadrada seja a soma das dezenas formadas pela diviso acima.
Exemplo:

9801 = 99 = 98 + 01.
Portanto, 9801 um dos nmeros a ser impresso.
Programa 8.4: Soluo do exerccio 8.1.
#include <stdio.h>
/* Imprime os nmeros inteiros positivos de 4 dgitos cuja raiz quadrada igual soma dos seus dois primeiros e dois ltimos dgitos */
int main(void)
{
int numero, DD, dd;
for (numero = 1000; numero <= 9999; numero++) {
DD = numero / 100;
dd = numero % 100;
if ( (DD + dd) * (DD + dd) == numero )
printf("%d\n", numero);
}
return 0;
}

8.2 Dado um nmero inteiro no-negativo n, escreva um programa que determine quantos
dgitos o nmero n possui.
Programa 8.5: Soluo do exerccio 8.8.
/* Recebe um inteiro e imprime a quantidade de dgitos que possui */
#include <stdio.h>
int main(void)
{
int n, digitos;
printf("Informe n: ");
scanf("%d", n);
do {
n = n / 10;
digitos++;
} while (n > 0);
printf("O nmero tem %d dgitos\n", digitos);
return 0;
}

FACOM

UFMS

78

O UTRAS

ESTRUTURAS DE REPETIO

8.3 Dado um nmero natural na base binria, transform-lo para a base decimal.
Exemplo:
Dado 10010 a sada ser 18, pois 1 24 + 0 23 + 0 22 + 1 21 + 0 20 = 18.
8.4 Dado um nmero natural na base decimal, transform-lo para a base binria.
Exemplo:
Dado 18 a sada dever ser 10010.
8.5 Dado um nmero inteiro positivo n que no contm um dgito 0, imprimi-lo na ordem
inversa de seus dgitos.
Exemplo:
Dado 26578 a sada dever ser 87562.
8.6 Dizemos que um nmero natural n com pelo menos 2 algarismos palndromo se
o primeiro algarismo de n igual ao seu ltimo algarismo;
o segundo algarismo de n igual ao se penltimo algarismo;
e assim sucessivamente.
Exemplos:
567765 palndromo;
32423 palndromo;
567675 no palndromo.
Dado um nmero natural n, n > 10, verificar se n palndromo.
8.7 Dados um nmero inteiro n > 0 e uma seqncia de n nmeros inteiros, determinar
quantos segmentos de nmeros iguais consecutivos compem essa seqncia.
Exemplo:
z}|{ z }| { z }| { z}|{
Para n = 9, a seqncia 5 , 2, 2, 4, 4, 4, 4, 1, 1 formada por 4 segmentos
de nmeros iguais.
8.8 Dados um nmero inteiro n > 0 e uma seqncia de n nmeros inteiros, determinar o
comprimento de um segmento crescente de comprimento mximo.
Exemplos:
z }| {
Na seqncia 5, 10, 6, 2, 4, 7, 9, 8, 3 o comprimento do segmento crescente mximo 4.
Na seqncia 10, 8, 7, 5, 2 o comprimento do segmento crescente mximo 1.

FACOM

UFMS

AULA

N MEROS

COM PONTO FLUTUANTE

Dadas as dificuldades inerentes da representao de nmeros reais nos computadores, as


linguagens de programao de alto nvel procuram super-las abstraindo essa representao
atravs do uso de nmeros com ponto flutuante. Na linguagem C, nmeros com ponto flutuante podem ser manipulados como constantes ou variveis do tipo ponto flutuante. O armazenamento destes nmeros em memria se d de forma distinta do armazenamento de nmeros
inteiros e necessita de mais espao, como poderamos supor.
Nesta aula veremos como manipular nmeros de ponto flutuante, formalizando as definies de constantes e variveis envolvidas, alm de aprender as regras de uso desses elementos
em expresses aritmticas.
Esta aula baseada nos livros [15, 16].

9.1 Constantes e variveis do tipo ponto flutuante


Nmeros inteiros no so suficientes ou adequados para solucionar todos os problemas
algortmicos. Muitas vezes so necessrias variveis que possam armazenar nmeros com
dgitos aps a vrgula, nmeros muito grandes ou nmeros muito pequenos. A vrgula, especialmente em pases de lngua inglesa, substituda pelo ponto decimal. A linguagem C permite
que variveis sejam declaradas de forma a poderem armazenar nmeros de ponto flutuante,
com os tipos bsicos float e double .
Uma constante do tipo ponto flutuante se distingue de uma constante do tipo inteiro pelo
uso do ponto decimal. Dessa forma, 3.0 uma constante do tipo ponto flutuante, assim como
1.125 e -765.567 . Podemos omitir os dgitos antes do ponto decimal ou depois do ponto
decimal, mas obviamente no ambos. Assim, 3. e -.1115 so constantes do tipo ponto
flutuante vlidas.
Na linguagem C, uma varivel do tipo ponto flutuante pode armazenar valores do tipo
ponto flutuante e deve ser declarada com a palavra reservada float ou double . Por exemplo, a declarao

float x, y;
double arco;

realiza a declarao das variveis x e y como variveis do tipo ponto flutuante.


79

80

N MEROS

COM PONTO FLUTUANTE

A distino entre os tipos de ponto flutuante float e double se d pela quantidade de


preciso necessria. Quando a preciso no crtica, o tipo float adequado. O tipo double
fornece preciso maior.
A tabela a seguir mostra as caractersticas dos tipos de ponto flutuante quando implementados de acordo com o padro IEEE1. Em computadores que no seguem o padro IEEE, esta
tabela pode no ser vlida.
Tipo
float
double

Menor valor (positivo)


1.17549 1038
2.22507 10308

Maior valor
3.40282 1038
1.79769 10308

Preciso
6 dgitos
15 dgitos

O padro IEEE 754 estabelece dois formatos primrios para nmeros de ponto flutuante:
o formato de preciso simples, com 32 bits, e o formato de preciso dupla, com 64 bits. Os
nmeros de ponto flutuante so armazenados no formato de notao cientfica, composto por
trs partes: um sinal, um expoente e uma frao. O nmero de bits reservado para representar o
expoente determina quo grande o nmero pode ser, enquanto que o nmero de bits da frao
determina sua preciso.
Um exemplo de um programa que usa constantes e variveis do tipo float apresentado
no programa 9.1. Neste programa, uma seqncia de cem nmeros do tipo ponto flutuante
informada pelo usurio. Em seguida, a mdia aritmtica desses nmeros calculada e, por fim,
mostrada na sada padro.
Programa 9.1: Calcula a mdia de 100 nmeros do tipo ponto flutuante.
#include <stdio.h>
/* Recebe uma seqncia de 100 nmeros reais e mostra a mdia desses nmeros */
int main(void)
{
int i;
float numero, soma, media;
soma = 0.0;
for (i = 1; i <= 100; i++) {
printf("Informe um nmero: ");
scanf("%f", &numero);
soma = soma + numero;
}
media = soma / 100;
printf("A mdia dos 100 nmeros %f\n", media);
return 0;
}

Observe que a cadeia de caracteres de formatao contm um especificador de converso


para um nmero de ponto flutuante %f , diferentemente do especificador de converso para
nmeros inteiros ( %d ) que vimos anteriormente.
1

Instituto de Engenheiros Eltricos e Eletrnicos, do ingls Institute of Electrical and Eletronics Engineers (IEEE).

FACOM

UFMS

9.2 E XPRESSES

ARITMTICAS

81

9.2 Expresses aritmticas


Na linguagem C existem regras de converso implcita de valores do tipo inteiro e do tipo
ponto flutuante. A regra principal diz que a avaliao de uma expresso aritmtica, isto , seu
resultado, ser do tipo ponto flutuante caso algum de seus operandos resultante da avaliao
de uma expresso aritmtica seja tambm do tipo ponto flutuante. Caso contrrio, isto , se
todos os operandos so valores do tipo inteiro, o resultado da expresso aritmtica ser um
valor do tipo inteiro. Vejamos um exemplo no programa 9.2.
Programa 9.2: Relao entre valores do tipo inteiro e do tipo ponto flutuante.
#include <stdio.h>
int main(void)
{
int i1, i2;
float f1, f2;
i1 = 190;
f1 = 100.5;
i2 = i1 / 100;
printf("i2 = %d\n",
f2 = i1 / 100;
printf("f2 = %f\n",
f2 = i1 / 100.0;
printf("f2 = %f\n",
f2 = f1 / 100;
printf("f2 = %f\n",
return 0;

i2);
f2);
f2);
f2);

O resultado da execuo desse programa apresentado a seguir.

i2
f2
f2
f2

=
=
=
=

1
1.000000
1.900000
1.005000

O primeiro valor um nmero do tipo inteiro que representa o quociente da diviso de


dois nmeros do tipo inteiro 190 e 100 . J tnhamos trabalhado com expresses aritmticas
semelhantes em aulas anteriores. No segundo valor temos de olhar para a expresso aritmtica direita do comando de atribuio. Esta expresso uma expresso aritmtica que s
contm operandos do tipo inteiro. Por isso, o resultado o nmero do tipo inteiro 1 , que
atribudo varivel f2 . O comando printf mostra o contedo da varivel f2 como um
nmero do tipo ponto flutuante e assim a sada f2 = 1.000000 . Em seguida, nas prximas
duas impresses, as expresses aritmticas correspondentes contm operandos do tipo ponto
flutuante: a constante do tipo ponto flutuante 100.0 na primeira e a varivel do tipo ponto
flutuante f1 na segunda. Por isso, as expresses aritmticas tm como resultados nmeros do
tipo ponto flutuante e a sada mostra os resultados esperados.
FACOM

UFMS

82

N MEROS

COM PONTO FLUTUANTE

Suponha, no entanto, que um programa semelhante, o programa 9.3, tenha sido desenvolvido, compilado e executado.
Programa 9.3: Operaes e tipos inteiro e de ponto flutuante.
#include <stdio.h>
int main(void)
{
int i1, i2;
float f1;
i1 = 3;
i2 = 2;
f1 = i1 / i2;
printf("f1 = %f\n", f1);
return 0;
}

O resultado da execuo deste programa :

f1 = 1.000000

Mas e se quisssemos que a diviso i1/ i2 tenha como resultado um valor do tipo ponto
flutuante? Neste caso, devemos usar um operador unrio chamado operador conversor de
tipo, do ingls type cast operator, sobre alguma das variveis da expresso. No caso acima,
poderamos usar qualquer uma das atribuies abaixo:

f1 = (float) i1 / (float) i2;


f1 = (float) i1 / i2;
f1 = i1 / (float) i2;

e o resultado e a sada do programa seria ento:

f1 = 1.500000

O operador (float) assim chamado de operador conversor do tipo ponto flutuante.


Um outro operador unrio, que faz o inverso do operador conversor do tipo ponto flutuante,
o operador conversor do tipo inteiro, denotado por (int) . Esse operador conversor do tipo
inteiro converte o valor de seu operando, no caso uma expresso aritmtica, para um valor do
tipo inteiro.
Vejamos agora o programa 9.4.
FACOM

UFMS

9.2 E XPRESSES

ARITMTICAS

83

Programa 9.4: Uso de operadores conversores de tipo.


#include <stdio.h>
int main(void)
{
int i1, i2, i3, i4;
float f1, f2;
f1 = 10.8;
f2 = 1.5;
i1 = f1 / f2;
printf("i1 = %d\n", i1);
i2 = (int) f1 / f2;
printf("i2 = %d\n", i2);
i3 = f1 / (int) f2;
printf("i3 = %d\n", i3);
i4 = (int) f1 / (int) f2;
printf("i4 = %d\n", i4);
return 0;
}

A sada do programa 9.4

i1
i2
i3
i4

=
=
=
=

7
6
10
10

As primeiras duas atribuies fazem com que as variveis f1 e f2 recebam as constantes de


ponto flutuante 10.8 e 1.5 . Em seguida, a atribuio i1 = f1 / f2; faz com que o resultado da expresso aritmtica direita da instruo de atribuio seja atribudo varivel i1
do tipo inteiro. A expresso aritmtica devolve um valor de ponto flutuante: 10.8 / 1.5 =
7.2 . Porm, como do lado esquerdo da atribuio temos uma varivel do tipo inteiro, a parte
fracionria deste resultado descartada e o valor 7 ento armazenado na varivel i1 e
mostrado com printf . Na prxima linha, a expresso aritmtica do lado direito da atribuio
(int) f1 / f2 que avaliada como (int) 10.8 / 1.5 = 10 / 1.5 = 6.666666 e,
como do lado direito da instruo de atribuio temos uma varivel do tipo inteiro i2 , o valor
6 armazenado nesta varivel e mostrado na sada atravs do printf na linha seguinte. Na
prxima linha, a expresso aritmtica f1 / (int) f2 avaliada como 10.8 / (int) 1.5
= 10.8 / 1 = 10.8 e, de novo, como do lado direito da instruo de atribuio temos uma
varivel do tipo inteiro i3 , o valor armazenado nesta varivel 10 , que tambm mostrado na sada atravs de printf logo a seguir. E, por fim, a expresso aritmtica seguinte
(int) f1 / (int) f2 e sua avaliao dada por (int) 10.8 / (int) 1.5 = 10 / 1 =
10 e portanto este valor atribudo varivel i4 e apresentado na sada com printf .
FACOM

UFMS

84

N MEROS

COM PONTO FLUTUANTE

Um compilador da linguagem C considera qualquer constante com ponto flutuante como


sendo uma constante do tipo double , a menos que o programador explicitamente diga o
contrrio, colocando o smbolo f no final da constante. Por exemplo, a constante 3.1415f
uma constante com ponto flutuante do tipo float , ao contrrio da constante 55.726 , que
do tipo double .
Uma constante de ponto flutuante tambm pode ser expressa em notao cientfica. O valor
1.342e-3 um valor de ponto flutuante e representa o valor 1,342103 ou 0,001324. O valor
antes do smbolo e chamado mantissa e o valor aps esse smbolo chamado expoente do

nmero de ponto flutuante.


Para mostrar um nmero com ponto flutuante do tipo double na sada padro podemos
usar a mesmo caracter de converso de tipo %f que usamos para mostrar um nmero com
ponto flutuante do tipo float . Para realizar a leitura de um nmero de ponto flutuante que
ser armazenado em uma varivel do tipo double usamos os caracteres %lf como caracteres
de converso de tipo.
Um outro exemplo do uso de constantes e variveis do tipo ponto flutuante ( float e
double ) mostrado no programa 9.5, que computa a rea de um crculo cujo valor do raio
informado pelo usurio em radianos.
Programa 9.5: Clculo da rea do crculo.
#include <stdio.h>
/* Recebe o raio de um crculo e mostra sua rea */
int main(void)
{
float pi;
double raio, area;
pi = 3.141592f;
printf("Digite o valor do raio: ");
scanf("%lf", &raio);
area = (double) pi * raio * raio;
printf("A rea do crculo %f\n", area);
return 0;
}

Exerccios
9.1 Uma pessoa aplicou um capital de x reais a juros mensais de y% durante 1 ano. Determinar o montante de cada ms durante este perodo.
9.2 Os pontos (x, y) que pertencem figura H (veja a figura 9.1) so tais que x > 0, y > 0 e
x2 + y 2 6 1. Dados n pontos reais (x, y), verifique se cada ponto pertence ou no a H.
FACOM

UFMS

9.2 E XPRESSES

85

ARITMTICAS

Programa 9.6: Uma soluo para o exerccio 9.1.


#include <stdio.h>
int main(void)
{
int mes;
float x, y;
printf("Informe o capital inicial: ");
scanf("%d", &x);
printf("Informe a taxa de juros: ");
scanf("%d", &y);
for (mes = 1; mes <= 12; mes++) {
x = x * (1 + y / 100);
printf("Ms: %d Montante: %f\n", mes, x);
}
return 0;
}

1111111111
0000000000
0000000000
1111111111
0000000000
1111111111
0000000000
1111111111
0000000000
1111111111
H
0000000000
1111111111
0000000000
1111111111
0000000000
1111111111
0000000000x
1111111111

Figura 9.1: rea H de um quarto de um crculo.


9.3 Considere o conjunto H = H1 H2 de pontos reais, onde
H1 = {(x, y)|x 6 0, y 6 0, y + x2 + 2x 3 6 0}
H2 = {(x, y)|x > 0, y + x2 2x 3 6 0}

Dado um nmero inteiro n > 0, leia uma seqncia de n pontos reais (x, y) e verifique se
cada ponto pertence ou no ao conjunto H, contando o nmero de pontos da seqncia
que pertencem a H.
9.4 Dado um natural n, determine o nmero harmnico Hn definido por
n
X
1
.
Hn =
k
k=1

9.5 Para n > 0 alunos de uma determinada turma so dadas 3 notas de provas. Calcular a
mdia aritmtica das provas de cada aluno, a mdia da classe, o nmero de aprovados e
o nmero de reprovados, onde o critrio de aprovao mdia > 5.0.
9.6 Dados nmeros reais a, b e c, calcular as razes de uma equao do 2o grau da forma
ax2 + bx + c = 0. Imprimir a soluo em uma das seguintes formas:
FACOM

UFMS

86

N MEROS
a.

DUPLA
raiz

b.

REAIS DISTINTAS
raiz 1
raiz 2

c.

COM PONTO FLUTUANTE

COMPLEXAS
parte real
parte imaginria

9.7 Dado um inteiro positivo n, calcular e imprimir o valor da seguinte soma


2
3
n
1
+
+
+ ... + .
n n1 n2
1
9.8 Escreva um algoritmo que calcule a soma
1

1 1 1
1
1
+ + ... +

2 3 4
9999 10000

pelas seguintes maneiras:


(a) adio dos termos da esquerda para a direita;
(b) adio dos termos da direita para a esquerda;
(c) adio separada dos termos positivos e dos termos negativos da esquerda para a
direita;
(d) adio separada dos termos positivos e dos termos negativos da direita para a esquerda.
9.9 Uma maneira de calcular o valor do nmero utilizar a seguinte srie:
=4

4 4 4 4
4
+ +
+ ...
3 5 7 9 11

Escreva um algoritmo que calcule e imprima o valor de atravs da srie acima, com
preciso de 4 casas decimais. Para obter a preciso desejada, adicionar apenas os termos
cujo valor absoluto seja maior ou igual a 0.0001.
9.10 Dado um nmero real x tal que 0 6 x 6 1, calcular uma aproximao do arco tangente
de x em radianos atravs da srie infinita:
arctan x = x

x3 x5 x7
+

+ ...
3
5
7

incluindo todos os termos da srie at | xk | < 0.0001, com k mpar.


9.11 Uma maneira de calcular o valor de ex utilizar a seguinte srie:
e x = x0 +

x1 x2 x3
+
+
+ ...
1!
2!
3!
k

Dados dois nmeros reais x e , calcular o valor de ex incluindo todos os termos Tk = xk! ,
com k > 0, at que Tk < . Mostre na sada o valor computado e o nmero total de termos
usados na srie.
9.12 Dados x real e n natural, calcular uma aproximao para cos x, onde x dado em radianos, atravs dos n primeiros termos da seguinte srie:
cos x = 1

x2k
x2 x4 x6
+

+ . . . + (1)k
+ ...
2!
4!
6!
(2k)!

com k > 0. Compare com os resultados de sua calculadora.


FACOM

UFMS

9.2 E XPRESSES

87

ARITMTICAS

9.13 Dados x e reais, > 0, calcular uma aproximao para sen x, onde x dado em radianos,
atravs da seguinte srie infinita
sen x =

x
x3 x5
x2k+1

+
. . . + (1)k
+ ...
1!
3!
5!
(2k + 1)!

incluindo todos os termos Tk =


resultados de sua calculadora.

FACOM

x2k+1
(2k+1)! ,

com k > 0, at que Tk < . Compare com os

UFMS

88

FACOM

N MEROS

COM PONTO FLUTUANTE

UFMS

AULA

10

C ARACTERES

Nesta aula vamos estudar um novo tipo primitivo de dados, o tipo caractere. O tipo caractere um tipo primitivo que podemos trabalhar com um conjunto pequeno e previsvel de
valores. Na linguagem C existem dois tipos de caracteres: caractere com sinal e caractere sem
sinal. Esses dois tipos so apenas interpretaes diferentes do conjunto de todas as seqncias
de 8 bits, sendo que essa diferena irrelevante na prtica. O estudo dos caracteres ser estendido, mais til e melhor compreendido na aula 13, quando veremos as cadeias de caracteres.
Esta aula baseada especialmente nas referncias [15, 16].

10.1 Representao grfica


Na prtica, em todas as linguagens de programao de alto nvel incluindo a linguagem C, cada caractere armazenado em um nico byte na memria do computador, ou
seja, em 8 bits. Conseqentemente, na linguagem C um caractere sem sinal um nmero do conjunto {0, 1, . . . , 254, 255} e um caractere com sinal um nmero do conjunto
{128, . . . , 1, 0, 1, . . . , 127}. Ou seja, um caractere uma seqncia de 8 bits, dentre as 256
seqncias de 8 bits possveis.
A impresso de um caractere na sada padro a sua representao como um smbolo
grfico. Por exemplo, o smbolo grfico do caractere 97 a . Alguns caracteres tm representaes grficas especiais, como o caractere 10 que representado por uma mudana de
linha.
Os smbolos grficos dos caracteres 0 a 127 , de 7 bits, foram codificados e padronizados
pelo Cdigo Padro Americano para Troca de Informaes (do ingls American Standard Code for
Information Interchange). Por conta disso, essa representao grfica dos caracteres conhecida
como tabela ASCII. Essa codificao foi desenvolvida em 1960 e tem como base o alfabeto da
lngua inglesa. Muitas das codificaes de caracteres mais modernas herdaram como base a
tabela ASCII.
As limitaes do conjunto de caracteres da proposta da tabela ASCII, e tambm da tabela
logo mostraram-se aparentes e outros mtodos foram desenvolvidos para estend-las.
A necessidade de incorporar mltiplos sistemas de escrita, incluindo a famlia dos caracteres do
leste asitico, exige suporte a um nmero bem maior de caracteres. Por exemplo, o repertrio
completo do UNICODE compreende mais de 100 mil caracteres. Outros repertrios comuns
incluem ISO 8859-1 bastante usado nos alfabetos latinos e, por isso, tambm conhecido como
ISO Latin1.
EBCDIC ,

89

90

C ARACTERES

Dos 128 caracteres padronizados da tabela ASCII e de seus smbolos grficos correspondentes, 33 deles so no-imprimveis e os restantes 95 so imprimveis. Os caracteres noimprimveis so caracteres de controle, criados nos primrdios da computao, quando se usavam mquinas teletipo e fitas de papel perfurado, sendo que atualmente grande parte deles
esto obsoletos. Na tabela a seguir, apresentamos alguns desses caracteres no-imprimveis.
Muitos deles no so mostrados por opo ou por terem cado em desuso.
Bin
0000 0000
0000 0111
0000 1001
0000 1010
0000 1011
0000 1100
0000 1101
0111 1111

Dec
00
07
09
10
11
12
13
127

Significado
Nulo
Campainha
Tabulao horizontal
Mudana de linha
Tabulao vertical
Quebra de pgina
Retorno do carro/cursor
Delete

A tabela a seguir mostra os 95 caracteres imprimveis da tabela ASCII.


Bin
0010 0000
0010 0001
0010 0010
0010 0011
0010 0100
0010 0101
0010 0110
0010 0111
0010 1000
0010 1001
0010 1010
0010 1011
0010 1100
0010 1101
0010 1110
0010 1111
0011 0000
0011 0001
0011 0010
0011 0011
0011 0100
0011 0101
0011 0110
0011 0111
0011 1000
0011 1001
0011 1010
0011 1011
0011 1100
0011 1101
0011 1110
0011 1111
FACOM

Dec
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

Sim
!
"
#
$
%
&

(
)
*
+
,
.
/
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?

Bin
0100 0000
0100 0001
0100 0010
0100 0011
0100 0100
0100 0101
0100 0110
0100 0111
0100 1000
0100 1001
0100 1010
0100 1011
0100 1100
0100 1101
0100 1110
0100 1111
0101 0000
0101 0001
0101 0010
0101 0011
0101 0100
0101 0101
0101 0110
0101 0111
0101 1000
0101 1001
0101 1010
0101 1011
0101 1100
0101 1101
0101 1110
0101 1111

Dec
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

Sim
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_

Bin
0110 0000
0110 0001
0110 0010
0110 0011
0110 0100
0110 0101
0110 0110
0110 0111
0110 1000
0110 1001
0110 1010
0110 1011
0110 1100
0110 1101
0110 1110
0110 1111
0111 0000
0111 0001
0111 0010
0111 0011
0111 0100
0111 0101
0111 0110
0111 0111
0111 1000
0111 1001
0111 1010
0111 1011
0111 1100
0111 1101
0111 1110

Dec
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

Sim

a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~

UFMS

10.2 C ONSTANTES

E VARIVEIS

91

Os caracteres com sinal, quando dispostos em ordem crescente, apresentam-se de tal forma
que as letras acentuadas precedem as no-acentuadas. Os caracteres sem sinal, ao contrrio, em
ordem crescente apresentam-se de forma que as letras no-acentuadas precedem as acentuadas.
Essa a nica diferena entre caracteres com e sem sinal.

10.2 Constantes e variveis


Uma varivel do tipo caractere com sinal pode ser declarada na linguagem C com a palavra
reservada char . Uma varivel do tipo caractere sem sinal pode ser declarada com a mesma
palavra reservada char , mas com o especificador de tipo unsigned a precedendo. Especificadores de tipos bsicos sero estudados em detalhes em uma prxima aula. Dessa forma,

char c, d, e;
unsigned char f, g, h;

so declaraes vlidas de variveis do tipo caractere.


Uma constante do tipo caractere um nmero no intervalo de 0 a 255 ou de 128 a 127. Por
exemplo, para as variveis c , d e e declarada acima, podemos fazer

c = 122;
d = 59;
e = 51;

Mais comum e confortavelmente, podemos especificar uma constante do tipo caractere atravs da representao grfica de um caractere, envolvendo-o por aspas simples. Por exemplo,
z , ; e 3 so exemplos de constantes do tipo caractere. Assim, bem mais cmodo
fazer as atribuies

c = z;
d = ;;
e = 3;

que, na prtica, so idnticas s anteriores.


Alguns caracteres produzem efeitos especiais tais como acionar um som de campainha ou
realizar uma tabulao horizontal. Para representar um caractere como esse na linguagem C
usamos uma seqncia de dois caracteres consecutivos iniciada por uma barra invertida. Por
exemplo, \n o mesmo que 10 e representa uma mudana de linha. A tabela a seguir
mostra algumas constantes do tipo caractere.
FACOM

UFMS

92

C ARACTERES
caractere
0
9
10
11
12
13
32
55
92
97

constante
\0
\t
\n
\v
\f
\r

7
\\
a

smbolo grfico
caractere nulo
tabulao horizontal
mudana de linha
tabulao vertical
quebra de pgina
retorno do carro/cursor
espao
7
\
a

Na linguagem C, um branco (do ingls whitespace) definido como sendo um caractere que
uma tabulao horizontal, uma mudana de linha, uma tabulao vertical, uma quebra de
pgina, um retorno de carro/cursor e um espao. Ou seja, os caracteres 9, 10, 11, 12, 13 e 32
so brancos e as constantes correspondentes so \t , \n , \v , \f , \r e .
A funo scanf trata todos os brancos como se fossem , assim como outras funes da
linguagem C tambm o fazem.
Para imprimir um caractere na sada padro com a funo printf devemos usar o especificador de converso de tipo caractere %c na seqncia de caracteres de formatao. Para ler
um caractere a partir da entrada padro com a funo scanf tambm devemos usar o mesmo
especificador de converso de tipo caractere %c na seqncia de caracteres de formatao. Um
exemplo de uso do tipo bsico caractere mostrado no programa 10.1.
Programa 10.1: Um programa usando o tipo char .
#include <stdio.h>
int main(void)
{
char c;
c = a;
printf("%c\n", c);
c = 97;
printf("%c\n", c);
printf("Informe um caractere: ");
scanf("%c", &c);
printf("%c = %d\n", c, c);
return 0;
}

Como vimos at aqui nesta seo, por enquanto no h muita utilidade para constantes
e variveis do tipo caractere. Mas em breve iremos us-las para construir um tipo de dados
muito importante chamado de cadeia de caracteres.
FACOM

UFMS

10.3 E XPRESSES

COM CARACTERES

93

10.3 Expresses com caracteres

Como caracteres so implementados como nmeros inteiros em um byte, as expresses


envolvendo caracteres herdam todas as propriedades das expresses envolvendo nmeros inteiros. Em particular, as operaes aritmticas envolvendo variveis do tipo unsigned char
e char so executadas em aritmtica int .
Dessa forma, considere o trecho de cdigo a seguir:

unsigned char x, y, z;
x = 240;
y = 65;
z = x + y;

Na ltima linha o resultado da expresso x + y 305 . No entanto, atribuies de nmeros inteiros a variveis do tipo caractere so feitas mdulo 256. Por isso, a varivel z acima
receber o valor 49 .
Do mesmo modo, aps a execuo do trecho de cdigo a seguir:

unsigned char x;
char c;
x = 256;
c = 136;

a varivel x conter o valor 0 e a varivel c conter o valor -120 .


Expresses relacionais podem naturalmente envolver caracteres. No trecho de cdigo a
seguir, algumas expresses lgicas envolvendo caracteres so mostradas:

.
.
.
char c;
c = a;
if (a <= c && c <= z)
c = c - ;
printf("%c = %d\n", c, c);
if (65 <= c && c <= 122)
c = c + a;
printf("%c = %d\n", c, c);
.
.
.

Tente verificar a sada gerada pelas duas chamadas da funo printf no trecho de cdigo
acima.
FACOM

UFMS

94

C ARACTERES

Exerccios
10.1 Verifique se o programa 10.2 est correto.
Programa 10.2: O que faz este programa?
#include <stdio.h>
int main(void)
{
char c;
for (c = 0; c < 128; c++)
printf(".");
printf("\ntchau!\n");
return 0;
}

10.2 Escreva um programa que imprima todas as letras minsculas e todas as letras maisculas do alfabeto.
10.3 Escreva um programa que traduz um nmero de telefone alfabtico de 8 dgitos em um
nmero de telefone na forma numrica. Suponha que a entrada sempre dada em caracteres maisculos.
Exemplo:
Se a entrada URGENCIA a sada deve ser 87436242 .
1111FOGO a sada deve ser 11113646 .

Se a entrada

Se voc no possui um telefone, ento as letras que correspondem s teclas so as seguintes: 2=ABC, 3=DEF, 4=GHI, 5=JKL, 6=MNO, 7=PQRS, 8=TUV e 9=WXYZ.
10.4 Scrabble um jogo de palavras em que os jogadores formam palavras usando pequenos
quadrados que contm uma letra e um valor. O valor varia de uma letra para outra, baseado na sua raridade. Os valores so os seguintes: AEILNORSTU=1, DG=2, BCMP=3,
FHVWY=4, K=5, JX=8 e QZ=10.
Escreva um programa que receba uma palavra e compute o seu valor, somando os valores de suas letras. Seu programa no deve fazer distino entre letras maisculas e
minsculas.
Exemplo:
Se a palavra de entrada programa a sada tem de ser 13 .
10.5 Escreva um programa que receba dois nmeros inteiros a e b e um caractere op, tal que
op pode ser um dos cinco operadores aritmticos disponveis na linguagem C ( + , - , * ,
/ , % ), realize a operao a op b e mostre o resultado na sada.

FACOM

UFMS

AULA

T IPOS

11

PRIMITIVOS DE DADOS

Como vimos at esta aula, a linguagem C suporta fundamentalmente dois tipos de dados
numricos: tipos inteiros e tipos com ponto flutuante. Valores do tipo inteiro so nmeros
inteiros em um dado intervalo finito e valores do tipo ponto flutuante so tambm dados em
um intervalo finito e podem ter uma parte fracionria. Alm desses, o tipo caractere tambm
suportado pela linguagem e um valor do tipo caractere tambm um nmero inteiro em um
intervalo finito mais restrito que o dos tipos inteiros.
Nesta aula faremos uma reviso dos tipos primitivos de dados da linguagem C e veremos os
especificadores desses tipos, seus especificadores de converso para entrada e sada de dados,
as converses entre valores de tipos distintos, alm de definir nossos prprios tipos. Esta aula
uma reviso das aulas sobre o tipo inteiro (aula 7), o tipo ponto flutuante (aula 9) e o tipo
carctere, que vimos em conjunto com nas aulas tericas da disciplina. tambm uma extenso
desses conceitos, podendo ser usada como uma referncia para tipos primitivos de dados.
As referncias usadas nesta aula so [15, 16].

11.1 Tipos inteiros


Valores do tipo inteiro na linguagem C so nmeros inteiros em um intervalo bem definido.
Os tipos de dados inteiros na linguagem C tm tamanhos diferentes. O tipo int tem geralmente 32 bits: o bit mais significativo reservado para o sinal do nmero inteiro. Por isso, o
tipo int chamado de tipo inteiro com sinal. A palavra reservada signed pode ser usada
em conjunto com int para declarar uma varivel do tipo inteiro com sinal, embora signed
seja completamente dispensvel. Uma varivel do tipo inteiro sem sinal pode ser declarada
com a palavra unsigned precedendo a palavra reservada int .
Alm disso, programas podem necessitar de armazenar nmeros inteiros grandes e podemos declarar variveis do tipo inteiro para armazenar tais nmeros com a palavra reservada
long . Do mesmo modo, quando h necessidade de economia de espao em memria, podemos declarar uma varivel para armazenar nmeros inteiros menores com a palavra reservada
short precedendo a palavra reservada int .
Dessa forma, podemos construir um tipo de dados inteiro que melhor represente nossa necessidade usando as palavras reservadas signed , unsigned , short e long . Essas palavras
reservadas so chamadas de especificadores de tipos, do ingls type specifiers, da linguagem C.
Podemos combinar os especificadores de tipos descritos acima na declarao de uma varivel do tipo inteiro. No entanto, apenas seis combinaes desses especificadores e da palavra
reservada int produzem tipos de dados diferentes:
95

96

T IPOS

PRIMITIVOS DE DADOS

short int
unsigned short int
int
unsigned int
long int
unsigned long int

Qualquer outra combinao de especificadores na declarao de uma varivel equivalente a uma das combinaes acima. A ordem que os especificadores ocorrem no tem
influncia sobre o resultado final: declaraes feitas com unsigned short int ou com
short unsigned int tm o mesmo resultado. Quando no estritamente necessrio, a
linguagem C permite que a palavra reservada int seja omitida, como por exemplo em
unsigned short e long .
O intervalo de valores representado por cada um dos seis tipos inteiros varia de uma mquina para outra. Os compiladores, entretanto, devem obedecer algumas regras fundamentais.
Em especial, o padro especifica que o tipo int no seja menor que o tipo short int e que
long int no seja menor que int .
As mquinas mais atuais so de 64 bits e a tabela abaixo mostra os intervalos de cada um
dos possveis tipos inteiros. A principal diferena entre mquinas de 32 e de 64 bits est no
tipo long int . Em mquinas de 32 bits, o tipo long int e o tipo int so equivalentes. Em
mquinas de 64 bits, h diferenciao entre esses dois tipos, como apresentado abaixo.
Tipo
short int
unsigned short int
int
unsigned int
long int
unsigned long int

Menor valor
32.768
0
2.147.483.648
0
9.223.372.036.854.775.808
0

Maior valor
32.767
65.535
2.147.483.647
4.294.967.294
9.223.372.036.854.775.807
18.446.744.073.709.551.615

Constantes numricas, como vimos, so nmeros que ocorrem no cdigo dos programas,
em especial em expresses aritmticas. As constantes, assim como as variveis, podem ser
nmeros inteiros ou nmeros com ponto flutuante.
Na linguagem C, as constantes numricas do tipo inteiro podem ser descritas em decimal
ou base 10, octal ou base 8 ou ainda hexadecimal ou base 16. Constantes decimais contm
dgitos de 0 (zero) a 9 (nove), mas no devem iniciar com 0 (zero). Exemplos de constantes
decimais so mostrados a seguir:

75

-264

32767

Constantes octais contm somente dgitos entre 0 (zero) e 7 (sete) e devem comear necessariamente com o dgito 0 (zero). Exemplos de constantes octais so mostrados a seguir:

075
FACOM

0367

07777
UFMS

11.1 T IPOS

97

INTEIROS

E constantes hexadecimais contm dgitos entre 0 (zero) e 9 (nove) e letras entre a e f, e sempre
devem iniciar com os caracteres 0x. As letras podem ser maisculas ou minsculas. Exemplos
de constantes hexadecimais so mostrados a seguir:

0xf

0x8aff

0X12Acf

importante destacar que a descrio de constantes como nmeros na base octal e hexadecimal apenas uma forma alternativa de escrever nmeros que no tem efeito na forma como
so armazenados na memria, j que sempre so armazenados na base binria. Alm disso,
essas notaes so mais usadas quando trabalhamos com programas de baixo nvel.
No h necessidade de se convencionar uma nica notao para escrever constantes e podemos trocar de uma notao para outra a qualquer momento. Na verdade, podemos inclusive
misturar essas notaes em expresses aritmticas como a seguir:

117 + 077 + 0xf0

e o resultado dessa expresso 420 na base decimal.


O tipo de uma constante que um nmero inteiro na base decimal normalmente int .
Se o valor da constante for muito grande para armazen-la como um int , a constante ser
armazenada como um long int . Se mesmo nesse caso ainda no for possvel armazenar
tal constante, o compilador tenta, como um ltimo recurso, armazenar o valor como um
unsigned long int . Constantes na base octal ou hexadecimal so armazenadas de maneira semelhante, com o compilador tentando armazen-la progressivamente como um int ,
unsigned int , long int ou unsigned long int .
Para forar que o compilador trate uma constante como um nmero inteiro grande, devemos adicionar a letra L ou l ao final da constante. Como exemplo, as constantes abaixo so
do tipo long int :

22L

055l

0xffffL

Para indicar que uma constante do tipo inteiro no tem sinal, devemos adicionar a letra
U ou u ao final da constante. Por exemplo, as constantes apresentadas abaixo so do tipo
unsigned int :

22u

072U

0xa09DU

Podemos indicar que uma constante um nmero inteiro grande e sem sinal usando uma
combinao das letras acima, em qualquer ordem. Por exemplo, as constantes abaixo so do
tipo unsigned long int :

FACOM

UFMS

98

T IPOS

22ul

07777UL

PRIMITIVOS DE DADOS

0xFFFFAALU

A funo printf usada para imprimir, entre outros, nmeros inteiros. Relembrando, a
funo printf tem o seguinte formato:
printf(cadeia, expresso 1, expresso 2, . . .);

onde cadeia a cadeia de caracteres de formatao. Quando a funo printf chamada,


a impresso da cadeia de caracteres de formatao ocorre na sada. Essa cadeia pode conter caracteres usuais, que sero impressos diretamente, e tambm especificaes de converso, cada
uma iniciando com o caractere % e representando um valor a ser preenchido durante a impresso. A informao que sucede o caractere % especifica como o valor deve ser convertido a
partir de sua representao interna binria para uma representao imprimvel. Caracteres
usuais na cadeia de caracteres de formatao so impressos na sada exatamente como ocorrem na cadeia enquanto que as especificaes de converso so trocadas por valores a serem
impressos.
A tabela abaixo mostra tipos e especificadores de tipos e tambm especificadores de converso para cadeias de caracteres de formatao da funo printf , especificamente para tratamento de nmeros inteiros.
Especificador e tipo
short int
unsigned short int
int
unsigned int
long int
unsigned long int

Especificador de converso
%hd ou %hi
%hu
%d ou %i
%u
%ld ou %li
%lu

A forma geral de um especificador de converso para nmeros inteiros em uma cadeia de


caracteres de formatao da funo printf a seguinte:

%[flags][comprimento][.preciso][hl]conversor

Os campos opcionais so mostrados entre colchetes. Ou seja, apenas conversor obrigatrio, que chamamos de especificador de converso. A tabela a seguir mostra os possveis
flags para um especificador de converso de uma cadeia de caracteres de formatao da funo
printf .
Flag
+

espaos
0
FACOM

Significado
Valor alinhado esquerda
Valor precedido por + ou Valor positivo precedido por espaos
Nmero preenchido com zeros esquerda
UFMS

11.1 T IPOS

INTEIROS

99

Os especificadores de converso o e x (ou X ) permitem ainda que um nmero inteiro


a ser mostrado na sada o seja na base octal ou hexadecimal, respectivamente. Se o nmero
inteiro pequeno, grande, com ou sem sinal, essas opes tambm podem ser descritas no
especificador.
O programa 11.1 usa os tipos primitivos conhecidos para nmeros inteiros e seus especificadores, juntamente com caracteres especificadores de converso nas cadeias de caracteres de
formatao das chamadas da funo printf .
Programa 11.1: Exemplo de tipos e especificadores de tipos inteiros e tambm de formatao
de impresso com especificadores de converso.
#include <stdio.h>
int main(void)
{
short int i1;
unsigned short int i2;
int i3;
unsigned int i4;
long int i5;
unsigned long int i6;
i1
i2
i3
i4
i5
i6

=
=
=
=
=
=

159;
630u;
-991023;
98979U;
8393202L;
34268298UL;

printf("%hd %d %ho\n", i1, i1, i1);


printf("%hu %i %hx\n", i2, i2, i2);
printf("%+d % d %09d\n", i3, i3, i3);
printf("%X %d %u\n", i4, i4, i4);
printf("%+ld %ld %10ld\n", i5, i5, i5);
printf("%lu %10.8lu %-lu\n", i6, i6, i6);
return 0;
}

Assim como para a funo printf , outras opes de formatao tambm esto disponveis
para a funo scanf , mais que aquelas vistas at esta aula. Neste caso tambm vale o conceito
de especificadores de converso. Quando uma funo scanf executada, especificadores de
converso so procurados na cadeia de caracteres de formatao (de leitura), aps o smbolo
usual % .
Os especificadores de converso h e l podem ser usados em uma cadeia de caracteres de
formatao de leitura, juntamente com a chamada da funo scanf , com o mesmo sentido que
na cadeia de caracteres de formatao de escrita, na funo printf , isto , para indicar que a
leitura ser feita como um nmero inteiro curto ou longo, respectivamente. Um comprimento
tambm pode ser usado, indicando o comprimento mximo do valor a ser armazenado na
varivel correspondente.
FACOM

UFMS

100

T IPOS
Especificador

PRIMITIVOS DE DADOS

Significado
valor a ser lido expresso em notao decimal; o argumento correspondente do tipo
int, a menos que os modificadores de converso h ou l tenham sido usados, casos
em que o valor ser short int ou long int, respectivamente

como %d, exceto nmeros na base octal (comeando com 0) ou hexadecimal


(comeando com 0x ou 0X,) que tambm podem ser lidos

valor a ser lido um inteiro e o argumento correspondente do tipo unsigned int

valor a ser lido expresso na notao octal e pode opcionalmente ser precedido por 0;
o argumento correspondente um int, a menos que os modificadores de converso
h ou l tenham sido usados, casos em que short int ou long int,
respectivamente

valor a ser lido expresso na notao hexadecimal e pode opcionalmente ser precedido
por 0x ou 0X; o argumento correspondente um unsigned int, a menos que os
modificadores de converso h ou l tenham sido usados, casos em que short int
ou long int, respectivamente

A funo scanf executada primeiro esperando por um valor a ser informado pelo usurio e, depois, formatando este valor atravs do uso da cadeia de caracteres de formatao e do
especificador de converso.
A funo scanf finaliza uma leitura sempre que o usurio informa um branco, que o
caractere 32 (espao ou ), o caractere 9 (tabulao horizontal ou \t ), o caractere 10
(tabulao vertical ou \v ), o caractere 11 (retorno de carro/cursor ou \r ), o caractere 12
(mudana de linha ou \n ) ou o caractere 13 (avano de pgina ou \f ). Nesse sentido,
considere uma entrada como no trecho de cdigo abaixo:

scanf("%d%d", &a, &b);

Neste caso, se o usurio informar

prompt$ ./a.out
4 7

ou
prompt$ ./a.out
4
7

ou ainda
prompt$ ./a.out
4
7
FACOM

UFMS

11.2 N MEROS

101

COM PONTO FLUTUANTE

o resultado ser o mesmo, ou seja, os valores 4 e 7 sero armazenados nas variveis a e b ,


respectivamente.

11.2 Nmeros com ponto flutuante


fcil notar que apenas os nmeros inteiros no so capazes de nos auxiliar na soluo dos
diversos problemas, mesmo quando encontramos formas de estender seu intervalo de valores,
como no caso da linguagem C. Dessa forma, valores reais se fazem muito necessrios, mais
especificamente para descrever nmeros imensamente grandes ou pequenos. Nmeros reais
so armazenados na linguagem C como nmeros com ponto flutuante.
A linguagem C fornece trs tipos de dados numricos com ponto flutuante:
float
double
long double

Ponto flutuante de preciso simples


Ponto flutuante de preciso dupla
Ponto flutuante de preciso estendida

O tipo float usado quando a necessidade de preciso no crtica. O tipo double fornece maior preciso, suficiente para a maioria dos problemas. E o tipo long double fornece
a maior preciso possvel e raramente usado.
A linguagem C no estabelece padro para a preciso dos tipos com ponto flutuante, j
que diferentes computadores podem armazenar nmeros com ponto flutuante de formas diferentes. Os computadores mais recentes seguem, em geral, as especificaes do Padro 754 da
IEEE. A tabela abaixo, mostrada na aula 9, mostra as caractersticas dos tipos numricos com
ponto flutuante quando implementados sob esse padro.
Tipo
float
double

Menor valor (positivo)


1.17549 1038
2.22507 10308

Maior valor
3.40282 1038
1.79769 10308

Preciso
6 dgitos
15 dgitos

Constantes com ponto flutuante podem ser descritas de diversas formas. Por exemplo, as
constantes abaixo so formas vlidas de escrever o nmero 391,0:

391.0

391.

391.0e0

391E0

3.91e+2

.391e3

3910.e-1

Uma constante com ponto flutuante deve conter um ponto decimal e/ou um expoente,
que uma potncia de 10 pela qual o valor multiplicado. Se um expoente dado, deve vir
precedido da letra e ou E . Opcionalmente, um sinal + ou - pode ocorrer logo aps a letra.
Por padro, constantes com ponto flutuante so armazenadas como nmeros de ponto flutuante de preciso dupla. Isso significa que, quando um compilador C encontra em um programa uma constante 391.0 , por exemplo, ele armazena esse nmero na memria no mesmo
formato de uma varivel do tipo double . Se for necessrio, podemos forar o compilador a
armazenar uma constante com ponto flutuante no formato float ou long double . Para indicar preciso simples basta adicionar a letra f ou F ao final da constante, como por exemplo
391.0f . Para indicar preciso estendida necessrio adicionar a letra l ou L ao final da
constante, como por exemplo 391.0L .
FACOM

UFMS

102

T IPOS

PRIMITIVOS DE DADOS

Os especificadores de converso para nmeros com ponto flutuante de preciso simples so


%e , %f e %g , tanto para escrita como para leitura. O formato geral de um especificador de

converso para nmeros com ponto flutuante parecido com aquele descrito na seo anterior,
como podemos observar abaixo:

%[flags][comprimento][.preciso][lL]conversor

O especificador de converso %e mostra/solicita um nmero com ponto flutuante no formato exponencial ou notao cientfica. A preciso indica quantos dgitos aps o ponto sero
mostrados/solicitados ao usurio, onde o padro 6. O especificador de converso %f mostra/solicita um nmero com ponto flutuante no formato com casas decimais fixas, sem expoente. A preciso indica o mesmo que para %e . E o especificador de converso %g mostra o
nmero com ponto flutuante no formato exponencial ou com casas decimais fixas, dependendo
de seu tamanho. Diferentemente dos especificadores anteriores, a preciso neste caso indica o
nmero mximo de dgitos significativos a ser mostrado/solicitado.
Ateno deve ser dispensada com pequenas diferenas na escrita e na leitura de nmeros
com ponto flutuante de preciso dupla e estendida. Quando da leitura de um valor do tipo
double necessrio colocar a letra l precedendo e , f ou g . Esse procedimento necessrio apenas na leitura e no na escrita. Quando da leitura de um valor do tipo long double
necessrio colocar a letra L precedendo e , f ou g .

11.3 Caracteres
Como mencionamos quando discutimos caracteres nas nossas aulas tericas e prticas, na
linguagem C cada caractere armazenado em um nico byte na memria do computador.
Assim, um caractere sem sinal um nmero do conjunto {0, . . . , 255} e um caractere com sinal
um nmero do conjunto {128, . . . , 1, 0, 1, . . . , 127}. Ou seja, um caractere uma seqncia
de 8 bits, dentre as 256 seqncias de 8 bits possveis. A impresso de um caractere na sada
padro a sua representao como um smbolo grfico. Por exemplo, o smbolo grfico do
caractere 97 a . Alguns caracteres tm representaes grficas especiais, como o caractere
10 que representado por uma mudana de linha.
Uma varivel do tipo caractere (com sinal) pode ser declarada na linguagem C com a palavra reservada char . Uma varivel do tipo caractere sem sinal pode ser declarada com a
mesma palavra reservada char , mas com o especificador de tipo unsigned a precedendo:

char c, d, e;
unsigned char f, g, h;

Uma constante do tipo caractere sem sinal um nmero no intervalo de 0 a 255 e uma
constante do tipo caractere com sinal uma constante no intervalo de 128 a 127. Por exemplo,
para as variveis c , d e e declaradas acima, podemos fazer
FACOM

UFMS

11.3 C ARACTERES

103

c = 122;
d = 59;
e = 51;

Mais comum e confortavelmente, podemos especificar uma constante do tipo caractere atravs da representao grfica de um caractere, envolvendo-o por aspas simples. Por exemplo,
z , ; e 3 so exemplos de constantes do tipo caractere. Assim, bem mais cmodo
fazer as atribuies

c = z;
d = ;;
e = 3;

que, na prtica, so idnticas.


Alguns caracteres produzem efeitos especiais tais como acionar um som de campainha ou
realizar uma tabulao horizontal. Para representar um caractere como esse na linguagem C
usamos uma seqncia de dois caracteres consecutivos iniciada por uma barra invertida. Por
exemplo, \n o mesmo que 10 e representa uma mudana de linha. A tabela a seguir
mostra algumas constantes do tipo caractere.
caractere
0
9
10
11
12
13
32
55
92
97

constante
\0
\t
\n
\v
\f
\r

7
\\
a

smbolo grfico
caractere nulo
tabulao horizontal
mudana de linha
tabulao vertical
quebra de pgina
retorno do carro/cursor
espao
7
\
a

Na linguagem C, um branco (do ingls whitespace) definido como sendo um caractere que
uma tabulao horizontal, uma mudana de linha, uma tabulao vertical, uma quebra de
pgina, um retorno de carro/cursor ou um espao. Ou seja, os caracteres 9, 10, 11, 12, 13 e 32
so brancos e as constantes correspondentes so \t , \n , \v , \f , \r e . A
funo scanf trata todos os brancos como se fossem , assim como outras funes tambm
o fazem.
O especificador de converso %c permite que as funes scanf e printf possam ler ou
escrever um nico caractere. importante reiterar que a funo scanf no salta caracteres
brancos antes de ler um caractere. Se o prximo caractere a ser lido foi digitado como um
espao ou uma mudana de linha, ento a varivel correspondente conter um espao ou uma
mudana de linha. Para forar a funo scanf desconsiderar espaos em branco antes da
leitura de um caractere, necessrio adicionar um espao na cadeia de caracteres de formatao
de leitura antes do especificador de formatao %c , como a seguir:
FACOM

UFMS

104

T IPOS

PRIMITIVOS DE DADOS

scanf(" %c", &c);

Um espao na cadeia de caracteres de formatao de leitura significa que haver um salto de


zero ou mais caracteres brancos.
O programa 11.2 mostra um exemplo de uso da funo scanf e de uma cadeia de caracteres de formatao contendo um especificador de tipo %c .
Programa 11.2: Conta o nmero de vogais minsculas na frase digitada pelo usurio.
#include <stdio.h>
/* Recebe um frase e conta o nmero de vogais minsculas que ela possui */
int main(void)
{
char c;
int conta;
printf("Digite uma frase: ");
conta = 0;
do {
scanf("%c", &c);
if (c == a || c == e || c == i || c == o || c == u)
conta++;
} while (c != \n);
printf("A frase tem %d vogais minsculas\n", conta);
return 0;
}

A funo scanf tem compreenso dificultada em alguns casos, especialmente quando


queremos ralizar a entrada de caracteres ou ainda quando misturamos a entrada de nmeros
e caracteres em um programa. A funo scanf essencialmente uma funo de casamento
de cadeias de caracteres que tenta emparelharar grupos de caracteres com especificaes de
converso. Essa funo tambm controlada por uma cadeia de caracteres de formatao e,
quando chamada, comea o processamento da informao nessa cadeia a partir do caractere
mais a esquerda. Para cada especificao de converso na cadeia de caracteres de formatao,
a funo scanf tenta localizar um item do tipo apropriado na cadeia de entrada, saltando
brancos se necessrio. scanf l ento esse item, parando quando encontra um caractere que
que no pode pertencer quele item. Se o item foi lido corretamente, a funo scanf continua
processando o restante da cadeia de caracteres de formatao. Se qualquer item no pode ser
lido com sucesso, a funo scanf pra imediatamente sem olhar para o resto da cadeia de
caracteres de formatao e o restante da cadeia de entrada.
Considere, por exemplo, que temos duas variveis do tipo int com identificadores a e
b e duas variveis do tipo float com identificadores x e y . Considere a seguinte chamada
funo scanf :

scanf("%d%d%f%f", &a, &b, &x, &y);


FACOM

UFMS

11.3 C ARACTERES

105

Suponha que o usurio informou os valores da seguinte forma:

prompt$ ./a.out
-10
2
0.33
27.8e3

Como, nesse caso, a leitura busca por nmeros, a funo ignora os brancos. Dessa forma, os
nmeros acima podem ser colocados todos em uma linha, separados por espaos, ou em vrias
linhas, como mostramos acima. A funo scanf enxerga a entrada acima como uma cadeia
de caracteres como abaixo:
-102

0.33 27.8e3

representa o caractere espao e representa o caractere de mudana de linha (ou a


onde
tecla Enter ). Como a funo salta os brancos, ento os nmeros so lidos de forma correta.
Se a cadeia de caracteres de formatao de leitura contm caracteres usuais alm dos especificadores de tipo, ento o casamento dessa cadeia de caracteres e da cadeia de caracteres
de entrada se d de forma ligeiramente diferente. O processamento de um caractere usual na
cadeia de caracteres de formatao de uma funo scanf depende se o caractere um branco
ou no. Ou seja,
um ou mais brancos consecutivos na cadeia de caracteres de formatao faz com que a
funo scanf leia repetidamente brancos na entrada at que um caractere no branco
seja lido; o nmero de brancos na cadeia de caracteres de formatao irrelevante;
outros caracteres na cadeia de caracteres de formatao, no brancos, faz com que a funo scanf o compare com o prximo caractere da entrada; se os dois caracteres so
idnticos, a funo scanf descarta o caractere de entrada e continua o processamento
da cadeia de caracteres de formatao; seno, a funo scanf aborta sua execuo no
processando o restante da cadeia de caracteres de formatao e os caracteres de entrada.
Por exemplo, suponha que temos uma leitura como abaixo:

scanf("%d/%d", &dia, &mes);

Suponha que a entrada seja:


2/ 33

ento, a funo scanf salta o primeiro espao, associa %d com 2 , casa / e / , salta o espao
e associa %d com 33 . Por outro lado, se a entrada
2 / 33

a funo scanf salta o espao, associa %d com 2 , tenta casar o caractere / da cadeia de
da entrada e como esses caracteres no casam, a
caracteres de formatao com um espao
funo termina e o restante / 33 da entrada permanecer armazenado na memria at que
uma prxima chamada funo scanf seja realizada.
FACOM

UFMS

106

T IPOS

PRIMITIVOS DE DADOS

Por convenincia e simplicidade, muitas vezes preferimos usar funes mais simples de
entrada e sada de caracteres. As funes getchar e putchar so funes da biblioteca
padro de entrada e sada da linguagem C e so usadas exclusivamente com caracteres. A
funo getchar l um caractere da entrada e devolve esse caractere. A funo putchar
toma um caractere como parmetro e o exibe na sada. Dessa forma, se c uma varivel do
tipo char as linhas a seguir:

scanf("%c", &c);
printf("%c", c);

so equivalentes s linhas abaixo:

c = getchar();
putchar(c);

Observe que a funo getchar no tem parmetros de entrada, mas, por ser uma funo,
carrega os parnteses como sufixo. Alm disso, essa funo devolve um caractere, que pode
ser usado em uma expresso. Nas linhas acima, getchar usada em uma atribuio. Por
outro lado, a funo putchar tem como parmetro uma expresso do tipo caractere que, aps
avaliada, seu valor ser exibido na sada. A funo putchar no devolve qualquer valor.

11.4 Converso de tipos


As arquiteturas dos computadores em geral restringem as operaes em expresses para
que sejam realizadas apenas com operandos de mesmo comprimento, isto , mesmo nmero
de bytes. A linguagem C, por outro lado, menos restritiva nesse sentido e permite que valores
de tipos primitivos sejam misturados em expresses. Isso acarreta um maior trabalho para o
compilador, j que necessria a converso de alguns operandos da expresso. Como essas
converses so realizadas pelo compilador, elas so chamadas de converses implcitas. A
linguagem C tambm permite que o programador faa suas prprias converses, chamadas
de converses explcitas, usando operadores de converso de tipo, como vimos na aula 9 e
revisaremos adiante.
Converses implcitas so realizadas nas seguintes situaes:
quando os operandos em uma expresso no so do mesmo tipo;
quando o tipo do valor resultante da avaliao de uma expresso ao lado direito de um
comando de atribuio no compatvel com o tipo da varivel do lado esquerdo de um
comando de atribuio;
quando o tipo de um argumento em uma chamada de uma funo no compatvel com
o tipo do parmetro correspondente;
quando o tipo do valor resultante de uma expresso de devoluo de uma funo, junto
da palavra reservada return , no compatvel com o tipo da funo.
FACOM

UFMS

11.4 C ONVERSO

DE TIPOS

107

Veremos agora os dois primeiros casos, sendo que os dois ltimos sero vistos adiante.
As converses usuais em expresses so aplicadas aos operandos de todos os operadores binrios aritmticos, relacionais e lgicos. A linguagem C faz a converso dos operandos de
maneira que fiquem mais seguramente acomodados. Logo, o menor nmero de bits que mais
seguramente acomode os operandos ser usado nessa converso, se uma converso for de fato
necessria. As regras de converso de tipos podem ento ser divididas em dois tipos:
o tipo de pelo menos um dos operandos de ponto flutuante: se um dos operandos do tipo
long double , ento o outro operando ser convertido para o tipo long double . Caso
contrrio, se um dos operandos do tipo double , ento o outro operando ser convertido para o tipo double . Seno, um dos operandos do tipo float e o outro ser
convertido para esse mesmo tipo;
nenhum dos operandos do tipo ponto flutuante: primeiro, se qualquer um dos operandos
do tipo char ou short int , ser convertido para o tipo int ; depois, se um dos operandos do tipo unsigned long int , ento o outro operando ser convertido para o
tipo unsigned long int . Caso contrrio, se um dos operandos do tipo long int ,
ento o outro operando ser convertido para o tipo long int . Ainda, se um dos operandos do tipo unsigned int , ento o outro operando ser convertido para o tipo
unsigned int . Por fim, um dos operandos do tipo int e o outro ser convertido
para esse mesmo tipo.
importante alertar para um caso em que uma operao envolve um dos operandos com
sinal e o outro sem sinal. Pelas regras acima, o operando com sinal convertido para um operando sem sinal. Assim, se um dos operandos do tipo int e contm um nmero negativo e
o outro operando do tipo unsigned int e contm um nmero positivo, ento uma operao envolvendo esses dois operandos deve ser realizada cuidadosamente. Nesse caso, o valor
do tipo int ser promovido para o tipo unsigned int , mas a converso ser feita usando
a frmula k + 232 , onde k o valor com sinal. Esse problema uma das causas de erro mais
difceis de depurar. Veja o programa 11.3 para um exemplo bastante ilustrativo.
Programa 11.3: Dificuldade na converso de valores em expresses.
#include <stdio.h>
int main(void)
{
int i;
unsigned int j;
i = -1;
j = 1;
printf("i = %+d i = %u\n", i, (unsigned int) i);
printf("j = %+d j = %u\n", (int) j, j);
if (i < j)
printf("i < j\n");
else
printf("j < i\n");
return 0;
}

FACOM

UFMS

108

T IPOS

PRIMITIVOS DE DADOS

A sada do programa 11.3 mostrada a seguir.

prompt$ ./a.out
i = -1
i = 4294967295
j = +1
j = 1
j < i

As converses implcitas da linguagem C so bastante convenientes, como pudemos perceber at aqui. No entanto, muitas vezes necessrio que o programador tenha maior controle
sobre as converses a serem realizadas, podendo assim realizar converses explcitas. Dessa
forma, a linguagem C possui operadores de converso de tipo, ou casts, que j tomamos contato especialmente na aula 9. Um operador de converso de tipo um operador unrio que
tem o seguinte formato geral:

(nome-do-tipo) expresso

onde nome-do-tipo o nome de qualquer tipo primitivo de dados que ser usado para converter o valor da expresso , aps sua avaliao.
Por exemplo, supondo que f e frac so variveis do tipo float , ento o trecho de
cdigo a seguir:

f = 123.4567f;
frac = f - (int) f;

far com que a varivel frac contenha apenas o valor da parte fracionria da varivel f .

11.5 Tipos de dados definidos pelo programador


A linguagem C, como vimos at aqui, possui poucos tipos primitivos de dados. No entanto,
ela permite que um(a) programador(a) possa definir seus prprios tipos de dados, de acordo
com sua convenincia. Para tanto, devemos usar a palavra reservada typedef no seguinte
formato geral:

typedef tipo-primitivo tipo-novo;

onde tipo-primitivo o nome de um dos tipos primitivos de dados da linguagem C e


tipo-novo o nome do novo tipo de dados definido pelo(a) programador(a). Um exemplo
de definio e uso de um tipo apresentado no trecho de cdigo a seguir:
FACOM

UFMS

11.6 O PERADOR sizeof

109

typedef int Logic;


Logic primo, crescente;

Na primeira linha, typedef uma palavra reservada da linguagem C, int o tipo primitivo de dados para nmeros inteiros com sinal e Logic o nome do novo tipo de dados
criado pelo(a) programador(a). Na segunda linha, ocorre a declarao de duas variveis do
tipo Logic : a varivel primo e a varivel crescente . O nome Logic desse novo tipo
foi descrito com a primeira letra maiscula, mas isso no uma obrigatoriedade. O novo tipo
Logic criado a partir de typedef faz com que o compilador o adicione a sua lista de tipos conhecidos. Isso significa que podemos, a partir de ento, declarar variveis com esse tipo novo,
us-lo como operador conversor de tipo, entre outras coisas. Observe ainda que o compilador
trata Logic como um sinnimo para int . Dessa forma, as variveis primo e crescente
so, na verdade, variveis do tipo int .
Como principais vantagens podemos dizer que definies de tipos em programas permitem
fazer com que um cdigo torne-se mais compreensvel, mais fcil de modificar e mais fcil de
transportar de uma arquitetura de computadores para outra.

11.6 Operador sizeof


O operador unrio sizeof permite que se determine quanto de memria necessrio para
armazenar valores de um tipo qualquer. A expresso abaixo:

sizeof (nome-do-tipo)

determina um valor que um inteiro sem sinal representando o nmero de bytes necessrios
para armazenar um valor do tipo dado por nome-do-tipo .
Veja o programa 11.4.
Programa 11.4: Exemplo do uso do operador unrio sizeof.
#include <stdio.h>
int main(void)
{
printf("Caracteres: %lu\n", sizeof(char));
printf("Inteiros:\n");
printf(" short: %lu\n", sizeof(short int));
printf(" int: %lu\n", sizeof(int));
printf(" long int: %lu\n", sizeof(long int));
printf("Nmeros de ponto flutuante:\n");
printf(" float: %lu\n", sizeof(float));
printf(" double: %lu\n", sizeof(double));
printf(" long double: %lu\n", sizeof(long double));
return 0;
}

FACOM

UFMS

110

T IPOS

PRIMITIVOS DE DADOS

A sada do programa 11.4, executado em um computador com processador de 64 bits,


apresentada abaixo:

Caracteres:
1
Inteiros:
short:
2
int:
4
long int:
8
Nmeros de ponto flutuante:
float:
4
double:
8
long double: 16

11.7 Exerccios
Exerccios para treinar os conceitos aprendidos nesta aula. Faa muitos testes com suas
entradas e sadas.
11.1 Dadas n triplas compostas por um smbolo de operao aritmtica (+, , ou /) e dois
nmeros reais, calcule o resultado ao efetuar a operao indicada para os dois nmeros.
Faremos esse exerccio usando a estrutura condicional switch , que compara uma expresso com uma seqncia de valores. Essa estrutura tem o seguinte formato:

switch (expresso lgica) {


case constante:
.
.
.
instrues
.
.
.
break;
case constante:
.
.
.
instrues
.
.
.
break;
.
.
.
default:
.
.
.
instrues
.
.
.
break;
}

Veja o programa 11.5. Observe especialmente a leitura dos dados.


FACOM

UFMS

11.7 E XERCCIOS

111
Programa 11.5: Soluo do exerccio 11.1.

#include <stdio.h>
/* Recebe um operador aritmtico e dois operandos inteiros e
devolve o resultado da operao sobre os dois operandos */
int main(void)
{
char operador;
int n;
float op1, op2, result;
printf("Informe n: ");
scanf("%d", &n);
for ( ; n > 0; n--) {
printf("Informe a expresso (ex.: 5.3 * 3.1): ");
scanf("%f %c%f", &op1, &operador, &op2);
switch (operador) {
case +:
result = op1 + op2;
break;
case -:
result = op1 - op2;
break;
case *:
result = op1 * op2;
break;
case /:
result = op1 / op2;
break;
default:
break;
}
printf("%f %c %f = %f\n", op1, operador, op2, result);
}
return 0;
}

11.2 Um matemtico italiano da idade mdia conseguiu modelar o ritmo de crescimento da


populao de coelhos atravs de uma seqncia de nmeros naturais que passou a ser conhecida como seqncia de Fibonacci. A seqncia de Fibonacci descrita pela seguinte
frmula de recorrncia:

F1 = 1
F = 1
2
Fi = Fi1 + Fi2 , para i > 3.
Escreva um programa que dado n > 1 calcule e exiba Fn .

11.3 Os babilnios descreveram a mais de 4 mil anos um mtodo para calcular a raiz quadrada
de um nmero. Esse mtodo ficou posteriormente conhecido como mtodo de Newton.
Dado um nmero x, o mtodo parte de um chute inicial y para o valor da raiz quadrada
de x e sucessivamente encontra aproximaes desse valor calculando a mdia aritmtica
FACOM

UFMS

112

T IPOS

PRIMITIVOS DE DADOS

de y e de x/y. O exemplo a seguir mostra o mtodo em funcionamento para o clculo da


raiz quadrada de 3, com chute inicial 1:
x
3
3
3
3
3

y
1
2
1.75
1.732143
1.732051

x/y
3
1.5
1.714286
1.731959
1.732051

(y + x/y)/2
2
1.75
1.732143
1.732051
1.732051

Escreva um programa que receba um nmero real positivo x e um nmero real e calcule
a raiz quadrada de x usando o mtodo de Newton, at que o valor absoluto da diferena
entre dois valores consecutivos de y seja menor que . Mostre tambm na sada a quantidade de passos realizados para obteno da raiz de x.

FACOM

UFMS

AULA

12

V ETORES

Os tipos primitivos de dados na linguagem C se caracterizam pelo fato que seus valores no
podem ser decompostos. Isso significa que um valor armazenado em uma varivel de um tipo
primitivo nico e no faz parte de uma composio de valores organizada de alguma maneira.
Tipos primitivos de dados tambm so de bsicos ou elementares. Por outro lado, se os valores
de um tipo de dados podem ser decompostos ou subdivididos em valores mais simples, ento
o tipo de dados chamado de complexo, composto ou estruturado. A organizao desses
valores e as relaes estabelecidas entre eles determinam o que conhecemos como estrutura de
dados. Nesta aula iniciaremos o estudo sobre variveis compostas, partindo de uma varivel
conhecida como varivel composta homognea unidimensional ou simplesmente vetor.
Esta aula inspirada nas referncias [16, 15].

12.1 Motivao
Como um exemplo da necessidade do uso da estrutura de dados conhecida como vetor,
considere o seguinte problema:
Dadas cinco notas de uma prova dos(as) estudantes de uma disciplina, calcular a
mdia das notas da prova e a quantidade de estudantes que obtiveram nota maior
que a mdia e a quantidade de estudantes que obtiveram nota menor que a mdia.
Uma tentativa natural e uma idia inicial para solucionar esse problema consiste no uso
de uma estrutura de repetio para acumular o valor das cinco notas informadas e o clculo
posterior da mdia destas cinco notas. Esses passos resolvem o problema inicial do clculo da
mdia das provas dos estudantes. Mas e a computao das quantidades de alunos que obtiveram nota maior e menor que a mdia j computada? Observe que aps lidas as cinco notas
e processadas para o clculo da mdia em uma estrutura de repetio, a tarefa de encontrar
as quantidades de estudantes que obtiveram nota superior e inferior mdia impossvel, j
que as notas dos estudantes no esto mais disponveis na memria. Isto , a menos que o(a)
programador(a) pea ao usurio para informar as notas dos(as) estudantes novamente, no h
como computar essas quantidades.
Apesar disso, ainda podemos resolver o problema usando uma estrutura seqencial em
que todas as cinco notas informadas pelo usurio ficam armazenadas na memria e assim podemos posteriormente computar as quantidades solicitadas consultando estes valores. Veja o
programa 12.1.
113

114

V ETORES
Programa 12.1: Mdia de 5 notas.
#include <stdio.h>
/* Recebe 5 notas (nmeros reais), calcula a mdia desses valores e mostra
essa mdia e quantos dos valores so superiores e inferiores mdia */
int main(void)
{
int menor, maior;
float nota1, nota2, nota3, nota4, nota5, media;
printf("Informe as notas dos alunos: ");
scanf("%f%f%f%f%f", nota1, nota2, nota3, nota4, nota5);
media = (nota1 + nota2 + nota3 + nota4 + nota5) / 5;
printf("Media das provas: %f\n", media);
menor = 0;
if (nota1 < media)
menor = menor +
if (nota2 < media)
menor = menor +
if (nota3 < media)
menor = menor +
if (nota4 < media)
menor = menor +
if (nota5 < media)
menor = menor +
maior = 0;
if (nota1 > media)
maior = maior +
if (nota2 > media)
maior = maior +
if (nota3 > media)
maior = maior +
if (nota4 > media)
maior = maior +
if (nota5 > media)
maior = maior +

1;
1;
1;
1;
1;

1;
1;
1;
1;
1;

printf("Quantidade com nota inferior mdia: %d\n", menor);


printf("Quantidade com nota superior mdia: %d\n", maior);
return 0;
}

A soluo que apresentamos no programa 12.1 uma soluo correta para o problema.
Isto , dadas as cinco notas dos(as) estudantes em uma prova, o programa computa as sadas
que esperamos, ou seja, as quantidades de estudantes com nota inferior e superior mdia
da prova. No entanto, o que aconteceria se a sala de aula tivesse mais estudantes, como por
exemplo 100? Ou 1000 estudantes? Certamente, as estruturas seqencial e condicional no
seriam apropriadas para resolver esse problema, j que o(a) programador(a) teria de digitar
centenas ou milhares de linhas repetitivas, incorrendo inclusive na possibilidade de propagao de erros e na dificuldade de encontr-los. E assim como esse, outros problemas no podem
ser resolvidos sem uma extenso na maneira de armazenar e manipular as entradas de dados.
FACOM

UFMS

12.2 D EFINIO

115

12.2 Definio
Uma varivel composta homognea unidimensional, ou simplesmente um vetor, uma
estrutura de armazenamento de dados que se dispe de forma linear na memria e usada
para armazenar valores de um mesmo tipo. Um vetor ento uma lista de clulas na memria de tamanho fixo cujos contedos so do mesmo tipo primitivo. Cada uma dessas clulas
armazena um, e apenas um, valor. Cada clula do vetor tem um endereo ou ndice atravs
do qual podemos referenci-la. O termo varivel composta homognea unidimensional bem
explcito e significa que temos uma: (i) varivel, cujos valores podem ser modificados durante
a execuo de um programa; (ii) composta, j que h um conjunto de valores armazenado na
varivel; (iii) homognea, pois os valores armazenados na varivel composta so todos de um
mesmo tipo primitivo; e (iv) unidimensional, porque a estrutura de armazenamento na varivel
composta homognea linear. No entanto, pela facilidade, usamos o termo vetor com o mesmo
significado.
A forma geral de declarao de um vetor na linguagem C dada a seguir:
tipo identificador[dimenso];

onde:
tipo um tipo de dados conhecido ou definido pelo(a) programador(a);
identificador o nome do vetor, fornecido pelo(a) programador(a); e
dimenso a quantidade de clulas a serem disponibilizadas para uso no vetor.
Por exemplo, a declarao a seguir

float nota[100];

faz com que 100 clulas contguas de memria sejam reservadas, cada uma delas podendo
armazenar nmeros de ponto flutuante do tipo float . A referncia a cada uma dessas clulas
realizada pelo identificador do vetor nota e por um ndice. Na figura 12.1 mostramos o
efeito da declarao do vetor nota na memria de um computador.
0

98

99

memria
nota

Figura 12.1: Vetor com 100 posies.


Observe que, na linguagem C, a primeira clula de um vetor tem ndice 0, a segunda clula
tem ndice 1, a terceira tem ndice 2 e assim por diante. Para referenciar o contedo da clula 0
do vetor nota , devemos usar o identificador do vetor e o ndice 0, envolvido por colchetes, isto
, nota[0] . Assim, o uso de nota[35] em uma expresso qualquer referencia o trigsimo
FACOM

UFMS

116

V ETORES

sexto elemento do vetor nota . Podemos, tambm, usar uma varivel do tipo inteiro como
ndice de um vetor ou ainda uma expresso aritmtica do tipo inteiro. Por exemplo, nota[i]
acessa a (i + 1)-sima clula do vetor nota . Ou ainda, podemos fazer nota[2*i+j] para
acessar a posio de ndice 2i + j + 1 do vetor nota . O compilador da linguagem C no
verifica de antemo se os limites dos ndices de um vetor esto corretos, trabalho que deve ser
realizado pelo(a) programador(a).
Um erro comum, aparentemente inocente, mas que pode ter causas desastrosas, mostrado
no trecho de cdigo abaixo:

int A[10], i;
for (i = 1; i <= 10; i++)
A[i] = 0;

Alguns compiladores podem fazer com que a estrutura de repetio for acima seja executada infinitamente. Isso porque quando a varivel i atinge o valor 10 , o programa armazena
o valor 0 em A[10] . Observe, no entanto, que A[10] no existe e assim 0 armazenado
no compartimento de memria que sucede A[9] . Se a varivel i ocorre na memria logo
aps A[9] , como bem provvel, ento i receber o valor 0 fazendo com que o lao inicie
novamente.

12.3 Declarao com inicializao


Podemos atribuir valores iniciais a quaisquer variveis de qualquer tipo primitivo no momento de suas respectivas declaraes. At o momento, no havamos usado declaraes e
inicializaes em conjunto. O trecho de cdigo abaixo mostra declaraes e inicializaes simultneas de variveis de tipos primitivos:

char c = a;
int num, soma = 0;
float produto = 1.0, resultado;

No exemplo acima, as variveis c , soma e produto so inicializadas no momento da


declarao, enquanto que num e resultado so apenas declaradas.
Apesar de, por alguns motivos, no termos usado declaraes e inicializaes simultneas
com variveis de tipos primitivos, essa caracterstica da linguagem C muito favorvel quando
tratamos de variveis compostas. Do mesmo modo, podemos atribuir um valor inicial a um
vetor no momento de sua declarao. As regras para declarao e atribuio simultneas para
vetores so um pouco mais complicadas, mas veremos as mais simples no momento. A forma
mais comum de se fazer a inicializao de um vetor atravs de uma lista de expresses constantes envolvidas por chaves e separadas por vrgulas, como no exemplo abaixo:

int A[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};


FACOM

UFMS

12.4 E XEMPLO

COM VETORES

117

Se o inicializador tem menos elementos que a capacidade do vetor, os elementos restantes


so inicializados com o valor 0 (zero), como abaixo:

int A[10] = {1, 2, 3, 4};

O resultado na memria equivalente a termos realizado a inicializao abaixo:

int A[10] = {1, 2, 3, 4, 0, 0, 0, 0, 0, 0};

No entanto, no permitido que o inicializador tenha mais elementos que a quantidade de


compartimentos do vetor.
Podemos ento facilmente inicializar um vetor todo com zeros da seguinte maneira:

int A[10] = {0};

Se um inicializador est presente em conjunto com a declarao de um vetor, ento o seu


tamanho pode ser omitido, como mostrado a seguir:

int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

O compilador ento interpreta que o tamanho do vetor A determinado pela quantidade


de elementos do seu inicializador. Isso significa que, aps a execuo da linha do exemplo
de cdigo acima, o vetor A tem 10 compartimentos de memria, do mesmo modo como se
tivssemos especificado isso explicitamente, como no primeiro exemplo.

12.4 Exemplo com vetores


Vamos agora resolver o problema da seo 12.1 do clculo das mdias individuais de estudantes e da verificao da quantidade de estudantes com mdia inferior e tambm superior
mdia da classe. Solucionaremos esse problema construindo um programa que usa vetores e veremos como nossa soluo se mostra muito mais simples, mais eficiente e facilmente
extensvel para qualquer quantidade de estudantes que se queira. Vejamos o programa 12.2.
Observe que o programa 12.2 mais conciso e de mais fcil compreenso que o programa 12.1. O programa tambm mais facilmente extensvel, no sentido que muito poucas
modificaes so necessrias para que esse programa possa solucionar problemas semelhantes com outras quantidades de estudantes. Isto , se a turma tem 5, 10 ou 100 estudantes, ou
ainda um nmero desconhecido n que ser informado pelo usurio durante a execuo do programa, uma pequena quantidade de esforo ser necessria para alterao de poucas linhas do
programa.
FACOM

UFMS

118

V ETORES
Programa 12.2: Soluo do problema proposto na seo 12.1 usando um vetor.
#include <stdio.h>
/* Recebe 5 notas (nmeros reais), calcula a mdia desses valores e mostra
essa mdia e quantos dos valores so superiores e inferiores mdia */
int main(void)
{
int i, menor, maior;
float nota[5], soma, media;
for (i = 0; i < 5; i++) {
printf("Informe a nota do(a) estudante %d: ", i+1);
scanf("%f", &nota[i]);
}
soma = 0.0;
for (i = 0; i < 5; i++)
soma = soma + nota[i];
media = soma / 5;
menor = 0;
maior = 0;
for (i = 0; i < 5; i++) {
if (nota[i] < media)
menor++;
if (nota[i] > media)
maior++;
}
printf("\nMedia das provas: %2.2f\n", media);
printf("Quantidade de alunos com nota inferior mdia: %d\n", menor);
printf("Quantidade de alunos com nota superior mdia: %d\n", maior);
return 0;
}

12.5 Macros para constantes


Em geral, quando um programa contm constantes, uma boa idia dar nomes a essas
constantes. Podemos atribuir um nome ou identificador a uma constante usando a definio
de uma macro. Uma macro definida atravs da diretiva de pr-processador #define e tem
o seguinte formato geral:

#define identificador constante

onde #define uma diretiva do pr-processador da linguagem C e identificador um


nome associado constante que vem logo a seguir. Observe que, por ser uma diretiva do
pr-processador, a linha contendo uma definio de uma macro no finalizada por ; . Em geral, a definio de uma macro ocorre logo no incio do programa, aps as diretivas #include
para incluso de cabealhos de bibliotecas de funes. Alm disso, o identificador de uma
FACOM

UFMS

12.5 M ACROS

PARA CONSTANTES

119

macro , preferencial mas no obrigatoriamente, descrito em letras maisculas. Exemplos de


macros so apresentados a seguir:

#define
#define
#define
#define

CARAC
NUMERADOR
MIN
TAXA

a
4
-10000
0.01567

Quando um programa compilado, o pr-processador troca cada macro definida no cdigo


pelo valor que ela representa. Depois disso, um segundo passo de compilao executado. O
programa que calcula a rea do crculo visto em uma aula prtica pode ser reescrito com o uso
de uma macro, como podemos ver no programa 12.3, onde uma macro com identificador PI
definida e usada no cdigo.

Programa 12.3: Clculo da rea do crculo.


#include <stdio.h>
#define PI 3.141592f
/* Recebe um raio de um crculo (real) e mostra a rea desse crculo */
int main(void)
{
double raio, area;
printf("Digite o valor do raio: ");
scanf("%lf", &raio);
area = PI * raio * raio;
printf("A rea do crculo de raio %f %f\n", raio, area);
return 0;
}

O uso de macros com vetores bastante til porque, como j vimos, um vetor faz alocao esttica da memria, o que significa que em sua declarao ocorre uma reserva prvia
de um nmero fixo de compartimentos de memria. Por ser uma alocao esttica, no h
possibilidade de aumento ou diminuio dessa quantidade aps a execuo da linha de cdigo contendo a declarao do vetor. O programa 12.2 pode ser ainda modificado como no
programa 12.4 com a incluso de uma macro que indica a quantidade de notas a serem processadas.
A macro MAX usada quatro vezes no programa 12.4: na declarao do vetor nota , nas
expresses relacionais das duas estruturas de repetio for e no clculo da mdia. A vantagem de se usar uma macro que, caso seja necessrio modificar a quantidade de notas do
programa por novas exigncias do usurio, isso pode ser feito rpida e facilmente em uma
nica linha do cdigo, onde ocorre a definio da macro.
FACOM

UFMS

120

V ETORES

Programa 12.4: Soluo do problema proposto na seo 12.1 usando uma macro e um vetor.
#include <stdio.h>
#define MAX 5
/* Recebe 5 notas (nmeros reais), calcula a mdia desses valores e mostra
essa mdia e quantos dos valores so superiores e inferiores mdia */
int main(void)
{
int i, menor, maior;
float nota[MAX], soma, media;
for (i = 0; i < MAX; i++) {
printf("Informe a nota do(a) estudante %d: ", i+1);
scanf("%f", &nota[i]);
}
soma = 0.0;
for (i = 0; i < MAX; i++)
soma = soma + nota[i];
media = soma / MAX;
menor = 0;
maior = 0;
for (i = 0; i < MAX; i++) {
if (nota[i] < media)
menor++;
if (nota[i] > media)
maior++;
}
printf("\nMedia das provas: %2.2f\n", media);
printf("Quantidade com nota inferior mdia: %d\n", menor);
printf("Quantidade com nota superior mdia: %d\n", maior);
return 0;
}

Exerccios
12.1 Dada uma seqncia de n nmeros inteiros, com 1 6 n 6 100, imprimi-la em ordem
inversa de leitura.
12.2 Uma prova consta de 30 questes, cada uma com cinco alternativas identificadas pelas
letras A, B, C, D e E. Dado o carto gabarito da prova e o carto de respostas de n estudantes, com 1 6 n 6 100, computar o nmero de acertos de cada um dos estudantes.
12.3 Tentando descobrir se um dado era viciado, um dono de cassino o lanou n vezes. Dados
os n resultados dos lanamentos, determinar o nmero de ocorrncias de cada face.
12.4 Um jogador viciado de cassino deseja fazer um levantamento estatstico simples sobre
uma roleta. Para isso, ele fez n lanamentos nesta roleta. Sabendo que uma roleta contm
FACOM

UFMS

12.5 M ACROS

121

PARA CONSTANTES

Programa 12.5: Soluo do exerccio 12.1.


#include <stdio.h>
#define MAX 100
/* Recebe um nmero inteiro n e mais n nmeros inteiros
e escreve esses nmeros na ordem inversa da de leitura */
int main(void)
{
int i, n, A[MAX];
printf("Informe n: ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("Informe o nmero %d: ", i+1);
scanf("%d", &A[i]);
}
printf("Nmeros na ordem inversa da leitura:\n");
for (i = n-1; i >= 0; i--)
printf("%d ", A[i]);
printf("\n");
return 0;
}

37 nmeros (de 0 a 36), calcular a freqncia de cada nmero desta roleta nos n lanamentos realizados.
12.5 Dados dois vetores x e y, ambos com n elementos, 1 6 n 6 100, determinar o produto
escalar desses vetores.
12.6 Calcule o valor do polinmio p(x) = a0 + a1 x + . . . + an xn em k pontos distintos. So
dados os valores de n (grau do polinmio), com 1 6 n 6 100, de a0 , a1 , . . . an (coeficientes
reais do polinmio), de k e dos pontos x1 , x2 , . . . , xk .
12.7 Dado o polinmio p(x) = a0 + a1 x + . . . an xn , isto , os valores de n e de a0 , a1 , . . . , an ,
com 1 6 n 6 100 determine os coeficientes reais da primeira derivada de p(x).
12.8 Dados dois polinmios reais
p(x) = a0 + a1 x + . . . + an xn

q(x) = b0 + b1 x + . . . + bm xm

determinar o produto desses dois polinmios. Suponha que 1 6 m, n 6 100.


12.9 Dadas duas seqncias com n nmeros inteiros entre 0 e 9, interpretadas como dois nmeros inteiros de n algarismos, 1 6 n 6 100, calcular a seqncia de nmeros que representa a soma dos dois inteiros.
Exemplo:
n = 8,
1a seqncia
2a seqncia

FACOM

+
1

8
3
1

2
3
6

4
7
1

3
5
8

4
2
6

2
3
5

5
3
8

1
7
8
UFMS

122

V ETORES

12.10 Dados dois nmeros naturais m e n, com 1 6 m, n 6 100, e duas seqncias ordenadas
com m e n nmeros inteiros, obter uma nica seqncia ordenada contendo todos os
elementos das seqncias originais sem repetio.
12.11 Dada uma seqncia de n nmeros inteiros, com 1 6 n 6 100, imprimi-la em ordem
crescente de seus valores.
12.12 Dizemos que uma seqncia de n elementos, com n par, balanceada se as seguintes
somas so todas iguais:
a soma do maior elemento com o menor elemento;
a soma do segundo maior elemento com o segundo menor elemento;
a soma do terceiro maior elemento com o terceiro menor elemento;
e assim por diante . . .
Exemplo:
2 12 3 6 16 15 uma seqncia balanceada, pois 16 + 2 = 15 + 3 = 12 + 6.
Dados n (n par e 0 6 n 6 100) e uma seqncia de n nmeros inteiros, verificar se essa
seqncia balanceada.
12.13 Dada uma seqncia x1 , x2 , . . . , xk de nmeros inteiros, com 1 6 k 6 100, verifique se
existem dois segmentos consecutivos iguais nesta seqncia, isto , se existem i e m tais
que
xi , xi+1 , . . . , xi+m1 = xi+m , xi+m+1 , . . . , xi+2m1 .
Imprima, caso existam, os valores de i e m.
Exemplo:
Na seqncia 7, 9, 5, 4, 5, 4, 8, 6 existem i = 3 e m = 2.
12.14 Dadas duas seqncias de caracteres (uma contendo uma frase e outra contendo uma
palavra), determine o nmero de vezes que a palavra ocorre na frase. Considere que
essas seqncias tm no mximo 100 caracteres cada uma.
Exemplo:
Para a palavra ANA e a frase:
ANA E MARIANA GOSTAM DE BANANA.
Temos que a palavra ocorre 4 vezes na frase.
12.15 So dadas as coordenadas reais x e y de um ponto, um nmero natural n e as coordenadas
reais de n pontos, com 1 6 n 6 100. Deseja-se calcular e imprimir sem repetio os
raios das circunferncias centradas no ponto (x, y) que passem por pelo menos um dos n
pontos dados.
Exemplo:

(x, y) = (1.0, 1.0)


n=5

Pontos: (1.0, 1.2), (1.5, 2.0), (0.0, 2.0), (0.0, 0.5), (4.0, 2.0)
Nesse caso h trs circunferncias de raios 1.12, 2.01 e 3.162.

Observaes:
FACOM

UFMS

12.5 M ACROS

123

PARA CONSTANTES

(a) A distncia entre os pontos (a, b) e (c, d)

p
(a c)2 + (b d)2 .

(b) Dois pontos esto na mesma circunferncia se esto mesma distncia do centro.

FACOM

UFMS

124

FACOM

V ETORES

UFMS

AULA

C ADEIAS

13

DE CARACTERES

Veremos nesta aula uma estrutura que possui tratamento especial na linguagem C: a cadeia
de caracteres. Esta estrutura similar a um vetor de caracteres, diferenciando-se apenas por
conter um caracter especial no final, aps o ltimo caracter vlido. Essa caracterstica evita, em
muitos casos, que tenhamos de manter uma varivel que contenha o comprimento do vetor
para saber o nmero de caracteres contidos nele. Outras caractersticas e diferenas importantes sero vistas a seguir.
Diversas funes que manipulam cadeias de caracteres esto disponveis na biblioteca
string.

Esta aula inspirada nas referncias [15, 16].

13.1 Literais
Vimos tomando contato com cadeias de caracteres desde quando escrevemos nosso primeiro programa na linguagem C. Por exemplo, na sentena abaixo:

printf("Programar bacana!\n");

o nico argumento passado para a funo printf a cadeia de caracteres (de formatao)
"Programar bacana!\n" . As aspas duplas so usadas para delimitar uma constante do
tipo cadeia de caracteres, que pode conter qualquer combinao de letras, nmeros ou caracteres especiais que no sejam as aspas duplas. Mesmo assim, possvel inserir as aspas duplas
no interior de uma constante cadeia de caracteres, inserindo a seqncia \" nessa cadeia. Na
linguagem C, uma constante do tipo cadeia de caracter chamada de literal.
Quando estudamos o tipo de dados char , aprendemos que uma varivel deste tipo pode
conter apenas um nico caracter. Para atribuir um caracter a uma varivel, o caracter deve ser
envolvido por aspas simples. Dessa forma, o trecho de cdigo a seguir:

char sinal;
sinal = +;

125

126

C ADEIAS

DE CARACTERES

tem o efeito de atribuir o caractere cuja constante + para a varivel sinal . Alm disso,
aprendemos que existe uma distino entre as aspas simples e as aspas duplas, sendo que no
primeiro caso elas servem para definir constantes do tipo caracter e no segundo para definir
constantes do tipo cadeia de caracteres. Assim, o seguinte trecho de cdigo:

char sinal;
sinal = "+";

no est correto, j que que a varivel sinal foi declarada do tipo char , podendo conter um
nico caracter. Lembre-se que na linguagem C as aspas simples e as aspas duplas so usadas
para definir dois tipos de constantes diferentes.
Usamos literais especialmente quando chamamos as funes printf e scanf em um
programa, ou seja, quando descrevemos cadeias de caracteres de formatao. Essencialmente,
a linguagem C trata as literais como cadeias de caracteres. Quando o compilador da linguagem
C encontra uma literal com n caracteres em um programa, ele reserva n + 1 compartimentos de
memria para armazenar a cadeia de caracteres correspondente. Essa rea na memria conter
os caracteres da cadeia mais um caractere extra, o caractere nulo, que registra o final da cadeia.
O caractere nulo um byte cujos bits so todos 0 (zeros) e representado pela seqncia \0 .
importante destacar a diferena entre o caractere nulo e o caractere zero: o primeiro um
caractere no-imprimvel, tem valor decimal 0 e constante \0 ; o segundo um caractere
imprimvel, tem valor 48, smbolo grfico 0 e constante 0 .
A literal "abc" armazenada como um vetor de quatro caracteres na memria, como
mostra a figura 13.1.
a

\0

Figura 13.1: Armazenamento de uma literal na memria.


Por outro lado, uma literal tambm pode ser vazia. A literal "" uma literal vazia, representada na memria como na figura 13.2.
\0

Figura 13.2: Literal vazia na memria.

13.2 Vetores de caracteres


Se queremos trabalhar com variveis que comportam mais que um nico caracter, temos de
trabalhar com vetores de caracteres. No exerccio 13.6, devemos definir dois vetores palavra
e frase do tipo caracter, da seguinte forma:
FACOM

UFMS

13.3 C ADEIAS

DE CARACTERES

127

char palavra[MAX+1], frase[MAX+1];

Para ler, por exemplo, o contedo da varivel palavra , produzimos o seguinte trecho de
programa:

printf("Informe a palavra: ");


i = 0;
do {
scanf("%c", &palavra[i]);
i++;
} while (palavra[i-1] != \n);
m = i-1;

Para imprimir o contedo dessa mesma varivel palavra , devemos escrever um trecho de
programa da seguinte forma:

printf("Palavra: ");
for (i = 0; i < m; i++)
printf("%c", palavra[i]);
printf("\n");

Note que sempre necessitamos de uma varivel adicional para controlar o comprimento
de um vetor de caracteres quando da sua leitura. A varivel m faz esse papel no primeiro
trecho de programa acima. Alm disso, tanto para leitura como para escrita de um vetor de
caracteres, precisamos de uma estrutura de repetio para processar os caracteres um a um.
Com as cadeias de caracteres, evitamos esta sobrecarga de trabalho para o programador, como
veremos daqui por diante.

13.3 Cadeias de caracteres


Algumas linguagens de programao de alto nvel oferecem ao() programador(a) um tipo
de dados especial para que variveis do tipo cadeia de caracteres possam ser declaradas. Por
outro lado, na linguagem C no h um tipo de dados como esse e, assim, qualquer vetor de
caracteres pode ser usado para armazenar uma cadeia de caracteres. A diferena, nesse caso,
que uma cadeia de caracteres sempre terminada por um caractere nulo. Uma vantagem dessa
estratgia que no h necessidade de se manter o comprimento da cadeia de caracteres associado a ela. Por outro lado, esse mesmo comprimento, se necessrio, s pode ser encontrado
atravs de uma varredura no vetor.
Suponha que necessitamos de uma varivel capaz de armazenar uma cadeia de caracteres
de at 50 caracteres. Como a cadeia de caracteres necessitar de um caractere nulo no final,
ento a cadeia de caracteres tm de ser declarada com 51 compartimentos para armazenar
valores do tipo char , como mostrado a seguir:
FACOM

UFMS

128

C ADEIAS

DE CARACTERES

#define MAX 50
char cadeia[MAX+1];

Na declarao de uma varivel que pode armazenar uma cadeia de caracteres, sempre devemos reservar um compartimento a mais para que o caractere nulo possa ser armazenado.
Como diversas funes da linguagem C supem que as cadeias de caracteres so terminadas
com o caractere nulo, se isso no ocorre em algum caso, o comportamento do programa passa
a ser imprevisvel.
A declarao de um vetor de caracteres com dimenso MAX+1 no quer dizer que ele sempre conter uma cadeia de caracteres com MAX caracteres. O comprimento de uma cadeia de
caracteres depende da posio do caractere nulo na cadeia, no do comprimento do vetor onde
a cadeia est armazenada.
Como em qualquer vetor, uma cadeia de caracteres tambm pode ser declarada e inicializada simultaneamente. Por exemplo,

char cidade[13] = "Campo Grande";

faz com que o compilador insira seqencialmente os caracteres da cadeia de caracteres


"Campo Grande" no vetor cidade e ento adicione o caractere nulo ao final da cadeia. Apesar de "Campo Grande" parecer uma literal, na realidade, a linguagem C a enxerga como uma
abreviao para um inicializador de um vetor, que poderia ter sido escrito equivalentemente
como abaixo:
char cidade[13] = {C,a,m,p,o, ,G,r,a,n,d,e,\0};

Se um inicializador tem menor comprimento que o comprimento do vetor, o compilador


preencher os caracteres restantes do vetor com o caractere nulo. Se, por outro lado, o inicializador tem maior comprimento que a capacidade de armazenamento do vetor associado, os
caracteres iniciais do inicializador sero armazenados no vetor, sem que o ltimo deles seja o
caractere nulo, impedindo assim que essa varivel seja usada como uma legtima cadeia de
caracteres.
Vejamos agora o programa 13.1 que determina o comprimento de uma varivel que uma
cadeia de caracteres. Qual ser a sada deste programa?
H uma forma de ler e escrever cadeias de caracteres na linguagem C que facilita o trabalho
de um(a) programador(a), evitando que sempre lance mo de uma estrutura de repetio para
realizar uma dessas duas tarefas. O especificador de converso %s no interior de uma cadeia
de caracteres de formatao de entrada pode ser usado para mostrar um vetor de caracteres
que terminado por um caracter nulo, isto , uma cadeia de caracteres. Assim se palavra
um vetor de caracteres terminado com o caractere nulo, a chamada da funo abaixo:

printf("%s\n", palavra);

FACOM

UFMS

13.3 C ADEIAS

DE CARACTERES

129

Programa 13.1: Determina o comprimento de uma cadeia de caracteres.


#include <stdio.h>
int main(void)
{
char palavra[10] = "Ola!";
int n;
n = 0;
while (palavra[n] != \0)
n++;
printf("O comprimento da palavra %d\n", n);
return 0;
}

pode ser usada para mostrar o contedo completo da cadeia de caracteres palavra na sada
padro. Quando a funo printf encontra o especificador de converso %s , supe que o
argumento correspondente uma cadeia de caracteres, isto , um vetor de caracteres terminado
por um caractere nulo.
Podemos tambm usar a mesma cadeia de caracteres de formatao "%s" para leitura de
uma cadeia de caracteres. A funo scanf pode ser usada com o especificador de converso
%s para ler uma cadeia de caracteres at que a leitura de um branco seja realizada. Assim, a
chamada da funo scanf abaixo:

scanf("%s", palavra);

tem o efeito de ler uma cadeia de caracteres digitada pelo usurio e de armazen-la no vetor
de caracteres palavra .
muito importante ressaltar que, ao contrrio das chamadas anteriores da funo scanf ,
no caso de leitura de cadeias de caracteres, o smbolo & no adicionado como prefixo do
identificador da varivel. Veremos o porqu disto quando estudarmos apontadores.
Se na execuo da funo scanf anterior um(a) usurio(a) digita os caracteres abcdefg , a
cadeia de caracteres "abcdefg" armazenada no vetor palavra . Se, diferentemente, um(a)
usurio(a) digita os caracteres Campo Grande , ento apenas a cadeia de caracteres "Campo"
armazenada no vetor palavra , devido ao branco ( ). Os caracteres restantes da cadeia digitada ficaro disponveis no buffer de entrada at que uma prxima chamada funo scanf
seja realizada.
Para evitar os brancos na leitura de uma cadeia de caracteres, usamos o especificador de
converso %[...] , que tambm usado na leitura de cadeias de caracteres, delimitando, dentro dos colchetes, quais so os caracteres permitidos em uma leitura. Qualquer outro caractere
diferente dos especificados dentro dos colchetes finalizam a leitura. Alm disso, podemos inverter essas permisses, indicando o caractere ^ como o primeiro caractere dentro dos colchetes. Por exemplo,
FACOM

UFMS

130

C ADEIAS

DE CARACTERES

scanf("%[^\n]", palavra);

realiza a leitura de uma cadeia de caracteres, armazenando seu contedo no vetor de caracteres palavra . O caracter que finaliza a leitura o \n . Qualquer outro caracter ser lido e
armazenado no vetor palavra .
muito importante destacar que a funo scanf termina automaticamente uma cadeia de
caracteres que lida com o especificador de converso "%s" ou "%[...]" com um caracter
nulo, fazendo assim que o vetor de caracteres se torne de fato uma cadeia de caracteres aps
sua leitura.
Veja um exemplo simples do uso dos conceitos de entrada e sada de cadeias de caracteres
no programa 13.2.
Programa 13.2: Entrada e sada de uma cadeia de caracteres.
#include <stdio.h>
#define MAX 20
/* Recebe uma palavra com at MAX caracteres e imprime seu comprimento */
int main(void)
{
char palavra[MAX];
int n;
printf("Informe uma palavra (com at %d caracteres): ", MAX);
scanf("%s", palavra);
n = 0;
while (palavra[n] != \0)
n++;
printf("A palavra [%s] tem %d caracteres\n", palavra, n);
return 0;
}

Exerccios
13.1 Dada uma frase com no mximo 100 caracteres, determinar quantos caracteres espao a
frase contm.
13.2 Dada uma cadeia de caracteres com no mximo 100 caracteres, contar a quantidade de
letras minsculas, letras maisculas, dgitos, espaos e smbolos de pontuao que essa
cadeia possui.
13.3 Dadas duas cadeias de caracteres cadeia1 e cadeia2 , concatenar cadeia2 no final
de cadeia1 , colocando o caracter nulo no final da cadeia resultante. A cadeia resultante
a ser mostrada deve estar armazenada em cadeia1 . Suponha que as cadeias sejam
informadas com no mximo 100 caracteres.
FACOM

UFMS

13.3 C ADEIAS

DE CARACTERES

131

Programa 13.3: Soluo do exerccio 13.1.


#include <stdio.h>
#define MAX 100
/* Dada uma frase, determina quantos espaos ela possui */
int main(void)
{
char frase[MAX+1];
int esp, i;
printf("Informe uma frase: ");
scanf("%[^\n]", frase);
esp = 0;
for (i = 0; frase[i] != \0; i++)
if (frase[i] == )
esp++;
printf("Frase tem %d espaos\n", esp);
return 0;
}

13.4 Dada uma cadeia de caracter cadeia com no mximo 100 caracteres e um caractere c ,
buscar a primeira ocorrncia de c em cadeia . Se c ocorre em cadeia , mostrar a
posio da primeira ocorrncia; caso contrrio, mostrar o valor -1 .
13.5 Dadas duas cadeias de caracteres cadeia1 e cadeia2 , cada uma com no mximo 100
caracteres, compar-las e devolver um valor menor que zero se cadeia1 lexicograficamente menor que cadeia2 , o valor zero se cadeia1 igual ou tem o mesmo contedo
que cadeia2 , ou um valor maior que zero se cadeia1 lexicograficamente maior que
cadeia2 .
13.6 Dadas duas seqncias de caracteres (uma contendo uma frase e outra contendo uma
palavra), determine o nmero de vezes que a palavra ocorre na frase. Considere que
essas seqncias tm no mximo 100 caracteres cada uma.
Exemplo:
Para a palavra ANA e a frase:
ANA E MARIANA GOSTAM DE BANANA.
Temos que a palavra ocorre 4 vezes na frase.

FACOM

UFMS

132

FACOM

C ADEIAS

DE CARACTERES

UFMS

AULA

14

M ATRIZES

Na aula 12, tivemos contato com vetores ou variveis compostas homogneas unidimensionais. No entanto, uma varivel composta homognea pode ter qualquer nmero de dimenses. A partir desta aula, aprenderemos a trabalhar com as estruturas denominadas de
matrizes ou variveis compostas homogneas bidimensionais. Do mesmo modo como vimos
com os vetores, as matrizes so variveis porque podem ter os valores de suas clulas alterados
durante a execuo do algoritmo/programa, compostas porque representam a composio de
um conjunto de valores indivisveis, homogneas porque esses valores so de um mesmo tipo
de dados e bidimensionais porque, ao contrrio dos vetores que so lineares ou tm uma nica
dimenso, estas estruturas tm duas dimenses. A extenso de variveis compostas homogneas para trs ou mais dimenses simples e imediata, como veremos posteriormente. Nesta
aula, que tem como referncias os livros [15, 16], aprenderemos a declarar matrizes, a declarar
e inicializar simultaneamente as matrizes e tambm a usar matrizes para solucionar problemas.

14.1 Definio, declarao e uso


Em matemtica, uma matriz uma tabela ou um quadro contendo m linhas e n colunas e
usada, entre outros usos, para a resoluo de sistemas de equaes lineares e transformaes
lineares. Uma matriz com m linhas e n colunas chamada de uma matriz m por n e denotase m n. Os valores m e n so chamados de dimenses, tipo ou ordem da matriz. Um
elemento de uma matriz A que est na linha i e na coluna j chamado de elemento i, j ou
(i, j)-simo elemento de A. Este elemento denotado por Ai,j ou A(i, j). Uma matriz onde
uma de suas dimenses igual a 1 geralmente chamada de vetor. Uma matriz de dimenses
1 n, contendo uma linha e n colunas, chamada de vetor linha ou matriz linha, e uma matriz
de dimenses m 1, contendo m linhas e uma coluna, chamada de vetor coluna ou matriz
coluna.
Na linguagem C, as matrizes so declaradas similarmente aos vetores. Ou seja, isso significa que um tipo de dados usado para a declarao, em seguida um identificador ou nome
da varivel matriz e, ainda, dois nmeros inteiros envolvidos individualmente por colchetes,
indicando as dimenses da matriz, isto , seu nmero de linhas e seu nmero de colunas.
Na linguagem C, a forma geral da declarao de uma matriz dada a seguir:

tipo identificador[dimenso1][dimenso2];

133

134

M ATRIZES

onde tipo um dos tipos de dados da linguagem C ou um tipo definido pelo(a) programador(a), identificador o nome da varivel matriz fornecido pelo(a) programador(a) e
dimenso1 e dimenso2 determinam a quantidade de linhas e colunas, respectivamente, a
serem disponibilizadas para uso na matriz. Por exemplo, a declarao a seguir:

int A[20][30];

faz com que 600 clulas de memria sejam reservadas, cada uma delas podendo armazenar
valores do tipo int . A referncia a cada uma dessas clulas realizada pelo identificador da
matriz A e por dois ndices, o primeiro que determina a linha e o segundo que determina a
coluna da matriz. Veja a figura 14.1.
0

28

29

0
1
2

18
19

Figura 14.1: Matriz A com 20 linhas e 30 colunas.


Na linguagem C, a primeira linha de uma matriz tem ndice 0, a segunda linha tem ndice
1, e assim por diante. Do mesmo modo, a primeira coluna da matriz tem ndice 0, a segunda
tem ndice 1 e assim por diante. Para referenciar o valor da clula da linha 0 e da coluna 3 da
matriz A , devemos usar o identificador da varivel e os ndices 0 e 3 envolvidos por colchetes,
ou seja, A[0][3] .
Apesar de visualizarmos uma matriz na forma de uma tabela bidimensional, essa no a
forma de armazenamento dessa varivel na memria. A linguagem C armazena uma matriz
na memria linha a linha, como mostrado na figura 14.2 para a matriz A .
linha 0

memria

A[0][0]

linha 1

A[0][29] A[1][0]

linha 19

A[1][29]

A[19][0]

A[19][29]

Figura 14.2: Matriz A com 20 linhas e 30 colunas disposta na memria.


FACOM

UFMS

14.2 D ECLARAO

E INICIALIZAO SIMULTNEAS

135

14.2 Declarao e inicializao simultneas


Da mesma forma como com os vetores, uma matriz pode ser inicializada no momento de
sua declarao. Na verdade, variveis compostas de qualquer dimenso podem ser inicializadas seguindo as mesmas regras. Para uma matriz, a declarao e inicializao simultneas
deve ser realizada agrupando os inicializadores de uma dimenso como abaixo:

int A[4][7] = { {0,


{1,
{2,
{3,

1,
2,
2,
7,

1,
0,
2,
9,

0,
1,
1,
6,

0,
5,
1,
2,

0,
7,
2,
1,

2},
1},
1},
0} };

Na declarao e inicializao acima, cada inicializador fornece valores para uma linha da matriz. A linguagem C possui algumas pequenas regras para declarar e inicializar matrizes ou
variveis compostas homogneas de qualquer dimenso:
se um inicializador no grande o suficiente para inicializar um varivel composta homognea, ento o restante dos elementos sero inicializados com 0 (zero). Por exemplo,

int A[4][7] = { {0, 1, 1, 0, 0, 0, 2},


{3, 7, 9, 6, 2, 1, 0} };

inicializa as duas primeiras linhas da matriz A . As duas ltimas linhas sero inicializadas com 0 (zero);
se um inicializador mais interno no longo o suficiente para inicializar uma linha, ento
o restante dos elementos na linha inicializado com 0 (zero). Por exemplo,

int A[4][7] = { {0,


{1,
{2,
{3,

1,
2,
2,
7,

1},
0, 1, 5, 7, 1},
2, 1, 1, 2},
9, 6, 2, 1, 0} };

as chaves internas, que determinam as inicializaes das linhas, podem ser omitidas.
Neste caso, uma vez que o compilador tenha lido elementos suficientes para preencher
uma linha, ele o faz e inicia o preenchimento da prxima linha. Por exemplo,

int A[4][7] = {0,


1,
2,
3,

FACOM

1,
2,
2,
7,

1,
0,
2,
9,

0,
1,
1,
6,

0,
5,
1,
2,

0,
7,
2,
1,

2,
1,
1,
0};

UFMS

136

M ATRIZES

14.3 Exemplo
Apresentamos a seguir o programa 14.1, que resolve o seguinte problema:
Dada uma matriz real B, de 5 linhas e 10 colunas, calcule o somatrio dos elementos
da oitava coluna e que calcule o somatrio da terceira linha.
Programa 14.1: Exemplo de um programa que usa uma matriz.
#include <stdio.h>
/* Dada uma matriz de nmeros reais de dimenso 5 x 10, mostra
a soma da sua oitava coluna e da sua terceira linha */
int main(void)
{
int i, j;
float soma_c8, soma_l3, B[5][10];
for (i = 0; i < 5; i++)
for (j = 0; j < 10; j++) {
printf("Informe B[%d][%d]: ", i, j);
scanf("%f", B[i][j]);
}
soma_c8 = 0.0;
for (i = 0; i < 4; i++)
soma_c8 = soma_c8 + B[i][7];
printf("Valor da soma da oitava coluna %f\n", soma_c8);
soma_l3 = 0.0;
for (j = 0; j < 10; j++)
soma_l3 = soma_l3 + B[2][j];
printf("Valor da soma da terceira linha %f\n", soma_l3);
return 0;
}

Exerccios
14.1 Dadas duas matrizes de nmeros inteiros A e B, de dimenses mn, com 1 6 m, n 6 100,
fazer um programa que calcule a matriz Cmn = A + B.
14.2 Faa um programa que, dada uma matriz de nmeros reais Amn , determine At . Suponha que 1 6 m, n 6 100.
14.3 Dada uma matriz de nmeros reais A com m linhas e n colunas, 1 6 m, n 6 100, e um
vetor de nmeros reais v com n elementos, determinar o produto de A por v.
14.4 Um vetor de nmeros reais x com n elementos apresentado como resultado de um
sistema de equaes lineares Ax = b, cujos coeficientes so representados em uma matriz
de nmeros reais Amn e o lados direitos das equaes em um vetor de nmeros reais
b de m elementos. Dados A, x e b, verificar se o vetor x realmente soluo do sistema
Ax = b, supondo que 1 6 m, n 6 100.
FACOM

UFMS

14.3 E XEMPLO

137
Programa 14.2: Soluo do exerccio 14.1.

#include <stdio.h>
#define MAX 100
/* Dadas duas matrizes de nmeros inteiros de dimenses m n,
calcula a matriz soma dessas matrizes, mostrando-a na sada */
int main(void)
{
int m, n, i, j, A[MAX][MAX], B[MAX][MAX], C[MAX][MAX];
printf("Informe as dimenses (m, n) das matrizes: ");
scanf("%d%d", &m, &n);
for (i = 0; i < m; i++)
for (j = 0; j < n; j++) {
printf("Informe A[%2d][%2d]: ", i, j);
scanf("%d", &A[i][j]);
}
for (i = 0; i < m; i++)
for (j = 0; j < n; j++) {
printf("Informe B[%2d][%2d]: ", i, j);
scanf("%d", &B[i][j]);
}
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
C[i][j] = A[i][j] + B[i][j];
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++)
printf("%2d ", C[i][j]);
printf("\n");
}
return 0;
}

14.5 Dadas duas matrizes de nmeros reais Amn e Bnp , com 1 6 m, n, p 6 100, calcular o
produto de A por B.
14.6 Dada uma matriz de nmeros inteiros Amn , com 1 6 m, n 6 100, imprimir o nmero de
linhas e o nmero de colunas nulas da matriz.
Exemplo:
Se a matriz A tem m = 4 linhas, n = 4 colunas e contedo

1 0 2 3
4 0 5 6

0 0 0 0
0 0 0 0
ento A tem 2 linhas nulas e 1 coluna nula.

FACOM

UFMS

138

M ATRIZES

14.7 Dizemos que uma matriz de nmeros inteiros Ann uma matriz de permutao se em
cada linha e em cada coluna houver n 1 elementos nulos e um nico elemento 1.
Exemplo:

A matriz abaixo de permutao

0 1 0 0
0 0 1 0

1 0 0 0 .
0 0 0 1

Observe que

2 1 0
1
2 0
0
0 1

no de permutao.

Dada uma matriz de nmeros inteiros Ann , com 1 6 n 6 100, verificar se A de permutao.
14.8 Dada uma matriz de nmeros reais Amn , com 1 6 m, n 6 100, verificar se existem
elementos repetidos em A.
14.9 Dizemos que uma matriz quadrada de nmeros inteiros distintos um quadrado mgico1 se a soma dos elementos de cada linha, a soma dos elementos de cada coluna e a
soma dos elementos da diagonal principal e secundria so todas iguais.
Exemplo:
A matriz

8 0 7
4 5 6
3 10 2

um quadrado mgico.
Dada uma matriz quadrada de nmeros inteiros Ann , com 1 6 n 6 100, verificar se A
um quadrado mgico.
14.10

(a) Imprimir as n primeiras linhas do tringulo de Pascal2 , com 1 6 n 6 100.


1
1
1
1
1
1
..
.

1
2
3
4
5

1
3
6
10

1
4
10

1
5

(b) Imprimir as n primeiras linhas do tringulo de Pascal usando apenas um vetor.


1
2

O primeiro registro conhecido de um quadrado mgico vem da China e data do ano de 650 a.c.
Descoberto em 1654 pelo matemtico francs Blaise Pascal.

FACOM

UFMS

14.3 E XEMPLO

139

14.11 Um jogo de palavras cruzadas pode ser representado por uma matriz Amn onde cada
posio da matriz corresponde a um quadrado do jogo, sendo que 0 indica um quadrado
branco e 1 indica um quadrado preto. Indicar em uma dada matriz Amn de 0 e 1,
com 1 6 m, n 6 100, as posies que so incio de palavras horizontais e/ou verticais nos
quadrados correspondentes (substituindo os zeros), considerando que uma palavra deve
ter pelo menos duas letras. Para isso, numere consecutivamente tais posies.
Exemplo:
Dada a matriz

0 1
0 1 1
0 1
0
0
0
0
0 1
0
0
0

0
0
1
1
0
0
1
0

1
0
0
0
0 1
0
0
0
0 1
0
0
0 1 1

a sada dever ser

1 1
2 1 1
3 1
4
5
6
0
0 1
7
0
0

8
0
1
1
9
0
1
0

1 10
0 11
0 1 12
0
13
0 1 14
0
0 1 1

14.12 Os elementos aij de uma matriz de nmeros inteiros Ann representam os custos de transporte da cidade i para a cidade j. Dados uma matriz Ann , com 1 6 n 6 100, um nmero
inteiro m > 0 representando a quantidade de itinerrios, um nmero k representando o
nmero de cidades em cada um dos itinerrios, calcular o custo total para cada itinerrio.
Exemplo:
Dado

4
5
A=
2
7

1
2
1
1

2
3
1 400

3
8
2
5

m = 1, k = 8 e o itinerrio 0 3 1 3 3 2 1 0, o custo total desse itinerrio


a03 + a31 + a13 + a33 + a32 + a21 + a10 = 3 + 1 + 400 + 5 + 2 + 1 + 5 = 417 .
14.13 Dados um caa-palavra, representado por uma matriz A de letras de dimenso m n,
com 1 6 m, n 6 50, e uma lista de k > 0 palavras, encontrar a localizao (linha e coluna)
no caa-palavras em que cada uma das palavras pode ser encontrada.
Uma palavra encontrada no caa-palavras se uma seqncia ininterrupta de letras na
tabela coincide com a palavra. Considere que as letras so apenas as minsculas. A busca
por uma palavra deve ser feita em qualquer das oito direes no caa-palavras.

FACOM

UFMS

140

M ATRIZES
a
q
b
p
o
h
z
o
t
q
r
m

c
y
m
f
c
j
l
b
s
b
o
u

t
s
m
x
j
a
a
j
z
s
o
q

a
u
a
a
g
o
c
g
y
r
d
l

g
z
o
v
u
q
d
h
l
o
m
c

u
j
r
n
a
y
b
c
o
a
a
k

d
l
a
e
t
s
m
t
k
e
y
a

k
l
w
t
d
c
o
a
e
p
s
z

h
c
e
q
k
z
r
w
u
h
l
g

amora

14.14 Considere n cidades numeradas de 0 a n 1 que esto interligadas por uma srie de
estradas de mo nica, com 1 6 n 6 100. As ligaes entre as cidades so representadas
pelos elementos de uma matriz quadrada Ann , cujos elementos aij assumem o valor 1 ou
0, conforme exista ou no estrada direta que saia da cidade i e chegue cidade j. Assim,
os elementos da coluna j indicam as estradas que chegam cidade j. Por conveno
aii = 1.
A figura abaixo mostra um exemplo para n = 4.

A 0

(a) Dado k, determinar quantas estradas saem e quantas chegam cidade k.


(b) A qual das cidades chega o maior nmero de estradas?
(c) Dado k, verificar se todas as ligaes diretas entre a cidade k e outras so de mo
dupla.
(d) Relacionar as cidades que possuem sadas diretas para a cidade k.
FACOM

UFMS

14.3 E XEMPLO

141

(e) Relacionar, se existirem:


i. As cidades isoladas, isto , as que no tm ligao com nenhuma outra;
ii. As cidades das quais no h sada, apesar de haver entrada;
iii. As cidades das quais h sada sem haver entrada.
(f) Dada uma seqncia de m inteiros cujos valores esto entre 0 e n 1, verificar se
possvel realizar o roteiro correspondente. No exemplo dado, o roteiro representado
pela seqncia 2 0 1 2 3, com m = 5, impossvel.
(g) Dados k e p, determinar se possvel ir da cidade k para a cidade p pelas estradas
existentes. Voc consegue encontrar o menor caminho entre as duas cidades?

FACOM

UFMS

142

FACOM

M ATRIZES

UFMS

AULA

15

R EGISTROS

Nas aulas 12 e 14 aprendemos a trabalhar com variveis compostas homogneas unidimensionais e bidimensionais ou os vetores e as matrizes , que permitem que um programador
agrupe valores de um mesmo tipo em uma nica entidade lgica. Como mencionamos antes,
a dimenso de uma varivel composta homognea no fica necessariamente restrita a uma ou
duas. Isto , tambm podemos declarar e usar variveis compostas homogneas com trs ou
mais dimenses. Importante relembrar tambm que, para referenciar um elemento em uma
varivel composta homognea so necessrios o seu identificador e um ou mais ndices.
A linguagem C dispe tambm de uma outra forma para agrupamento de dados, chamada
varivel composta heterognea, registro ou estrutura1 . Nelas, diferentemente do que nas variveis compostas homogneas, podemos armazenar sob uma mesma entidade lgica valores de
tipos diferentes. Alm disso, ao invs de ndices ou endereos usados nas variveis compostas
homogneas para acesso a um valor, especificamos o nome de um campo para selecionar um
campo particular do registro. Os registros so os objetos de estudo desta aula, que inspirada
nas referncias [15, 16].

15.1 Definio
Uma varivel composta heterognea ou registro uma estrutura onde podemos armazenar valores de tipos diferentes sob uma mesma entidade lgica. Cada um desses possveis
valores armazenado em um compartimento do registro denominado campo do registro, ou
simplesmente campo. Um registro composto pelo seu identificador e pelos seus campos.
Suponha que queremos trabalhar com um agrupamento de valores que representam uma
determinada mercadoria de uma loja, cujas informaes relevantes so o cdigo do produto e
seu valor. Na linguagem C, podemos ento declarar um registro com identificador produto
da seguinte forma:

struct {
int codigo;
int quant;
float valor;
} produto;
1
struct e member (of a structure) so jarges comuns na linguagem C. A traduo literal dessas palavras pode nos
confundir com outros termos j usados durante o curso. Por isso, escolhemos registro e campo (do registro) como
tradues para o portugus.

143

144

R EGISTROS

A figura 15.1 mostra a disposio do registro produto na memria do computador.


produto
memria
codigo quant

valor

Figura 15.1: Representao do registro produto na memria.


Na linguagem C, a declarao de um registro sempre inicia com a palavra-chave struct .
Logo em seguida, o delimitador de bloco { deve ocorrer. Depois disso, um bloco de declaraes iniciado. Nesse bloco, podemos declarar os campos do registro, linha aps linha. Cada
linha deve conter o tipo, de um dos tipos primitivos da linguagem C ou de um tipo criado
pelo(a) programador(a), e mais o identificador do campo do registro. Finalizamos ento as declaraes dos campos do registro o delimitador de bloco } . Depois disso, realizamos de fato a
declarao do registro, digitando o seu identificador. A varivel do tipo registro com identificador produto declarada acima contm trs campos, dois do tipo inteiro com identificadores
codigo e quant , e outro do tipo ponto flutuante valor .
O formato geral de declarao de um registro apresentado abaixo:

struct {
.
.
.
bloco de declaraes
.
.
.
} identificador;

Podemos declarar outras variveis do tipo registro com os mesmos campos da varivel
produto , declarada acima, da seguinte forma:

struct {
int codigo;
int quant;
float valor;
} produto, estoque, baixa;

Uma maneira alternativa de declarao dos campos de um registro declarar campos de


um mesmo tipo em uma nica linha de cdigo, seperando-os com vrgulas. Por exemplo, na
linguagem C, a instruo a seguir:

struct {
char sala, turma;
int horas_inicio, minutos_inicio, horas_fim, minutos_fim;
float largura, comprimento;
} aula;
FACOM

UFMS

15.1 D EFINIO

145

declara um registro com identificador aula com seis campos, dois campos do tipo char ,
quatro outros campos do tipo int e dois campos do tipo float . Apesar dessa declarao
estar correta e de economizar algumas linhas de cdigo, sempre optamos pela declarao dos
campos separadamente, linha a linha, para que os campos fiquem bem destacados e, assim,
facilitem sua identificao rpida no cdigo. Dessa forma, em geral optamos pela seguinte
declarao do registro aula :

struct {
char sala;
char turma;
int horas_inicio;
int minutos_inicio;
int horas_fim;
int minutos_fim;
float largura;
float comprimento;
} aula;

Diferentemente da atribuio de um valor a uma varivel ou a um compartimento de uma


varivel composta homognea, a atribuio de um valor a um campo de uma varivel do tipo
registro realizada atravs do acesso a esse campo, especificando o identificador do registro,
um ponto e o identificador do campo.
Por exemplo, para atribuir os valores 12, 5 e 34.5 aos campos codigo , quant e valor ,
respectivamente, da varivel do tipo registro produto declarada anteriormente, devemos fazer como abaixo:
produto.codigo = 12;
produto.quant = 5;
produto.valor = 34.5;

Observe acima que, quando referenciamos um campo de uma varivel do tipo registro, no
so permitidos espaos entre o identificador do registro, o operador ponto e o identificador
do campo.
Tambm podemos usar o valor de um campo de um registro em quaisquer expresses. Por
exemplo, a expresso relacional abaixo correta:

if (produto.valor < 150.0)


printf("Comprar produto\n");
else
printf("Acima do preo de mercado!\n");

Declaraes de registros diferentes podem conter campos com mesmo identificador. Por
exemplo,

FACOM

UFMS

146

R EGISTROS

struct {
char tipo;
char fatorRH;
int idade;
float altura;
} coleta;
struct {
char codigo;
int tipo;
int idade;
} certidao;

so declaraes vlidas na linguagem C. O acesso aos campos dessas variveis se diferencia justamente pelo identificador dos registros. Isto , a partir das declaraes dos registros coleta
e certidao , as atribuies abaixo esto corretas:

coleta.tipo = O;
certidao.tipo = 0;
coleta.idade = 29;
certidao.idade = coleta.idade + 2;

15.2 Declarao e inicializao simultneas


Declarao e inicializao simultneas tambm so vlidas com registros. As regras so
idnticas s dos vetores. Por exemplo, o registro produto que declaramos acima pode ter sua
inicializao realizada no momento de sua declarao como segue:

struct {
int codigo;
int quant;
float valor;
} produto = {1, 5, 34.5};

Neste caso, o campo codigo inicializado com o valor 1 , o campo quant inicializado
com o valor 5 e o campo valor com 34.5 . Como mencionado, as regras de declarao e
inicializao simultneas para registros so equivalentes quelas para vetores. Assim,

struct {
int codigo;
int quant;
float valor;
} produto = {0};

far a inicializao dos campos codigo e quant com 0 e do campo valor com 0.0 .
FACOM

UFMS

15.3 O PERAES

SOBRE REGISTROS

147

15.3 Operaes sobre registros

Variveis compostas heterogneas possuem uma caracterstica importante, que no observada em variveis compostas homogneas.
Lembre-se que quando queremos copiar o contedo completo de todos os compartimentos
de uma varivel composta homognea para os compartimentos respectivos de outra varivel
composta homognea, necessrio realizar a cpia elemento a elemento, escrevendo uma ou
mais estruturas de repetio para que essa cpia seja efetuada com sucesso. Isto , se A e B
so, por exemplo, vetores de um mesmo tipo de dados e mesma dimenso, errado tentar
fazer uma atribuio como abaixo:

A = B;

para copiar os valores do vetor B no vetor A . O compilador da linguagem C deve acusar


um erro como esse. O correto ento, neste caso, fazer a cpia elemento a elemento de uma
varivel para outra. Supondo que n a dimenso desses vetores, uma forma correta de realizar
essa cpia mostrada a seguir:

for (i = 0; i < n; i++)


A[i] = B[i];

Por outro lado, quando tratamos de registros, podemos fazer uma atribuio direta e realizar a cpia de todos os seus campos nessa nica atribuio. O trecho de cdigo a seguir mostra
um exemplo com a declarao de dois registros com mesmos campos, a atribuio de valores
ao primeiro registro e uma cpia completa de todos os campos do primeiro registro para o
segundo:

.
.
.
struct {
char tipo;
int codigo;
int quant;
float valor;
} mercadoria1, mercadoria2;
.
.
.
mercadoria1.tipo = A;
mercadoria1.codigo = 10029;
mercadoria1.quant = 62;
mercadoria1.valor = 10.32 * TAXA + 0.53;
.
.
.
mercadoria2 = mercadoria1;
.
.
.

FACOM

UFMS

148

R EGISTROS

15.4 Exemplo
O programa 15.1 a seguir recebe um horrio no formato de horas, minutos e segundos, com
as horas no intervalo de 0 a 23, e atualiza este horrio em um segundo.
Programa 15.1: Atualiza o horrio em 1 segundo
#include <stdio.h>
/* Recebe um horrio no formato hh:mm:ss e o atualiza
em 1 segundo, mostrando o novo horrio na sada */
int main(void)
{
struct {
int hh;
int mm;
int ss;
} agora, prox;
printf("Informe o horrio atual (hh:mm:ss): ");
scanf("%d:%d:%d", agora.hh, agora.mm, agora.ss);
prox = agora;
prox.ss = prox.ss + 1;
if (prox.ss == 60) {
prox.ss = 0;
prox.mm = prox.mm + 1;
if (prox.mm == 60) {
prox.mm = 0;
prox.hh = prox.hh + 1;
if (prox.hh == 24)
prox.hh = 0;
}
}
printf("Prximo horrio %d:%d:%d\n", prox.hh, prox.mm, prox.ss);
return 0;
}

Exerccios
15.1 Dada uma data no formato dd/mm/aaaa, escreva um programa que mostre a prxima
data, isto , a data que representa o dia seguinte data fornecida.
Observao: No esquea dos anos bissextos. Lembre-se que um ano bissexto se divisvel por 400 ou, em caso negativo, se divisvel por 4 mas no por 100.
15.2 Dados dois horrios de um mesmo dia expressos no formato hh:mm:ss, calcule o tempo
decorrido entre estes dois horrios, apresentando o resultado no mesmo formato.
FACOM

UFMS

15.4 E XEMPLO

149
Programa 15.2: Soluo do exerccio 15.1.

#include <stdio.h>
/* Recebe uma data no formato dd:mm:aaaa e a atualiza em 1 dia, mostrando a nova data na sada */
int main(void)
{
struct {
int dia;
int mes;
int ano;
} data, prox;
printf("Informe uma data (dd/mm/aa): ");
scanf("%d/%d/%d", &data.dia, &data.mes, &data.ano);
prox = data;
prox.dia++;
if (prox.dia > 31 ||
(prox.dia == 31 && (prox.mes == 4 || prox.mes == 6 ||
prox.mes == 9 || prox.mes == 11)) ||
(prox.dia == 30 && prox.mes == 2) ||
(prox.dia == 29 && prox.mes == 2 && (prox.ano % 400 != 0 &&
(prox.ano % 100 == 0 || prox.ano % 4 != 0)))) {
prox.dia = 1;
prox.mes++;
if (prox.mes > 12) {
prox.mes = 1;
prox.ano++;
}
}
printf("%02d/%02d/%02d\n", prox.dia, prox.mes, prox.ano);
return 0;
}

15.3 Dadas duas datas, calcule o nmero de dias decorridos entre estas duas datas.
Uma maneira provavelmente mais simples de computar essa diferena usar a frmula 15.1 para calcular um nmero de dias N baseado em uma data:

 

1461 f (ano, ms)
153 g(ms)
N=
+
+ dia
(15.1)
4
5
onde
f (ano, ms) =
e
g(ms) =

ano 1, se ms 6 2 ,
ano,
caso contrrio

ms + 13, se ms 6 2 ,
ms + 1, caso contrrio .

Podemos calcular o valor N1 para a primeira data informada, o valor N2 para a segunda
data informada e a diferena N2 N1 o nmero de dias decorridos entre estas duas
datas informadas.
FACOM

UFMS

150

R EGISTROS

15.4 Seja N computado como na equao 15.1. Ento, o valor


D = (N 621049) mod 7
um nmero entre 0 e 6 que representa os dias da semana, de domingo a sbado. Por
exemplo, para a data de 21/06/2007 temos

 

1461 f (2007, 6)
153 g(6)
N=
+
+ 21
4
5

 

1461 2007
153 7
=
+
+ 21
4
5
= 733056 + 214 + 21
= 733291
e ento
D = (733291 621049) mod 7
= 112242 mod 7
=4.
Dada uma data fornecida pelo usurio no formato dd/mm/aaaa, determine o dia da
semana para esta data.

FACOM

UFMS

AULA

V ETORES ,

16

MATRIZES E REGISTROS

Nesta aula, vamos trabalhar com uma extenso natural do uso de registros, declarando e
usando variveis compostas homogneas de registros como, por exemplo, vetores de registros
ou matrizes de registros. Por outro lado, estudaremos tambm registros contendo variveis
compostas homogneas como campos. Veremos que combinaes dessas declaraes tambm
podem ser usadas de modo a representar e organizar os dados na memria para soluo de problemas. Alm disso, veremos ainda registros cujos campos podem ser variveis no somente de
tipos primitivos, de tipos definidos pelo usurio, ou ainda variveis compostas homogneas,
mas tambm de variveis compostas heterogneas ou registros. O conjunto dessas combinaes de variveis que acabamos de mencionar fornece ao() programador(a) uma liberdade e
flexibilidade na declarao de qualquer estrutura para armazenamento de informaes que lhe
seja necessria na soluo de um problema computacional, especialmente daqueles problemas
mais complexos.
Esta aula baseada nas referncias [16, 15].

16.1 Variveis compostas homogneas de registros


Como vimos nas aulas 12 e 14, podemos declarar variveis compostas homogneas a partir
de qualquer tipo bsico ou ainda de um tipo definido pelo(a) programador(a). Ou seja, podemos declarar, por exemplo, um vetor do tipo inteiro, uma matriz do tipo ponto flutuante, uma
varivel composta homognea de k dimenses do tipo caracter e etc. A partir de agora, poderemos tambm declarar variveis compostas homogneas, de quaisquer dimenses, de registros.
Por exemplo, podemos declarar um vetor com identificador cronometro como mostrado a
seguir:

struct {
int horas;
int minutos;
int segundos;
} cronometro[10];

ou ainda declarar, por exemplo, uma matriz com identificador agenda como abaixo:
151

152

V ETORES ,

MATRIZES E REGISTROS

struct {
int horas;
int minutos;
int segundos;
} agenda[10][30];

O vetor cronometro declarado anteriormente contm 10 compartimentos de memria,


sendo que cada um deles do tipo registro. Cada registro contm, por sua vez, os campos
horas , minutos e segundos , do tipo inteiro. J a matriz com identificador agenda uma
matriz contendo 10 linhas e 30 colunas, onde cada compartimento contm um registro com os
mesmos campos do tipo inteiro horas , minutos e segundos . Essas duas variveis compostas homogneas tambm poderiam ter sido declaradas em conjunto, numa mesma sentena de
declarao, como apresentado a seguir:

struct {
int horas;
int minutos;
int segundos;
} cronometro[10], agenda[10][30];

A declarao do vetor cronometro tem um efeito na memria que pode ser ilustrado como
na figura 16.1.

cronometro

horas
minutos
segundos

Figura 16.1: Efeito da declarao do vetor cronometro na memria.


Atribuies de valores do tipo inteiro aos campos do registro no primeiro compartimento
deste vetor cronometro podem ser realizadas usando o identificador do vetor, o ndice 0
(zero) envolvido por colchetes, o smbolo seletor de um campo . e o identificador do campo,
como ilustrado nas atribuies abaixo:

cronometro[0].horas = 20;
cronometro[0].minutos = 39;
cronometro[0].segundos = 18;
FACOM

UFMS

16.1 VARIVEIS

COMPOSTAS HOMOGNEAS DE REGISTROS

153

Alm disso, como fizemos na aula 15, podemos fazer a atribuio direta de registros para
registros declarados da mesma maneira. Assim, por exemplo, se declaramos as variveis
cronometro e aux como abaixo:

struct {
int horas;
int minutos;
int segundos;
} cronometro[10], aux;

ento as atribuies a seguir so vlidas e realizam a troca dos contedos das posies i e j
do vetor de registros cronometro :

aux = cronometro[i];
cronometro[i] = cronometro[j];
cronometro[j] = aux;

importante observar novamente que todos os campos de um registro so atualizados


automaticamente quando da atribuio de um registro a outro registro, no havendo a necessidade da atualizao campo a campo. Ou seja, podemos fazer:

cronometro[i] = cronometro[j];

ao invs de:
cronometro[i].horas = cronometro[j].horas;
cronometro[i].minutos = cronometro[j].minutos;
cronometro[i].segundos = cronometro[j].segundos;

As duas formas de atribuio acima esto corretas, apesar da primeira forma ser muito mais
prtica e direta.
Nesse contexto, considere o seguinte problema:

Dado um nmero inteiro n, com 1 6 n 6 100, e n medidas de tempo dadas em


horas, minutos e segundos, distintas duas a duas, ordenar essas medidas de tempo
em ordem crescente.

O programa 16.1 soluciona o problema acima usando o mtodo de ordenao das trocas
sucessivas ou mtodo da bolha.
FACOM

UFMS

154

V ETORES ,

MATRIZES E REGISTROS

Programa 16.1: Um programa usando um vetor de registros.


#include <stdio.h>
/* Recebe um inteiro n, 1 6 n 6 100, e n medidas de tempo
hh:mm:ss, e mostra esses tempos em ordem crescente */
int main(void)
{
int i, j, n;
struct {
int hh;
int mm;
int ss;
} cron[100], aux;
printf("Informe a quantidade de medidas de tempo: ");
scanf("%d", &n);
printf("\n");
for (i = 0; i < n; i++) {
printf("Informe uma medida de tempo (hh:mm:ss): ");
scanf("%d:%d:%d", &cron[i].hh, &cron[i].mm, &cron[i].ss);
}
for (i = n-1; i > 0; i--) {
for (j = 0; j < i; j++) {
if (cron[j].hh > cron[j+1].hh) {
aux = cron[j];
cron[j] = cron[j+1];
cron[j+1] = aux;
}
else {
if (cron[j].hh == cron[j+1].hh) {
if (cron[j].mm > cron[j+1].mm) {
aux = cron[j];
cron[j] = cron[j+1];
cron[j+1] = aux;
}
}
else {
if (cron[j].mm == cron[j+1].mm) {
if (cron[j].ss > cron[j+1].ss) {
aux = cron[j];
cron[j] = cron[j+1];
cron[j+1] = aux;
}
}
}
}
}
}
printf("\nHorrios em ordem crescente\n");
for (i = 0; i < n; i++)
printf("%d:%d:%d\n", cron[i].hh, cron[i].mm, cron[i].ss);
return 0;
}

FACOM

UFMS

16.2 R EGISTROS

CONTENDO VARIVEIS COMPOSTAS HOMOGNEAS

155

16.2 Registros contendo variveis compostas homogneas


Na aula 15 definimos registros que continham campos de tipos bsicos de dados ou, no
mximo, de tipos definidos pelo(a) programador(a). Na seo 16.1, estudamos vetores no
mais de tipos bsicos de dados, mas de registros, isto , vetores contendo registros. Essa idia
pode ser estendida para matrizes ou ainda para variveis compostas homogneas de qualquer
dimenso. Por outro lado, podemos tambm declarar registros que contm variveis compostas homogneas como campos. Um exemplo bastante comum a declarao de um vetor de
caracteres, ou uma cadeia de caracteres, dentro de um registro, isto , como um campo deste
registro:

struct {
int dias;
char nome[3];
} mes;

A declarao do registro mes permite o armazenamento de um valor do tipo inteiro no


campo dias , que pode representar, por exemplo, a quantidade de dias de um ms, e de trs
valores do tipo caracter no campo vetor nome , que podem representar os trs primeiros caracteres do nome de um ms do ano. Assim, se declaramos as variveis mes e aux como a
seguir:

struct {
int dias,
char nome[3];
} mes, aux;

podemos fazer a seguinte atribuio vlida ao registro mes :

mes.dias = 31;
mes.nome[0] = J;
mes.nome[1] = a;
mes.nome[2] = n;

Os efeitos da declarao da varivel mes na memria e da atribuio de valores acima podem


ser vistos na figura 16.2.
nome
dias
mes

31

Figura 16.2: Varivel mes na memria.


FACOM

UFMS

156

V ETORES ,

MATRIZES E REGISTROS

importante salientar mais uma vez que as regras para cpias de registros permanecem as
mesmas, mesmo que um campo de um desses registros seja uma varivel composta. Assim, a
cpia abaixo perfeitamente vlida:

aux = mes;

Suponha agora que temos o seguinte problema.


Dadas duas descries de tarefas e seus horrios de incio no formato hh:mm:ss, escreva um programa que verifica qual das duas tarefas ser iniciada antes. Considere
que a descrio de uma tarefa tenha no mximo 50 caracteres.
Uma soluo para esse problema apresentada no programa 16.2.
Programa 16.2: Exemplo do uso de um vetor como campo de um registro.
#include <stdio.h>
/* Recebe a descrio e o horrio de incio de duas atividades, no
formato hh:mm:ss, e verifica qual delas ser realizada primeiro */
int main(void)
{
int tempo1, tempo2;
struct {
int horas;
int minutos;
int segundos;
char descricao[51];
} t1, t2;
printf("Informe a descrio da primeira atividade: ");
scanf("%[^\n]", t1.descricao);
printf("Informe o horrio de incio dessa atividade (hh:mm:ss): ");
scanf("%d:%d:%d", &t1.horas, &t1.minutos, &t1.segundos);
printf("Informe a descrio da segunda atividade: ");
scanf(" %[^\n]", t2.descricao);
printf("Informe o horrio de incio dessa atividade (hh:mm:ss): ");
scanf("%d:%d:%d", &t2.horas, &t2.minutos, &t2.segundos);
tempo1 = t1.horas * 3600 + t1.minutos * 60 + t1.segundos;
tempo2 = t2.horas * 3600 + t2.minutos * 60 + t2.segundos;
if (tempo1 <= tempo2)
printf("%s ser realizada antes de %s\n", t1.descricao, t2.descricao);
else
printf("%s ser realizada antes de %s\n", t2.descricao, t1.descricao);
return 0;
}

FACOM

UFMS

16.3 R EGISTROS

157

CONTENDO REGISTROS

16.3 Registros contendo registros


importante observar que a declarao de um registro pode conter um outro registro como
um campo, em seu interior. Ou seja, uma varivel composta heterognea pode conter campos
de tipos bsicos, iguais ou distintos, campos de tipos definidos pelo usurio, campos que so
variveis compostas homogneas, ou ainda campos que se constituem tambm como variveis
compostas heterogneas.
Como exemplo, podemos declarar uma varivel do tipo registro com nome ou identificador
estudante contendo um campo do tipo inteiro rga , um campo do tipo vetor de caracteres
nome e um campo do tipo registro nascimento , contendo por sua vez trs campos do tipo
inteiro com identificadores dia , mes e ano :

struct {
int rga;
char nome[51];
struct {
int dia;
int mes;
int ano;
} nascimento;
} estudante;

A figura 16.3 mostra o efeito da declarao da varivel estudante na memria.


estudante
dia

rga

nome

mes

ano

nasc

49

50

Figura 16.3: Efeitos da declarao do registro estudante na memria.


Observe que a varivel estudante um registro que mistura campos de um tipo bsico
o campo rga que do tipo inteiro , um campo que um vetor de um tipo bsico o campo
nome do tipo vetor de caracteres e um campo do tipo registro o campo nascimento do
tipo registro, contendo, por sua vez, trs campos do tipo inteiro: os campos dia , mes e ano .
Um exemplo do uso do registro estudante e de seus campos dado a seguir atravs de
atribuies de valores a cada um de seus campos:
FACOM

UFMS

158

V ETORES ,

MATRIZES E REGISTROS

estudante.rga = 200790111;
estudante.nome[0] = J;
estudante.nome[1] = o;
estudante.nome[2] = s;
estudante.nome[3] = e;
estudante.nome[4] = \0;
estudante.nasc.dia = 22;
estudante.nasc.mes = 2;
estudante.nasc.ano = 1988;

Suponha finalmente que temos o seguinte problema.


Dados um inteiro positivo n, uma seqncia de n nomes, telefones e datas de aniversrio, e uma data no formato dd/mm, imprima os nomes e telefones das pessoas
que aniversariam nesta data.
Uma soluo para esse problema apresentada no programa 16.3.
Podemos destacar novamente, assim como fizemos na aula 15, que registros podem ser atribudos automaticamente para registros, no havendo necessidade de faz-los campo a campo.
Por exemplo, se temos declarados os registros:

struct {
int rga;
char nome[51];
struct {
int dia;
int mes;
int ano;
} nascimento;
} estudante1, estudante2, aux;

ento, as atribuies a seguir so perfeitamente vlidas e realizam corretamente a troca de


contedos dos registros estudante1 e estudante2 :

aux = estudante1;
estudante1 = estudante2;
estudante2 = aux;

FACOM

UFMS

16.3 R EGISTROS

CONTENDO REGISTROS

159

Programa 16.3: Um exemplo de uso de registros contendo registros.


#include <stdio.h>
#define DIM 100
#define MAX 50
/* Recebe um inteiro positivo n e n nomes, telefones e datas de
aniversrio, recebe uma data de consulta e mostra os nomes
e telefones das pessoas que aniversariam nesta data */
int main(void)
{
int i, n;
struct {
char nome[MAX+1];
int telefone;
struct {
int dia;
int mes;
int ano;
} aniver;
} agenda[DIM];
struct {
int dia;
int mes;
} data;
printf("Informe a quantidade de amigos: ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("\nAmigo(a): %3d\n", i+1);
printf("
Nome
: ");
scanf(" %[^\n]", agenda[i].nome);
printf("
Telefone
: ");
scanf("%d", &agenda[i].telefone);
printf("
Aniversrio: ");
scanf("%d/%d/%d", &agenda[i].aniver.dia, &agenda[i].aniver.mes,
&agenda[i].aniver.ano);
}
printf("\nInforme uma data (dd/mm): ");
scanf("%d/%d", &data.dia, &data.mes);
for (i = 0; i < n; i++)
if (agenda[i].aniver.dia == data.dia && agenda[i].aniver.mes == data.mes)
printf("%-50s %8d\n", agenda[i].nome, agenda[i].telefone);
return 0;
}

FACOM

UFMS

160

V ETORES ,

MATRIZES E REGISTROS

Exerccios
16.1 Dadas n datas, com 1 6 n 6 100, e uma data de referncia d, verifique qual das n datas
mais prxima data d.
Programa 16.4: Soluo do exerccio 16.1.
#include <stdio.h>
#define MAX 100
/* Recebe um inteiro n, 1 6 n 6 100, n datas e uma data de referncia,
e verifica qual das n datas mais prxima da data de referncia */
int main(void)
{
int dif[MAX], menor;
struct {
int dia;
int mes;
int ano;
} d, data[MAX];
printf("Informe uma data de referncia (dd/mm/aa): ");
scanf("%d/%d/%d", &d.dia, &d.mes, &d.ano);
printf("Informe a quantidade de datas: ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("[%03d] Informe uma data (dd/mm/aa): ", i+1);
scanf("%d/%d/%d", &data[i].dia, &data[i].mes, &data[i].ano);
}
if (d.mes <= 2)
N1 = (1461*(d.ano-1))/4 + ((153*d.mes+13)/5) + d.dia;
else
N1 = (1461*d.ano)/4 + ((153*d.mes+1)/5) + d.dia;
for (i = 0; i < n; i++) {
if (data[i].mes <= 2)
N2 = (1461*(data[i].ano-1))/4+((153*data[i].mes+13)/5)+data[i].dia;
else
N2 = (1461*data[i].ano)/4 + ((153*data[i].mes+1)/5) + data[i].dia;
if (N1 >= N2)
dif[i] = N1 - N2;
else
dif[i] = N2 - N1;
}
menor = 0;
for (i = 1; i < n; i++)
if (dif[i] < dif[menor])
menor = i;
printf("Data mais prxima de %2d/%2d/%2d %2d/%2d/%d\n",
d.dia, d.mes, d.ano, data[menor].dia, data[menor].mes, data[menor].ano);
return 0;
}

FACOM

UFMS

16.3 R EGISTROS

CONTENDO REGISTROS

161

16.2 Dadas trs fichas de produtos de um supermercado, contendo as informaes de seu


cdigo, sua descrio com at 50 caracteres e seu preo unitrio, orden-las em ordem
alfabtica de seus nomes.
16.3 Dados um nmero inteiro n > 1 e mais n fichas de doadores de um banco de sangue, contendo o cdigo do doador, seu nome, seu tipo sangneo e seu fator Rhesus, escreva um
programa que lista os doadores do banco das seguintes formas: (i) em ordem crescente
de cdigos de doadores; (ii) em ordem alfabtica de nomes de doadores e (iii) em ordem
alfabtica de tipos sangneos e fatores Rhesus.
16.4 Suponha que em um determinado galpo estejam armazenados os materiais de construo de uma loja que vende tais materiais. Este galpo quadrado e mede 2020 = 400m2
e a cada 22 = 4m2 h uma certa quantidade de um material armazenado. O encarregado
do setor tem uma tabela de 10 linhas por 10 colunas, representando o galpo, contendo,
em cada clula, o cdigo do material, sua descrio e sua quantidade. O cdigo do material um nmero inteiro, a descrio o material contm no mximo 20 caracteres e a
quantidade do material um nmero de ponto flutuante.
Escreva um programa que receba as informaes armazenadas na tabela do encarrerado
e liste cada material e a sua quantidade disponvel no galpo. Observe que um mesmo
material pode encontrar-se em mais que um local no galpo.
16.5 Escreva um programa que receba o nome, o telefone e a data de nascimento de n pessoas,
com 1 6 n 6 100, e implemente uma agenda telefnica com duas listagens possveis: (i)
uma lista dos nomes e telefones das pessoas em ordem alfabtica de nomes e (ii) uma lista
dos nomes e telefones das pessoas em ordem de datas de aniversrios das pessoas.

FACOM

UFMS

162

FACOM

V ETORES ,

MATRIZES E REGISTROS

UFMS

AULA

I NTRODUO

17

S FUNES

Se concordamos que uma grande tarefa pode ser solucionada atravs de sua diviso em
sub-tarefas e da combinao de suas solues parciais, ento podemos ter nosso trabalho facilitado focando na construo de solues para essas sub-tarefas. Em programao essas solues
menores so chamadas de mdulos de programao e fazem parte de todo processo de construo de programas para soluo de problemas reais.
Os mdulos so uma ferramenta da programao estruturada que fornecem ao() programador(a) um mecanismo para construir programas que so fceis de escrever, ler, compreender, corrigir, modificar e manter. Na linguagem C, essa caracterstica em um cdigo obtida
atravs do uso de funes. Na verdade, todos os programas que codificamos at o momento
de alguma forma j fizeram uso de funes. Por exemplo, scanf e printf so funes de
entrada e sada de dados da linguagem C que j usamos muitas e muitas vezes. Alm disso,
temos construdo nossas prprias funes main para solucionar todos os problemas vistos at
aqui. Apesar do termo funo vir da matemtica, uma funo da linguagem C nem sempre
se parece com uma funo matemtica, j que pode no ter argumentos nem computar um
valor. Cada funo na linguagem C pode ser vista como um pequeno programa com suas prprias declaraes de variveis e sentenas de programao. Alm de facilitar a compreenso
e a modificao de um programa e evitar a duplicao de cdigo usado mais que uma vez, as
funes podem ser usadas no s no programa para o qual foram projetadas, mas tambm em
outros programas.
Esta aula baseada nas referncias [16, 15].

17.1 Noes iniciais


Antes de aprender as regras formais para definir uma funo, vejamos trs pequenos exemplos de programas que definem funes.
Suponha que computamos freqentemente a mdia de dois valores do tipo double . A
biblioteca de funes da linguagem C no tem uma funo que computa a mdia, mas podemos
escrever facilmente a nossa prpria funo. Vejamos a seguir:

/* Recebe dois nmeros reais e devolve a mdia aritmtica deles */


double media(double a, double b)
{
return (a + b) / 2;
}

163

164

I NTRODUO

S FUNES

A palavra-chave double na primeira linha o tipo do valor devolvido da funo media ,


que o tipo do valor devolvido pela funo cada vez que ela chamada. Os identificadores a
e b , chamados de parmetros da funo, representam os dois nmeros que sero fornecidos
quando a funo media chamada. Assim como uma varivel, um parmetro deve ter um
tipo. No exemplo, ambos os parmetros a e b so do tipo double . Observe que um parmetro de uma funo essencialmente uma varivel cujo valor inicial fornecido quando da
sua chamada.
Toda funo tem um trecho executvel, chamado de corpo, envolvido por abre e fecha
chaves. O corpo de funo media consiste de uma nica sentena return . A execuo dessa
sentena faz com que a funo regresse para o ponto de onde foi chamada. O valor resultante
da avaliao da expresso aritmtica (a + b) / 2 ser devolvido pela funo.
Para chamar uma funo, escrevemos o nome da funo seguido por uma lista de argumentos. Por exemplo, media(x, y) uma chamada da funo media . Os argumentos so
usados para fornecer informaes para a funo, como nesse caso, em que a funo media
necessita de dois valores para calcular a mdia. O efeito da chamada media(x, y) primeiro
copiar os valores de x e y nos parmetros a e b e, em seguida, executar o corpo de media .
Um argumento no tem de ser necessariamente uma varivel. Qualquer expresso de um tipo
compatvel pode ser um argumento, o que nos permite escrever media(5.1, 8.9) ou ainda
media(x/2, y/3) .
Devemos fazer uma chamada funo media no ponto do cdigo onde usamos o seu valor
devolvido. Por exemplo, para computar a mdia de x e y , e escrever o resultado na sada,
poderamos escrever:

printf("Mdia: %g\n", media(x, y));

A sentena acima tem o seguinte efeito:


1. a funo media chamada com argumentos x e y ;
2. x e y so copiados em a e b ;
3. a funo media executa sua sentena return , devolvendo a mdia de a e b ;
4. a funo printf imprime a cadeia de caracteres e o valor que media devolve, sendo
que esse valor devolvido torna-se um argumento da funo printf .
Observe que o valor devolvido pela funo media no salvo em lugar algum. A sentena
imprime o valor e ento o descarta. Se h necessidade de usar o valor devolvido posteriormente, podemos captur-lo em uma varivel, como abaixo:

m = media(x, y);

A sentena acima chama a funo media e ento salva o valor devolvido na varivel m .
FACOM

UFMS

17.1 N OES

INICIAIS

165

Vamos usar a funo media em no programa 17.1. Entre outras coisas, este programa
mostra que uma funo pode ser chamada tantas vezes quanto necessrio.

Programa 17.1: Primeiro exemplo do uso de funo.


#include <stdio.h>
/* Recebe dois nmeros reais e devolve a mdia aritmtica deles */
double media(double a, double b)
{
return (a + b) / 2;
}
/* Recebe trs nmeros reais e calcula
a mdia aritmtica para cada par */
int main(void)
{
double x, y, z;
printf("Informe trs valores: ");
scanf("%lf%lf%lf", &x, &y, &z);
printf("Mdia de %g e %g %g\n", x, y, media(x, y));
printf("Mdia de %g e %g %g\n", x, z, media(x, z));
printf("Mdia de %g e %g %g\n", y, z, media(y, z));
return 0;
}

Observe que a definio da funo media vem antes da definio da funo main , j que
teramos problemas de compilao se fizssemos o contrrio.
Nem toda funo devolve um valor como a funo media faz. Por exemplo, uma funo
cujo trabalho enviar informaes para a sada muito provavelmente no devolve valor algum.
Para indicar que uma funo no tem valor devolvido, especificamos que seu valor devolvido
do tipo void , onde void um tipo sem valor. Considere o seguinte exemplo, que imprime
na sada uma mensagem uma certa quantidade de vezes:

/* Recebe um nmero inteiro e o imprime na sada com uma mensagem */


void imprimeContador(int n)
{
printf("%d e contando...\n", n);
return;
}

A funo imprimeContador tem um nico parmetro n do tipo int e no devolve valor


algum. Nesse caso, especificamos void como o tipo do valor a ser devolvido e podemos
opcionalmente omitir a sentena return . Dessa forma, a funo imprimeContador tambm
poderia ser descrita corretamente como abaixo:
FACOM

UFMS

166

I NTRODUO

S FUNES

/* Recebe um nmero inteiro e o imprime na sada com uma mensagem */


void imprimeContador(int n)
{
printf("%d e contando...\n", n);
}

Como a funo imprimeContador no devolve um valor, no podemos cham-la da


mesma maneira que chamamos a funo media no exemplo anterior. Ao contrrio, qualquer chamada da funo imprimeContador deve aparecer como uma nica sentena, como
no exemplo a seguir:

imprimeContador(i);

O programa 17.2 chama a funo imprimeContador 10 vezes em uma estrutura de repetio for .

Programa 17.2: Segundo exemplo do uso de funo.


#include <stdio.h>
/* Recebe um nmero inteiro e o imprime na sada com uma mensagem */
void imprimeContador(int n)
{
printf("%d e contando...\n", n);
return;
}

/* Imprime um contador inteiro descrescente de 10 a 1 */


int main(void)
{
int i;
for (i = 10; i > 0; i--)
imprimeContador(i);
return 0;
}

Inicialmente, a varivel i tem o valor 10. Quando a funo imprimeContador chamada


pela primeira vez, o valor em i copiado no parmetro n e a partir de ento n tambm contm o valor 10. Como resultado, a primeira chamada da funo imprimeContador imprimir
a seguinte mensagem:

10 e contando...
FACOM

UFMS

17.1 N OES

INICIAIS

167

A funo imprimeContador regressa para o ponto em que foi chamada, no corpo da estrutura de repetio for , imprimeContador chamada novamente e imprime a mensagem:

9 e contando...

Cada vez que imprimeContador chamada, o valor armazenado na varivel i diferente e, assim, imprimeContador imprimir 10 mensagens diferentes na sada.
importante salientar ainda que algumas funes podem tambm no ter parmetros.
Considere a funo imprimeMsg , que imprime uma mensagem cada vez que chamada:

/* Imprime uma mensagem na sada */


void imprimeMsg(void)
{
printf("Programar bacana!\n");
return;
}

A palavra reservada void entre parnteses aps o identificador da funo indica que
imprimeMsg no tem argumentos. Para chamar uma funo sem argumentos, devemos escrever o nome da funo seguido obrigatoriamente por parnteses, como mostramos abaixo:

imprimeMsg();

O programa 17.3 mostra o uso da funo imprimeMsg .


Programa 17.3: Terceiro exemplo do uso de funo.
#include <stdio.h>
/* Imprime uma mensagem na sada */
void imprimeMsg(void)
{
printf("Programar bacana!\n");
}
/* Imprime 10 vezes uma mensagem na sada */
int main(void)
{
int i;
for (i = 1; i <= 10; i++)
imprimeMsg();
return 0;
}

FACOM

UFMS

168

I NTRODUO

S FUNES

A execuo do programa 17.3 comea com a primeira sentena na funo main , que a
declarao da varivel i do tipo int . Ems eguida, uma estrutura de repetio faz com que
a funo imprimeMsg seja executada 10 vezes. Quando imprimeMsg comea sua execuo,
ela chama a funo printf para mostrar uma mensagem na sada. Quando printf termina
sua execuo, imprimeMsg termina sua execuo e volta para main .

17.2 Definio e chamada de funes


Uma funo da linguagem C um trecho de cdigo que pode receber um ou mais valores de
entrada armazenados em variveis, chamados de parmetros (de entrada), que realiza algum
processamento especfico e que pode devolver um nico valor de sada. Em geral, construmos
funes para resolver pequenos problemas bem especficos e, em conjunto com outras funes,
resolver problemas maiores e mais complexos. A definio de uma funo na linguagem C
fornece quatro informaes importantes ao compilador:
1. quem pode cham-la;
2. o tipo do valor que a funo devolve;
3. seu identificador;
4. seus parmetros de entrada.
Uma funo composta por:
uma interface, que faz a comunicao entre a funo e o meio exterior; a interface definida pela primeira linha da funo, onde especificamos o tipo do valor devolvido da
funo, seu identificador e a lista de parmetros de entrada separados por vrgulas e envolvidos por um par de parnteses; e
um corpo, que realiza o processamento sobre os valores armazenados nos parmetros de
entrada, e tambm nas variveis declaradas internamente funo, e devolve um valor
na sada; o corpo de uma funo composto pela declarao de variveis locais da funo
e sua lista de comandos.
Depois de ter visto vrios exemplos de funes na seo anterior, a forma geral de uma
definio de uma funo dada a seguir:

tipo identificador(parmetros)
{
declarao de variveis
sentena1 ;
.
.
.
sentenan ;
}
FACOM

UFMS

17.2 D EFINIO

E CHAMADA DE FUNES

169

A primeira linha apresentada a interface da funo e as linhas seguintes, envolvidas por


chaves, compem o corpo da funo. A interface da funo inicia com um tipo , que especifica
o tipo do valor a ser devolvido pela funo. Funes no podem devolver variveis compostas
homogneas, mas no h qualquer outra restrio quanto ao tipo de valor a ser devolvido. No
entanto, especificar que o valor devolvido do tipo void indica que a funo no devolve
um valor. Depois, a interface contm o identificador da funo, que seu nome e que a
identifica e diferencia de outras funes. E, finalmente, a interface contm os parmetros , que
armazenam valores a serem recebidos como entrada pela funo, envolvidos por parnteses. A
lista de parmetros composta por tipos e identificadores de variveis, separados por vrgulas.
Um tipo deve ser especificado para cada parmetro, mesmo que vrios parmetros sejam do
mesmo tipo. Por exemplo, errado escrever a funo media como abaixo:

/* Recebe dois nmeros reais e devolve a mdia aritmtica deles */


double media(double a, b)
{
return (a + b) / 2;
}

Se a funo no tem parmetros, a palavra reservada void deve ocorrer entre os parnteses.
Aps a interface, a funo contm um corpo, que uma seqncia de comandos da linguagem C envolvida por chaves. O corpo de uma funo pode incluir declaraes e sentenas. Por
exemplo, a funo media poderia ser escrita como abaixo:

/* Recebe dois nmeros reais e devolve a mdia aritmtica deles */


double media(double a, double b)
{
double soma;
soma = a + b;
return soma / 2;
}

A declarao de variveis de uma funo deve vir primeiro, antes de qualquer sentena do
corpo da funo. As variveis declaradas no corpo de uma funo pertencem exclusivamente
quela funo e no podem ser examinadas ou modificadas por outras funes.
Uma chamada de funo consiste de um identificador da funo seguido por uma lista de
argumentos entre parnteses. Por exemplo, abaixo temos trs chamadas de funes:

media(x, y)
imprimeContador(i)
imprimeMsg()

FACOM

UFMS

170

I NTRODUO

S FUNES

Uma chamada de uma funo com valor devolvido void sempre seguida por um ;
para torn-la uma sentena. Por exemplo:

imprimeContador(i);
imprimeMsg();

Por outro lado, uma chamada de uma funo com valor devolvido diferente de void produz um valor que pode ser armazenado em uma varivel ou usado em uma expresso aritmtica, relacional ou lgica. Por exemplo,

if (media(x, y) > 0)
printf("Mdia positiva\n");
printf("A mdia %g\n", media(x, y));

O valor devolvido por uma funo que devolve um valor diferente de void sempre pode
ser descartado, como podemos ver na chamada a seguir:

media(x, y);

Esta chamada funo media um exemplo de uma sentena que avalia uma expresso mas
descarta o resultado. Apesar de estranho na chamada funo media , ignorar o valor devolvido pode fazer sentido em alguns casos. Por exemplo, a funo printf sempre devolve o
nmero de caracteres impressos na sada. Dessa forma, aps a chamada abaixo, a varivel nc
ter o valor 19:
nc = printf("Programar bacana\n");

Como em geral no estamos interessados no nmero de caracteres impressos, normalmente


descartamos o valor devolvido pela funo printf e fazemos:

printf("Programar bacana\n");

Uma funo que devolve um valor diferente de void deve usar a sentena return para
especificar qual valor ser devolvido. A sentena return tem a seguinte forma geral:

return expresso;

A expresso em geral uma constante ou uma varivel, como abaixo:


FACOM

UFMS

17.3 F INALIZAO

DE PROGRAMAS

171

return 0;
return estado;

Expresses mais complexas so possveis, como por exemplo:

return (a + b) / 2;
return a * a * a + 2 * a * a - 3 * a - 1;

Quando uma das sentenas acima executada, primeiramente a avaliao da expresso realizada e o valor obtido ento devolvido pela funo.
Se o tipo da expresso na sentena return diferente do tipo devolvido pela funo, a
expresso ser implicitamente convertida para o tipo da funo.

17.3 Finalizao de programas


Como main uma funo, ela deve ter um tipo de valor de devoluo. Normalmente, o
tipo do valor a ser devolvido pela funo main int e por isso que temos definido main
da forma como fizemos at aqui.
O valor devolvido pela funo main um cdigo de estado do programa que, em alguns
sistemas operacionais, pode ser verificado quando o programa termina. A funo main deve
devolver o valor 0 (zero) se o programa termina normalmente ou um valor diferente de 0 (zero)
para indicar um trmino anormal. Por exemplo, quando uma seqncia de programas que
se comunicam entre si executada no sistema operacional LINUX, esse padro de valores
adotado e verificado nesse processo. No entanto, no h uma regra rgida para o uso do valor
devolvido pela funo main e, assim, podemos usar esse valor para qualquer propsito.
uma boa prtica de programao fazer com que todo programa na linguagem C devolva um
cdigo de estado, mesmo se no h planos de us-lo, j que um(a) usurio(a) pode decidir
verific-lo. o que vimos sempre fazendo na ltima sentena de nossas funes main , quando
escrevemos return 0; .
Executar a sentena return na funo main uma forma de terminar um programa.
Outra maneira chamar a funo exit que pertence biblioteca stdlib . O argumento
passado para exit tem o mesmo significado que o valor a ser devolvido por main , isto
, ambos indicam o estado do programa ao seu trmino. Para indicar um trmino normal,
passamos 0 (zero) como argumento, como abaixo:

exit(0);

Como o argumento 0 no muito significativo, a linguagem C nos permite usar o argumento EXIT_SUCCESS , que tem o mesmo efeito:
FACOM

UFMS

172

I NTRODUO

S FUNES

exit(EXIT_SUCCESS);

O argumento EXIT_FAILURE indica trmino anormal:

exit(EXIT_FAILURE);

EXIT_SUCCESS e EXIT_FAILURE so macros definidas na stdlib.h . Os valores associados


so definidos pela arquitetura do computador em uso, mas em geral so 0 e 1 , respectivamente.

Como mtodos para terminar um programa, return e exit so muito semelhantes. Ou


seja, a sentena

return expresso;

na funo main equivalente sentena

exit(expresso);

A diferena entre return e exit que exit causa o trmino de um programa independente do ponto em que se encontra essa chamada, isto , no considerando qual funo
chamou a funo exit . A sentena return causa o trmino de um programa apenas se
aparece na funo main . Alguns(mas) programadores(as) usam exit exclusivamente para
depurar programas. Depurao de programas um tpico importante para uma linguagem de
programao e teremos uma breve introduo ao assunto na aula 23.

17.4 Exemplo
Vamos resolver agora o seguinte problema:
Construa uma funo que receba dois inteiros positivos e devolva o mximo divisor
comum entre eles.
J resolvemos o problema de encontrar o mximo divisor comum entre dois nmeros inteiros positivos antes, usando o algoritmo de Euclides, mas com o uso de uma nica funo,
a funo ou programa principal. Agora, faremos uma funo que recebe esses dois nmeros e
devolve o mximo divisor comum. Uma possvel funo que soluciona o problema mostrada
a seguir.
FACOM

UFMS

17.4 E XEMPLO

173

/* Recebe dois nmeros inteiros e devolve


o mximo divisor comum entre eles */
int mdc(int a, int b)
{
int aux;
while (b != 0) {
aux = a % b;
a = b;
b = aux;
}
return a;
}

Um exemplo de um programa principal que faz uma chamada funo mdc descrita acima
mostrado no programa 17.4.

Programa 17.4: Exemplo de um programa com uma funo mdc .


#include <stdio.h>
/* Recebe dois nmeros inteiros e devolve
o mximo divisor comum entre eles */
int mdc(int a, int b)
{
int aux;
while (b != 0) {
aux = a % b;
a = b;
b = aux;
}
return a;
}
/* Recebe dois nmeros inteiros e mostra
o mximo divisor comum entre eles */
int main(void)
{
int x, y;
printf("Informe dois valores: ");
scanf("%d%d", &x, &y);
printf("O mdc entre %d e %d %d\n", x, y, mdc(x, y));
return 0;
}

FACOM

UFMS

174

I NTRODUO

S FUNES

17.5 Declarao de funes


Nos programas que vimos nas sees 17.1 e 17.4 a definio de cada funo sempre foi
feita acima do ponto onde ocorrem suas chamadas. Ou seja, se a funo main faz chamada
a uma funo escrita pelo programador, a definio dessa funo tem de ocorrer antes dessa
chamada, acima da prpria funo main . No entanto, a linguagem C na verdade no obriga
que a definio de uma funo preceda suas chamadas.
Suponha que rearranjamos o programa 17.1 colocando a definio da funo media depois
da definio da funo main , como abaixo:

#include <stdio.h>
/* Recebe trs valores reais e mostra a mdia aritmtica entre cada um dos 3 pares de nmeros fornecidos */
int main(void)
{
double x, y, z;
printf("Informe trs valores: ");
scanf("%lf%lf%lf", &x, &y, &z);
printf("Mdia de %g e %g %g\n", x, y, media(x, y));
printf("Mdia de %g e %g %g\n", x, z, media(x, z));
printf("Mdia de %g e %g %g\n", y, z, media(y, z));
return 0;
}
/* Recebe dois nmeros reais e devolve a mdia aritmtica entre eles */
double media(double a, double b)
{
return (a + b) / 2;
}

Quando o compilador encontra a primeira chamada da funo media na linha 7 da funo


main , ele no tem informao alguma sobre media : no conhece quantos parmetros media
tem, quais os tipos desses parmetros e qual o tipo do valor que media devolve. Ao invs de
uma mensagem de erro, o compilador faz uma tentativa de declarao, chamada de declarao
implcita, da funo media e, em geral, nos passos seguintes da compilao, um ou mais erros
decorrem dessa declarao: um erro do tipo do valor devolvido, do nmero de parmetros ou
do tipo de cada parmetro.
Uma forma de evitar erros de chamadas antes da definio de uma funo dispor o programa de maneira que a definio da funo preceda todas as suas chamadas. Infelizmente,
nem sempre possvel arranjar um programa dessa maneira e, mesmo quando possvel, pode
tornar mais difcil sua compreenso j que as definies das funes sero dispostas em uma
ordem pouco natural.
Felizmente, a linguagem C oferece uma soluo melhor, com a declarao de uma funo
antes de sua chamada. A declarao de uma funo fornece ao compilador uma viso inicial
FACOM

UFMS

17.5 D ECLARAO

175

DE FUNES

da funo cuja declarao completa ser dada posteriormente. A declarao de uma funo
composta exatamente pela primeira linha da definio de uma funo com um ponto e vrgula
adicionado no final:
tipo identificador(parmetros);

Desnecessrio dizer que a declarao de uma funo tem de ser consistente com a definio da mesma funo. A seguir mostramos como nosso programa ficaria com a adio da
declarao de media :

#include <stdio.h>
double media(double a, double b);

/* declarao */

/* Recebe trs valores reais e mostra a mdia aritmtica entre cada um dos 3 pares de nmeros fornecidos */
int main(void)
{
double x, y, z;
printf("Informe trs valores: ");
scanf("%lf%lf%lf", &x, &y, &z);
printf("Mdia de %g e %g %g\n", x, y, media(x, y));
printf("Mdia de %g e %g %g\n", x, z, media(x, z));
printf("Mdia de %g e %g %g\n", y, z, media(y, z));
return 0;
}
/* Recebe dois nmeros reais e devolve a mdia aritmtica entre eles */
double media(double a, double b)
/* definio */
{
return (a + b) / 2;
}

A declarao de uma funo tambm conhecida como prottipo da funo. Um prottipo de uma funo fornece ao compilador uma descrio completa de como chamar a funo:
quantos argumentos fornecer, de quais tipos esses argumentos devem ser e qual o tipo do resultado a ser devolvido.

Exerccios
17.1

(a) Escreva uma funo com a seguinte interface:


double area_triangulo(double base, double altura)

FACOM

UFMS

176

I NTRODUO

S FUNES

que receba dois nmeros de ponto flutuante que representam a base e a altura de
um tringulo e compute e devolva a rea desse tringulo.
(b) Escreva um programa que receba uma seqncia de n pares de nmeros de ponto
flutuante, onde cada par representa a base e a altura de um tringulo, e calcule e
escreva, para cada par, a rea do tringulo correspondente. Use a funo descrita no
item (a).
Programa 17.5: Soluo do exerccio 17.1.
#include <stdio.h>
/* Recebe a base e a altura, dois nmeros reais,
e devolve a rea do tringulo correspondente */
double area_triangulo(double base, double altura)
{
return (base * altura) / 2;
}
/* Recebe um nmero inteiro n > 0 e uma seqncia
de n pares de nmeros reais, base e altura de
um tringulo, e mostra a rea de cada tringulo */
int main(void)
{
int i, n;
double b, a;
printf("Informe n: ");
scanf("%d", &n);
for (i = 0; i < n;
printf("Informe
scanf("%lf%lf",
printf("rea do
}

i++) {
a base e a altura do tringulo: ");
&b, &a);
tringulo: %g\n", area_triangulo(b, a));

return 0;
}

17.2

(a) Escreva uma funo com a seguinte interface:


int mult(int a, int b)

que receba dois nmeros inteiros positivos a e b e determine e devolva um valor que
representa o produto desses nmeros, usando o seguinte mtodo de multiplicao:
i. dividir, sucessivamente, o primeiro nmero por 2, at que se obtenha 1 como
quociente;
ii. em paralelo, dobrar, sucessivamente, o segundo nmero;
iii. somar os nmeros da segunda coluna que tenham um nmero mpar na primeira coluna; o total obtido o produto procurado.
Por exemplo, para os nmeros 9 e 6, temos que 9 6
FACOM

UFMS

17.5 D ECLARAO
9
4
2
1

177

DE FUNES

6
12
24
48

48
54

(b) Escreva um programa que leia n > 1 pares de nmeros e calcule os respectivos
produtos desses pares, usando a funo do item (a).
17.3 Para determinar o nmero de lmpadas necessrias para cada aposento de uma residncia, existem normas que fornecem o mnimo de potncia de iluminao exigida por metro
quadrado (m2 ) conforme o uso desse ambiente. Suponha que s temos lmpadas de 60
watts para uso.
Seja a seguinte tabela de informaes sobre possveis aposentos de uma residncia:
Utilizao
quarto
sala de TV
salas
cozinha
varandas
escritrio
banheiro

Classe
1
1
2
2
2
3
3

Potncia/m2 (W)
15
15
18
18
18
20
20

(a) Escreva uma funo com a seguinte interface:


int num_lampadas(int classe, double a, double b)

que receba um nmero inteiro representando a classe de iluminao de um aposento


e dois nmeros com ponto flutuante representando suas duas dimenses e devolva
um nmero inteiro representando o nmero de lmpadas necessrias para iluminar
adequadamente o aposento.
(b) Escreva um programa que receba uma seqncia de informaes contendo o nome
do aposento da residncia, sua classe de iluminao e as suas dimenses e, usando
a funo num_lampadas , imprima a rea de cada aposento, sua potncia de iluminao e o nmero total de lmpadas necessrias para o aposento. Alm disso, seu
programa deve calcular o total de lmpadas necessrias e a potncia total necessria
para a residncia toda.
Suponha que o trmino se d quando o nome do aposento informado fim .
17.4

(a) Escreva uma funo com interface


int mdc(int a, int b)

que receba dois nmeros inteiros positivos a e b e calcule e devolva o mximo divisor
comum entre eles.
FACOM

UFMS

178

I NTRODUO

S FUNES

(b) Usando a funo do item anterior, escreva um programa que receba n > 1 nmeros
inteiros positivos e calcule o mximo divisor comum entre todos eles.
17.5

(a) Escreva uma funo com interface


int verifica_primo(int p)

que receba um nmero inteiro positivo p e verifique se p primo, devolvendo 1 em


caso positivo e 0 em caso negativo.
(b) Usando a funo do item anterior, escreva um programa que receba n > 1 nmeros
inteiros positivos e calcule a soma dos que so primos.
17.6 Um nmero inteiro a dito ser permutao de um nmero inteiro b se os dgitos de a
formam uma permutao dos dgitos de b.
Exemplo:
5412434 uma permutao de 4321445, mas no uma permutao de 4312455.
Observao: considere que o dgito 0 (zero) no ocorre nos nmeros.
(a) Escreva uma funo com interface
int conta_digitos(int n, int d)

que receba dois nmeros inteiros n e d, com 0 < d 6 9, devolva um valor que
representa o nmero de vezes que o dgito d ocorre no nmero n.
(b) Usando a funo do item anterior, escreva um programa que leia dois nmeros inteiros positivos a e b e responda se a permutao de b.
17.7

(a) Escreva uma funo com interface


int sufixo(int a, int b)

que receba dois nmeros inteiros a e b e verifique se b um sufixo de a. Em caso


positivo, a funo deve devolver 1; caso contrrio, a funo deve devolver 0.
Exemplo:
a
567890
1234
2457
457

b
890
1234
245
2457

sufixo
sufixo
no sufixo
no sufixo

(b) Usando a funo do item anterior, escreva um programa que leia dois nmeros inteiros a e b e verifique se o menor deles subseqncia do outro.
Exemplo:
FACOM

UFMS

17.5 D ECLARAO

179

DE FUNES

a
567890
1234
235

b
678
2212345
236

b subseqncia de a
a subseqncia de b
um no subseqncia do outro

17.8 Uma seqncia de n nmeros inteiros no nulos dita m-alternante se constituda por
m segmentos: o primeiro com um elemento, o segundo com dois elementos e assim por
diante at o m-simo, com m elementos. Alm disso, os elementos de um mesmo segmento devem ser todos pares ou todos mpares e para cada segmento, se seus elementos
forem todos pares (mpares), os elementos do segmento seguinte devem ser todos mpares (pares).
Por exemplo:
A seqncia com n = 10 elementos: 8 3 7 2 10 4 5 13 9 11 4-alternante.
A seqncia com n = 3 elementos: 7 2 8 2-alternante.

A seqncia com n = 8 elementos: 1 12 4 3 13 5 8 6 no alternante, pois o ltimo


segmento no tem tamanho 4.
(a) Escreva uma funo com interface
int bloco(int m)

que receba como parmetro um inteiro m e leia m nmeros inteiros, devolvendo um


dos seguintes valores:
0, se os m nmeros lidos forem pares;
1, se os m nmeros lidos forem mpares;
1, se entre os m nmeros lidos h nmeros com paridades diferentes.

(b) Usando a funo do item anterior, escreva um programa que, dados um inteiro n,
com n > 1, e uma seqncia de n nmeros inteiros, verifica se a seqncia malternante. O programa deve imprimir o valor de m ou exibir uma mensagem informando que a seqncia no alternante.

FACOM

UFMS

180

FACOM

I NTRODUO

S FUNES

UFMS

AULA

A RGUMENTOS

18

E PARMETROS DE
FUNES

Como vimos at aqui, a interface de uma funo define muito do que queremos saber sobre
ela: o tipo de valor que a funo devolve, seu identificador e seus parmetros. Isso implica na
conseqente elevao do nvel de abstrao dos nossos programas, j que podemos entender o
que um programa faz sem a necessidade de examinar os detalhes de suas funes. Caso alguns
detalhes sejam de nosso interesse, tambm h a vantagem de que sabemos onde examinlos. Nesta aula, baseada nas referncias [16, 15], focaremos nos argumentos e parmetros das
funes e no escopo de seus dados.

18.1 Argumentos e parmetros


Uma diferena importante entre um parmetro e um argumento deve ser destacada aqui.
Parmetros aparecem na definio de uma funo e so nomes que representam valores a serem
fornecidos quando a funo chamada. J os argumentos so expresses que aparecem nas
chamadas das funes.
Conceitualmente, existem trs tipos de parmetros:
de entrada, que permitem que valores sejam passados para a funo;
de sada, que permite que um valor seja devolvido da funo;
de entrada e sada, que permitem que valores sejam passados para a funo e devolvidos
da funo.
At o momento, entramos em contato com parmetros de entrada e parmetros de sada
nos programas que j fizemos. Os valores dos parmetros de entrada so passados para uma
funo atravs de um mecanismo denominado passagem por cpia ou passagem por valor.
Por exemplo, na chamada

x = quadrado(num);

o valor da expresso num um argumento da funo quadrado e atribudo ao parmetro


correspondente da funo. A passagem desse valor feita por cpia, ou seja, o valor copiado
no parmetro correspondente da funo quadrado .
181

182

A RGUMENTOS

E PARMETROS DE FUNES

J os valores dos parmetros de entrada e sada so passados/devolvidos por um mecanismo chamado referncia. Nesse caso, temos uma varivel especificada na chamada da funo e um parmetro especificado na interface da funo que compartilham a mesma rea de
armazenamento na memria e isso significa que qualquer alterao realizada no contedo do
parmetro dentro da funo acarreta alterao no contedo da varivel que o argumento da
chamada. Vejamos um exemplo no programa 18.1.

Programa 18.1: Exemplo de passagem de parmetros por referncia.


#include <stdio.h>
/* Recebe um nmero de ponto flutuante x e devolve sua parte inteira e sua parte fracionria */
void decompoe(float x, int *parte_int, float *parte_frac)
{
*parte_int = (int) x;
*parte_frac = x - *parte_int;
return;
}
/* Recebe um nmero de ponto flutuante e mostra na sada
o nmero, sua parte inteira e sua parte fracionria */
int main(void)
{
float num, b;
int a;
printf("Informe um nmero de ponto flutuante: ");
scanf("%f", &num);
decompoe(num, &a, &b);
printf("Nmero: %f\n", num);
printf("Parte inteira: %d\n", a);
printf("Parte fracionria: %f\n", b);
return 0;
}

Uma primeira observao importante sobre a interface da funo decompoe . Note que
os parmetros parte_int e parte_frac vem precedidos do smbolo * . Essa a forma
que definimos parmetros de entrada e sada na linguagem C. No corpo da funo decompoe ,
observe que os parmetros de entrada e sada so usados como de costume no corpo de uma
funo, isto , como vimos usando os parmetros de entrada. No entanto, os parmetros de
entrada e sada sempre devem vir precedidos pelo smbolo * no corpo de uma funo, como
mostrado acima. E por ltimo, a chamada da funo decompoe na funo main ligeiramente diferente. Observe que os argumentos a e b so precedidos pelo smbolo & , indicando
que as variveis a e b da funo main , de tipos inteiro e ponto flutuante respectivamente,
so passadas como parmetros de entrada e sada para a funo decompoe , ou seja, so passadas por referncia, e qualquer alterao realizada nos parmetros correspondentes da funo
refletiro nos argumentos da chamada.
FACOM

UFMS

18.2 E SCOPO

183

DE DADOS E DE FUNES

18.2 Escopo de dados e de funes


O escopo de uma funo e das variveis de uma funo o trecho, ou os trechos, de cdigo
em que a funo ou as variveis pode(m) ser acessada(s). Em particular, o escopo de uma
funo determina quais funes podem cham-la e quais ela pode chamar.
Variveis definidas internamente nas funes, bem como os parmetros de uma funo, so
chamadas de variveis locais da mesma, ou seja, o escopo dessas variveis circunscreve-se ao
trecho de cdigo definido pelo corpo da funo. Isso significa que elas so criadas durante a
execuo da funo, manipuladas e destrudas ao trmino de sua execuo, quando o comando
return encontrado.
As funes de um programa so organizadas por nveis. No primeiro nvel temos apenas a
funo principal main , aquela pela qual o programa ser iniciado. As funes que so chamadas pela funo main so ditas estarem no segundo nvel. No terceiro nvel esto as funes
que so chamadas pelas funes do segundo nvel. E assim sucessivamente. Veja a figura 18.1.
main

Figura 18.1: Um esquema de um programa contendo funes distribudas em trs nveis.

Exerccios
18.1

(a) Escreva uma funo com a seguinte interface:


void troca(int *a, int *b)

que receba dois nmeros inteiros a e b e troque os seus contedos.


(b) Usando a funo troca definida acima, escreva um programa que leia um nmero
inteiro n e um vetor contendo n nmeros inteiros, com 1 6 n 6 100, ordene seus
elementos em ordem crescente usando o mtodo das trocas sucessivas e imprima o
vetor resultante na sada.
(c) Repita a letra (b) implementando o mtodo da seleo.
(d) Repita a letra (b) implementando o mtodo da insero.
FACOM

UFMS

184

A RGUMENTOS

E PARMETROS DE FUNES

Programa 18.2: Soluo do exerccio 18.1(b).


#include <stdio.h>
#define MAX 100
/* Recebe dois nmeros inteiros a e b e devolve seus valores trocados */
void troca(int *a, int *b)
{
int aux;
aux = *a;
*a = *b;
*b = aux;
return;
}
/* Recebe um um nmero inteiro n, com 1 <= n <= 100, e uma seqncia
de n nmeros inteiros, e mostra essa seqncia em ordem crescente */
int main(void)
{
int i, j, n, A[MAX];
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d", &A[i]);
for (i = n-1; i > 0; i--)
for (j = 0; j < i; j++)
if (A[j] > A[j+1])
troca(&A[j], &A[j+1]);
for (i = 0; i < n; i++)
printf("%d ", A[i]);
printf("\n");
return 0;
}

18.2 Em um dado pas a moeda corrente possui apenas quatro cdulas de papel: $1, $5, $10 e
$20.
(a) Escreva uma funo com a seguinte interface:
void cedulas(int val, int *um, int *cin, int *dez, int *vin)

que receba um nmero no-negativo de ponto flutuante que representa um valor


em dinheiro e determine a menor quantidade de cdulas de 1, 5, 10 e 20 necessrias
para pagar o valor especificado.
(b) Escreva um programa que dado um nmero no-negativo de ponto flutuante que
representa um valor na moeda corrente determine a menor quantidade de cdulas
para pagar esse valor. Use a funo do item (a).
FACOM

UFMS

18.2 E SCOPO

185

DE DADOS E DE FUNES

18.3 Dizemos que um nmero natural n palndromo se lido da esquerda para direita e da
direita para esquerda o mesmo nmero.
Exemplos:
567765 palndromo.
32423 palndromo.
567675 no palndromo.
(a) Escreva uma funo com a seguinte interface:
void quebra(int n, int *prim, int *ult, int *miolo)

que receba um nmero inteiro n > 0 e devolva trs nmeros inteiros: o primeiro
dgito de n, o ltimo dgito de n e um inteiro que represente o nmero n sem seu
primeiro e ltimo dgitos.
Exemplo:
valor inicial de n
732
14738
78
7

primeiro dgito
7
1
7
7

ltimo dgito
2
8
8
7

miolo de n
3
473
0
0

(b) Usando a funo do item (a), escreva um programa que receba um nmero inteiro
n > 0 e verifique se n palndromo. Suponha que n no contm o dgito 0.
18.4

(a) Escreva uma funo com a seguinte interface:


int divisao(int *m, int *n, int d)

que receba trs nmeros inteiros positivos m, n e d e devolva 1 se d divide m, n ou


ambos, e 0, caso contrrio. Alm disso, em caso positivo, a funo deve devolver um
valor que representa o quociente da diviso de m por d e outro valor que representa
o quociente da diviso de n por d.
(b) Escreva um programa que leia dois nmeros inteiros positivos m e n e calcule,
usando a funo do item (a), o mnimo mltiplo comum entre m e n.
18.5

(a) Escreva uma funo com a seguinte interface:


int somabit(int b1, int b2, int *vaium)

que receba trs nmeros inteiros e devolva um nmero inteiro representando a soma
dos trs bits, e devolva tambm um outro valor do tipo inteiro representando o valor
do vai um.
(b) Escreva um programa que receba dois nmeros na base binria e, usando a funo
do item (a), calcule um nmero na base binria que a soma dos dois nmeros
dados.
FACOM

UFMS

186

FACOM

A RGUMENTOS

E PARMETROS DE FUNES

UFMS

AULA

F UNES

19

E VETORES

Nas aulas prticas e tericas vimos funes, argumentos de funes e passagem de parmetros para funes na linguagem C, onde trabalhamos apenas com argumentos de tipos bsicos.
Observe que chegamos a passar o valor de um elemento de um vetor como um argumento para
uma funo, por cpia e por referncia. Nesta aula veremos como realizar passagem de parmetros de tipos complexos, mais especificamente de parmetros que so variveis compostas
homogneas unidimensionais ou vetores. Esta aula baseada nas referncias [16, 15].

19.1 Vetores como argumentos de funes


Assim como fizemos com variveis de tipos bsicos, possvel passar um vetor todo como
argumento em uma chamada de uma funo. O parmetro correspondente deve ser um vetor
com a mesma dimenso. Vejamos um exemplo no programa 19.1.
Programa 19.1: Um programa com uma funo que tem um vetor como parmetro.
#include <stdio.h>
/* Recebe um vetor com 10 nmeros inteiros e devolve o menor deles */
int minimo(int A[10])
{
int i, min;
min = A[0];
for (i = 1; i < 10; i++)
if (A[i] < min)
min = A[i];
return min;
}
/* Recebe 10 nmeros inteiros e mostra o menor deles na sada */
int main(void)
{
int i, vet[10];
for (i = 0; i < 10; i++)
scanf("%d", &vet[i]);
printf("O menor valor do conjunto %d\n", minimo(vet));
return 0;
}

187

188

F UNES

E VETORES

Observe a interface da funo minimo do programa acima. Essa interface indica que a funo devolve um valor do tipo inteiro, tem identificador minimo e tem como seu argumento um
vetor contendo 10 elementos do tipo inteiro. Referncias feitas ao parmetro A , no interior da
funo minimo , acessam os elementos apropriados dentro do vetor que foi passado funo.
Para passar um vetor inteiro para uma funo necessrio apenas descrever o identificador
do vetor, sem qualquer referncia a ndices, na chamada da funo. Essa situao pode ser
visualizada na ltima linha do programa principal, na chamada da funo minimo(pontos) .
importante destacar tambm que a nica restrio de devoluo de uma funo relativa
s variveis compostas homogneas. De fato, um valor armazenado em uma varivel de qualquer tipo pode ser devolvido por uma funo, excluindo variveis compostas homogneas.

19.2 Vetores so parmetros passados por referncia


Nesta aula, o que temos visto at o momento so detalhes de como passar vetores como
parmetros para funes, detalhes na chamada e na interface de uma funo que usa vetores
como parmetros. No entanto, esses elementos por si s no so a principal peculiaridade dos
vetores neste contexto. Vejamos o programa 19.2.
Programa 19.2: Um vetor sempre um parmetro passado por referncia para uma funo.
#include <stdio.h>
/* Recebe um vetor com n nmeros inteiros e
devolve o vetor com seus valores dobrados */
void dobro(int vetor[100], int n)
{
int i;
for (i = 0; i < n; i++)
vetor[i] = vetor[i] * 2;
}
/* Recebe n nmeros inteiros, com 1 <= n <= 100, e mostra o dobro de cada um desses valores informados */
int main(void)
{
int i, n, valor[100];
printf("Informe a quantidade de elementos: ");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("Informe o %d-simo valor: ", i+1);
scanf("%d", &valor[i]);
}
dobro(valor, n);
printf("Resultado: ");
for (i = 0; i < n; i++)
printf("%d ", valor[i]);
printf("\n");
return 0;
}

FACOM

UFMS

19.3 V ETORES

COMO PARMETROS COM DIMENSES OMITIDAS

189

Perceba que a funo dobro do programa acima modifica os valores do vetor valor , uma
varivel local do programa principal que passada como parmetro para a funo dobro na
varivel vetor , uma varivel local da funo dobro . importante observar que, quando
usamos vetores como argumentos, uma funo que modifica o valor de um elemento do vetor, modifica tambm o vetor original que foi passado como parmetro para a funo. Esta
modificao tem efeito mesmo aps o trmino da execuo da funo.
Nesse sentido, podemos dizer que um vetor, uma matriz ou uma varivel composta homognea de qualquer dimenso sempre um parmetro de entrada e sada, isto , sempre
passado por referncia a uma funo.
No entanto, lembre-se que a modificao de elementos de um vetor em uma funo se
aplica somente quando o vetor completo passado como parmetro funo e no elementos
individuais do vetor. Esse ltimo caso j foi tratado em aulas anteriores.

19.3 Vetores como parmetros com dimenses omitidas


Na definio de uma funo, quando um de seus parmetros um vetor, seu tamanho
pode ser deixado sem especificao. Essa prtica de programao freqente e permite que
a funo torne-se ainda mais geral. Dessa forma, a funo dobro , por exemplo, definida na
seo anterior, poderia ser reescrita como a seguir:

/* Recebe um vetor com n nmeros inteiros e


devolve o vetor com seus valores dobrados */
void dobro(int vetor[], int n)
{
int i;
for (i = 0; i < n; i++)
vetor[i] = vetor[i] * 2;
return;
}

Observe que a dimenso do parmetro vetor da funo dobro , que um vetor, foi omitida. A duas definies da funo dobro , nesta seo e na seo anterior, so equivalentes. No
entanto, a definio com a dimenso omitida permite que a funo dobro possa ser chamada
com vetores de quaisquer dimenses como argumentos.
Por exemplo, se temos dois vetores de inteiros A e B, com dimenses 50 e 200, respectivamente, a funo dobro pode ser chamada para computar o dobro de cada coordenada do
vetor A e, do mesmo modo, tambm pode se chamada para computar o dobro de cada coordenada do vetor B. Ou seja, a funo dobro pode ser chamada com vetores de dimenses
diferentes como parmetros.

dobro(A, 50);
dobro(B, 200);

FACOM

UFMS

190

F UNES

E VETORES

Exerccios
19.1

(a) Escreva uma funo com a seguinte interface:


int subconjunto(int A[MAX], int m, int B[MAX], int n)

que receba como parmetros um vetor A de nmeros inteiros com m elementos e


um vetor B de nmeros inteiros com n elementos, ambos representando conjuntos,
e verifica se A est contido em B (A B).

(b) Escreva um programa que receba dois vetores de nmeros inteiros U e W , com u e
w elementos respectivamente, 1 6 u, w 6 100, e verifique se os dois conjuntos so
iguais (U = W se e somente se U W e W U ). Use a funo do item (a).
Programa 19.3: Soluo do exerccio 19.1.
#include <stdio.h>
#define MAX
100
#define VERDADEIRO 1
#define FALSO
0
/* Recebe um vetor A com m nmeros inteiros e um vetor B com
n nmeros inteiros e verifica se A est contido em B */
int subconjunto(int A[MAX], int m, int B[MAX], int n)
{
int i, j, contido;
contido = VERDADEIRO;
for (i = 0; i < m && contido; i++) {
for (j = 0; j < n && B[j] != A[i]; j++)
;
if (j == n)
contido = FALSO;
}
return contido;
}
/* Recebe dois conjuntos de nmeros inteiros e verifica se so iguais */
int main(void)
{
int tamU, i, U[MAX], tamW, j, W[MAX];
scanf("%d", &tamU);
for (i = 0; i < tamU; i++)
scanf("%d", &U[i]);
scanf("%d", &tamW);
for (j = 0; j < tamW; j++)
scanf("%d", &W[j]);
if (subconjunto(U, tamU, W, tamW) && subconjunto(W, tamW, U, tamU))
printf("U == W\n");
else
printf("U != W\n");
return 0;
}

FACOM

UFMS

19.3 V ETORES

COMO PARMETROS COM DIMENSES OMITIDAS

191

19.2 Em um programa na linguagem C, um conjunto pode ser representado por um vetor da


seguinte forma: V[0] contm o nmero de elementos do conjunto; V[1], V[2], ...
so os elementos do conjunto, sem repeties.
(a) Escreva uma funo com a seguinte interface:
void intersec(int A[MAX+1], int B[MAX+1], int C[MAX+1])

que dados dois conjuntos de nmeros inteiros A e B, construa um terceiro conjunto


C tal que C = A B. Lembre-se de que em C[0] a sua funo deve colocar o
tamanho da interseco.
(b) Escreva um programa que leia um nmero inteiro n > 2 e uma seqncia de n
conjuntos de nmeros inteiros, cada um com no mximo 100 elementos, e construa
e imprima um vetor que representa a interseco dos n conjuntos.
Observao: no leia todos os conjuntos de uma s vez. Leia os dois primeiros conjuntos e
calcule a primeira interseco. Depois, leia o prximo conjunto e calcule uma nova interseco entre esse conjunto lido e o conjunto da interseco anterior, e assim por diante.
19.3

(a) Escreva uma funo com a seguinte interface:


void ordena_insercao(int A[MAX], int m)

que receba um vetor A de m nmeros inteiros, com 1 6 m 6 100, e ordene os


elementos desse vetor em ordem crescente usando o mtodo da insero.
(b) Escreva uma funo com a seguinte interface:
void intercala(int A[MAX], int m, int B[MAX], int n,
int C[2*MAX], int *k)

que receba um vetor A de nmeros inteiros em ordem crescente de dimenso m e


um vetor B de nmeros inteiros em ordem crescente de dimenso m e compute um
vetor C contendo os elementos de A e de B sem repetio e em ordem crescente.
(c) Escreva um programa que receba dois conjuntos de nmeros inteiros e distintos X e
Y , com no mximo 100 elementos, ordene cada um deles usando a funo do item (a)
e intercale esses dois vetores usando a funo do item (b), obtendo como resultado
um vetor de nmeros inteiros em ordem crescente.

FACOM

UFMS

192

FACOM

F UNES

E VETORES

UFMS

AULA

F UNES

20

E MATRIZES

Na aula 19 vimos funes e vetores e destacamos como estas estruturas so tratadas de


forma diferenciada neste caso. Em especial, muito importante lembrar que vetores so sempre parmetros passados por referncia s funes na linguagem C. Como veremos adiante,
isso vale para qualquer varivel composta homognea, isto , para variveis compostas homogneas de qualquer dimenso. Esta aula baseada nas referncias [16, 15].

20.1 Matrizes
Um elemento de uma matriz pode ser passado como parmetro para uma funo assim
como fizemos com uma varivel de um tipo bsico ou como um elemento de um vetor. Ou
seja, a sentena

p = paridade(matriz[i][j]);

chama a funo paridade passando o valor contido em matriz[i][j] como um argumento


para a funo.
Uma matriz toda pode ser passada a uma funo da mesma forma que um vetor todo pode
ser passado, bastando listar o identificador da matriz. Por exemplo, se a matriz A declarada
como uma matriz bidimensional de nmeros inteiros, a sentena

multiplica_escalar(A, escalar);

pode ser usada para chamar uma funo que multiplica cada elemento de uma matriz A pelo
valor armazenado na varivel escalar . Assim como com vetores, uma modificao realizada
no corpo de uma funo sobre qualquer elemento de uma matriz que um parmetro dessa
funo provoca uma modificao no argumento da chamada da funo, ou seja, na matriz que
foi passada funo durante sua chamada.
O programa 20.1 recebe uma matriz A44 de nmeros inteiros e um escalar e realiza o
produto da matriz por esse escalar.
193

194

F UNES

E MATRIZES

Programa 20.1: Uma funo com um parmetro que uma matriz.


#include <stdio.h>
/* Recebe uma matriz de dimenso 4x4 de nmeros inteiros e um escalar e
devolve uma matriz resultante do produto entre a matriz e o escalar */
void multiplica_escalar(int A[4][4], int escalar)
{
int i, j;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
A[i][j] = A[i][j] * escalar;
}
/* Recebe uma traiz de dimenso 4x4 de nmeros
inteiros e mostra seu contedo na sada */
void imprime_matriz(int A[4][4])
{
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++)
printf("%3d ", A[i][j]);
printf("\n");
}
}
/* Recebe um nmero inteiro e uma matriz de dimenso 4x4
de nmeros inteiros e mostra a matriz de entrada e a
matriz resultante do produto desse nmero pela matriz */
int main(void)
{
int i, j, esc, matriz[4][4];
scanf("%d", &esc);
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
scanf("%d", &matriz[i][j]);
imprime_matriz(matriz);
multiplica_escalar(matriz, esc);
imprime_matriz(matriz);
return 0;
}

20.2 Matrizes como parmetros com uma dimenso omitida


Se um parmetro de uma funo uma varivel composta homognea k-dimensional, com
k > 2, ento somente o tamanho da primeira dimenso pode ser omitida quando o parmetro
declarado. Por exemplo, na funo multiplica_escalar da seo anterior, onde A um de
seus parmetros e uma matriz, o nmero de colunas de A deve ser espeficiado, embora seu
nmero de linhas no seja necessrio. Assim, na definio da funo, poderamos escrever:
FACOM

UFMS

20.2 M ATRIZES

COMO PARMETROS COM UMA DIMENSO OMITIDA

195

void multiplica_escalar(int A[][4], int escalar)

Exerccios
20.1

(a) Escreva uma funo com a seguinte interface:


void troca(int *a, int *b)

que receba dois nmeros inteiros a e b e troque os seus contedos.


(b) Usando a funo anterior, escreva um programa que receba uma matriz de nmeros
inteiros A, de dimenso m n, com 1 6 m, n 6 100, e dois nmeros inteiros i e j,
troque os contedos das linhas i e j da matriz A e imprima a matriz resultante.
Programa 20.2: Soluo do exerccio 20.1.
#include <stdio.h>
#define MAX 100
/* Recebe dois nmeros inteiros a e b e devolve esses valores trocados */
void troca(int *a, int *b)
{
int aux;
aux = *a;
*a = *b;
*b = aux;
}
/* Recebe uma matriz de dimenso mxn de nmeros inteiros
e os ndices i e j de duas linhas da matriz, troca o
contedo dessas linhas e mostra a matriz resultante */
int main(void)
{
int m, n, i, j, k, A[MAX][MAX];
scanf("%d%d", &m, &n);
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
scanf("%d", &A[i][j]);
scanf("%d%d", &i, &j);
for (k = 0; k < n; k++)
troca(&A[i][k], &A[j][k]);
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++)
printf("%d ", A[i][j]);
printf("\n");
}
return 0;
}

FACOM

UFMS

196

F UNES

E MATRIZES

20.2 A k-sima potncia de uma matriz quadrada Ann , denotada por Ak , a matriz obtida a
partir da matriz A da seguinte forma:
k

}|
{
z
Ak = In A A A ,

onde In a matriz identidade de ordem n.

Para facilitar a computao de Ak , podemos usar a seguinte frmula:



In ,
se k = 0 ,
k
A =
k1
A
A, se k > 0 .
(a) Escreva uma funo com a seguinte interface:
void identidade(int I[MAX][MAX], int n)

que receba uma matriz I e uma dimenso n e preencha essa matriz com os valores
da matriz identidade de ordem n.
(b) Escreva uma funo com a seguinte interface:
void multMat(int C[MAX][MAX], int A[MAX][MAX], int B[MAX][MAX], int n)

que receba as matrizes A, B e C, todas de ordem n, e compute C = A B.

(c) Escreva uma funo com a seguinte interface:

void copia(int A[MAX][MAX], int B[MAX][MAX], int n)

que receba as matrizes A e B de ordem n, e copie os elementos da matriz B na matriz


A.
(d) Escreva um programa que, usando as funes em (a) e (b), receba uma matriz de
nmeros inteiros A de dimenso n e um inteiro k e compute e imprima Ak .
20.3 Dizemos que uma matriz Ann um quadrado latino de ordem n se em cada linha e
em cada coluna aparecem todos os inteiros 1, 2, 3, . . . , n, ou seja, cada linha e coluna
permutao dos inteiros 1, 2, . . . , n.
Exemplo:

1
2

4
3

2
3
1
4

3
4
2
1

4
1

3
2

A matriz acima um quadrado latino de ordem 4.


(a) Escreva uma funo com a seguinte interface:
FACOM

UFMS

20.2 M ATRIZES

COMO PARMETROS COM UMA DIMENSO OMITIDA

197

int linha(int A[MAX][MAX], int n, int i)

que receba como parmetros uma matriz Ann de nmeros inteiros e um ndice i, e
verifique se na linha i de A ocorrem todos os nmeros inteiros de 1 a n, devolvendo
1 em caso positivo e 0 caso contrrio.
(b) Escreva uma funo com a seguinte interface:
int coluna(int A[MAX][MAX], int n, int j)

que receba como parmetros uma matriz Ann de nmeros inteiros e um ndice j, e
verifique se na coluna j de A ocorrem todos os nmeros inteiros de 1 a n, devolvendo
1 em caso positivo e 0 caso contrrio.
(c) Usando as funes dos itens (a) e (b), escreva um programa que verifique se uma
dada matriz Ann de nmeros inteiros, com 1 6 n 6 100, um quadrado latino de
ordem n.

FACOM

UFMS

198

FACOM

F UNES

E MATRIZES

UFMS

AULA

F UNES

21

E REGISTROS

J vimos funes com parmetros de tipos bsicos e de tipos complexos, como vetores e
matrizes. Nesta aula, aprenderemos como comportam-se os registros no contexto das funes.
Como veremos, um registro, diferentemente das variveis compostas homogneas, comportase como uma varivel de um tipo bsico qualquer quando trabalhamos com funes. Ou seja,
um registro comporta-se como qualquer outra varivel excluindo as compostas homogneas,
isto , um registro sempre um argumento passado por cpia a uma funo. Se quisermos
que um registro seja um argumento passado por referncia a uma funo, devemos explicitamente indicar essa opo usando o smbolo & no argumento e o smbolo * no parmetro
correspondente, como fazemos com variveis de tipos primitivos.
Esta aula baseada nas referncias [16, 15].

21.1 Tipo registro


Antes de estudar diretamente o funcionamento das funes com registros, precisamos
aprender algo mais sobre esses ltimos. Primeiro, importante notar que apesar das aulas
anteriores mostrarem como declarar variveis que so registros, no discutimos em detalhes
o que um tipo registro. Ento, suponha que um programa precisa declarar diversas variveis que so registros com mesmos campos. Se todas as variveis podem ser declaradas ao
mesmo tempo, no h problemas. Mas se for necessrio declarar essas variveis em diferentes
pontos do programa, ento temos uma situao mais complicada. Para super-la, precisamos
saber definir um nome que representa um tipo registro, no uma varivel registro particular.
A linguagem C fornece duas boas maneiras para realizar essa tarefa: declarar uma etiqueta de
registro ou usar typedef para criar um tipo registro.
Uma etiqueta de registro um nome usado para identificar um tipo particular de registro.
Essa etiqueta no reserva compartimentos na memria para armazenamento dos campos e do
registro, mas sim adiciona informaes a uma tabela usada pelo compilador para que variveis
registros possam ser declaradas a partir dessa etiqueta. A seguir temos a declarao de uma
etiqueta de registro com nome cadastro :

struct cadastro {
int codigo;
char nome[MAX+1];
int fone;
};

199

200

F UNES

E REGISTROS

Observe que o caractere ponto e vrgula ( ; ) segue o caractere fecha chaves } . O ; deve
estar presente neste ponto para terminar a declarao da etiqueta do registro.
Uma vez que criamos a etiqueta cadastro , podemos us-la para declarar variveis:

struct cadastro ficha1, ficha2;

Infelizmente, no podemos abreviar a declarao acima removendo a palavra reservada


struct , j que cadastro no o nome de um tipo. Isso significa que sem a palavra reservada
struct a declarao acima no tem sentido.

Tambm, a declarao de uma etiqueta de um registro pode ser combinada com a declarao de variveis registros, como mostrado a seguir:

struct cadastro {
int codigo;
char nome[MAX+1];
int fone;
} ficha1, ficha2;

Ou seja, acima temos a declarao da etiqueta de registro cadastro e a declarao de duas


variveis registros ficha1 e ficha2 . Todas as variveis registros declaradas com o tipo
struct cadastro so compatveis entre si e, portanto, podemos atribuir uma a outra sem
problemas, como mostramos abaixo:

struct cadastro ficha1 = {10032, "Sir Lancelot", 77165115};


struct cadastro ficha2;
ficha2 = ficha1;

Uma alternativa para declarao de etiquetas de registros o uso da palavra reservada


typedef para definir o nome de um tipo genuno. Por exemplo, poderamos definir um tipo
com nome Cadastro da seguinte forma:

typedef struct {
int codigo;
char nome[MAX+1];
int fone;
} Cadastro;

Observe que o nome do tipo, Cadastro , deve ocorrer no final, no aps a palavra reservada struct . Alm disso, como Cadastro um nome de um tipo definido por typedef ,
no permitido escrever struct Cadastro . Todas as variveis do tipo Cadastro so compatveis, desconsiderando onde foram declaradas. Assim, a declarao de registros com essa
definio pode ser dada como abaixo:
FACOM

UFMS

21.2 R EGISTROS

E PASSAGEM POR CPIA

201

Cadastro ficha1, ficha2;

Quando precisamos declarar um nome para um registro, podemos escolher entre declarar uma etiqueta de registro ou definir um tipo registro com a palavra reservada typedef .
Entretanto, em geral preferimos usar etiquetas de registros por diversos motivos que sero
justificados posteriormente.

21.2 Registros e passagem por cpia


O valor de um campo de um registro pode ser passado como argumento na chamada de
uma funo assim como fizemos com um valor associado a uma varivel de um tipo bsico ou
a uma clula de um vetor ou matriz. Ou seja, a sentena

x = raiz_quadrada(poligono.diagonal);

chama a funo raiz_quadrada com argumento poligono.diagonal , isto , com o valor


armazenado no campo diagonal do registro poligono .
Um registro todo pode ser argumento na chamada de funes da mesma forma que um
vetor ou uma matriz podem ser, bastando listar o identificador do registro. Por exemplo, se temos um registro tempo , contendo os campos hora , minutos e segundos , ento a sentena
a seguir:

s = total_segundos(tempo);

pode ser usada para chamar a funo totalSegundos que provavelmente calcula o total de
segundos de uma medida de tempo armazenada no registro tempo .
Diferentemente das variveis compostas homogneas, uma modificao realizada em qualquer campo de um registro que um parmetro de uma funo no provoca uma modificao no contedo do campo correspondente que um argumento da funo. Nesse caso, a
princpio, um argumento que um registro em uma chamada de uma funo tem o mesmo
comportamento de um argumento que uma varivel de um tipo bsico qualquer, ou seja,
uma expresso que um argumento de uma chamada de uma funo e que, na verdade ou
contm um registro, de fato um parmetro de entrada da funo, passado por cpia. Dessa
forma, voltamos a repetir que somente as variveis compostas homogneas tm um comportamento deferenciado na linguagem C, no que ser refere a argumentos e parmetros de funes
neste caso especfico.
Um exemplo com uma chamada de uma funo contendo um registro como argumento
mostrado no programa 21.1.
FACOM

UFMS

202

F UNES

E REGISTROS

Programa 21.1: Um programa com uma funo com parmetro do tipo registro.
#include <stdio.h>
struct
int
int
int
};

marca {
hh;
mm;
ss;

/* Recebe um registro marca que contm uma medida de tempo no formato


hh:mm:ss, converte essa medida em segundos e devolve esse valor */
int converte_segundos(struct marca tempo)
{
return tempo.hh * 3600 + tempo.mm * 60 + tempo.ss;
}
/* Recebe uma medida de tempo no formato hh:mm:ss e mostra a quantidade de segundos relativos esse tempo com referncia ao mesmo dia */
int main(void)
{
int segundos;
struct marca horario;
printf("Informe um horario (hh:mm:ss): ");
scanf("%d:%d:%d", &horario.hh, &horario.mm, &horario.ss);
segundos = converte_segundos(horario);
printf("Passaram-se %d segundo(s) neste dia\n", segundos);
return 0;
}

Devemos destacar pontos importantes neste programa. O primeiro, e talvez o mais importante, a definio da etiqueta de registro marca . Em nenhuma outra oportunidade anterior
havamos desenvolvido um programa que continha uma declarao de uma etiqueta de registro. Observe ainda que a declarao da etiqueta marca do programa 21.1 foi feita fora dos
corpos das funes converte_segundos e main . Em todos os programas descritos at aqui,
no temos um exemplo de uma declarao de uma etiqueta de registro, ou mesmo uma declarao de uma varivel de qualquer tipo, fora do corpo de qualquer funo. A declarao
da etiqueta marca realizada dessa maneira se deve ao fato que a mesma usada nas funes
converte_segundos e main , obrigando que essa declarao seja realizada globalmente, ou
seja, fora do corpo de qualquer funo. Todas as outras declaraes que fizemos so declaraes locais, isto , esto localizadas no interior de alguma funo.
Os outros pontos de destaque do programa 21.1 so todos relativos ao argumento da chamada da funo converte_segundos e do parmetro da mesma, descrito em sua interface.
Note que essa funo tem como parmetro o registro tempo do tipo struct marca . O argumento da funo, na chamada dentro da funo main o registro horario de mesmo tipo
struct marca .
FACOM

UFMS

21.3 R EGISTROS

E PASSAGEM POR REFERNCIA

203

Finalmente, importante repetir que a passagem de um registro para uma funo feita
por cpia, ou seja, o parmetro correspondente um parmetro de entrada e, por isso, qualquer
alterao realizada em um ou mais campos do registro dentro da funo no afeta o contedo
dos campos do registro que um argumento na sua chamada. No exemplo acima no h
alteraes nos campos do registro tempo no corpo da funo converte_segundos , mas, caso
houvesse, isso no afetaria qualquer um dos campos do registro horario da funo main .

21.3 Registros e passagem por referncia


Se precisamos de uma funo com um parmetro de entrada e sada, isto , um parmetro
passado por referncia, devemos fazer como usualmente fazemos com qualquer varivel de
um tipo bsico e usar os smbolos usuais & e * . O tratamento dos campos do registro em
questo tem uma peculiaridade que precisamos observar com cuidado e se refere ao uso do
smbolo * no parmetro passado por referncia no corpo da funo. Veja o programa 21.2.
Programa 21.2: Funo com um registro como parmetro de entrada e sada.
#include <stdio.h>
struct
int
int
int
};

marca {
hh;
mm;
ss;

/* Recebe um registro marca que contm uma medida de tempo no formato


hh:mm:ss e devolve o tempo neste registro atualizado em 1 segundo */
void adiciona_segundo(struct marca *tempo)
{
(*tempo).ss++;
if ((*tempo).ss == 60) {
(*tempo).ss = 0;
(*tempo).mm++;
if ((*tempo).mm == 60) {
(*tempo).mm = 0;
(*tempo).hh++;
if ((*tempo).hh == 24)
(*tempo).hh = 0;
}
}
}
/* Recebe uma medida de tempo (hh:mm:ss) e mostra o tempo atualizado em 1s */
int main(void)
{
struct marca horario;
printf("Informe um horario (hh:mm:ss): ");
scanf("%d:%d:%d", &horario.hh, &horario.mm, &horario.ss);
adiciona_segundo(&horario);
printf("Novo: %02d:%02d:%02d\n", horario.hh, horario.mm, horario.ss);
return 0;
}

FACOM

UFMS

204

F UNES

E REGISTROS

Uma observao importante sobre o programa 21.2 a forma como um registro que um
parmetro passado por referncia apresentado no corpo da funo. Como o smbolo . que
seleciona um campo de um registro tem prioridade sobre o smbolo * , que indica que o parmetro foi passado por referncia, os parnteses envolvendo o o smbolo * e o identificador do
registro so essenciais para evitar erros. Dessa forma, uma expresso envolvendo, por exemplo, o campo ss do registro tempo , escrita como *tempo.ss , est incorreta e no realiza a
seleo do campo do registro que tencionamos.
Alternativamente, podemos usar os smbolos -> para indicar o acesso a um campo de um
registro que foi passado por referncia a uma funo. O uso desse smbolo simplifica bastante
a escrita do corpo das funes que tm parmetros formais que so registros passados por
referncia. Dessa forma, o programa 21.2 pode ser reescrito como o programa 21.3. Observe
que esses dois programas tm a mesma finalidade, isto , dada uma entrada, realizam o mesmo
processamento e devolvem as mesmas sadas.
Programa 21.3: Uso do smbolo -> para registros passados por referncia.
#include <stdio.h>
struct
int
int
int
};

marca {
hh;
mm;
ss;

/* Recebe um registro marca que contm uma medida de tempo no formato


hh:mm:ss e devolve o tempo neste registro atualizado em 1 segundo */
void adiciona_segundo(struct marca *tempo)
{
tempo->ss++;
if (tempo->ss == 60) {
tempo->ss = 0;
tempo->mm++;
if (tempo->mm == 60) {
tempo->mm = 0;
tempo->hh++;
if (tempo->hh == 24)
tempo->hh = 0;
}
}
}
/* Recebe uma medida de tempo no formato hh:mm:ss
e mostra esse tempo atualizado em 1 segundo */
int main(void)
{
struct marca horario;
printf("Informe um horario (hh:mm:ss): ");
scanf("%d:%d:%d", &horario.hh, &horario.mm, &horario.ss);
adiciona_segundo(&horario);
printf("Novo horrio %02d:%02d:%02d\n", horario.hh, horario.mm, horario.ss);
return 0;
}

FACOM

UFMS

21.4 F UNES

QUE DEVOLVEM REGISTROS

205

Observe que o argumento passado por referncia para a funo adiciona_segundo


idntico nos programas 21.2 e 21.3. Mais que isso, a interface da funo adiciona_segundo
idntica nos dois casos e o parmetro declarado como struct marca *tempo . No corpo
desta funo do programa 21.3 que usamos o smbolo -> como uma abreviao, ou uma simplificao, da notao usada no corpo da funo adiciona_segundo do programa 21.2. Assim, por exemplo, a expresso (*tempo).ss no programa 21.2 reescrita como tempo->ss
no programa 21.3.

21.4 Funes que devolvem registros


Uma funo pode devolver valores de tipos bsicos, mas tambm pode devolver um valor
de um tipo complexo como um registro. Observe que variveis compostas homogneas, pelo
fato de sempre poderem ser argumentos que correspondem a parmetros de entrada e sada,
isto , de sempre poderem ser passadas por referncia, nunca so devolvidas explicitamente
por uma funo, atravs do comando return . O nico valor de um tipo complexo que podemos devolver um valor do tipo registro. Fazemos isso muitas vezes quando prorgramamos
para solucionar grandes problemas.
No problema da seo anterior, em que dado um horrio em um formato especfico e
queremos atualiz-lo em um segundo, usamos um registro como parmetro de entrada e sada
na funo adiciona_segundo . Por outro lado, podemos fazer com que a funo apenas receba uma varivel do tipo registro contendo um horrio como parmetro de entrada e devolva
um registro com o horrio atualizado como sada. Ou seja, teremos ento um parmetro de
entrada e um parmetro de sada que so registros distintos. Dessa forma, os programas 21.2
e 21.3 poderiam ser reescritos como no programa 21.4.
Observe que a interface da funo adiciona_segundo bastante diferente das definies
anteriores no programa 21.4. O tipo do valor devolvido o tipo struct marca uma etiqueta de um registro , indicando que a funo devolver um registro. O corpo dessa funo
tambm diferente das funes anteriores e h a declarao de uma varivel atualizado
do tipo struct marca que ao final conter o horrio do registro tempo , parmetro de entrada da funo, atualizado em um segundo. Na funo principal, a chamada da funo
adiciona_segundo tambm diferente, j que descrita do lado direito de uma instruo
de atribuio, indicando que o registro devolvido pela funo ser armazenado no registro
apresentado do lado esquerdo da atribuio: novo = adiciona_segundo(agora); .

FACOM

UFMS

206

F UNES

E REGISTROS

Programa 21.4: Um programa com uma funo que devolve um registro.


#include <stdio.h>
struct
int
int
int
};

marca {
hh;
mm;
ss;

/* Recebe um registro marca que contm uma medida de tempo no formato


hh:mm:ss e devolve um registro com tempo atualizado em 1 segundo */
struct marca adiciona_segundo(struct marca tempo)
{
struct marca atualizado;
atualizado.ss = tempo.ss + 1;
if (atualizado.ss == 60) {
atualizado.ss = 0;
atualizado.mm = tempo.mm + 1;
if (atualizado.mm == 60) {
atualizado.mm = 0;
atualizado.hh = tempo.hh + 1;
if (atualizado.hh == 24)
atualizado.hh = 0;
}
else
atualizado.hh = tempo.hh;
}
else {
atualizado.mm = tempo.mm;
atualizado.hh = tempo.hh;
}
return atualizado;
}
/* Recebe uma medida de tempo no formato hh:mm:ss
e mostra esse tempo atualizado em 1 segundo */
int main(void)
{
struct marca agora, novo;
printf("Informe um horario (hh:mm:ss): ");
scanf("%d:%d:%d", &agora.hh, &agora.mm, &agora.ss);
novo = adiciona_segundo(agora);
printf("Novo horrio %02d:%02d:%02d\n", novo.hh, novo.mm, novo.ss);
return 0;
}

FACOM

UFMS

21.4 F UNES

207

QUE DEVOLVEM REGISTROS

Exerccios
21.1

(a) Escreva uma funo com a seguinte interface:


int bissexto(struct data d)

que receba uma data no formato dd/mm/aaaa e verifique se o ano bissexto, devolvendo 1 em caso positivo e 0 caso contrrio. Um ano bissexto se divisvel por 4 e
no por 100 ou divisvel por 400.
(b) Escreva uma funo com a seguinte interface:
int dias_mes(struct data d)

que receba uma data e devolva o nmero de dias do ms em questo.


Exemplo:
Se a funo recebe a data 10/04/1992 deve devolver 30 e se recebe a data
20/02/2004 deve devolver 29 .
(c) Escreva uma funo com a seguinte interface:
struct data dia_seguinte(struct data d)

que receba uma data no formato dd/mm/aaaa e devolva a data que representa o dia
seguinte. Use as funes dos itens (a) e (b).
(d) Escreva um programa que receba uma data no formato dd/mm/aaaa e imprima a
data que representa o dia seguinte. Use as funes dos itens anteriores.
21.2 Reescreva a funo do item (c) do exerccio 21.1, de modo que a funo dia_seguinte
tenha o registro d como um parmetro de entrada e sada. Isto , a interface da funo
deve ser:
void dia_seguinte(struct data *d)

21.3

(a) Escreva uma funo com a seguinte interface:


struct tempo tempo_decorr(struct tempo t1, struct tempo t2)

que receba duas medidas de tempo no formato hh:mm:ss e calcule o tempo decorrido entre essas duas medidas de tempo. Tenha cuidado com um par de medidas de
tempo que cruzam a meia noite.
(b) Escreva um programa que receba dois horrios no formato hh:mm:ss e calcule o
tempo decorrido entre esses dois horrios. Use a funo anterior.

FACOM

UFMS

208

FACOM

F UNES

E REGISTROS

UFMS

AULA

B IBLIOTECA

22

PADRO

Nas ltimas aulas aprendemos a construir nossas prprias funes. Os benefcios dessa
prtica so muitos, como percebemos. Entre eles, podemos destacar abstrao, organizao e reaproveitamento de cdigo, por exemplo. Felizmente, no sempre que precisamos de um trecho de cdigo que realiza um determinado processamento que temos necessariamente de programar esse trecho, construindo uma funo. A linguagem C fornece
uma biblioteca padro de funes que nos ajuda em muitas tarefas importantes, desde funes de entrada e sada de dados, manipulao de cadeias de caracteres at funes matemticas. Nesta aula, veremos algumas funes importantes, destacando que muitas outras
no sero cobertas aqui. Os interessados em mais informaes devem buscar a pgina do
guia de referncia da biblioteca da linguagem C. Nesta aula, cobrimos com algum detalhe os
arquivos que contm definies de macros, tipos e os prottipos das funes da biblioteca
padro de funes da linguagem C. Esses arquivos so tambm conhecidos como arquivoscabealhos e tm extenso .h, do ingls header.
Iniciamos com uma viso sobre os qualificadores de tipos existentes na linguagem C, fundamentais especialmente na declarao de parmetros sensveis alterao, tais como os vetores
e as matrizes, que so sempre parmetros por referncia. Em seguida, definimos arquivoscabealhos para, por fim, cobrir os arquivos-cabealhos da biblioteca padro da linguagem C.
Esta aula um guia de referncia da biblioteca padro da linguagem C, suas constantes, tipos
e funes principais. Algumas funes, por serem muito especficas, no foram listadas aqui.
A aula baseada nas referncias [17, 16].

22.1 Qualificadores de tipos


Um qualificador de tipo fornece informao adicional sobre um tipo de uma varivel ao
compilador. Na linguagem C, um qualificador de tipo informa o compilador que a varivel,
ou as clulas de memria que so reservadas para seu uso, tem alguma propriedade especial,
a saber, um valor que no deve ser modificado pelo(a) programador(a) durante a execuo do
programa ou ainda um valor que potencialmente se modifica durante a execuo do programa
sem que haja controle do(a) programador(a) sobre o processo.
Os qualificadores de tipo const e volatile so, respectivamente, os dois qualificadores
da linguagem C que correspondem a essas descries. O segundo, por tratar de programao
de baixo nvel, ser omitido neste ponto. O qualificador de tipo const usado para declarar
objetos que se parecem com variveis mas so variveis apenas de leitura, isto , um programa pode acessar seu valor, mas no pode modific-lo. Por exemplo, a declarao abaixo:
209

210

B IBLIOTECA

PADRO

const int n = 10;

cria um objeto const do tipo int com identificador n cujo valor 10 . A declarao abaixo:

const int v[] = {71, 13, 67, 88, 4, 52};

cria um vetor const de nmeros inteiros e identificador v .


Muitas vantagens podem ser destacadas quando declaramos um objeto com o qualificador
de tipo const , como por exemplo a auto-documentao e a verificao pelo compilador de
tentativas de alterao desse objeto.
A primeira vista, pode parecer que o qualificador de tipo const tem o mesmo papel da
diretiva #define , que foi usada em aulas anteriores para definir nomes para constantes ou
macros. Existem diferenas significativas entre as duas, que so listadas abaixo:
podemos usar #define para criar um nome para uma constante numrica, caractere ou
cadeia de caracteres; por outro lado, podemos usar const para criar objetos somente
para leitura de qualquer tipo, incluindo vetores, estruturas, unies, apontadores, etc;
objetos criados com const esto sujeitos s mesmas regras de escopo de qualquer varivel, mas constantes criadas com #define no;
o valor de um objeto criado com const pode ser visto em um depurador de programas;
o valor de uma macro no pode;
objetos criados com const no podem ser usados em expresses constantes; as constantes criadas com #define podem;
podemos aplicar o operador de endereamento & sobre um objeto const , j que ele
possui um endereo; uma macro no tem um endereo.
No h uma regra bem definida que determina o uso de #define ou const na declarao de constantes. Em geral, usamos a diretiva #define mais especificamente para criar
constantes que representam nmeros ou caracteres.

22.2 Arquivo-cabealho
A diretiva #include ordena o pr-processador a abrir um arquivo especificado e a inserir seu contedo no arquivo atual. Assim, se queremos que vrios arquivos de cdigo fonte
tenham acesso mesma informao, devemos colocar essa informao em um arquivo e ento usar a diretiva #include para trazer o contedo do arquivo em cada arquivo de cdigo
fonte. Arquivos que so includos dessa forma so chamados de arquivos-cabealhos, do ingls header files ou tambm include files. Por conveno, um arquivo como esse tem a extenso
.h .
A diretiva #include pode ser usada de duas formas. A primeira forma usada para
arquivos-cabealhos que pertencem biblioteca padro da linguagem C:
FACOM

UFMS

22.2 A RQUIVO - CABEALHO

211

#include <arquivo.h>

A segunda forma usada para todos os outros arquivos-cabealhos, incluindo aqueles que
so escritos por programadores(as):

#include "arquivo.h"

A diferena entre as duas formas se d pela maneira como o compilador busca o arquivocabealho. Na primeira, o compilador busca o arquivo-cabealho no(s) diretrio(s) em que os
arquivos-cabealhos do sistema se encontram. Nos sistemas baseados no UNIX, como o LINUX,
os arquivos-cabealhos so mantidos usualmente no diretrio /usr/include . Na segunda
forma, a busca realizada no diretrio corrente e, em seguida, no(s) diretrio(s) em que os
arquivos-cabealhos do sistema se encontram.
Arquivos-cabealhos auxiliam no compartilhamento de definies de macros, de tipos e de
prottipos de funes por dois ou mais arquivos de cdigo fonte.
Abaixo apresentamos o arquivo-cabealho completo assert.h da biblioteca padro da
linguagem C.

/* Copyright (C) 1991,1992,1994-2001,2003,2004,2007


Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
*
*/

FACOM

ISO C99 Standard: 7.2 Diagnostics

<assert.h>

UFMS

212

B IBLIOTECA

PADRO

#ifdef _ASSERT_H
# undef _ASSERT_H
# undef assert
# undef __ASSERT_VOID_CAST
# ifdef __USE_GNU
# undef assert_perror
# endif
#endif /* assert.h

*/

#define _ASSERT_H
1
#include <features.h>
#if defined __cplusplus && __GNUC_PREREQ (2,95)
# define __ASSERT_VOID_CAST static_cast<void>
#else
# define __ASSERT_VOID_CAST (void)
#endif
/* void assert (int expression);
If NDEBUG is defined, do nothing.
If not, and EXPRESSION is zero, print an error message and abort.
#ifdef NDEBUG
# define assert(expr)

(__ASSERT_VOID_CAST (0))

/* void assert_perror (int errnum);


If NDEBUG is defined, do nothing. If not, and ERRNUM is not zero,
print an error message with the error text for ERRNUM and abort.
(This is a GNU extension.) */
# ifdef __USE_GNU
# define assert_perror(errnum)
# endif

(__ASSERT_VOID_CAST (0))

#else /* Not NDEBUG. */


#ifndef _ASSERT_H_DECLS
#define _ASSERT_H_DECLS
__BEGIN_DECLS
/* This prints an "Assertion failed"message and aborts. */
extern void __assert_fail (__const char *__assertion,
__const char *__file, unsigned int __line,
__const char *__function) __THROW __attribute__ ((__noreturn__));

FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

213

/* Likewise, but prints the error text for ERRNUM. */


extern void __assert_perror_fail (int __errnum, __const char *__file,
unsigned int __line, __const char *__function)
__THROW __attribute__ ((__noreturn__));
/* The following is not at all used here but needed for standard
compliance. */
extern void __assert (const char *__assertion, const char *__file,
int __line) __THROW __attribute__ ((__noreturn__));

__END_DECLS
#endif /* Not _ASSERT_H_DECLS */
# define assert(expr)
\
((expr)
\
? __ASSERT_VOID_CAST (0)
\
: __assert_fail (__STRING(expr), __FILE__, __LINE__,
__ASSERT_FUNCTION))
# ifdef __USE_GNU
# define assert_perror(errnum)
\
(!(errnum)
\
? __ASSERT_VOID_CAST (0)
\
: __assert_perror_fail ((errnum), __FILE__, __LINE__,
__ASSERT_FUNCTION))
# endif
/* Version 2.4 and later of GCC define a magical variable
__PRETTY_FUNCTION__ which contains the name of
the function currently being defined.
This is broken in G++ before version 2.6.
C9x has a similar variable called __func__, but prefer the GCC
one since it demangles C++ function names. */
# if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)
#
define __ASSERT_FUNCTION
__PRETTY_FUNCTION__
# else
#
if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#
define __ASSERT_FUNCTION
__func__
#
else
#
define __ASSERT_FUNCTION
((__const char *) 0)
#
endif
# endif
#endif /* NDEBUG. */

22.3 Arquivos-cabealhos da biblioteca padro


22.3.1 Diagnsticos
assert.h o arquivo-cabealho que contm informaes sobre a biblioteca de diagnsticos. Contm uma nica macro, assert , que permite aos programadores inserirem pontos de
FACOM

UFMS

214

B IBLIOTECA

PADRO

verificao nos programas. Se uma verificao falha, o programa termina sua execuo.
No exemplo de trecho de cdigo a seguir, a macro assert monitora o valor do ndice i do
vetor v. Se esse valor no est no intervalo especificado, o programa terminado.

assert(0 <= i && i <= 9);


v[i] = 0;

22.3.2 Manipulao, teste e converso de caracteres


A biblioteca de manipulao, teste e converso de caracteres pode ser acessada atravs das
informaes contidas no arquivo-cabealho ctype.h.
Funes is...
Uma funo cujo prottipo se encontra no arquivo-cabealho ctype.h com identificador
da forma is... verifica alguma propriedade de um caractere, argumento na chamada da
funo, e devolve um valor diferente de zero, indicando verdadeiro, isto , que o caractere
tem a propriedade, ou um valor igual a zero, indicando falso ou que o caractere no possui a
propriedade.
Listamos abaixo as interfaces das funes da forma is... em ctype.h, acompanhadas de
explicaes:
int isalnum(int c)

Devolve verdadeiro se o contedo do parmetro c uma letra (de A a Z ou de a a


z) ou um dgito (de 0 a 9);
int isalpha(int c)

Devolve verdadeiro se o contedo do parmetro c uma letra (de A a Z ou de a a


z);
int iscntrl(int c)

Devolve verdadeiro se o contedo do parmetro c um caractere de controle (de 0 a 31


ou 127);
int isdigit(int c)

Devolve verdadeiro se o contedo do parmetro c um dgito (de 0 a 9);

FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

215

int isgraph(int c)

Devolve verdadeiro se o contedo do parmetro c um caractere imprimvel, exceto o


espao em branco, isto , caracteres 33 a 126);
int islower(int c)

Devolve verdadeiro se o contedo do parmetro c uma letra minscula (de a a z);


int isprint(int c)

Devolve verdadeiro se o contedo do parmetro c um caractere imprimvel, isto ,


caracteres de 32 a 126;
int ispunct(int c)

Devolve verdadeiro se o contedo do parmetro c um caractere de pontuao;


int isspace(int c)

Devolve verdadeiro se o contedo do parmetro c um branco (whitespace);


int isupper(int c)

Devolve verdadeiro se o contedo do parmetro c uma letra maiscula (de A a Z);


int isxdigit(int c)

Devolve verdadeiro se o contedo do parmetro c um dgito em hexadecimal (de 0 a


9, ou de a a f, ou ainda de A a F).
Funes to...
Uma funo em ctype.h com identificador da forma to... faz a converso de um caractere. Se o caractere atende a uma condio, ento convertido. Caso contrrio, o caractere
devolvido sem modificaes.
Listamos abaixo as interfaces das funes da forma to... em ctype.h, acompanhadas de
explicaes:
int tolower(int c)

Se o parmetro c uma letra maiscula (de A a Z), ento o caractere convertido


para uma letra minscula e devolvido;
int toupper(int c)

Se o parmetro c uma letra minscula (de a a z), ento o caractere convertido


para uma letra maiscula e devolvido.

22.3.3 Erros
A biblioteca de monitoramento de erros pode ser acessada por meio do arquivo-cabealho
errno.h. Algumas funes da biblioteca padro da linguagem C indicam ocorrncia de uma
falha atravs do armazenamento de um cdigo de erro, um nmero inteiro positivo, em
errno , uma varivel do tipo int declarada em errno.h. O trecho de cdigo a seguir mostra
o uso da varivel errno :
FACOM

UFMS

216

B IBLIOTECA

PADRO

errno = 0;
y = sqrt(x);
if (errno != 0)
exit(EXIT_FAILURE);

Nesse trecho de cdigo, observe que inicializamos a varivel errno declarada na biblioteca
errno.h. Se o valor dessa varivel diferente de zero aps a execuo da funo sqrt , isso
significa que um erro ocorreu em sua execuo, como por exemplo, quando o valor de x
negativo.
O valor armazenado na varivel errno , em geral, EDOM ou ERANGE , ambas macros
definidas em errno.h. Essas macros representam os dois tipos de erros que podem ocorrer
quando uma funo matemtica chamada: erro de domnio ou erro de intervalo, respectivamente. No exemplo acima, se x tem valor negativo, ento o valor de EDOM armazenado na
varivel errno . Por outro lado, se o valor devolvido por uma funo muito grande, ultrapassando a capacidade de representao do tipo do valor a ser devolvido pela funo, ento
o valor ERANGE armazenado em errno . Por exemplo, se 1000 argumento da funo exp,
ento isso provoca um erro de intervalo j que e1000 muito grande para ser representado por
um double .

22.3.4 Caractersticas dos tipos com ponto flutuante


Caractersticas dos tipos com ponto flutuante podem ser obtidas atravs da incluso do
arquivo-cabealho float.h. Esse arquivo fornece apenas macros que definem o intervalo e a
preciso dos tipos float , double e long double . No h variveis, tipos ou funes em
float.h.
Duas macros se aplicam a todos os tipos de ponto flutuante: FLT_ROUNDS e FLT_RADIX .
A primeira descreve a direo do arredondamento. A segunda especifica o comprimento da
representao do expoente.
As macros restantes descrevem as caractersticas dos tipos especficos de ponto flutuante.

22.3.5 Localizao
locale.h o arquivo-cabealho que contm as informaes da biblioteca de funes que
ajudam um programa a adaptar seu comportamento a um pas ou a uma regio geogrfica.
O comportamento especfico de um local inclui a forma como os nmeros so impressos, o
formato dos valores monetrios, o conjunto de caracteres e a aparncia da data e da hora.

Com a mudana de um local, um programa pode adaptar seu comportamento para uma
rea diferente do mundo. Mas essa mudana pode afetar muitas partes da biblioteca, algumas
das quais podemos preferir no alterar.

Constantes
Podemos usar uma das macros a seguir para especificar uma categoria:
FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

217

DA BIBLIOTECA PADRO

LC_COLLATE

Afeta o comportamento de duas funes de comparao de cadeias de caractere: strcoll


e strxfrm, ambas declaradas em string.h;
LC_CTYPE

Afeta o comportamento das funes em ctype.h, a menos de isdigit e isxdigit.


LC_MONETARY

Afeta a informao de formato monetrio devolvida pela funo localeconv, descrita


na prxima seo;
LC_NUMERIC

Afeta o caractere separador de decimais usado nas funes de formatao de entrada e


sada e as funes de converso numrica;
LC_TIME

Afeta o comportamento da funo strftime declarada em time.h, que converte um


horrio em uma cadeia de caracteres.

Funes
Duas funes so declaradas nesta biblioteca:
char *setlocale(int category, const char *locale)

Altera o local atual para uma nica categoria ou para todas. Se o primeiro argumento
uma das macros definidas na seo anterior, uma chamada a esta funo afeta apenas
uma categoria. Se o primeiro argumento LC_ALL , a chamada afeta todas as categorias.
A linguagem C padro define apenas dois valores para o segundo argumento: "C" e "".
O primeiro o padro e, por exemplo, o separador decimal um ponto. Se o segundo argumento especificado ento as funes da biblioteca comportam-se como local nativo
e permitem que o programa adapte seu comportamento para o ambiente local.
struct lconv *localeconv(void)

Devolve um apontador para um registro do tipo struct lconv. Os campos desse registro contm informaes detalhadas sobe o local atual.

22.3.6 Matemtica
A biblioteca matemtica da linguagem C pode ser acessada atravs do arquivo-cabealho
math.h, que contm os prottipos de diversas funes matemticas teis, agrupadas em fun-

es trigonomtricas, funes logartmicas, de exponenciao e de potenciao, alm de outras


funes.
Quando inclumos o arquivo-cabealho math.h em um programa e usamos suas funes,
importante destacar que h necessidade de adicionar a diretiva de compilao -lm no processo de compilao deste programa, na chamada do gcc . Caso contrrio, um erro de compilao ser emitido pelo compilador da linguagem C.
FACOM

UFMS

218

B IBLIOTECA

PADRO

Constantes
Uma nica macro definida neste arquivo-cabealho: HUGE_VAL . Essa macro indica que
o valor devolvido por uma funo muito grande para ser representado como um nmero de
preciso dupla. HUGE_VAL do tipo double e pode ser entendido como infinito.
Erros
Todas as funes da biblioteca matemtica da linguagem C manipulam erros de forma similar. No caso em que o argumento passado funo excede o intervalo permitido, ento a
varivel errno recebe o valor EDOM . O valor devolvido pela funo depende da mquina. No
caso do valor devolvido ser muito grande para ser representado como um nmero de preciso
dupla, ento a funo devolve a macro HUGE_VAL e atualiza a varivel errno para ERANGE .
Se o valor muito pequeno para ser representado como um nmero de preciso dupla, ento
a funo devolve zero. Nesse caso, se a varivel errno recebe ERANGE ou no uma deciso
dependente da mquina.
Funes trigonomtricas
Listamos abaixo as interfaces das funes trigonomtricas no arquivo-cabealho math.h,
acompanhadas de explicaes:
double cos(double x)

Devolve o cosseno de um ngulo x dado em radianos. O valor devolvido est no intervalo


[1, +1];
double sin(double x)

Devolve o seno de um ngulo x dado em radianos. O valor devolvido est no intervalo


[1, +1];
double tan(double x)

Devolve a tangente de um ngulo x dado em radianos;


double acos(double x)

Devolve o arco-cosseno de x em radianos. O valor de x deve estar no intervalo [1, +1].


O valor devolvido est no intervalo [0, ];
double asin(double x)

Devolve o arco-seno de x em radianos. O valor de x deve estar no intervalo [1, +1]. O


valor devolvido est no intervalo [/2, +/2];
double atan(double x)

Devolve o arco-tangente de x em radianos.


[/2, +/2];

O valor devolvido est no intervalo

double atan2(double y, double x)

Devolve o arco-tangente em radianos de y/x baseado nos sinais de ambos os valores para
determinar o quadrante correto. O valor devolvido est no intervalo [/2, /2];
FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

219

double cosh(double x)

Devolve o cosseno hiperblico de x;


double sinh(double x)

Devolve o seno hiperblico de x;


double tanh(double x)

Devolve a tangente hiperblica de x. O valor devolvido est no intervalo [1, +1].


Funes logartmicas, de exponenciao e de potenciao
Listamos abaixo as interfaces das funes logartmicas, de exponenciao e de potenciao
em math.h, acompanhadas de explicaes:
double exp(double x)

Devolve o valor de e elevado x-sima potncia;


double frexp(double x, int *expoente)

O nmero com ponto flutuante x subdividido em uma mantissa e um expoente. O valor


devolvido pela funo a mantissa e o parmetro de entrada e sada expoente contm o
expoente. Observe que
x = matissa 2expoente .
A mantissa deve estar no intervalo [0.5, 1.0].
double ldexp(double x, int expoente)

Devolve x multiplicado por 2 elevado potncia expoente, isto , x 2expoente .


double log(double x)

Devolve o logaritmo natural de x, isto , o logaritmo na base e;


double log10(double x)

Devolve o logaritmo de x na base 10;


double modf(double x, double *inteiro)

Subdivide o nmero com ponto flutuante x nas partes inteira e fracionria. O valor devolvido pela funo a parte fracionria, depois do ponto decimal, e o parmetro de entrada
e sada inteiro contm a parte inteira de x;
double pow(double x, double y)

Devolve x elevado potncia y. O valor de x no pode ser negativo se y um valor


fracionrio. x no pode ser zero se y menor ou igual a zero.
double sqrt(double x)

Devolve a raiz quadrada de x. O valor armazenado em x no pode ser negativo.


FACOM

UFMS

220

B IBLIOTECA

PADRO

Outras funes
Listamos abaixo as interfaces de outras funes matemticas em math.h, acompanhadas de
explicaes:
double ceil(double x)

Devolve o menor inteiro que maior ou igual a x;


double floor(double x)

Devolve o maior inteiro que menor ou igual a x;


double fabs(double x)

Devolve o valor absoluto de x. Isto , se x um valor negativo, a funo devolve o valor


positivo. Caso contrrio, devolve o valor de x;
double fmod(double x, double y)

Devolve o resto de x dividido por y. O valor de y deve ser diferente de zero.

22.3.7 Saltos no-locais


setjmp.h o arquivo-cabealho que contm informaes sobre saltos no-locais de baixo
nvel para controle de chamadas de funes e desvio de fluxo de execuo das mesmas. Duas
funes constam desta biblioteca, uma delas que marca um ponto no programa e outra que
pode ser usada para fazer com que o programa tenha seu fluxo de execuo desviado para
um dos pontos marcados. Isso significa que possvel, com o uso das funes desta biblioteca,
uma funo saltar diretamente para uma outra funo sem que tenha encontrado uma sentena
return . Esses recursos so usados especialmente para depurao de erros.

O tipo typedef jmp_buf definido nesta biblioteca. Uma varivel desse tipo armazena as
informaes atuais do ambiente, para uso posterior nas funes da biblioteca.
As duas funes desta biblioteca so listadas abaixo:
int setjmp(jmp_buf amb)

Armazena o ambiente na varivel amb . Se um valor diferente de zero devolvido, ento


isso indica que o ponto exato neste cdigo foi alcanado por uma chamada funo
longjmp . Caso contrrio, zero devolvido indicando que o ambiente foi armazenado
na varivel.
void longjmp(jmp_buf amb, int valor)

O ambiente armazenado na varivel amb por uma chamada prvia funo setjmp
recuperado. Uma salto ao ponto onde setjmp foi chamada realizado, e o contedo
armazenado em valor devolvido setjmp . Esse valor deve ser um nmero inteiro
diferente de zero.
FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

221

22.3.8 Manipulao de sinais


Arquivo-cabealho signal.h que contm informaes sobre a biblioteca de manipulao
de sinais signal.h. Contm funes que tratam de condies excepcionais, incluindo interrupes e erros de tempo de execuo. Alguns sinais so assncronos e podem acontecer a
qualquer instante durante a execuo de um programa, no apenas em certos pontos do cdigos que so conhecidos pelo programador.

Constantes e variveis
O tipo sig_atomic_t , na verdade um apelido para o tipo int , usado para declarao
de variveis que manipulam erros.
As macros com identificadores iniciando com SIG_ so usadas com a funo signal :
SIG_DFL

Manipulador de erros padro;


SIG_ERR

Sinal de erro;
SIG_IGN

Ignora sinal.
As macros com identificadores iniciando com SIG so usadas para representar um nmero
de sinal:
SIGABRT

Trmino anormal gerado pela funo abort ;


SIGFPE

Erro de ponto flutuante, causado por diviso por zero, operao no vlida, etc;
SIGILL

Operao ilegal;
SIGINT

Sinal de ateno interativo, tal como um Ctrl-c ;


SIGSEGV

Acesso no vlido a uma poro de memria, tal como violao de segmento ou violao
de memria;
SIGTERM

Requisio de trmino.
FACOM

UFMS

222

B IBLIOTECA

PADRO

Funes
void (*signal(int sinal, void (*func)(int)))(int)

Controla como um sinal manipulado. O parmetro sinal representa o nmero do


sinal compatvel com as macros SIG . func a funo a ser chamada quando o sinal
ocorre. A funo deve ter um argumento do tipo int que representa o nmero do sinal.
int raise(int sinal)

Faz com que o sinal sinal seja gerado. O argumento sinal compatvel com as macros SIG .

22.3.9 Nmero varivel de argumentos


Biblioteca de ferramentas para tratamento de funes que possuem um nmero varivel
de argumentos acessada pelo arquivo-cabealho stdarg.h. Funes como printf e scanf
permitem um nmero varivel de argumentos e programadores tambm podem construir suas
prprias funes com essa caracterstica.

22.3.10 Definies comuns


O arquivo-cabealho stddef.h contm informaes sobre definies de tipos e macros que
so usadas com freqncia nos programas. No h funes declaradas neste arquivo.

22.3.11 Entrada e sada


A biblioteca padro de entrada e sada da linguagem C acessada atravs do arquivocabealho stdio.h e contm tipos, macros e funes para efetuar entrada e sada de dados,
incluindo operaes sobre arquivos. Listamos a seguir apenas alguns desses elementos.
Entrada e sada formatadas
Listamos abaixo as interfaces das funes de entrada e sada formatadas em stdio.h, acompanhadas de explicaes:
int printf(const char *formato, ...)

Imprime informaes na sada padro, tomando uma cadeia de caracteres de formatao


especificada pelo argumento formato e aplica para cada argumento subseqente o especificador de converso na cadeia de caracteres de formatao, da esquerda para direita.
Veja as aulas tericas Veja a aula 11 para informaes sobre especificadores de converso.
O nmero de caracteres impressos na sada padro devolvido. Se um erro ocorreu na
chamada da funo, ento o valor 1 devolvido.
int scanf(const char *formato, ...)

L dados de uma forma que especificada pelo argumento formato e e armazenada


cada valor lido nos argumentos subseqentes, da esquerda para direita. Cada entrada
FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

223

formatada definida na cadeia de caracteres de formatao, atravs de um especificador


de converso precedido pelo smbolo % que especifica como uma entrada deve ser armazenada na varivel respectiva. Outros caracteres listados na cadeia de caracteres de
formatao especificam caracteres que devem corresponder na entrada mas no armazenados nos argumentos da funo. Um branco pode corresponder a qualquer outro branco
ou ao prximo caractere incompatvel. Mais informaes sobre entrada formatada, veja a
aula 11.
Se a execuo da funo obteve sucesso, o nmero de valores lidos, convertidos e armazenados nas variveis devolvido.
Entrada e sada de caracteres
Listamos abaixo as interfaces das funes de entrada e sada de caracteres em stdio.h,
acompanhadas de explicaes:
int getchar(void)

L um caractere (um unsigned char) da entrada padro. Se a leitura tem sucesso, o


caractere devolvido;
int putchar(int caractere)

Imprime um caractere (um unsigned char) especificado pelo argumento caractere na


sada padro. Se a impresso tem sucesso, o caractere devolvido.

22.3.12 Utilitrios gerais


A biblioteca de utilitrios gerais da linguagem C pode ser acessada pelo arquivo-cabealho
stdlib.h. uma miscelnea de definies de tipos, macros e funes que no se encaixam nos

outros arquivos-cabealhos.
Constantes
Listamos abaixo as macros definidas em stdlib.h, acompanhadas de explicaes:
NULL

Valor de um apontador nulo;


EXIT_FAILURE e EXIT_SUCCESS

Valores usados pela funo exit para devolver o estado do trmino da execuo de um
programa;
RAND_MAX

Valor mximo devolvido pela funo rand .


FACOM

UFMS

224

B IBLIOTECA

PADRO

Funes sobre cadeias de caracteres


Listamos abaixo as interfaces das funes de cadeias de caracteres em stdlib.h, acompanhadas de explicaes:
double atof(const char *cadeia)

A cadeia de caracteres cadeia convertida e devolvida como um nmero de ponto


flutuante do tipo double . Brancos iniciais so ignorados. O nmero pode conter um
sinal opcional, uma seqncia de dgitos com um caractere de ponto decimal opcional,
mais uma letra e ou E opcional seguida por um expoente opcionalmente sinalizado. A
converso pra quando o primeiro caractere no reconhecvel encontrado.
Se a converso foi realizada com sucesso, o nmero devolvido. Caso contrrio, zero
devolvido;
int atoi(const char *cadeia)

A cadeia de caracteres cadeia convertida e devolvida como um nmero inteiro do tipo


int . Bancos iniciais so ignorados. O nmero pode conter um sinal opcional, mais uma
seqncia de dgitos. A converso pra quando o primeiro caractere no reconhecvel
encontrado.
Se a converso foi realizada com sucesso, o nmero devolvido. Caso contrrio, zero
devolvido;
long int atol(const char *cadeia)

A cadeia de caracteres cadeia convertida e devolvida como um nmero inteiro do


tipo long int . Brancos iniciais so ignorados. O nmero pode conter um sinal opcional, mais uma seqncia de dgitos. A converso pra quando o primeiro caractere no
reconhecvel encontrado.
Se a converso foi realizada com sucesso, o nmero devolvido. Caso contrrio, zero
devolvido.
Funes de ambiente
Listamos abaixo as interfaces das funes de ambiente em stdlib.h, acompanhadas de
explicaes:
void abort(void)

Finaliza o programa anormalmente, sinalizando o trmino sem sucesso para o ambiente;


void exit(int estado)

Finaliza o programa normalmente, sinalizando para o ambiente o valor armazenado em


estado , que pode ser EXIT_FAILURE ou EXIT_SUCCESS .
Funes matemticas
Listamos abaixo as interfaces das funes matemticas em stdlib.h, acompanhadas de
explicaes:
FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

225

int abs(int x)

Devolve o valor absoluto de x ;


long int labs(long int x)

Devolve o valor absoluto de x ;


int rand(void)

Devolve um nmero pseudo-aleatrio no intervalo [0, RAND_MAX ];


void srand(unsigned int semente)

Inicializa o gerador de nmero pseudo-aleatrios usado pela funo rand . Inicializar


srand com o mesmo valor de semente faz com que a funo rand devolva a mesma
seqncia de nmeros pseudo-aleatrios. Se srand no for executada, rand age como
se srand(1) tivesse sido executada.

22.3.13 Manipulao de cadeias


A biblioteca de manipulao de cadeias de caracteres pode ser acessada atravs do arquivocabealho string.h.
Constantes e tipos
A macro NULL definida em string.h, para denotar uma cadeia de caracteres vazia, assim
como o tipo typedef size_t, que permite a manipulao de variveis que contm comprimentos de cadeias de caracteres. Ou seja, esse tipo na verdade um tipo int .
Funes
Listamos abaixo as principais funes em string.h, acompanhadas de explicaes:
char *strcat(char *cadeia1, const char *cadeia2)

Concatena a cadeia de caracteres cadeia2 no final da cadeia de caracteres cadeia1 .


O caractere nulo \0 da cadeia1 sobrescrito. A concatenao termina quando o
caractere nulo da cadeia2 copiado. Devolve um apontador para a cadeia1 ;
char *strncat(char *cadeia1, const char *cadeia2, size_t n)

Concatena at n caracteres da cadeia de caracteres cadeia2 no final da cadeia de caracteres cadeia1 . O caractere nulo \0 da cadeia1 sobrescrito. O caractere nulo
sempre adicionado na cadeia1 . Devolve um apontador para a cadeia1 ;
int strcmp(const char *cadeia1, const char *cadeia2)

Compara as cadeias de caracteres cadeia1 e cadeia2 . Devolve zero se cadeia1 e


cadeia2 so iguais. Devolve um valor menor que zero ou maior que zero se cadeia1
menor que ou maior que cadeia2 , respectivamente;
FACOM

UFMS

226

B IBLIOTECA

PADRO

int strncmp(const char *cadeia1, const char *cadeia2, unsigned int n)

Compara no mximo os primeiros n caracteres de cadeia1 e cadeia2 . Finaliza a


comparao aps encontrar um caractere nulo. Devolve zero se os n primeiros caracteres, ou os caracteres at alcanar o caractere nulo, de cadeia1 e cadeia2 so iguais.
Devolve um valor menor que zero ou maior que zero se cadeia1 menor que ou maior
que cadeia2 , respectivamente;
char *strcpy(char *cadeia1, const char *cadeia2)

Copia a cadeia de caracteres cadeia2 na cadeia de caracteres cadeia1 . Copia at o


caractere nulo de cadeia2 , inclusive. Devolve um apontador para cadeia1 ;
char *strncpy(char *cadeia1, const char *cadeia2, unsigned int n)

Copia at n caracteres de cadeia2 em cadeia1 . A cpia termina quando n caracteres


so copiados ou quando o caractere nulo em cadeia2 alcanado. Se o caractere nulo
alcanado, os caracteres nulos so continuamente copiados para cadeia1 at que n
caracteres tenham sido copiados;
size_t strlen(const char *cadeia)

Computa o comprimento da cadeia , no incluindo o caractere nulo. Devolve o nmero


de caracteres da cadeia ;
char *strpbrk(const char *cadeia1, const char *cadeia2)

Procura o primeiro caractere na cadeia1 que corresponde a algum caractere especificado na cadeia2 . Se encontrado, um apontador para a localizao deste caractere
devolvido. Caso contrrio, o apontador para nulo devolvido;
char *strchr(const char *cadeia, int c)

Busca pela primeira ocorrncia do caractere c na cadeia de caracteres cadeia . Devolve


um apontador para a posio que contm o primeiro caractere na cadeia que corresponde a c ou nulo se c no ocorre em cadeia ;
char *strrchr(const char *cadeia, int c)

Busca pela ltima ocorrncia do caractere c na cadeia de caracteres cadeia . Devolve


um apontador para a posio que contm o ltimo caracter na cadeia que corresponde
c ou nulo se c no ocorre em cadeia ;
size_t strspn(const char *cadeia1, const char *cadeia2)

Encontra a primeira seqncia de caracteres na cadeia1 que contm qualquer caracter da cadeia2 . Devolve o comprimento desta primeira seqncia de caracteres que
corresponde cadeia2 ;
size_t strcspn(const char *cadeia1, const char *cadeia2)

Encontra a primeira seqncia de caracteres na cadeia1 que no contm qualquer caracter da cadeia2 . Devolve o comprimento desta primeira seqncia de caracteres que
no corresponde cadeia2 ;

FACOM

UFMS

22.3 A RQUIVOS - CABEALHOS

DA BIBLIOTECA PADRO

227

char *strstr(const char *cadeia1, const char *cadeia2)

Encontra a primeira ocorrncia da cadeia2 na cadeia1 . Devolve um apontador para


a localizao da primeira ocorrncia da cadeia2 na cadeia1 . Se no h correspondncia, o apontador nulo devolvido. Se cadeia2 contm uma cadeia de caracteres de
comprimento zero, ento cadeia1 devolvida.

22.3.14 Data e hora


A biblioteca que contm funes para determinar, manipular e formatar horrios e datas
pode ser acessada atravs do arquivo-cabealho time.h.

Exerccios
22.1

(a) Escreva uma funo com a seguinte interface


double cosseno(double x, double epsilon)

que receba um nmero real x e um nmero positivo real > 0, e calcule uma aproximao para cos x, onde x dado em radianos, atravs da seguinte srie:
cos x = 1

x2 x4 x6
x2k
+

+ . . . + (1)k
+ ...
2!
4!
6!
(2k)!

incluindo todos os termos Tk =

x2k
(2k)! ,

at que Tk < .

(b) Escreva uma funo com a seguinte interface:


double seno(double x, double epsilon)

que receba um nmero real x e um nmero real > 0, e calcule uma aproximao
para sen x, onde x dado em radianos, atravs da seguinte srie:
sen x =

x2k+1
x3 x5
x

+
. . . + (1)k
+ ...
1!
3!
5!
(2k + 1)!

incluindo todos os termos Tk =

x2k+1
(2k+1)! ,

at que Tk < .

(c) Escreva um programa que receba um nmero real x representando um ngulo em


radianos e um nmero real > 0 representando uma preciso, e calcule o valor de
tan x de duas formas: usando as funes dos itens acima e usando a funo tan da
biblioteca math . Compare os resultados.
22.2

(a) Escreva uma funo com a seguinte interface:


int ocorre(char palavra[], char frase[], int pos)

FACOM

UFMS

228

B IBLIOTECA

PADRO

que receba duas cadeias de caracteres palavra e frase e um inteiro pos e verifique se a cadeia de caracteres palavra ocorre na posio pos da cadeia de caracteres frase . Em caso positivo, a funo deve devolver 1. Em caso negativo, deve
devolver zero.
(b) Escreva um programa que receba duas cadeias de caracteres padrao e texto ,
com m e n caracteres respectivamente e m 6 n, e imprima o nmero de vezes que
padrao ocorre em texto .
Use todas as funes da biblioteca string que puder.

FACOM

UFMS

AULA

D EPURAO

23

DE PROGRAMAS

medida que temos resolvido problemas maiores e mais complexos, natural e conseqentemente nossos programas tm ganhado complexidade e extenso. Uso correto de estruturas
de programao, identificadores de variveis significativos, indentao, documentao, tudo
isso tem sido feito na tentativa de escrever programas corretamente. Ou seja, nosso desejo
sempre escrever programas eficientes, coesos e corretos.
Infelizmente, nem sempre isso possvel. Por falta de ateno, de experincia, de disciplina,
ou mesmo pela complexidade do problema que precisamos resolver, no incomum o desenvolvimento de um programa que contm erros. Nesta aula, aprenderemos a usar um poderoso
depurador de programas interativo, chamado GDB, como aliado na construo de programas
corretos. Veremos algumas de suas principais caractersticas, talvez as mais teis. Interessados(as) em mais informaes e caractersticas avanadas desta ferramenta devem consultar a
pgina e o manual da mesma.

23.1 Depurador GDB


Um depurador um programa que permite a um programador visualizar o que acontece
no interior de um outro programa durante sua execuo. Neste sentido, podemos dizer que
um depurador uma poderosa ferramenta de auxlio programao. O depurador GDB, do
Projeto GNU, projetado inicialmente por Richard Stallman1 , usado com freqncia para depurar programas compilados com o compilador GCC, tambm do projeto GNU. Para auxiliar
um programador na procura por erros em um programa, o GDB pode agir de uma das quatro
principais formas abaixo:
iniciar a execuo de um programa, especificando qualquer coisa que possa afetar seu
comportamento;
interromper a execuo de um programa sob condies estabelecidas;
examinar o que aconteceu quando a execuo do programa foi interrompida;
modificar algo no programa, permitindo que o programador corrija um erro e possa continuar a investigar outros erros no mesmo programa.
O depurador GDB pode ser usado para depurar programas escritos nas linguagens de programao C, C++, Objective-C, Modula-2, Pascal e Fortran.
1

Richard Matthew Stallman (), nascido nos Estados Unidos, fsico, ativista poltico e ativista de software.

229

230

D EPURAO

DE PROGRAMAS

GDB um software livre, protegido pela Licena Pblica Geral (GPL) da GNU . A GPL d a
seu usurio a liberdade para copiar ou adaptar um programa licenciado, mas qualquer pessoa
que faz uma cpia tambm deve ter a liberdade de modificar aquela cpia o que significa que
deve ter acesso ao cdigo fonte , e a liberdade de distribuir essas cpias. Empresas de software
tpicas usam o copyright para limitar a liberdade dos usurios; a Fundao para o Software Livre
(Free Software Foundation) usa a GPL para preservar essas liberdades. Fundamentalmente, a
Licena Pblica Geral (GPL) uma licena que diz que todas as pessoas tm essas liberdades e
que ningum pode restringi-las.

Para executar um programa com auxlio do depurador GDB, o programa fonte na linguagem C deve ser compilado com o compilador GCC usando a diretiva de compilao ou opo
-g . Essa diretiva de compilao faz com que o compilador adicione informaes extras no
programa executvel que sero usadas pelo GDB.

23.2 Primeiro contato


De uma janela de comandos, voc pode chamar o depurador GDB, como a seguir:

prompt$ gdb
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
(gdb)

Em geral, quando queremos depurar um programa, digitamos o comando gdb programa


em uma janela de comandos, onde programa um programa executvel compilado e gerado
pelo compilador gcc usando a diretiva de compilao -g . Dessa forma,

prompt$ gdb ./consecutivos


GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb)

faz a chamada do depurador GDB com a carga do programa executvel consecutivos , que
foi previamente gerado pelo processo de compilao, usando o compilador GCC com a diretiva
de compilao -g .
FACOM

UFMS

23.3 S INTAXE

DOS COMANDOS DO GDB

Para sair do
seguir:

GDB

231

e retornar janela de comandos basta digitar o comando quit , como a

(gdb) quit
prompt$

23.3 Sintaxe dos comandos do GDB


Um comando do GDB composto por uma linha de entrada, contendo o nome do comando
seguido de zero ou mais argumentos. O nome de um comando do GDB pode ser truncado, caso
essa abreviao no seja ambga. O usurio tambm pode usar a tecla Tab para fazer com que
o GDB preencha o resto do nome do comando ou para mostrar as alternativas disponveis, caso
exista mais que uma possibilidade. Uma linha em branco como entrada significa a solicitao
para que o GDB repita o ltimo comando fornecido pelo usurio.
Podemos solicitar ao GDB informaes sobre os seus comandos usando o comando help .
Atravs do comando help , que pode ser abreviado por h , sem argumentos, obtemos uma
pequena lista das classes de comandos do GDB:

List of classes of commands:


aliases - Aliases of other commands
breakpoints - Making program stop at certain points
data - Examining data
files - Specifying and examining files
internals - Maintenance commands
obscure - Obscure features
running - Running the program
stack - Examining the stack
status - Status inquiries
support - Support facilities
tracepoints - Tracing of program execution without stopping the program
user-defined - User-defined commands
Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
(gdb)

Usando o nome de uma das classes gerais de ajuda como um argumento do comando
help , podemos obter uma lista dos comandos desta classe. Por exemplo,
FACOM

UFMS

232

D EPURAO

DE PROGRAMAS

(gdb) help status


Status inquiries.
List of commands:
info - Generic command for showing things about the program being debugged
macro - Prefix for commands dealing with C preprocessor macros
show - Generic command for showing things about the debugger
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.
(gdb)

Tambm podemos usar o comando help diretamente com o nome de um comando que
queremos ajuda. Por exemplo,

(gdb) help help


Print list of commands.
(gdb)

Para colocar um programa executvel sob execuo no

GDB

necessrio usar o comando

run , que pode ser abreviado por r . Este programa executvel deve ter sido usado como um

parmetro na chamada do depurador ou ento deve ser carregado no GDB usando o comando
file ou exec-file .

23.4 Pontos de parada


Uma das principais vantagens no uso de depuradores de programas a possibilidade de
interromper a execuo de um programa antes de seu trmino. Sob o GDB, um programa pode
ser interrompido intencionalmente por diversas razes. Neste ponto de interrupo, podemos
examinar e modificar o contedo de variveis, criar outros pontos de parada, ou remover antigos, e continuar a execuo do programa. Usualmente, as mensagens emitidas pelo GDB fornecem explicaes satisfatrias sobre o estado do programa, mas podemos tambm solicitar essas
informaes explicitamente a qualquer momento, atravs do comando info program . Esse
comando apresenta o estado do programa, sua identificao de processo, se est sob execuo
ou no e, neste ltimo caso, os motivos pelos quais sua execuo foi interrompida.
Um ponto de parada interrompe a execuo de um programa sempre que um determinado ponto do cdigo fonte alcanado e/ou uma determinada condio verificada. No
GDB existem trs tipos de pontos de parada: breakpoints, watchpoints e catchpoints. Nesta aula
aprenderemos a usar dois deles, os dois primeiros.
O GDB atribui um nmero para cada ponto de parada quando da sua criao. Esses nmeros so nmeros inteiros sucessivos comeando com 1. Em diversos comandos para controle
de pontos de parada, podemos usar seu nmero seqencial para referenci-lo. Assim que
criado, um ponto de parada est habilitado. No entanto, durante a execuo de um programa,
podemos desabilit-lo de acordo com nossa convenincia.
FACOM

UFMS

23.4 P ONTOS

233

DE PARADA

Um breakpoint um ponto de parada que interrompe a execuo de um programa em um


dado ponto especificado do cdigo fonte. Seu uso mais freqente com o argumento do ponto
de execuo como sendo o nmero da linha do cdigo fonte. Por exemplo, breakpoint 9
estabelece um ponto de parada na linha 9 do programa. O ponto de parada interromper o programa antes da execuo do cdigo localizado na linha especificada. O comando
breakpoint pode ser abreviado por br . Outra forma de uso de um breakpoint atravs
de sua associao a uma expresso lgica, estabelecendo um ponto de parada em uma dada
localizao do cdigo fonte, caso uma determinada condio seja satisfeita. Por exemplo,
breakpoint 18 if ant == prox estabelece um ponto de parada na linha 18, caso a expresso lgica descrita aps a palavra reservada if seja avaliada com valor verdadeiro. O ponto de
parada interromper ento o programa antes da execuo do cdigo na linha 18. Por outro lado,
um breakpoint tambm pode ser criado atravs do comando breakpoint identificador ,
onde o argumento identificador o nome de uma funo.
Podemos tambm usar um ponto de parada na execuo de um programa que suspende sua
execuo sempre que o valor de uma determinada expresso se modifica, sem ter de predizer
um ponto particular no cdigo fonte onde isso acontece. Esse ponto de parada chamado
de watchpoint do GDB. Por exemplo, watch iguais estabelece um ponto de parada que ir
suspender a execuo do programa quando o valor da expresso descrita que no caso contm
apenas a varivel iguais for modificado. O comando watch pode ser abreviado por wa .
O watchpoint s pode ser adicionado durante a execuo de um programa. Neste exemplo, a
expresso contm apenas uma varivel e o fluxo de execuo ser interrompido sempre que o
contedo da varivel iguais for modificado. Observe, no entanto, que a expresso pode ser
mais complexa que isso, como por exemplo uma expresso aritmtica a*b + c/d .
Como j mencionado, o GDB atribui um nmero seqencial, iniciando com 1, para cada
ponto de parada, quando da sua criao. Podemos imprimir uma tabela com informaes
bsicas sobre os pontos de parada associados ao programa em execuo com o comando
info breakpoints [n] , que pode ser abreviado por info break [n] . O argumento opcional n mostra as informaes apenas do ponto de parada especificado. Por exemplo, conforme
vimos nas descries acima, mostramos a seguir as informaes de todos os pontos de parada
que adicionamos execuo de um programa:

(gdb) info break


Num Type
Disp Enb Address
1
breakpoint
keep y
0x0000000000400575
breakpoint already hit 1 time
2
breakpoint
keep y
0x0000000000400630
stop only if ant == prox
3
hw watchpoint keep y
(gdb)

What
in main at consecutivos.c:9
in main at consecutivos.c:18
iguais

Muitas vezes, queremos eliminar um ponto de parada que j cumpriu o seu papel na depurao do programa e no queremos mais que o programa seja interrompido naquele ponto
previamente especificado. Podemos usar os comandos clear ou delete para remover um
ou mais pontos de parada de um programa. Os comandos clear e delete , com um argumento numrico, removem um ponto de parada especificado. Por exemplo, os comandos
clear 1 e delete 2 removem os pontos de parada identificados pelos nmeros 1 e 2, res-

FACOM

UFMS

234

D EPURAO

DE PROGRAMAS

pectivamente. A diferena entre esses comandos se d quando so usados sem argumentos:


o comando clear remove o ponto de parada da linha de cdigo em execuo, se existir algum, e o comando delete sem argumentos remove todos os pontos de parada existentes no
programa.
Ao invs de remover definitivamente um ponto de parada, pode ser til para o processo de
depurao apenas desabilit-lo temporariamente e, se for necessrio, reabilit-lo depois. O comando disable desabilita todos os pontos de parada de um programa. Podemos desabilitar
um ponto de parada especfico atravs do uso de seu nmero como argumento desse comando
disable . Por exemplo, disable 3 desabilita o ponto de parada de nmero 3. Podemos
tambm reabilitar um ponto de parada atravs do comando enable , que reabilita todos os
pontos de parada desabilitados anteriormente, ou enable n , que reabilita o ponto de parada
de nmero n .
Aps verificar o que aconteceu com o programa em um dado ponto de parada, podemos
retomar a execuo do programa a partir deste ponto de dois modos diferentes: atravs do
comando continue , que pode ser abreviado por c , atravs do comando step , que pode ser
abreviado por s , ou atravs do comando next , que pode ser abreviado por n . No primeiro
comando, a execuo retomada e segue at o final do programa ou at um outro ponto de
parada ser encontrado. No segundo, apenas a prxima sentena do programa em geral, a
prxima linha executada e o controle do programa novamente devolvido ao GDB. O comando step pode vir seguido por um argumento numrico, indicando quantas sentenas do
cdigo fonte queremos progredir na sua execuo. Por exemplo, step 5 indica que queremos
executar as prximas 5 sentenas do cdigo. Caso um ponto de parada seja encontrado antes
disso, o programa interrompido e o controle repassado ao GDB. O comando next muito
se assemelha ao comando step . A diferena se d na ocorrncia ou no de uma funo descrita pelo(a) programador(a) na sentena sendo executada: em caso positivo, o comando step
abandona a funo atual, desviando o fluxo de execuo, e inicia a execuo da outra funo;
o comando next evita que isso acontea e a prxima sentena da mesma funo executada.
Comumente, adicionamos um ponto de parada no incio de uma funo onde acreditamos
que exista um problema, um erro, executamos o programa at que ele atinja este ponto de parada e ento usamos o comando step ou next nessa rea suspeita, examinando o contedo
das variveis envolvidas, at que o problema se revele.

23.5 Programa fonte


O GDB pode imprimir partes do cdigo fonte do programa sendo depurado. Quando um
programa tem sua execuo interrompida por algum evento, o GDB mostra automaticamente o
contedo da linha do cdigo fonte onde o programa parou. Para ver outras pores do cdigo,
podemos executar comandos especficos do GDB.
O comando list mostra ao() programador(a) algumas linhas do cdigo fonte carregado
previamente. Em geral, mostra 10 linhas em torno do ponto onde a execuo do programa
se encontra. Podemos explicitamente solicitar ao GDB que mostre um intervalo de linhas do
cdigo fonte, como por exemplo, list 1,40 . Neste caso, as primeiras 40 linhas do cdigo
fonte do programa carregado no GDB sero mostradas.
FACOM

UFMS

23.6 V ERIFICAO

DE DADOS

235

(gdb) l 1,40
1
#include <stdio.h>
2
3
/* Recebe um nmero inteiro positivo e verifica se
4
esse nmero tem dois dgitos consecutivos iguais */
5
int main(void)
6
{
7
int num, ant, prox, iguais;
8
9
printf("\nInforme um nmero: ");
10
scanf("%d", &num);
11
12
prox = num % 10;
13
iguais = 0;
14
while (num != 0 && !iguais) {
15
num = num / 10;
16
ant = prox;
17
prox = num % 10;
18
if (ant == prox)
19
iguais = 1;
20
}
21
22
if (iguais)
23
printf("Nmero tem dois dgitos consecutivos iguais\n");
24
else
25
printf("Nmero no tem dois dgitos consecutivos iguais\n");
26
27
return 0;
28
}
(gdb)

23.6 Verificao de dados


Uma forma usual de examinar informaes em nosso programa atravs do comando
print , que pode ser abreviado por p . Esse comando avalia uma expresso e mostra seu
resultado. Por exemplo, print 2*a+3 mostra o resultado da avaliao da expresso 2*a+3 ,
supondo que a uma varivel do nosso programa. Sem argumento, esse comando mostra o
ltimo resultado apresentado pelo comando print .
Uma facilidade que o GDB nos oferece mostrar o valor de uma expresso freqentemente. Dessa forma, podemos verificar como essa expresso se comporta durante a execuo do programa. Podemos criar uma lista de impresso automtica que o GDB mostra cada
vez que o programa tem sua execuo interrompida. Podemos usar o comando display
para adicionar uma expresso lista de impresso automtica de um programa. Por exemplo,
display iguais adiciona a varivel iguais a essa lista e faz com que o GDB imprima o contedo dessa verivel sempre que a execuo do programa for interrompida por algum evento.
Aos elementos inseridos nessa lista so atribudos nmeros inteiros consecutivos, iniciando
com 1. Para remover uma expresso dessa lista, basta executar o comando delete display
n, onde n o nmero da expresso que desejamos remover. Para visualizar todas as expresses
nesta lista necessrio executar o comando info display .
Todas as variveis internas de uma funo, e seus contedos, podem ser visualizados atravs do comando info locals .
FACOM

UFMS

236

D EPURAO

DE PROGRAMAS

23.7 Alterao de dados durante a execuo


Podemos ainda alterar contedos de variveis durante a execuo de um programa no GDB.
Em qualquer momento da execuo, podemos usar o comando set var para alterar o contedo de uma varivel. Por exemplo, set var x = 2 modifica o contedo da varivel x
para 2. O lado direito aps o smbolo = no comando set var pode conter uma constante,
uma varivel ou uma expresso vlida.

23.8 Resumo dos comandos


Comando
P ROGRAMA F ONTE
list [n]

Significado

list m,n

Mostra linhas em torno da linha n ou as prximas 10 linhas, se no


especificada
Mostra linhas entre m e n

VARIVEIS E E XPRESSES
print expr
display expr
info display
delete display n
info locals
set var var = expr

Imprime expr
Adiciona expr lista de impresso automtica
Mostra a lista de impresso automtica
Remove a expresso de nmero n da lista de impresso automtica
Mostra o contedo de todas as variveis locais na funo corrente
Atribui expr para a varivel var

P ONTOS DE PARADA
break n
break n if expr
break func
watch expr
clear [n]
delete [n]
enable [n]
disable [n]
info break
E XECUO DO P ROGRAMA
file [prog]

Estabelece um breakpoint na linha n


Estabelece um breakpoint na linha n se o valor de expr for verdadeiro
Estabelece um breakpoint no incio da funo func
Estabelece um watchpoint na expresso expr
Remove o ponto de parada na linha n ou na prxima linha, se no
especificada
Remove o ponto de parada de nmero n ou todos os pontos de parada,
se no especificado
Habilita todos os pontos de parada suspensos ou o ponto de parada n
Desabilita todos os pontos de parada ou o ponto de parada n
Mostra todos os pontos de parada

info program
quit

Carrega o programa executvel prog e sua tabela de smbolos ou


libera o GDB da execuo corrente, se no especificado
Carrega o programa executvel prog ou libera o GDB da execuo
corrente, se no especificado
Inicia a execuo do programa
Continua a execuo do programa
Executa a prxima sentena do programa ou as prximas n sentenas
Executa a prxima sentena do programa ou as prximas n sentenas,
desconsiderando chamadas de funes do(a) programador(a)
Mostra o estado da execuo do programa
Encerra a execuo do GDB

A JUDA
help
help classe
help comando

Mostra as classes de ajuda de comandos do GDB


Mostra uma ajuda sobre a classe de comandos
Mostra uma ajuda sobre o comando

exec-file [prog]
run
continue
step [n]
next [n]

FACOM

UFMS

23.9 E XEMPLOS

DE EXECUO

237

Esta uma relao dos comandos que aprendemos nesta aula, com uma explicao breve
sobre cada um. A inteno agrupar os comandos em um lugar s, para que a relao nos sirva
de referncia. Vale reiterar que o GDB possui muitos outros comandos interessantes, mas que
infelizmente no puderam ser cobertos neste texto. O(A) leitor(a) interessado(a) deve consultar
as referncias desta aula para mais informaes.

23.9 Exemplos de execuo


Vamos usar o GDB sobre o programa 23.1 que soluciona o exerccio 7.3. No exerccio 7.3
temos de verificar se um nmero inteiro positivo fornecido como entrada contm dois dgitos
consecutivos e iguais.

Programa 23.1: Soluo do exerccio 7.3.


#include <stdio.h>
/* Recebe um nmero inteiro positivo e verifica se
esse nmero tem dois dgitos consecutivos iguais */
int main(void)
{
int num, ant, prox, iguais;
printf("\nInforme um nmero: ");
scanf("%d", &num);
prox = num % 10;
iguais = 0;
while (num != 0 && !iguais) {
num = num / 10;
ant = prox;
prox = num % 10;
if (ant == prox)
iguais = 1;
}
if (iguais)
printf("Nmero tem dois dgitos consecutivos iguais\n");
else
printf("Nmero no tem dois dgitos consecutivos iguais\n");
return 0;
}

Iniciamos o processo compilando o programa 23.1 adequadamente e carregando o programa executvel gerado no GDB:
FACOM

UFMS

238

D EPURAO

DE PROGRAMAS

prompt$ gcc consecutivos.c -o consecutivos -Wall -ansi -pedantic -g


prompt$ gdb ./consecutivos
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb)

Para verificar se o programa foi de fato carregado na chamada do GDB, podemos usar o
comando list para ver seu cdigo fonte ou ento o comando info program , para visualizar
o estado do programa:

(gdb) l 1,14
1
#include <stdio.h>
2
3
/* Recebe um nmero inteiro positivo e verifica se
4
esse nmero tem dois dgitos consecutivos iguais */
5
int main(void)
6
{
7
int num, ant, prox, iguais;
8
9
printf("\nInforme um nmero: ");
10
scanf("%d", &num);
11
12
prox = num % 10;
13
iguais = 0;
14
while (num != 0 && !iguais) {
(gdb)

ou
(gdb) info program
The program being debugged is not being run.
(gdb)

O programa pode ser executado neste momento, atravs do comando run :

(gdb) run
Starting program:

/ensino/disciplinas/api/2010/programas/consecutivos

Informe um nmero: 12233


Nmero tem dois dgitos consecutivos iguais
Program exited normally.
(gdb)

FACOM

UFMS

23.9 E XEMPLOS

DE EXECUO

239

A execuo acima foi realizada dentro do GDB, sem a adio de qualquer ponto de parada.
Como o programa ainda continua carregado no GDB, podemos execut-lo quantas vezes quisermos. Antes de iniciar a prxima execuo, vamos adicionar alguns pontos de parada no
programa:

(gdb) break 9
Breakpoint 1 at 0x400575: file consecutivos.c, line 9.
(gdb)

Note que no iniciamos a execuo do programa ainda. Ento,

(gdb) run
Starting program:

/ensino/disciplinas/api/programas/consecutivos

Breakpoint 1, main () at consecutivos.c:9


9
printf("\nInforme um nmero: ");
(gdb)

O ponto de parada estabelecido na linha 9 do programa foi encontrado e o GDB interrompeu


a execuo do programa neste ponto. Podemos visualizar todas as variveis, e seus contedos,
dentro da funo main usando o comando info locals :

(gdb) info locals


num = 4195456
ant = 0
prox = -12976
iguais = 32767
(gdb)

Observe que todas as variveis declaradas constam da relao apresentada pelo GDB e que seus
contedos so valores estranhos, j que nenhuma dessas variveis foi inicializada at a linha 9
do programa.
Vamos adicionar mais pontos de parada neste programa, um deles um breakpoint associado
a uma expresso lgica e o outro um watchpoint associado a uma varivel:

(gdb) break 18 if ant == prox


Breakpoint 2 at 0x400630: file consecutivos.c, line 18.
(gdb) watch iguais
Hardware watchpoint 3: iguais
(gdb)

Agora, podemos visualizar todos os pontos de parada associados a este programa com o
comando info break :

FACOM

UFMS

240

D EPURAO

(gdb) info break


Num Type
Disp Enb Address
1
breakpoint
keep y
0x0000000000400575
breakpoint already hit 1 time
2
breakpoint
keep y
0x0000000000400630
stop only if ant == prox
3
hw watchpoint keep y
(gdb)

DE PROGRAMAS

What
in main at consecutivos.c:9
in main at consecutivos.c:18
iguais

Podemos continuar a execuo do programa usando o comando continue :

(gdb) continue
Continuing.
Informe um nmero: 55123
Hardware watchpoint 3: iguais
Old value = 32767
New value = 0
0x00000000004005d3 in main () at consecutivos.c:13
13
iguais = 0;
(gdb)

Observe que na linha 13 do programa a varivel iguais inicializada, substituindo ento


um valor no vlido, um lixo que iguais continha aps sua declarao, pelo valor 0 (zero).
Assim, o GDB interrompe a execuo do programa nessa linha, devido ao watchpoint de nmero
3, e mostra a mudana de valores que ocorreu nessa varivel.
Vamos ento continuar a execuo do programa:

(gdb) continue
Continuing.
Breakpoint 2, main () at consecutivos.c:18
18
if (ant == prox)
(gdb)

O GDB ento interrompeu a execuo do programa devido ao breakpoint 2, na linha 18 do programa. Neste ponto, deve ter ocorrido o evento em que os contedos das variveis ant e
prox coincidem. Para verificar se esse evento de fato ocorreu, podemos usar o comando
print para verificar os contedos dessas variveis:

(gdb) print ant


$1 = 5
(gdb) print prox
$2 = 5
(gdb)

FACOM

UFMS

23.9 E XEMPLOS

DE EXECUO

241

Vamos continuar a execuo deste programa:

(gdb) continue
Continuing.
Hardware watchpoint 3: iguais
Old value = 0
New value = 1
main () at consecutivos.c:14
14
while (num != 0 && !iguais) {
(gdb)

Observe que o programa foi interrompido pelo watchpoint, j que o contedo da varivel
iguais foi modificado de 0 para 1 na linha 19 do programa. Assim, a prxima linha a ser
executada a linha 14, como mostrado pelo GDB.
Vamos dar uma olhada no contedo das variveis da funo main :

(gdb) info locals


num = 5
ant = 5
prox = 5
iguais = 1
(gdb)

O programa ento est quase no fim. Vamos continuar sua execuo:

(gdb) continue
Continuing.
Nmero tem dois dgitos consecutivos iguais.
Watchpoint 3 deleted because the program has left the block in
which its expression is valid.
0x00007fd256015934 in exit () from /lib/libc.so.6
(gdb)

Mais uma anlise detalhada e mais alguns testes sobre o programa 23.1 nos permitem afirmar com alguma convico que este programa est correto e que soluciona o exerccio 7.3. O
fato novo que essa afirmao foi feita tambm com o GDB nos auxiliando. Para provar formalmente que o programa 23.1 est correto, devemos descrever algum invariante do processo
iterativo das linhas 14 at 20 do programa e ento provar por induo a sua validade. Essa
tcnica de demonstrao de correo vale para programas que possuem uma ou mais estruturas de repetio, como o caso do programa 23.1. Aprenderemos mais sobre demonstrao de
correo de programas e algoritmos em disciplinas posteriores do nosso curso.
No prximo exemplo vamos executar um programa sob o controle do GDB que no soluciona o problema associado, isto , contm algum erro que, primeira vista, no conseguimos
corrigir. O programa 23.2 se prope a implementar a ordenao por seleo.
FACOM

UFMS

242

D EPURAO

DE PROGRAMAS

Programa 23.2: Uma verso de um programa que deveria realizar a ordenao por seleo.
#include <stdio.h>
#define MAX 10
/* Recebe um nmero inteiro n > 0 e uma seqncia de n nmeros inteiros, e mostra essa seqncia em ordem crescente */
int main(void)
{
int i, j, n, menor, indice, aux, A[MAX];
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d", &A[i]);
for (i = 0; i < n-1; i++) {
menor = A[i];
indice = i;
for (j = n-1; j > i; j++) {
if (A[j] < menor) {
menor = A[j];
indice = j;
}
}
aux = A[i];
A[i] = A[indice];
A[indice] = aux;
}
for (i = 0; i < n; i++)
printf("%d ", A[i]);
printf("\n");
return 0;
}

Em uma tentativa de execuo do programa 23.2, ocorre o seguinte erro:

prompt$ ./ord-selecao
8
7 5 4 1 8 6 2 3
Falha de segmentao
prompt$

Esse erro no nos d nenhuma dica de onde procur-lo. E se j nos debruamos sobre o
cdigo fonte e no conseguimos encontr-lo, a melhor idia usar um depurador para nos
ajudar. Neste exemplo, mostraremos o uso do GDB sem muitas interrupes no texto, a menos
que necessrias. Ento, segue uma depurao do programa 23.2.
FACOM

UFMS

23.9 E XEMPLOS

DE EXECUO

243

prompt$ gcc ord-selecao.c -o ord-selecao -Wall -ansi -pedantic -g


prompt$ gdb ./ord-selecao
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb) list 15,22
15
for (i = 0; i < n-1; i++) {
16
menor = A[i];
17
indice = i;
18
for (j = n-1; j > i; j++) {
19
if (A[j] < menor) {
20
menor = A[j];
21
indice = j;
22
}
(gdb) break 15
Breakpoint 1 at 0x4005bb: file ord-selecao.c, line 15.
(gdb) run
Starting program: /ensino/disciplinas/api/programas/ord-selecao
8
7 5 4 1 8 6 2 3
Breakpoint 1, main () at ord-selecao.c:15
15
for(i = 0; i < n-1; i++)
(gdb) step 4
19
if (A[j] < menor) {
(gdb) info locals
i = 0
j = 7
n = 8
menor = 7
indice = 0
aux = -1208630704
A = {7, 5, 4, 1, 8, 6, 2, 3, 134518484, -1075407768}
(gdb) display A[j]
1: A[j] = 3
(gdb) display j
2: j = 7
(gdb) display i
3: i = 0
(gdb) watch menor
Hardware watchpoint 2: menor
(gdb) continue
Continuing.
Hardware watchpoint 2: menor
Old value = 7
New value = 3
main () at ord-selecao.c:21
21
indice = j;
3: i = 0
2: j = 7
1: A[j] = 3

FACOM

UFMS

244

D EPURAO

DE PROGRAMAS

(gdb) continue
Continuing.
Hardware watchpoint 2: menor
Old value = 3
New value = -1075407768
main () at ord-selecao.c:21
21
indice = j;
3: i = 0
2: j = 9
1: A[j] = -1075407768
(gdb) c
Continuing.
Hardware watchpoint 2: menor
Old value = -1075407768
New value = -1208630704
main () at ord-selecao.c:21
21
indice = j;
3: i = 0
2: j = 15
1: A[j] = -1208630704
(gdb) step 100
Hardware watchpoint 2: menor
Old value = -1208630704
New value = -1210084267
main () at ord-selecao.c:21
21
indice = j;
3: i = 0
2: j = 18
1: A[j] = -1210084267
(gdb) set var j=-1
(gdb) set var i=n
(gdb) continue
Continuing.
7 5 4 1 8 6 2 3
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0x00007fd256015934 in exit () from /lib/libc.so.6
(gdb)

Encontramos um erro na linha 18 do programa, no passo da estrutura de repetio for .


Substituindo j++ por j-- nessa linha, temos um programa corrigido que realiza uma ordenao por seleo de n nmeros inteiros.
Um ltimo exemplo ser apresentado a seguir. Neste exemplo, temos uma funo a mais
alm da funo principal. Veremos que, com o uso de alguns comandos do GDB, podemos
interromper o fluxo de execuo de uma funo, desvi-lo para uma outra funo, executar
ento esta funo e retornar para o mesmo ponto da funo onde ocorreu aquela chamada.
Considere ento o programa 23.3 a seguir, que soluciona o exerccio 17.7.
A execuo do programa dentro do GDB apresentada a seguir.

FACOM

UFMS

23.9 E XEMPLOS

245

DE EXECUO

GNU gdb 6.8-debian


Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb) list
19
return suf;
20
}
21
22
/* Recebe um nmero inteiro n > 0 e n pares de nmeros inteiros
23
e verifica, para cada par, se um subseqncia do outro */
24
int main(void)
25
{
26
int n, a, b, x, y, aux, subseq;
27
28
scanf("%d", &n);
(gdb) list
29
while (n > 0) {
30
scanf("%d%d", &a, &b);
31
x = a;
32
y = b;
33
if (x < y) {
34
aux = x;
35
x = y;
36
y = aux;
37
}
38
else {
(gdb) list
39
aux = a;
40
a = b;
41
b = aux;
42
}
43
subseq = FALSO;
44
while (x >= y && !subseq)
45
if (sufixo(x, y))
46
subseq = VERDADEIRO;
47
else
48
x = x / 10;
(gdb) break 44
Breakpoint 1 at 0x4006fc: file subsequencia.c, line 44.
(gdb)
(gdb) run
Starting program: /disciplinas/api/aulas/praticas/subsequencia
1
55678 567
Breakpoint 1, main () at subsequencia.c:44
44
while (x >= y && !subseq)
(gdb) watch subseq
Hardware watchpoint 2: subseq
(gdb) info break
Num Type
Disp Enb Address
What
1
breakpoint
keep y
0x00000000004006fc in main at subsequencia.c:44
breakpoint already hit 1 time
2
hw watchpoint keep y
subseq
(gdb)

FACOM

UFMS

246

D EPURAO

(gdb)
45
(gdb)
48
(gdb)
44
45
46
47
48
49
50
(gdb)

DE PROGRAMAS

step
if (sufixo(x, y))
next
x = x / 10;
list 44,50
while (x >= y && !subseq)
if (sufixo(x, y))
subseq = VERDADEIRO;
else
x = x / 10;
if (subseq)
printf("%d S %d\n", a, b);
step

Breakpoint 1, main () at subsequencia.c:44


44
while (x >= y && !subseq)
(gdb) step
45
if (sufixo(x, y))
(gdb) info locals
n = 1
a = 567
b = 55678
x = 5567
y = 567
aux = 55678
subseq = 0
(gdb) step
sufixo (a=5567, b=567) at subsequencia.c:11
11
suf = VERDADEIRO;
(gdb) list 6,20
6
/* Recebe nmeros inteiros a e b e devolve 1 se b sufixo de a */
7
int sufixo(int a, int b)
8
{
9
int suf;
10
11
suf = VERDADEIRO;
12
while (b != 0 && suf)
13
if (a % 10 != b % 10)
14
suf = FALSO;
15
else {
16
a = a / 10;
17
b = b / 10;
18
}
19
return suf;
20
}
(gdb) info locals
suf = 1
(gdb) print a
$1 = 5567
(gdb) print b
$2 = 567
(gdb) break 19
Breakpoint 3 at 0x400644: file subsequencia.c, line 19.
(gdb)

FACOM

UFMS

23.9 E XEMPLOS

DE EXECUO

247

(gdb) continue
Continuing.
Breakpoint 3, sufixo (a=5, b=0) at subsequencia.c:19
19
return suf;
(gdb) print suf
$3 = 1
(gdb) step
20
}
(gdb) step
Hardware watchpoint 2 deleted because the program has left the block
in which its expression is valid.
main () at subsequencia.c:46
46
subseq = VERDADEIRO;
(gdb) step
Breakpoint 1, main () at subsequencia.c:44
44
while (x >= y && !subseq)
(gdb) step
49
if (subseq)
(gdb) step
50
printf("%d S %d\n", a, b);
(gdb) step
567 S 55678
53
n-;
(gdb) step
29
while (n > 0) {
(gdb) step
55
return 0;
(gdb) step
56
}
(gdb) step
0x00007fdc477561a6 in __libc_start_main () from /lib/libc.so.6
(gdb)

FACOM

UFMS

248

D EPURAO

DE PROGRAMAS

Programa 23.3: Soluo do exerccio 17.7.


#include <stdio.h>
#define VERDADEIRO 1
#define FALSO
0
/* Recebe dois nmeros inteiros a e b e devolve 1 se b sufixo de a */
int sufixo(int a, int b)
{
int suf;
suf = VERDADEIRO;
while (b != 0 && suf)
if (a % 10 != b % 10)
suf = FALSO;
else {
a = a / 10;
b = b / 10;
}
return suf;
}
/* Recebe um nmero inteiro n > 0 e uma lista de n pares de nmeros inteiros e verifica, para cada par, se um subseqncia do outro */
int main(void)
{
int n, a, b, x, y, aux, subseq;
scanf("%d", &n);
while (n > 0) {
scanf("%d%d", &a, &b);
x = a;
y = b;
if (x < y) {
aux = x;
x = y;
y = aux;
}
else {
aux = a;
a = b;
b = aux;
}
subseq = FALSO;
while (x >= y && !subseq)
if (sufixo(x, y))
subseq = VERDADEIRO;
else
x = x / 10;
if (subseq)
printf("%d S %d\n", a, b);
else
printf("N\n");
n--;
}
return 0;
}

FACOM

UFMS

AULA

24

P R - PROCESSADOR

O pr-processador um mdulo da linguagem C que edita um programa antes de sua compilao. uma ferramenta poderosa e que diferencia a linguagem C das demais linguagens de
programao do alto nvel. As diretivas #include e #define que usamos em aulas anteriores so manipuladas pelo pr-processador, assim como outras que veremos nesta aula. Apesar
de poderoso, o mal uso do pr-processador pode produzir programas praticamente ininteligveis e/ou com erros muito difceis de encontrar. Esta aula baseada na referncia [17].

24.1 Funcionamento
As diretivas de pr-processamento controlam o comportamento do pr-processador. Uma
diretiva do pr-processador um comando que inicia com o caractere # . At o momento,
vimos duas das diretivas do pr-processador da linguagem C: #include e #define . Revisaremos essas diretivas adiante.
A figura 24.1 ilustra o papel do pr-processador durante o processo de compilao.
programa em C

pr-processador

programa em C modificado

compilador

cdigo objeto

Figura 24.1: O papel do pr-processador durante a compilao.


249

250

P R - PROCESSADOR

A entrada para o pr-processador um programa escrito na linguagem C, possivelmente


contendo diretivas. O pr-processador executa ento estas diretivas, eliminando-as durante
este processo. A sada produzida pelo pr-processador um outro programa na linguagem
C, que representa uma verso editada do programa original, sem diretivas. A sada do prprocessador a entrada para o compilador, que verifica erros no programa e realiza sua traduo para o cdigo objeto, que contm apenas instrues diretas para a mquina.

24.2 Diretivas de pr-processamento


A maioria das diretivas de pr-processamento pertencem a uma das trs categorias a seguir:
definio de macros: a diretiva #define define uma macro, tambm chamada de constante simblica; a diretiva #undef remove a definio de uma macro;
incluso de arquivos: a diretiva #include faz com que o contedo de um arquivo especificado seja includo em um programa;
compilao condicional: as diretivas #if , #ifdef , #ifndef , #elif , #else e
#endif permitem que trechos de cdigo seja includos ou excludos do programa, dependendo das condies verificadas pelo pr-processador.
As outras diretivas #error , #line e #pragma so mais especficas e usadas com menos
freqncia. Antes de descrev-las com mais detalhes, listamos abaixo as regras que se aplicam
a todas elas:
Diretivas sempre iniciam com o smbolo # . No necessrio que o smbolo # seja o
primeiro caractere da linha. No entanto, apenas espaos podem preced-lo. Aps # o
identificador de uma diretiva deve ser descrito, seguido por qualquer outra informao
que a diretiva necessite.
Qualquer nmero de espaos e caracteres de tabulao horizontal podem separar os
itens em uma diretiva. Por exemplo, a diretiva a seguir est correta:

define

MAX

100

Diretivas sempre terminam no primeiro caractere de mudana de linha, a menos que a


continuao seja explcita. Para continuar uma diretiva em uma prxima linha, devemos
finalizar a linha atual com o caractere \ . Por exemplo, a diretiva abaixo define uma
macro que representa a capacidade de um disco medida em bytes:

#define CAPACIDADE_DISCO (LADOS *


TRILHAS_POR_LADO *
SETORES_POR_TRILHA *
BYTES_POR_SETOR)

FACOM

\
\
\

UFMS

24.3 D EFINIES

251

DE MACROS

Diretivas podem aparecer em qualquer lugar em um programa. Apesar de usualmente


colocarmos as diretivas #include e #define no comeo de um arquivo, outras diretivas so mais provveis de ocorrer em outros pontos do programa.
Comentrios podem ocorre na mesma linha de uma diretiva. Em geral, colocamos um
comentrio no final da definio de uma macro para explicar seu significado. Por exemplo:

#define MAXIMO 100

/* Dimenso dos vetores */

24.3 Definies de macros


O uso mais freqente da diretiva #define do pr-processador da linguagem C a atribuio de nomes simblicos para constantes. Macros como essas so conhecidas como macros
simples. O pr-processador tambm suporta definio de macros parametrizadas. Nesta aula
veremos apenas as macros simples.
A definio de uma macro simples tem a seguinte forma:

#define identificador lista-de-troca

onde lista-de-troca uma seqncia qualquer de itens. Essa lista pode incluir identificadores, palavras reservadas, constantes numricas, constantes de caracteres, literais, operadores
e pontuao. Quando encontra uma definio de uma macro, o pr-processador toma nota
que o identificador representa a lista-de-troca . Sempre que identificador ocorre
posteriormente no arquivo, o pr-processador o substitui pela lista-de-troca .
Um erro freqente na definio de macros a incluso de smbolos extras, que conseqentemente faro parte da lista de troca. Abaixo so mostrados dois exemplos de erros como esse.

#define TAM = 100


#define N 10;
.
.
.
int u[TAM];
double v[N];

A traduo do trecho de cdigo acima realizada pelo pr-processador gera o seguinte trecho
de cdigo modificado, correspondente s duas ltima linhas:

int u[= 100];


double v[10;];

certo que o compilador acusar erros nessas duas linhas do programa.


FACOM

UFMS

252

P R - PROCESSADOR

Podemos usar macros para dar nomes a valores numricos, caracteres e literais, como ilustrado abaixo:
#define
#define
#define
#define
#define
#define

COMPRIMENTO
VERDADEIRO
FALSO
PI
ENTER
ERRO

80
1
0
3.141592
\n
"Erro: memria insuficiente\n"

Usar a diretiva #define para criar nomes para constantes tem diversas vantagens, como
tornar os programas mais fceis de ler e de modificar, ajudar a evitar inconsistncias e erros
tipogrficos, permitir pequenas mudanas na sintaxe da linguagem, renomear tipos e controlar
a compilao condicional.

24.4 Incluso de arquivos-cabealhos


Vamos recordar a aula 22. A diretiva #include ordena o pr-processador a abrir um arquivo especificado e a inserir seu contedo no arquivo atual. Assim, se queremos que vrios
arquivos de cdigo fonte tenham acesso mesma informao, devemos colocar essa informao em um arquivo e ento usar a diretiva #include para trazer o contedo do arquivo
em cada arquivo de cdigo fonte. Arquivos que so includos dessa forma so chamados de
arquivos-cabealhos, do ingls header files ou tambm include files. Por conveno, um arquivo
como esse tem a extenso .h .
A diretiva #include pode ser usada de duas formas. A primeira forma usada para
arquivos-cabealhos que pertencem biblioteca padro da linguagem C:

#include <arquivo.h>

A segunda forma usada para todos os outros arquivos-cabealhos, incluindo aqueles que
so escritos por programadores(as):

#include "arquivo.h"

A diferena entre as duas formas se d pela maneira como o compilador busca o arquivocabealho. Na primeira, o compilador busca o arquivo-cabealho no(s) diretrio(s) em que os
arquivos-cabealhos do sistema se encontram. Nos sistemas baseados no UNIX, como o LINUX,
os arquivos-cabealhos so mantidos usualmente no diretrio /usr/include . Na segunda
forma, a busca realizada no diretrio corrente e, em seguida, no(s) diretrio(s) em que os
arquivos-cabealhos do sistema se encontram.
Arquivos-cabealhos auxiliam no compartilhamento de definies de macros, de tipos e de
prottipos de funes por dois ou mais arquivos de cdigo fonte.
FACOM

UFMS

24.4 I NCLUSO

DE ARQUIVOS - CABEALHOS

253

Programa 24.1: Um programa curioso.


#include <stdio.h>
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

PAR
IMPAR
Algoritmo
inicio
fim
escreva
leia
se
senao
enquanto
devolva

0
1
main
{
}
printf
scanf
if
else
while
return

/* Recebe um nmero inteiro positivo e verifica sua paridade */


int par_impar(int numero)
inicio
int paridade;
se (numero % 2 == 0)
paridade = PAR;
senao
paridade = IMPAR;
devolva paridade;
fim
/* Recebe um nmero inteiro n > 0 e uma seqncia de n nmeros inteiros, e imprime a soma dos pares e mpares */
int Algoritmo(void)
inicio
int i, n, numero, s_par, s_impar;
escreva("Informe a quantidade de elementos: ");
leia("%d", &n);
s_par = 0;
s_impar = 0;
i = 1;
enquanto (i <= n)
inicio
escreva("Informe um nmero: ");
leia("%d", &numero);
se (par_impar(numero) == PAR)
somapar = somapar + numero;
senao
somaimpar = somaimpar + numero;
i++;
fim
escreva("\nSoma dos nmeros pares: %d\n", s_par);
escreva("Soma dos nmeros mpares: %d\n", s_impar);
devolva 0;
fim

FACOM

UFMS

254

P R - PROCESSADOR

Futuramente, quando apresentamos formas de tratar programas muito grandes divididos


em arquivos diferentes, mencionamos novamente a diretiva #include , destacando formas de
seu uso no compartilhamento de definies de macros, de tipos e de prottipos de funes.

24.5 Compilao condicional


O pr-processador da linguagem C reconhece diretivas que permitem a incluso ou excluso de um trecho de programa dependendo do resultado da avaliao de um teste executado
pelo pr-processador. Esse processo chamado de compilao condicional. Em geral, as diretivas de compilao condicional so muito usadas para auxiliar na depurao dos programas.
As diretivas #if e #endif , por exemplo, so usadas em conjunto para verificar se um trecho
de cdigo ser ou no executado, dependendo da condio a ser avaliada. O formato geral da
diretiva #if

#if expresso-constante

e da diretiva #endif simplesmente o mesmo #endif .


Quando o pr-processador encontra a diretiva #if , ele avalia a expresso-constante .
Se o resultado da avaliao igual a zero, as linhas entre #if e #endif sero removidas do
programa durante o pr-processamento. Caso contrrio, as linhas entre #if e #endif sero
mantidas e processadas pelo compilador. O seguinte trecho de cdigo exemplifica o uso dessas
diretivas e permite verificar seu uso no auxlio do processo de depurao.

#define DEBUG 1
.
.
.
#if DEBUG
printf("Valor de i = %d\n", i);
printf("Valor de j = %d\n", j);
#endif

Durante o pr-processamento, a diretiva #if verifica o valor de DEBUG . Como seu valor diferente de zero, o pr-processador mantm as duas chamadas funo printf no
programa, mas as linhas contendo as diretivas #if e #endif sero eliminadas aps o prprocessamento. Se modificamos o valor de DEBUG para 0 (zero) e recompilamos o programa,
ento o pr-processador remove todas as 4 linhas do programa. importante notar que a diretiva #if trata identificadores no definidos como macros que tm o valor 0 (zero). Assim, se
esquecemos de definir DEBUG , o teste

#if DEBUG

ir falhar, mas no produzir uma mensagem de erro. O teste


FACOM

UFMS

24.5 C OMPILAO

255

CONDICIONAL

#if !DEBUG

produzir o resultado verdadeiro, nesse caso.


Nesse sentido, h duas outras diretivas para verificar se um identificador definido ou no
como uma macro naquele ponto do programa: #ifdef e #ifndef . O formato geral dessas
diretivas
#ifdef identificador
Linhas a serem includas se o identificador est definido como uma macro
#endif

e
#ifndef identificador
Linhas a serem includas se o identificador no est definido como uma macro
#endif

As diretivas #elif e #else podem ser usadas em conjunto com as diretivas #if ,
#ifdef e #ifndef quando aninhamento de blocos so necessrios. O formato geral dessas
diretivas apresentado abaixo:

#elif expresso-constante

e
#else

Por exemplo, podemos verificar uma srie de condies como a seguir:

#if expresso1
Linhas a serem includas se expresso1 diferente de zero
#elif expresso2
Linhas a serem includas se expresso2 diferente de zero
#else
Linhas a serem includas em caso contrrio
#endif

A compilao condicional, alm de auxiliar na depurao de programas, tambm tem outros usos como na construo de programas que podem executados em computadores diferentes, em sistemas operacionais diferentes, que podem ser compilados por compiladores diferentes, no suporte definies padronizadas de macros, entre outros.

FACOM

UFMS

256

P R - PROCESSADOR

24.6 Outras diretivas


As diretivas #error , #line e #pragma so mais especficas e por isso menos usadas.
A diretiva #error faz com que o pr-processador imprima uma mensagem de erro na
sada padro. A diretiva #error tem o seguinte formato geral:

#error mensagem

onde mensagem uma seqncia qualquer de caracteres. Um exemplo de uso dessa diretiva
apresentado no trecho de cdigo a seguir:

#ifdef LINUX
.
.
.
#else
#error Sistema operacional no especificado
#endif

Se o pr-processador encontra uma diretiva #error , isso sinal de que uma falha grave
ocorreu no programa e alguns compiladores terminam imediatamente a compilao.
A diretiva #line usada para alterar a forma como as linhas do programa so numeradas.
O formato geral dessa diretiva apresentado abaixo:

#line n

e
#line n "arquivo"

No primeiro formato, as linhas do programa so numeradas a partir do nmero n . No segundo, as linhas do programa no arquivo so numeradas a partir do nmero n . Muitos
compiladores usam essa informao quando precisam gerar mensagens de erro.
Por fim, a diretiva #pragma permite que uma diretiva seja criada pelo(a) programador(a).
O formato geral dessa diretiva dado abaixo:

#pragma diretiva

FACOM

UFMS

R EFERNCIAS B IBLIOGRFICAS

[1] Computer History from B.C. to today.


http://www.computerhope.com/history/.
ltimo acesso em 10 de maro de 2010. 1
[2] R. X. Cringely, A History of the Computer.
http://www.pbs.org/nerds/timeline/index.html.
ltimo acesso em 10 de maro de 2010. 1
[3] J. Kopplin, An Illustrated History of Computers.
http://www.computersciencelab.com/ComputerHistory/History.htm.
ltimo acesso em 10 de maro de 2010. 1
[4] A. Sapounov, E. Rosen, and J. Shaw, Computer History Museum.
http://www.computerhistory.org/.
ltimo acesso em 10 de maro de 2010. 1
[5] Wikipedia the Free Encyclopedia.
http://en.wikipedia.org/wiki/Main_Page.
ltimo acesso em 10 de maro de 2010. 1
[6] P. Breton, Histria da Informtica. Editora da UNESP, 1991. Traduo de Elcio Fernandes
do original Histoire de Linformatique, 1987, Editions La Decouvert. 1
[7] R. L. Shackelford, Introduction to Computing and Algorithms. Addison Wesley, 1997. 1
[8] T. Kowaltowski, John von Neumann: suas contribuies Computao, Revista de
Estudos Avanados, vol. 10, Jan/Abr 1996. Instituto de Estudos Avanados da Universidade de So Paulo. 2
[9] Departamento de Cincia da Computao IME/USP, listas de exerccios Introduo
Computao. http://www.ime.usp.br/~macmulti/.
ltimo acesso em 10 de maro de 2010. 2, 6
[10] M. F. Siqueira, Algoritmos e Estruturas de Dados I. Notas de aula, 1998. (ex-professor do
Departamento de Computao e Estatstica da Universidade Federal de Mato Grosso do
Sul (DCT/UFMS), atualmente professor do Departamento de Informtica e Matemtica
Aplicada da Universidade Federal do Rio Grande do Norte (DIMAp/UFRN)). 2
[11] A. M. Turing, On computable numbers, with an application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, vol. 42, no. 2, pp. 230265, 1936.
2.1, 2.4
257

258

REFERNCIAS BIBLIOGRFICAS

[12] K. Zuse, Verfahren zur selbstttigen Durchfhrung von Rechnungen mit Hilfe von Rechenmaschinen. Patentanmeldung Z 23 139 GMD Nr. 005/021, 1936. 2.1
[13] H. Lukoff, From Dits to Bits... a Personal History of the Electronic Computer. Hawley
Books, 1979. 2.1
[14] J. von Neumann, First draft of a report on the EDVAC, tech. rep., Moore School of Electrical Engineering University of Pennsylvania, 1945. 2.1, 2.3
[15] P. Feofiloff, Algoritmos em linguagem C. Editora Campus/Elsevier, 2009. 4.5, 4.5, 5, 5.3.1,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
[16] K. N. King, C Programming A Modern Approach. W. W. Norton & Company, Inc.,
2nd ed., 2008. 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
[17] E. Huss, The C Library Reference Guide.
http://www.acm.uiuc.edu/webmonkeys/book/c_guide/, 1997.
ltimo acesso em 10 de maro de 2010. 22, 24
[18] S. A. Cook, The complexity of theorem-proving procedures, in Proceedings of the Third
Annual ACM Symposium on Theory of Computing, (Shaker Heights, Ohio, United States), pp. 151158, SIGACT: ACM Special Interest Group on Algorithms and Computation
Theory, ACM, 1971.
[19] B. W. Kernighan and R. Pike, The Practice of Programming. Addison-Wesley Professional,
1999.
[20] B. W. Kernighan and D. M. Ritchie, C Programming Language. Prentice Hall, 2nd ed.,
1988.
[21] D. E. Knuth, The Art of Computer Programming, vol. 17. Addison-Wesley, 3rd ed., 1997.
[22] S. G. Kochan, Unix Shell Programming. Sams Publishing, 3rd ed., 2003.
[23] K. A. Lambert, D. W. Nance, and T. L. Naps, Introduction to Computer Science with C++.
West Publishing Company, 1996.
[24] L. A. Levin, Universal sequential search problems, Problemy Peredachi Informatsii,
vol. 9, no. 3, pp. 115116, 1973.
[25] G. J. Pothering and T. L. Naps, Introduction to Data Structures and Algorithm Analysis
with C++. West Publishing Company, 1995.
[26] S. S. Skiena and M. Revilla, Programming Challenges. Springer, 2003.
[27] A. Tucker, A. P. Bernat, W. J. Bradley, R. D. Cupper, and G. W. Scragg, Fundamentals
of Computing I Logic, Problem Solving, Programs, and Computers C++ Edition.
McGraw-Hill, 1995.
[28] The past is the future at Bletchley Park.
http://news.bbc.co.uk/2/hi/technology/6895759.stm.
Mark Ward, Technology Correspondent, BBC News website, julho de 2007, ltimo acesso
em 10 de maro de 2010.

FACOM

UFMS

Você também pode gostar