Escolar Documentos
Profissional Documentos
Cultura Documentos
Programação
Programação
Programação
em C
Primeira edio
Programao de Computadores
em
C
Primeira edio
Carlos Camaro
Anolan Milans
Luclia Figueiredo
Direitos exclusivos
c 2011 by Carlos Camaro, Anolan Milans e Luclia Figueiredo
Copyright
permitida a duplicao ou reproduo deste volume, no todo ou em parte, sob quaisquer
formas ou por quaisquer meios (eletrnico, mecnico, gravao, fotocpia, distribuio na Web ou
outros), desde que seja para ns no comerciais.
Sumrio
Prefcio
1
Computadores e Programas
1.1
Computadores e Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2
Algoritmo e Programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3
1.4
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.6
Notas Bibliogrcas
11
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
2.1
Varivel e Atribuio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.2
Operadores
15
2.3
Expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.4
Programando em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.5
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.6
Notas Bibliogrcas
22
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Programando em C
25
3.1
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.2
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
Escolha condicional
33
4.1
34
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Recurso e Iterao
35
5.1
Repetio
5.2
Multiplicao e Exponenciao
5.3
Fatorial
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.4
42
5.4.1
45
5.5
vii
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
No-terminao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
35
36
45
5.5.1
Denies Recursivas
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
5.5.2
Comandos de Repetio . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
5.5.3
Semntica Axiomtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
5.5.4
Exemplos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
5.6
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
5.7
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
69
6.1
69
Arranjos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1
70
6.1.2
70
6.1.3
. . . . . . . . . . . . .
71
6.1.4
. . . . . . . . . . . . . . . . . . . . . . . .
72
6.1.5
Arranjos de arranjos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
. . . . . . . . . . . . . . . . . . . . . . . .
vi
SUMRIO
Inicializao de Arranjos . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
6.1.7
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
6.2
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
6.3
Ponteiros
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
6.3.1
79
6.3.2
Ponteiros e arranjos
79
6.4
6.5
6.1.6
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Cadeias de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
6.4.1
80
6.4.2
. . . . . . . . . . . . . . . . . . . . . .
81
6.4.3
81
6.4.4
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
6.4.5
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Registros
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
typedef
6.5.1
6.5.2
6.5.3
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
87
89
89
. . . . . . . . . . . . . . . . . . . . . . . .
89
6.6
Exerccios Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
6.7
Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
6.8
Notas Bibliogrcas
94
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Exerccios
95
7.1
ENCOTEL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2
PAPRIMAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
96
7.3
ENERGIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
7.4
CIRCUITO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
7.5
POLEPOS
101
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
105
B Tipos bsicos em C
107
B.1
B.2
Nmeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
107
B.1.1
. . . . . . . . . . . . . . . . . .
108
Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
108
C Programas e Bibliotecas
111
Prefcio
Este livro se prope acompanhar voc no incio do longo caminho que leva ao desenvolvimento
do raciocnio abstrato necesrio para construir bons algoritmos e programas. Para isto, o leitor
ser introduzido nos conceitos bsicos de programao, de forma que posteriormente possa asimilar
contedos mais avanados.
Recursos Adicionais
Uma pgina na Internet associada a este livro pode ser encontrada no endereo:
http://www.dcc.ufmg.br/camarao/ipcc
O texto desse livro e os cdigos da maioria dos programas apresentados no livro como exemplos
encontram-se disponveis nesta pgina. Outros recursos disponveis incluem sugestes de exerccios
adicionais e projetos de programao, transparncias para uso em cursos baseados neste livro e
referncias para outras pginas da Internet que contm informaes sobre a linguagem
ou sobre
C,
http://pt.wikibooks.org/wiki/Programar_em_C:
ser encon-
a pro-
viii
Prefcio
http://publications.gbdirect.co.uk/c_book/:
edio do livro The C Book , de Mike Banahan, Declan Brady e Mark Doran, publicado pela
Addison Wesley em 1991.
http://www.cyberdiem.com/vin/learn.html:
http://c-faq.com/index.html:
C, e suas respostas
(em ingls).
http://cm.bell-labs.com/cm/cs/who/dmr/chist.html:
http://www.livinginternet.com/i/iw_unix_c.htm:
http://www.cs.ucr.edu/ nxiao/cs10/errors.htm:
in C".
Livros adicionais sobre a linguagem
incluem:
A linguagem de programao padro ANSI C . B. Kernighan & D.C. Ritchie. Editora Campus,
1990.
C: A Reference Manual , Samuel P. Harbison & Guy L. Steele, quinta edio, Prentice Hall,
2002.
http://www.youtube.com/watch?v=XHosLhPEN3k
Captulo 1
Computadores e Programas
1.1 Computadores e Algoritmos
Computadores so empregados atualmente nas mais diversas atividades, como edio e composio de textos, sons e imagens, mecanizao e automatizao de diversas tarefas, simulao dos
mais variados fenmenos e transferncia de grandes volumes de informao entre locais possivelmente muito distantes. Seu uso em atividades cientcas permitiu transpor inmeras fronteiras,
assim como criar novas e desaantes reas de investigao.
Como pode-se explicar to grande impacto? O que diferencia um computador de uma ferramenta qualquer?
Na realidade, o conjunto das operaes bsicas executadas por um computador to simples
quanto o de uma pequena calculadora. A grande distino de um computador, responsvel por
sua enorme versatilidade, est no fato dele ser programvel. Computadores podem realizar tarefas
complexas pela combinao de suas operaes bsicas simples. Mas, como isso possvel? Como
podemos descrever para o computador a tarefa que queremos que ele execute?
Para que um computador possa executar qualquer tarefa, preciso que lhe seja fornecida
uma descrio, em linguagem apropriada, de como essa tarefa deve ser realizada. Tal descrio
chamada de programa e a linguagem usada para essa descrio, de linguagem de programao . A
idia ou processo que esse programa representa chamada de algoritmo .
Essa
realizar clculos matemticos ou tocar um instrumento musical, so exemplos de tarefas que podem ser executadas usando um algoritmo. Receitas de cozinha, instrues de montagem, regras
de clculo e partituras musicais so exemplos de programas (representaes de algoritmos) para
realizar essas tarefas.
A distino entre algoritmo e programa similar distino existente, por exemplo, entre
nmero e numeral.
Por exemplo, no escrevemos nmero representado por 7 ou nmero denotado por 7, mas
simplesmente nmero 7. til saber, no entanto, que podem existir diversas denotaes para
um mesmo algoritmo, assim como um nmero pode ser escrito de diferentes maneiras, tais como:
VII
sete
seven
|||||||
Embora seja capaz de executar apenas um pequeno nmero de operaes bsicas bastante
simples, um computador pode ser usado, em princpio, para resolver qualquer problema cuja soluo
possa ser obtida por meio de um algoritmo. O segredo que um computador prov tambm um
conjunto de instrues para a combinao dessas operaes que, embora tambm reduzido,
suciente para expressar qualquer algoritmo. Essa tese, de que o conjunto de operaes bsicas e
instrues de um computador suciente para expressar qualquer algoritmo, constitui um resultado
Computadores e Programas
fundamental das primeiras pesquisas tericas em computao, as quais lanaram as bases para a
Como construir algoritmos para a soluo de problemas e como expressar tais algoritmos de
modo adequado usando uma linguagem de programao constituem os temas centrais deste livro.
Entretanto, faremos agora um pequeno parntese para estudar brevemente as bases da organizao
e o funcionamento de um sistema de computao. Esse conhecimento nos permitir entender como
o computador executa os nossos programas.
1.
computador, em uma linguagem que tem apenas esses dois smbolos, isto , uma linguagem binria.
processador l a instruo corrente, executa a operao especicada nessa instruo e determina
qual a prxima instruo do programa que deve ser executada. Isso se repete at a execuo de
uma instruo que indica o trmino do programa.
Muitas dessas instrues precisam de um lugar de onde tirar os operandos e onde armazenar
temporariamente os resultados. Esse lugar chamado de registrador, e podemos v-lo como um
conjunto de caixinhas etiquetadas onde guardamos dados (sequencias de bits que representam um
nmero, um caracter, ou outro valor),
um de cada vez.
corresponde sua posio nessa seqncia. Cada unidade de armazenamento de dados da memria
comumente chamada de uma palavra . Uma palavra de memria usualmente composta de um
pequeno nmero (em geral, 4 ou 8) de bytes cada byte armazena uma seqncia de 8 bits.
O outro grupo de componentes do computador constitudo pelos seus dispositivos de entrada
Linguagem de mquina
A linguagem de mquina de um computador consiste das instrues que seu processador pode
entender. Elas so instrues para comandar a execuo de operaes bsicas, tais como somar
dois nmeros ou comparar se dois nmeros so iguais, instrues para transferncia de dados entre
a memria e os registradores do processador, ou entre a memria e os dispositivos de entrada e
sada, e instrues para controlar o uxo de execuo das instrues de um programa. J que o
que o processador entende so sequencias de bits, um programa escrito em linguagem de mquina
deve estar escrito em esse formato. Vejamos um exemplo.
Vamos escrever um programa para calcular o fatorial de um nmero. Lembremos da matemtica
que o fatorial de um nmero o resultado da multiplicao sucessiva da sequncia de inteiros de
1 at o nmero em questo. O nosso programa pode executar ento:
fact
fact
fact
num
fact * (num - 1)
fact * (num - 2)
...
fact
fact * 1
Operao
Cdigo
0000
0001
0010
0011
0100
Assumamos que a nossa mquina tem no mnimo dois registros R1 e R2 em cujas etiquetas
aparece 00 e 01 respectivamente. O nosso programa ir:
R1
o valor numrico 1;
R2
o valor numrico 6;
R1;
R1
R2
e armazen-lo
R2;
R2
Computadores e Programas
R1
Localizao
Operao
0x00e2
CARREGAR #1 no registro R1
0x00e3
CARREGAR #6 no registro R2
0x00e5
0x00e7
Leitor atento: Os autores escolheram um valor pequeno para o clculo do fatorial por um bom
motivo. Repare que para valores maiores do que 6 no poderiamos efetuar este clculo nessa nossa
mquina: o resultado iria ultrapassar os 12 bits, e por tanto, o valor que pode ser armazenado em
um registro dessa mquina. Este problema chamado de
veja o exemplo ?? para mais detalhes.
a erros, difceis de detectar e corrigir. Por esse motivo, os programadores logo passaram a usar
nomes para as operaes e dados, escrevendo, por exemplo, as instrues acima, da seguinte forma:
MOV R1, 1
MOV R2, 6
L:
MUL R1, R2
SUB R2, 1
JNZ L
OUT R1
Linguagem de montagem
Um programa escrito nessa forma era ento manualmente traduzido para linguagem de mquina, e depois carregado na memria do computador para ser executado.
O passo seguinte foi transferir para o prprio computador essa tarefa de montar o programa
em linguagem de mquina, desenvolvendo um programa para realizar essa tarefa. Esse programa
chamado de montador ,
4
linguagem de montagem .
3 Em
4 Em
ingls,
ingls,
assembler .
assembly language .
Compilao
Para que um programa escrito em uma linguagem de alto nvel possa ser executado pelo computador, ele precisa ser primeiro traduzido para um programa equivalente em linguagem de mquina.
Esse processo de traduo chamado de compilao e o programa que faz essa traduo, de compi-
Interpretao
Outro processo para execuo de um programa em linguagem de alto nvel, em vez da compilao desse programa seguida pela execuo do cdigo objeto correspondente, a interpretao
do programa fonte diretamente. Um interpretador , como o nome indica, um programa que interpreta diretamente as frases do programa fonte, isto , simula a execuo dos comandos desse
programa sobre um conjunto de dados, tambm fornecidos como entrada para o interpretador. A
interpretao de programas escritos em uma determinada linguagem dene uma mquina virtual,
na qual realizada a execuo de instrues dessa linguagem.
A interpretao de um programa em linguagem de alto nvel pode ser centenas de vezes mais
lenta do que a execuo do cdigo objeto gerado para esse programa pelo compilador. A razo disso
que o processo de interpretao envolve simultaneamente a anlise e simulao da execuo de
cada instruo do programa, ao passo que essa anlise feita previamente, durante a compilao,
no segundo caso.
principalmente devido ao fato de que, em geral, mais fcil desenvolver um interpretador do que
um compilador para uma determinada linguagem.
Voc provavelmente j ouviu falar alguma vez da linguagem Java. Um sistema (ambiente) de
programao e execuo de programas em Java baseado em uma combinao dos processos de
compilao e interpretao: um compilador Java gera um cdigo de mais baixo nvel, chamado de
bytecodes , que ento interpretado. Um interpretador de bytecodes interpreta instrues da chamada Mquina Virtual Java (Em ingls JVM Java Virtual Machine) Esse esquema usado no
ambiente de programao Java no apenas contribuiu para facilitar a implementao da linguagem
em grande nmero de computadores diferentes, mas constitui uma caracterstica essencial no desenvolvimento de aplicaes voltadas para a Internet, pois possibilita que um programa compilado
em um determinado computador possa ser transferido atravs da rede e executado em qualquer
outro computador que disponha de um interpretador de bytecodes . Outras linguagens interpretadas muito conhecidas so Python e Lua. Lua uma linguagem de programao brasileira muito
utilisada na programao de jogos que forma parte do Ginga, o padro brasileiro de televiso
digital.
Ambientes de Programao
Alm de compiladores e interpretadores, um ambiente de programao de uma determinada
linguagem de alto nvel oferece, em geral, um conjunto de bibliotecas de componentes ou mdulos de
programas, usados comumente no desenvolvimento de programas para diversas aplicaes. Alm
Computadores e Programas
(i.e. criar ou modicar) qualquer documento textual (um texto signicando uma seqncia de
caracteres, separados linha por linha).
caracteres de controle, para facilitar a visualizao do texto editado, por exemplo colocando em
destaque (em negrito ou com uma cor diferente) palavras-chave da linguagem.
Um depurador um programa que oferece funes especcas para acompanhamento da execuo de um programa, com o objetivo de auxiliar o programador na deteco e identicao da
origem de erros que possam existir em um programa.
Em um ambiente de programao convencional, editores, compiladores, interpretadores e depuradores so programas independentes. Em um ambiente integrado de programao, ao contrrio,
as tarefas de edio, compilao, interpretao e depurao so oferecidas como opes disponveis
em um mesmo programa.
A execuo de programas em um computador iniciada e controlada por um programa denominado sistema operacional. O sistema operacional controla a operao em conjunto dos diversos
componentes do computador processador, memria e dispositivos de entrada e sada assim
como a execuo simultnea de diversos programas pelo computador. A execuo do ncleo do
sistema operacional iniciada no momento em que o computador ligado, quando esse ncleo
transferido do disco para a memria do computador, permanecendo residente na memria enquanto
o computador estiver ligado. O ncleo do sistema operacional prov uma interface adequada entre
a mquina e os demais programas do sistema operacional que, por sua vez, oferecem uma interface
adequada entre os diversos componentes do computador e os usurios e seus programas, em um
ambiente de programao.
qualquer, onde
p=
n
X
di bi
i=0
onde cada
di ,
para
i = 0, . . . , n,
b 1.
No sistema de numerao binrio (de base 2), o numeral 1011, por exemplo, representa o
nmero decimal 11, conforme se mostra a seguir (um subscrito usado para indicar a base
do sistema de numerao em cada caso):
10112 = 1 23 + 0 22 + 1 21 + 1 20 = 1110
1101012
p=
2n+1 < p 2n .
Pn
=
=
2q0 + d0
2(2q1 + d1 ) + d0 = 22 q1 + 2d1 + d0
.
.
.
=
=
=
uma vez que teremos
qn = 0.
29510
2. Uma das operaes bsicas que um computador capaz de realizar a operao de somar
dois nmeros inteiros. Como essa operao executada em um computador?
Os componentes bsicos dos circuitos eletrnicos de um computador moderno so chamados
de portas lgicas. Uma porta lgica simplesmente um circuito eletrnico que produz um
sinal de sada, representado como
respectivamente, que o resultado de uma operao lgica sobre os seus sinais de entrada.
Essas operaes lgicas no, , ou, ou exclusivo, representadas pelos smbolos (ou
conectivos lgicos)
, , , ,
Computadores e Programas
Operao
Operao
Resultado
no
V
V
F
F
F
V
V
F
Resultado
()
op
op
op
op
V
F
V
F
op =
V
F
F
F
(ou)
op =
V
V
V
F
(ou exclusivo)
op =
F
V
V
F
Para entender como portas lgicas podem ser usadas para implementar a soma de nmeros
inteiros positivos em um computador, considere primeiramente a soma de dois nmeros
m,
representados na base binria, cada qual com apenas 1 bit, ilustrada a seguir:
1
1
0
0
+
+
+
+
1
0
1
0
=
=
=
=
10
01
01
00
n
1
1
0
0
ou
m
1
0
1
0
vai um
1
0
0
0
r
0
1
1
0
Ao comparar a tabela acima com as operaes lgicas denidas na Tabela 1.1, fcil perceber
n + m:
o bit
igual a
contrrio. O bit vai um desse numeral obtido pela operao lgica : o bit vai um
igual a
quando
O resultado da soma
so iguais a
n+m
1,
e igual a
em caso contrrio.
(n m, n m),
em
m n = (m n) (m n).
Com base nessas observaes, ca fcil construir um circuito para somar dois nmeros binrios
m,
cada qual representado com apenas 1 bit. Esse circuito, chamado de meio-somador ,
apresentado na Figura 1.3. Smbolos usuais so empregados, nessa gura, para representar
as portas lgicas que implementam as operaes , ou e no.
O meio-somador pode ser usado para construir um circuito que implementa a soma de trs
nmeros binrios
n, m
p,
n + m + p = (n + m) + p. Sendo n + m = (v1 , r1 ) e
r1 + p = (v2 , r), temos que n + m + p = (v1 v2 , r), uma vez que v1 e v2 no podem ser
ambos iguais a 1. O circuito lgico que implementa a soma n + m + p, chamado de somador
A Figura 1.5 ilustra um circuito somador paralelo para somar nmeros binrios
qual representado com 3 bits,
ABC
DEF,
m,
cada
respectivamente.
3. Sabemos que um computador capaz de operar com nmeros inteiros, positivos ou negativos.
Como nmeros inteiros negativos so representados no computador?
Para maior facilidade de armazenamento e de operao, todo nmero representado, em um
computador, por uma seqncia de bits de tamanho xo. No caso de nmeros inteiros, esse
tamanho igual ao nmero de bits que podem ser armazenados na palavra do computador.
Em grande parte dos computadores modernos, esse tamanho de 32 bits ou, em computadores
ainda mais modernos, de 64 bits.
Para representar tanto nmeros inteiros no-negativos quanto negativos, um determinado
bit dessa seqncia poderia ser usado para indicar o sinal do nmero essa abordagem
chamada de sinal-magnitude .
A abordagem de sinal-magnitude no muito adequada, pois existem nesse caso duas possveis representaes para o zero e as operaes de somar nmeros no to simples quanto no
caso da representao em complemento de dois , usada em todos os computadores modernos.
A caracterstica fundamental dessa representao a de que a operao de somar
1 ao maior
inteiro positivo fornece o menor inteiro negativo. Desse modo existe apenas uma representao para o zero e pode-se realizar operaes aritmticas de modo bastante simples.
Ilustramos, na Tabela 1.2, a representao de nmeros na notao de complemento de
em um computador com uma palavra de apenas 4 bits. Note que existem
distintas em uma palavra de
2n
2n
nmeros inteiros,
combinaes
2(n1)
2(n1) 1.
10
Computadores e Programas
nmero positivo
2n p.
p 0
p<0
p, cn2 (|p|).
0000
-8
1000
0001
-1
1111
0010
-2
1110
0011
-3
1101
0100
-4
1100
0101
-5
1011
0110
-6
1010
0111
-7
1001
p,
Por exemplo:
representao de -1 em 4 bits
representao de -7 em 4
c2n (p), a representao de p na base binria pode ser obtida calculando o complemento de 2
n
n n
4
4
de c2 (p), ou seja, c2 (c2 (p)). Por exemplo: de c2 (p) = 11112 obtemos p = c2 (11112 ) = 00012 .
Exerccio : Determine a representao na base decimal do nmero
tal que
10011111,
01100001
Voc provavelmente ter observado que o bit mais esquerda da representao de um nmero
inteiro na notao de complemento de 2 igual a
1,
0,
caso contrrio. Esse bit pode ser, portanto, interpretado como o sinal do nmero.
Usando essa representao, a adio de dois nmeros inteiros
usual, sendo descartado o bit vai um obtido mais esquerda. Por exemplo:
01102
+ 10012
= 11112
Ou seja,
6 + (7) = 1
11102
+ 11012
= 10112
1.5 Exerccios
1. Determine a representao, no sistema de numerao binrio, de cada um dos seguintes
nmeros, escritos na base decimal:
(a) 19
11
(b) 458
11102
(b)
1101102
1011 + 101
(b)
10100 1101
(b) 108
11010011
(b)
11110000
6. Indique como seria feito o clculo das seguintes operaes, em um computador que utiliza
notao de complemento de 2 para representao de nmeros e tem palavra com tamanho
de 8 bits:
(a)
57 + (118)
(b)
(15) + (46)
Ao
leitor interessado em saber mais sobre esse assunto, recomendamos a leitura de [?]. Uma discusso
interessante sobre a inuncia dos recentes resultados da teoria da computao no desenvolvimento
tecnolgico e cientco alcanados no sculo 20 apresentada em [?] e [?].
Para um bom entendimento sobre os fundamentos tericos da computao, necessrio algum
conhecimento de matemtica discreta, que abrange temas como lgica matemtica, teoria de conjuntos, relaes e funes, induo e recurso. Dois livros excelentes, que abordam esses temas de
maneira introdutria, so [?] e [?].
O funcionamento e organizao de computadores, descritos brevemente neste captulo, discutido detalhadamente em diversos livros especcos sobre o assunto, dentre os quais recomendamos
[?,
?, ?].
12
Computadores e Programas
Captulo 2
Paradigmas de Programao: o
paradigma imperativo
O nmero de linguagens de programao existentes atualmente chega a ser da ordem de alguns
milhares
Carregar no registrador
R1
o valor numrico 1;
Carregar no registrador
R2
o valor numrico 6;
Decrementar o valor em
R2;
Voc concorda que o seguinte trecho de cdigo tem uma funcionalidade equivalente?
11
R1
12
R2
13
faz
14
R1
15
R2
1
6
R1 * R2
R2 - 1
16
enquanto R2 > 0
17
imprime (R1)
2O
termo instruo em geral usado para linguagens de mais baixo nvel, enquanto o termo comando, em
14
Este programa, apesar de pequeno, ilustra os tipos de comando bsicos presentes em um grande
grupo de linguagens de programao. Esse conjunto de comandos est enumerado na gura 2.1.
I.- um comando de atribuio usado para armazenar um valor em uma determinada posio
de memria (linhas 11, 12, 14 e 15);
II.- comandos para leitura de dados, de dispositivos de entrada, e para escrita de dados, em
dispositivos de sada (linha 17);
III.- trs formas distintas de combinao de comandos:
repetio execuo de um comando repetidas vezes, at que uma condio seja satisfeita (linhas 1316).
A linguagem
uma linguagem
imperativa.
Existem, em contraposio, outros paradigmas de programao, chamados declarativos , nos
quais um programa se assemelha mais a uma descrio de o que constitui uma soluo de um
determinado problema, em lugar de como proceder para obter essa soluo.
O foco deste livro est em apresentar uma viso geral dos principais conceitos da programao
imperativa. Para isto, dedicaremos os seguintes captulos ao estudo dos comandos que caracterizam as linguagens que suportam este paradigma, enumerados na gura
O leitor atento diz: Os autores armam que linguagens imperativas tem somente comandos de
atribuio, entrada/saida e combinaes deles. Ento me digam, como eu posso executar operaes
matemticas usando essas linguagens?
Os autores respondem: Na realidade, para descrever operaes utilizamos
expresses, e no
comandos. Uma expresso uma combinao de variveis, constantes e operadores que, quando
avaliada, resulta num valor. Antes de aprofundar no conceito de expresses precisamos falar um
pouco desses conceitos.
Exemplos de tipos so o tipo caractere (admite valores como 'c', 'a') e o tipo nmero
inteiro (admite valores como 3, -400). Veja o anexo B para uma descrio dos tipos bsicos em C.
O estado da memria aps a execuo do seguinte trecho de programa:
media
aluno
10
'P'
2.2 Operadores
15
media
aluno
comando:
media
aluno
177
'P'
media
aluno
Esse conceito de varivel difere daquele a que estamos acostumados em matemtica. Em uma
expresso matemtica, toda ocorrncia de uma determinada varivel denota um mesmo valor. Em
um programa em linguagem imperativa, ao contrrio, ocorrncias distintas de uma mesma varivel
podem representar valores diferentes, uma vez que tais linguagens so baseadas em comandos que
tm o efeito de modicar o valor armazenado em uma varivel, durante a execuo do programa.
Alm disso, uma determinada ocorrncia de uma varivel no texto de um programa pode tambm
representar valores diferentes, em momentos distintos da execuo desse programa, uma vez que
um comando pode ser executado repetidas vezes. Entretanto, uma varivel sempre ir representar
um valor de cada vez. Por exemplo, no programa anterior o valor de media muda aps a nova
atribuio.
2.2 Operadores
Operadores permitem descrever operaes a serem executadas, como soma, multiplicao e
comparao. Alm do operador de atribuio '=', a linguagem
relacionais e lgicos e de converso de tipo. Os operadores podem ser binrios ou unrios, dependendo de se atuam sobre dois operandos ou um, respectivamente. Operadores binrios se escrevem
entre os dois operandos.
Operadores aritmticos, como seu nome indica, permitem descrever operaes aritmticas, eles
so mostrados na Tabela 2.2.
int,
com ou sem
qualicadores) por outro valor inteiro, chamada em computao de diviso inteira , retorna em
Co
quociente da diviso (a parte fracionria, se existir, descartada). Veja o exemplo da Tabela 2.2:
5/2
igual a
2.
Para obter um resultado com parte fracionria, necessrio que pelo menos um
relacionais so 0 ou 1.
==
dois valores.
resultados da avaliao de
representada por
!=.
e1
e2
== e2
A operao de desigualdade
Leitor atento: Um erro que os principiantes cometem com frequncia tentar comparar mais
de dois valores em operaes relacionais. O compilador gcc retorna uma mensagem de erro curiosa
quando tentamos compilar comparaes no estilo da matemtica:
16
Operador
Signicado
Adio
Subtrao
Negao
Multiplicao
Diviso
Resto
Exemplo
2 + 1
2 + 1.0
2.0 + 1.0
2 - 1
2.0 - 1
2.0 - 1.0
-1
-1.0
2 * 3
2.0 * 3
2.0 * 3.0
5 / 2
5 / 2.0
5.0 / 2.0
5 % 2
5.0 % 2.0
Resultado
3
3.0
3.0
1
1.0
1.0
-1
-1.0
6
6.0
6.0
2
2.5
2.5
1
1.0
Operador
==
!=
<
>
<=
>=
Signicado
Exemplo
1 == 1
1 != 1
1 < 1
1 > 1
1 <= 1
1 >= 1
Igual a
Diferente de
Menor que
Maior que
Menor ou igual a
Maior ou igual a
Operador
!
&&
||
Resultado
verdadeiro
falso
falso
falso
verdadeiro
verdadeiro
Signicado
Negao
Conjuno (no-estrita) ()
Disjuno (no-estrita) (ou)
Por outro lado, operadores lgicos ou booleanos, relacionados na tabela 2.2 servem para combinar
expresses booleanas (operam com valores falso ou verdadeiro), ou seja: o e, ou e no das seguintes
operaes:
A = (b < c) e (c < 6)
A = (c > 3) ou (b > 5)
A = no A
A operao de negao (ou complemento) representada por
!;
mento (de modo que um valor falso (zero) que verdadeiro (diferente de zero), e o inverso tambm
verdadeiro.
O operador
de
e1 && e2
e2
no retorne
2.3 Expresses
17
0 && (0/0 == 0)
retorna falso (0).
Note que o operador de conjuno bit-a-bit,
e1 & e2
ou seja, a avaliao de
&,
e1
e de
e2
0 & (0/0 == 0)
provoca a ocorrncia de um erro (pois
0/0
e1
avaliao de
e1
e2 .
Dessa forma,
e1 && e2 igual ao
e2 s avaliado se a
Ao contrrio, a avaliao de
e1 & e2
e1 quanto de e2 .
|| (l-se ou): e1 || e2
e1 e e2 , tem como resultado
& e
&&, so vlidas para os operadores de disjuno bit-a-bit | e disjuno
||.
e2
em caso contrrio.
.
Por ltimo, est o operador de Converso de Tipo. Converses de tipo podem ocorrer, em
C,
v = e
v,
e em um comando
t.
t0
char
ou
short
ou
byte
igual a
t0
int.
t.
que
t0
(t) e
onde
da expresso
t.
em alterao de um valor pelo truncamento de bits mais signicativos (apenas os bits menos
signicativos so mantidos), no caso de converso para um tipo
por menos bits do que valores do tipo da expresso
e.
cujos valores so representados por mais bits do que valores do tipo da expresso
e,
h uma
t.
2.3 Expresses
Agora que falamos em variveis, atribuies e operadores, j estamos prontos para entender
as expresses. Uma expresso de uma linguagem de programao formada a partir de variveis
e constantes, usando operadores ou funes. Funes na computao, como na matemtica, so
relaes que associam univocamente membros de um conjunto com membros do outro. Elas so
18
Precedncia maior
Operadores
*, /, %
+, >, <, >=, <=
==,!=
&
|
&&
||
? :
Exemplos
* j / k
i + j * k
i < j + k
b == i < j
b & b1 == b2
i j & k
i < j | b1 & b2
i + j != k && b1
i1 < i2 || b && j < k
i < j || b ? b1 : b2
i
(i * j ) / k
i + (j *k )
i < (j +k )
b == (i < j )
b & (b1 == b2 )
i (j & k )
(i < j ) | (b1 & b2 )
((i + j) != k) && b1
(i1 <i2 ) || (b && (j <k ))
((i <j ) || b ) ? b1 : b2
Precedncia menor
(x +y )
s expresses x e y (nesse
precedncia desses operadores, assim como de outros operadores predenidos usados mais comumente, apresentada na Tabela 2.3.
que o operador de multiplicao (*) tem maior precedncia do que o de adio (+) (o que resulta na
como varivel
alvo de uma atribuio representa um lugar (o endereo da rea de memria alocada para
v,
durante a execuo do programa), e no o valor armazenado nessa rea, como no caso em que a
varivel ocorre em uma expresso.
do comando de atribuio x
C,
o prprio comando de atribuio uma expresso (com efeito colateral). Por exemplo,
2.4 Programando em C
19
+ 1;
+ 1
b + 1 no s retorna o valor b
4).
O comando de atribuio no o nico comando que pode modicar o valor de uma varivel.
Isso ocorre tambm no caso de comandos de entrada de dados, tambm chamados de comandos
de leitura , que transferem valores de dispositivos externos para variveis. Um comando de leitura
funciona basicamente como um comando de atribuio no qual o valor a ser armazenado na varivel
obtido a partir de um dispositivo de entrada de dados. Comandos de entrada e sada de dados
so abordados no Captulo
??.
Em
C,
um comando de
= e;
A execuo desse comando tem o efeito de atribuir o valor resultante da avaliao da expresso
varivel
v.
v,
O programa a seguir ilustra que no uma boa prtica de programao escrever programas que
dependam de forma crtica da ordem de avaliao de expresses, pois isso torna o programa mais
difcil de ser entendido e pode originar resultados inesperados, quando esse programa modicado.
A execuo do programa abaixo imprime
em vez de
20.
int
int
i
j
= 10;
= (i =2) * i ;
==.
Usar
em vez de
==
C,
C,
diferente do
2.4 Programando em C
Em
C,
um programa deve ser declarada antes de ser usada. Uma declarao de varivel especica o nome
e o tipo da varivel, e tem o efeito de criar uma nova varivel com o nome especicado.
A declarao reserva um espao na memria do tipo especicado e associa o nome a esse
espao, mas no atribui valor as variveis.
varivel estar indenido, pois no espao reservado estar ainda o valor armazenado previamente
na memria, chamado de lixo de memria. Estamos inicializando uma varivel quando, junto a
declarao da varivel, especicamos qual o valor a ser armazenado nela.
Assim, a declarao:
char x; int
3
= 10; int
z;
comum usar, indistintamente, os termos valor armazenado em uma varivel, valor contido em uma varivel
20
so variveis de tipo
C, e muitas
ecincia na execuo de programas (ou seja, procuram fazer com que programas escritos em
C,
compilao (ou seja, antes da execuo) ou, como comum dizer em computao, em tempo
de compilao (uma forma de dizer que tem inuncia da lngua inglesa). Isso permite que um
compilador
C possa detectar erros de tipo, que so erros devidos ao uso de expresses em contextos
Por exemplo, supondo que + um operador binrio (deve ser
chamado com dois argumentos para fornecer um resultado, seria detectado um erro na expresso
int
+)
de programao permitir que erros sejam detectados, sendo uma mensagam de erro emitida
pelo compilador, para que o programador possa corrigi-los (evitando assim que esses erros possam
ocorrer durante a execuo de programas).
Para impedir que o valor da varivel possa ser modicado usamos o atributo
const na declarao
de varivel. Essa varivel dever ser inicializada, e seu valor permanecer sempre igual no programa.
Ela ento, de fato, uma constante.
Um nome de uma varivel ou funo em
caractere sublinha
'_'),
existem nomes reservados, que no podem ser usados como nomes de variveis ou funes pelo
programador
C.
Por exemplo,
return
usado para especicar o resultado de uma funo e fazer com que a execuo da funo seja
interrompida, retornando o resultado especicado e portanto no pode ser usada como nome
de varivel ou funo. O limite no tamanho do nome depende do standard, o ANSI C Standard
de 1989 admite at 31 caracteres.
Dica de estilo:
O nome de uma varivel ou funo pode ser escolhido livremente pelo programador, mas importante que sejam escolhidos nomes signicativos ou seja, mnemnicos, que lembrem o propsito
ou signicado da entidade (varivel ou funo) representada. Por exemplo, procure usar nomes
como soma , media e pi para armazenar, respectivamente, a soma e a mdia de determinados valores, e uma aproximao do nmero
que no s, m e p so ainda menos mnemnicas, por no ter relao com soma , media e pi ). Isto
muito importante quando o nome ser usado em grande parte do programa. No entanto, til
procurar usar nomes pequenos, a m de tornar o programa mais conciso, quando em fragmentos
pequenos do programa.
Por isso, muitas vezes comum usar nomes como, por exemplo, i e j
double),
entre
um valor de tipo
void;
2.5 Exerccios
21
armazenar endereos de valores do tipo correspondente. Assim, da mesma forma que declaramos
variveis do tipo inteiro:
int a = 5; //reserva espao para armazenar um inteiro na memoria
podemos declarar variveis que armazenem valores de endereos onde existem valores inteiros
armazenados:
int *p;
que declara uma varivel p que pode armazenar valores de memria em que existe um inteiro
armazenado. A sintaxe da declarao de um ponteiro em C :
tipo * nome;
Usamos a atribuio p=NULL; para indicar que o ponteiro p no esta apontando para lugar
algum.
2.5 Exerccios
1. Algumas respostas ERRADAS 'a lista do laboratorio:
- Quando o dividendo inteiro,o programa realiza uma diviso inteira.
Com o (oat) o
programa faz uma diviso normal.Quando o dividendo real a operao feita normalmente.
- a instruo (oat) transforma o resultado da operao 'b / a' em um nmero inteiro para
de seja impresso como inteiro atravs da varivel 'c'.
Responda: O que elas tem de errado?
2. Qual o efeito das declaraes de variveis durante a execuo do trecho de programa abaixo?
int
int
x;
y
= 10;
5
8
e
e
10, respectivamente;
2, respectivamente.
= 0;
if (a > b ) s = (a +b )/2;
while (a <= b ) {
s = s + a;
a = a + 1;
b = b - 2;
}
s
22
fatorial
fatorial
0 = 1
n = n *
fatorial (n -1)
funes podem tambm ser vistas como regras de computao estabelece o carter operacional
dessas linguagens.
Uma caracterstica importante de linguagens funcionais o fato de que possibilitam denir
funes de ordem superior , isto , funes que podem ter funes como parmetros, ou retornar uma
funo como resultado. Essa caracterstica facilita grandemente a decomposio de programas em
componentes (funcionais) e a combinao desses componentes na construo de novos programas.
O maior interesse pela programao funcional apareceu a partir do desenvolvimento da linguagem ML e, mais recentemente, da linguagem Haskell (veja Notas Bibliogrcas).
No paradigma lgico , um programa tem a forma de uma srie de asseres (ou regras), que
denem relaes entre variveis. A denominao dada a esse paradigma advm do fato de que a
linguagem usada para especicar essas asseres um subconjunto da Lgica de Primeira Ordem
(tambm chamada de Lgica de Predicados ). Esse subconjunto da lgica de primeira ordem usado
em linguagens de programao em lgica usa asseres simples (formada por termos, ou expresses,
que tm valor verdadeiro ou falso), da forma:
se
P1 , P2 , . . . , Pn
P1 , . . . , Pn (n 0)
forem verdadeiros.
P2 ,
das avaliaes de
verdadeiro se e
etc., at
P,
execute
P1 ,
A linguagem Prolog a linguagem de programao mais conhecida e representativa do paradigma de programao em lgica. Existe tambm, atualmente, um interesse expressivo em pesquisas com novas linguagens que exploram o paradigma de programao em lgica com restries, e
com linguagens que combinam a programao em lgica, a programao funcional e programao
orientada por objetos (veja Notas Bibliogrcas).
Existem vrios livros introdutrios sobre programao de computadores, a maioria deles em
lngua inglesa, abordando aspectos diversos da computao. Grande nmero desses livros adota
a linguagem de programao PASCAL [?], que foi originalmente projetada, na dcada de 1970,
especialmente para o ensino de programao. Dentre esses livros, citamos [?,
?].
A dcada de 1970 marcou o perodo da chamada programao estruturada [?], que demonstrou
os mritos de programas estruturados, em contraposio programao baseada em linguagens
de mais baixo nvel, mais semelhantes a linguagens de montagem ou linguagens de mquina. A
linguagem Pascal, assim como outras linguagens tambm baseadas no paradigma de programao
imperativo, como
23
A programao orientada por objetos, que teve sua origem bastante cedo, com a linguagem
Simula [?], s comeou a despertar maior interesse a partir da segunda metade da dcada de 1980,
aps a denio da linguagem e do ambiente de programao Smalltalk [?]. A linguagem Smalltalk
teve grande inuncia sobre as demais linguagens orientadas por objeto subseqentes, tais como
C++ [?], Eiel [?] e Java [?].
?].
Um bom estilo de programao no imprescindivel para fazer com que os nossos programas
funcionem. No entanto, ele facilita a compreenso de um programa e por tanto, a sua depurao e
manuteno. O estilo inclui tanto regras de noemeao de variveis e funes quanto a indentao
e como comentar adequadamente seu cdigo. Existem vrios bons livros de estilo de programao.
Uma boa recomendao o captulo 1 do livro The Practice of Programming (A prtica da
programao) de Brian Kernighan e Rob Pike.
24
Captulo 3
Programando em C
Nessa seo voc vai escrever seu primeiro programa
C!
.c .
passo para traduzir o nosso programa de forma que o computador possa entend-lo a compilao.
Para isto, voc pode digitar no shell do Linux
./nome_do_executavel.
(Seno preste
Eles no tm nenhum efeito sobre o comportamento do programa, quando esse executado. Nos
exemplos apresentados neste livro, comentrios so muitas vezes omitidos, uma vez que a funo
e o signicado dos programas so explicados ao longo do texto.
no incio do nosso programa um exemplo desse tipo de comentrio. O segundo tipo de comentrio
comea com os caracteres
//
Na primeira linha tem uma ordem para o preprocessador incluir cdigo de uma biblioteca C
chamada stdio. Em
de E/S no fazem parte da linguagem propriamente dita, mas de uma biblioteca padro, que deve
ser implementada por todos os ambientes para desenvolvimento de programas na linguagem. Essa
biblioteca chamada de stdio . Essa biblioteca necessria porque ela contm o cdigo da funo
printf que usaremos para imprimir o texto que voc viu sair na tela.
A seguir, declarada a funo main , que a funo que inicia a execuo do programa.
denio de uma funo de nome main deve sempre estar presente, para que uma sequncia de
denies de funes forme um programa
C.
Logo aps a denio da funo aparece uma chave e uma sequncia de comandos.
Uma
como um terminador de comandos, devendo ocorrer aps cada comando do programa, que no
seja um bloco.
26
Programando em C
O corpo de essa funo est composto pela chamada a funo printf, que quando executada ir
imprimir o nosso texto, e o return que indica o m da execuo da funo e o retorno do controle
ao shell.
Voc deve ter notado que os comandos nesse programa esto organizados seguindo uma com-
c1
c2
escrita na forma:
c1 ; c2 ;
e consiste na execuo de
Os comandos
c1
c2
c1
e, em seguida, do comando
c2 .
podem, por sua vez, tambm ser formados por meio de composio
seqencial.
A composio seqencial de comandos naturalmente associativa (no sendo permitido o uso
de parnteses). Por exemplo, a seqncia de comandos:
int
a;
int b ; int c ;
= 10;
= 20;
+ b;
int.
alocar uma rea de memria e associar um nome a essa rea, que pode conter valores do tipo
declarado.
2. Analogamente, declarar variveis b e c , de tipo
3. Em seguida, atribuir o valor
10
varivel a.
20
varivel b.
30,
int.
resultante da avaliao de a
b, varivel c.
consistem em
27
/********************************************************
*
*
*
Primeiros exemplos
*
*
*
*
Definies de funes
*
*-*/
int
quadrado
(int
x)
{ return
x *x ;
1. Inicialmente especicado o tipo do valor fornecido como resultado, em uma chamada (aplicao) da funo.
O tipo do valor retornado por cada funo declarada acima
int
int
int
e nome y.
3. Finalmente, denido o corpo do mtodo, que consiste em um bloco, ou seja, uma sequncia
de comandos, delimitada por { (abre-chaves) e } (fecha-chaves).
{ return
retorna o quadrado do
O efeito
return e;
o de avaliar a expresso
e,
28
Programando em C
O nmero e o tipo dos argumentos em uma chamada de mtodo devem corresponder ao nmero
e tipo especicados na sua denio. Por exemplo, em uma chamada a tresIguais , devem existir
trs expresses
e1 , e2
e3 ,
como a seguir:
tresIguais
Essa chamada pode ser usada em qualquer contexto que requer um valor de tipo
palavras, em qualquer lugar onde uma expresso de tipo
int
pode ocorrer.
Soluo :
|,
0 & 0/0 == 0.
0 && 0/0 == 0
Soluo:
||
3.2 Exerccios
29
1 ||
1 |
0/0 == 0
0/0 == 0
&&
||
&&
b tem o
: 0
1 :
||
||
b.
b ) :
3.2 Exerccios
1. Sabendo que a ordem de avaliao de expresses em
2 + 4 - 3
(b)
4 - 3 * 5
(c)
(4 - 1) * 4 - 2
(d)
2 >= 1 && 2 != 1
2. A funo eQuadrado , denida a seguir, recebe como argumentos quatro valores inteiros e
retorna
true
false
em caso
contrrio.
Escreva uma denio de funo que, dados quatro nmeros inteiros, retorna verdadeiro se
eles podem representar os lados de um retngulo, e falso em caso contrrio.
Escreva um programa que leia quatro valores inteiros e imprima uma mensagem indicando
se eles podem ou no os lados de um retngulo, usando a funo acima.
30
Programando em C
&&
||.
Escreva um programa que leia um valor inteiro e responda se ele ou no um ano bissexto,
usando a funo denida acima com a expresso condicional.
4. Dena uma funo somaD3 que, dado um nmero inteiro representado com at trs algarismos, fornece como resultado a soma dos nmeros representados por esses algarismos.
Exemplo: somaD3 (123) deve fornecer resultado
6.
Escreva um programa que leia um valor inteiro, e imprima o resultado da soma desses 3
algarismos, usando a funo somaD3. Por simplicidade, voc pode supor que o inteiro lido
contm apenas 3 algarismos (o seu programa deve funcionar corretamente apenas nesse caso).
5. Dena uma funo inverteD3 que, dado um nmero representado com at trs algarismos,
fornece como resultado o nmero cuja representao obtida invertendo a ordem desses
algarismos. Por exemplo: o resultado de inverteD3 (123) deve ser
321.
Escreva um programa que leia um valor inteiro, e imprima o resultado de inverter esses
algarismos, usando a funo inverteD3. Por simplicidade, voc pode supor que o inteiro lido
contm apenas 3 algarismos (o seu programa deve funcionar corretamente apenas nesse caso).
final float
pi
3.1415:
= 3.1415f;
Use essa denio do valor de pi para denir uma funo que retorna o comprimento aproximado de uma circunferncia, dado o raio.
Escreva um programa que leia um nmero de ponto utuante, e imprima o comprimento de
uma circunferncia que tem raio igual ao valor lido, usando a funo denida acima.
Por
simplicidade, voc pode supor que o valor lido um nmero de ponto utuante algarismos
(o seu programa deve funcionar corretamente apenas nesse caso).
7. Dena uma funo que, dados cinco nmeros inteiros, retorna verdadeiro (inteiro diferente
de zero) se o conjunto formado pelos 2 ltimos nmeros um subconjunto daquele formado
pelos 3 primeiros, e falso em caso contrrio.
Escreva um programa que leia 5 valores inteiros, e imprima o resultado de determinar se o
conjunto formado pelos 2 ltimos um subconjunto daquele formado pelos trs primeiros,
usando a funo denida acima. Por simplicidade, voc pode supor que os valores lidos so
todos inteiros (o seu programa deve funcionar corretamente apenas nesse caso).
8. Dena uma funo que, dado um valor inteiro no-negativo que representa a nota de um
aluno em uma disciplina, retorna o caractere que representa o conceito obtido por esse aluno
nessa disciplina, de acordo com a tabela:
Nota
Conceito
0 a 59
60 a 74
75 a 89
90 a 100
Escreva um programa que leia um valor inteiro, e imprima a nota correspondente, usando a
funo denida acima. Por simplicidade, voc pode supor que o valor lido um valor inteiro
(o seu programa deve funcionar corretamente apenas nesse caso).
3.2 Exerccios
31
9. Dena uma funo que, dados dois caracteres, cada um deles um algarismo, retorna o maior
nmero inteiro que pode ser escrito com esses dois algarismos. Voc no precisa considerar
o caso em que os caracteres dados no so algarismos.
Escreva um programa que leia 2 caracteres, cada um deles um algarismo, e imprima o maior
nmero inteiro que pode ser escrito com esses dois algarismos. Por simplicidade, voc pode
supor que os valores lidos so de fato um caractere que um algarismo (o seu programa deve
funcionar corretamente apenas nesse caso).
10. Escreva uma funo que, dados um nmero inteiro e um caractere representando respectivamente a altura e o sexo de uma pessoa, sendo o sexo masculino representado por
'm'
'F'
ou
'f'
'M'
ou
mulheres
(72, 7 altura) 58
Escreva um programa que leia um nmero inteiro e um caractere, que voc pode supor que
sejam respectivamente o peso de uma pessoa e um dos caracteres dentre
e imprima o peso ideal para uma pessoa, usando a funo denida acima. Voc pode supor
que os dados de entrada esto corretos (o seu programa deve funcionar corretamente apenas
nesse caso).
32
Programando em C
Captulo 4
Escolha condicional
Frequentemente precisamos codicar decises do tipo: se o aluno no entregou a lista a sua
nota 0. A seleo, ou controle de uxo, outra forma de combinao de comandos que possibilita
selecionar um ou outro grupo de instrues para execuo de forma que
Se (condio) ento
executa_bloco_de_comandos
Seno
executa_outro_bloco_de_comandos
Fim Se
segundo o valor da condio seja verdadeiro ou falso.
Em
C,
if (
Nesse comando,
if,
) c1 ; else c2 ;
b,
int.
representa
0,
o comando
c2
0, o comando c1
if,
se o
executado; se
executado.
if (aluno_nao_submeteu_lista) {
nota_aluno = 0;
}
atribudo a varivel nota_aluno o valor 0 caso a condio aluno_nao_submeteu_lista for
verdadeira. Por outro lado, no seguinte exemplo:
impresso Aprovado (caso o valor de nota_aluno seja maior ou igual a 60) ou Reprovado caso
contrrio.
A parte else
c2 ;
(chamada de clusula
else)
b retorna falso.
C, para se usar uma seqncia com mais de um comando no lugar de c1 , ou no lugar de c2 ,
devem ser usadas chaves para indicar o incio e o m da seqncia de comandos. Por exemplo:
34
Escolha condicional
if.
if,
C.
O nosso primeiro problemas pode ser especicado como Dados dois nmeros inteiros, retornar
o mximo entre eles. Para resolv-lo devemos primeiramente entender o problema. A entrada da
nossa funo so dois nmeros inteiros irrestritos. A sada um valor inteiro que se corresponde
com o maior deles. Pense bem: os nmeros podem ser iguais? J que o problema no restringe esse
caso, podemos denir como pre-condio do nosso problema (a condio que deve cumprir a entrada
para podermos garantir a sada desejada pelo usurio) que ambos os nmeros so diferentes. Nesse
caso, para retornar o maior deles devemos compar-los e retornar o primeiro se ele for o maior ou
o segundo caso contrrio. Uma possvel codicao para esta soluo mostrada a seguir:
/* Funo max
* Pre-condio: Recebe dois nmeros inteiros diferentes
* Post-condio: O valor retornado o maior desses nmeros
*/
int max (int a, int b ) {
if (a > b )
return a;
else
return b;
}
O nosso segundo problema Dados trs nmeros inteiros, retornar o mximo entre eles resolve
o problema anterior para o caso de trs nmeros. J que o problema de encontrar o mximo de
dois nmeros pode ser resolvido usando a funo max, podemos us-la para resolver este problema
tambm: repare que o maior de trs nmeros o maior entre qualquer um deles e o maior dos
outros dois:
4.1 Exerccios
Captulo 5
Recurso e Iterao
5.1 Repetio
Em um comando de repetio, um determinado comando, chamado de corpo do comando
de repetio, executado repetidas vezes, at que uma condio de terminao do comando de
repetio se torne verdadeira, o que provoca o trmino da execuo desse comando.
Cada avaliao da condio de terminao, seguida da execuo do corpo desse comando,
denominada uma iterao , sendo o comando tambm chamado comando iterativo .
Para que a condio de terminao de um comando de repetio possa tornar-se verdadeira,
depois de um certo nmero de iteraes, preciso que essa condio inclua alguma varivel que
tenha o seu valor modicado pela execuo do corpo desse comando (mais especicamente exista
um comando de atribuio no corpo do comando de repetio que modique o valor de uma varivel
usada na condio de terminao).
O comando
while
condio de terminao, e
c,
C,
o corpo do comando:
while ( b ) c;
c, a
b avaliada; se o resultado for verdadeiro (isto , diferente de 0), o comando c executado,
e esse processo se repete; seno (i.e., se o resultado da avaliao de b for falso (igual a 0), ento a
1
execuo do comando while termina.
A execuo desse comando consiste nos seguintes passos: antes de ser executado o corpo
condio
1 Devido
loop
e depois
36
Recurso e Iterao
= 0;
= 1;
while ( i <= n ) {
soma = soma + i;
i = i + 1;
}
soma
i
Na execuo do comando
while,
while
armazenado em soma,
executado.
abordados no Captulo 5.
Os conceitos de recurso e iterao constituem, juntamente com as noes de composio
seqencial e seleo, as ferramentas fundamentais para construo de algoritmos e programas, a
partir de um conjunto apropriado de operaes ou comandos bsicos.
introduzidos neste captulo, por meio de uma srie de exemplos ilustrativos, de construo de
programas para clculo de operaes aritmticas simples, tais como:
A soluo de qualquer problema que envolva a realizao de uma ou mais operaes repetidas
vezes pode ser expressa, no paradigma de programao imperativo, por meio de um comando de
repetio (tambm chamado de comando iterativo, ou comando de iterao), ou usando funes
com denies recursivas.
Denies recursivas de funes so baseadas na mesma idia subjacente a um princpio de
prova fundamental em matemtica o princpio da induo . A idia a de que a soluo de um
problema pode ser expressa da seguinte forma: primeiramente, denimos a soluo desse problema
para casos bsicos; em seguida, denimos como resolver o problema para os demais casos, em
termos da soluo para casos mais simples que o original.
acordo com a idia exposta acima, precisamos agora pensar em como podemos expressar a soluo
desse problema no caso em que
n > 0,
37
/***************************************************
int mult (int m, int n) {
int r =0, i ;
for (i =1; i <=n ; i ++) r += m;
return r;
}
int multr (int m, int n) {
if (n ==0) return 0;
else return (m + multr (m ,
}
n -1));
Ou seja, a operao de multiplicao pode ento ser denida indutivamente pelas seguintes
equaes:
m0=0
m n = m + (m (n 1))
se
n>0
Uma maneira alternativa de pensar na soluo desse problema seria pensar na operao de multiplicao
m*n
como a repetio,
m,
isto :
m n = m + ... + m
{z
}
|
n vezes
Raciocnio anlogo pode ser usado para expressar a operao de exponenciao, com expoente
inteiro no-negativo, em termos da operao de multiplicao.
A Figura 5.1 apresenta duas denies alternativas, na linguagem
Note que essas denies so usadas apenas com ns didticos, para explicar inicialmente
denies recursivas e comandos de repetio.
38
Recurso e Iterao
A execuo de uma chamada de funo iniciada, como vimos na Seo 3, com a avaliao
dos argumentos a serem passados funo: no exemplo acima, essa avaliao fornece os valores
representados pelos literais
3 e 2,
do tipo
int.
for
0.
Em seguida, o comando
for
executado.
while,
introduzido na
consiste simplesmente em
adicionar (o valor contido em) m ao valor de r , a cada iterao, e armazenar o resultado dessa
adio em it r. O nmero de iteraes executadas igual a n. Por ltimo, o valor armazenado em
for
entre parnteses
a primeira parte, de inicializao , atribui valores iniciais a variveis, antes do incio das
iteraes. Essa parte de inicializao s executada uma vez, antes do incio das iteraes.
a segunda parte, chamada de teste de terminao , especica uma expresso booleana que
avaliada antes do incio de cada iterao (inclusive antes da execuo do corpo do comando
for pela primeira vez). Se o valor obtido pela avaliao dessa expresso for verdadeiro (em
C, diferente de zero), ento o corpo do comando for executado, seguido pela avaliao da
terceira clusula do cabealho desse comando, e depois uma nova iterao iniciada; caso
contrrio, ou seja, se o valor for falso (em
C,
for
termina.
= i +1,
for,
for:
atualizao.
instrutivo acompanhar a modicao do valor armazenado em cada varivel durante a exe-
cuo da chamada mult (3,2). Em outras palavras, acompanhar, em cada passo da execuo, o
estado da computao: o estado da computao uma funo que associa um valor a cada varivel.
A Tabela 5.1 ilustra os passos da execuo da chamada mult (3,2), registrando, a cada passo,
for
sempre descartado. Essa expresso avaliada apenas com o propsito de atualizar o valor de uma
ou mais variveis (ou seja, uma expresso com efeito colateral).
A varivel i usada no comando
for
0,
Vejamos agora, mais detalhadamente, a execuo de uma chamada multr (3,2). Cada chamada
da funo multr cria novas variveis, de mesmo nome m e n . Existem, portanto, vrias variveis
com nomes (m e n ), devido s chamadas recursivas. Nesse caso, o uso do nome refere-se varivel
local ao corpo da funo que est sendo executado. As execues das chamadas de funes so
feitas, dessa forma, em uma estrutura de pilha. Chamamos, genericamente, de estrutura de pilha
uma estrutura na qual a insero (ou alocao) e a retirada (ou liberao) de elementos feita de
maneira que o ltimo elemento inserido o primeiro a ser retirado.
Como a execuo de chamadas de funes feita na forma de uma estrutura de pilha, em cada
instante da execuo de um programa, o ltimo conjunto de variveis alocados na pilha corresponde
s variveis e parmetros da ltima funo chamada. No penltimo espao so alocadas as variveis
39
Comando/
Expresso
Resultado
Estado
(expresso)
(aps execuo/avaliao)
mult (3,2)
...
int
= 0
i = 1
i <= n
r += m
i ++
i <= n
r += m
i ++
i <= n
for ...
return r
mult (3,2)
r
m
m
m
verdadeiro
3
2
verdadeiro
6
3
falso
m
m
m
m
m
m
m
m
7
7
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
n
n
n
n
n
n
n
n
n
n
n
7
7
2
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
r
r
r
r
r
r
r
r
r
r
7
7
0
0,
0,
3,
3,
3,
6,
6,
6,
6,
i
i
i
i
i
i
i
i
i
7
7
1
1
1
2
2
2
3
3
3
parmetros alocado para uma funo chamado de registro de ativao dessa funo.
O registro de ativao de cada funo desalocado (isto , a rea de memria correspondente na
pilha liberada para uso por outra chamada de funo) no instante em que a execuo da funo
termina. Como o trmino da execuo da ltima funo chamada precede o trmino da execuo
da penltima, e assim por diante, o processo de alocao e liberao de registros de ativao de
chamadas de funes se d como em uma estrutura de pilha.
As variveis que podem ser usadas no corpo de uma funo so apenas os parmetros dessa
funo e as variveis internas a declaradas (chamadas de variveis locais da funo), alm das
variveis externas, declaradas no mesmo nvel da denio da funo, chamadas de varivveis
globais.
Variveis declaradas internamente a uma funo so criadas cada vez que uma chamada a essa
funo executada, enquanto variveis globais so criadas apenas uma vez, quando a execuo do
programa iniciada ou anteriormente, durante a carga do cdigo do programa na memria.
No momento da criao de uma varivel local a uma funo, se no foi especicado explicitamente um valor inicial para essa varivel, o valor nela armazenado ser indeterminado, isto , ser
o valor j existente nos bytes alocados para essa varivel na pilha de chamadas de funes.
Na Figura 5.2, representamos a estrutura de pilha criada pelas chamadas funo multr. Os
nomes m e n referem-se, durante a execuo, s variveis mais ao topo dessa estrutura.
Uma
chamada recursiva que vai comear a ser executada circundada por uma caixa. Nesse caso, o
resultado da expresso, ainda no conhecido, indicado por ....
As denies de exp e expr seguem o mesmo padro de denio das funes mult e multr ,
respectivamente. A denio de expr baseada na seguinte denio indutiva da exponenciao:
m0 = 1
mn = m mn1
se
n>0
Ecincia
Uma caracterstica importante da implementao de funes, e de algoritmos em geral, a sua
m0 = 1
mn = (mn/2 )2
mn = m mn1
se
se
n
n
mn
par
mpar
40
Recurso e Iterao
Comando/
Expresso
multr
n
(aps execuo/avaliao)
m
n
== 0
falso
== 0
n
m
...
n
m
falso
Estado
(expresso)
(3,2) . . .
Resultado
== 0
n
m
...
verdadeiro
return
+ 3
(3,2)
multr
n
m
return 0
return
n
m
+ 0
7
7
7
7
7
7
7
7
7
7
7
7
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
m
n
m
n
m
n
m
n
m
n
3
1
3
1
3
1
3
1
3
1
7
7
m
n
m
n
7
7
3
0
3
0
por
a cada chamada;
Por exemplo, as chamadas recursivas que ocorrem durante a avaliao da expresso exp2 (2,20)
exp2 (2,20)
exp2 (2,10)
exp2 (2,5)
exp2 (2,4)
exp2 (2,2)
exp2 (2,1)
exp2 (2,0)
A diferena em ecincia se torna mais signicativa quando o expoente
da ordem de
log2 (n)
n maior.
So realizadas
5.3 Fatorial
41
em mdia dividido por 2 em chamadas recursivas , ao passo que a execuo de exp (m,n ) requer
n iteraes.
Um exerccio interessante aplicar a mesma tcnica usada na denio de exp2 (ou seja, usar
diviso por 2 caso o segundo operando seja par) para obter uma denio mais eciente para a
multiplicao (procure resolver esse exerccio antes de ver sua soluo, no Exerccio Resolvido 2).
Questes sobre ecincia de algoritmos so importantes em computao, envolvendo aspectos
relativos ao tempo de execuo e ao consumo de memria (referidos abreviadamente como aspectos
de tempo e espao). A anlise da ecincia de algoritmos abordada supercialmente ao longo
deste texto, sendo um estudo mais detalhado desse tema deixado para cursos posteriores.
5.3 Fatorial
Nesta seo, exploramos um pouco mais sobre recurso e iterao, por meio do exemplo clssico
do clculo do fatorial de um nmero inteiro no-negativo
n,
n! = n (n 1) (n 2) . . . 3 2 1
Duas formas comuns para implementao dessa funo so mostradas a seguir:
*= i;
A funo fatr espelha diretamente a seguinte denio indutiva, que especica precisamente o
n! = 1
n! = n (n 1)!
n!
se
dada acima:
n=0
em caso contrrio
varia de
1 2 . . . i,
42
Recurso e Iterao
chamada recursiva de uma funo obtido pela aplicao de funes a valores obtidos na iterao
ou chamada recursiva anterior.
O exemplo mais simples o clculo do somatrio de termos de uma srie aritmtica.
exemplo, considere o clculo do somatrio dos termos da srie aritmtica de passo 1,
um dado
n,
Pn
Por
i=1 i, para
+= i;
Assim como para o clculo do fatorial, duas verses recursivas, que usam processos de clculo
diferentes, podem ser implementadas. Essas denies so mostradas a seguir. A primeira (pa1r )
espelha diretamente a denio indutiva de
Pn
simples modicar essas denies para o clculo de somatrios dos termos de sries aritmticas
com passo diferente de 1. Essas modicaes so deixadas como exerccio para o leitor.
Nenhuma dessas implementaes constitui a maneira mais eciente para calcular a soma de
termos de uma srie aritmtica, pois tal valor pode ser calculado diretamente, usando a frmula:
2O
leitor com interesse em matemtica pode procurar deduzir essas frmulas. Conta a histria que a frmula
n
X
i=
i=1
43
n(n + 1)
2
n
X
xi
i=0
Tambm nesse caso, podemos usar um comando de repetio, como na implementao de pa1 ,
sendo adequado agora usar uma varivel adicional para guardar a parcela obtida em cada iterao.
Essa varivel chamada parc na implementao apresentada a seguir, que calcula o somatrio das
parcelas da srie geomtrica,
Pn
i=0
xi ,
xi
exponenciao tenha que ser efetuada) a cada iterao. Em vez disso, a parcela da i-sima iterao
(contida em parc ), igual a
n
X
1
i=1
1/(i -1):
i=1
i=
n(n+1)
foi deduzida e usada por Gauss quando ainda garoto, em uma ocasio em que um professor de
2
matemtica pediu-lhe, como punio, que calculasse a soma dos 1000 primeiros nmeros naturais.
Deduzindo a
1
n
Pn
para o leitor.
3A
seqncia de nmeros
i=0
xi =
+
+
n
2
(n 1)
+
+
termos iguais a
...
...
+
+
(n 1)
2
+
+
n
1
n + 1.
xn+1 1
pode ser feita com artifcio semelhante, e deixada como exerccio
x1
1, 21 , 13 , . . . ,
1
, . . . denominada
n
srie harmnica .
44
Recurso e Iterao
Na maioria das vezes, uma parcela pode ser calculada de maneira mais fcil e eciente a partir da
parcela calculada anteriormente. Em vrios casos, esse clculo no usa a prpria parcela anterior,
mas valores usados no clculo dessa parcela. Por exemplo, considere o seguinte somatrio, para
clculo aproximado do valor de
:
= 4 (1
1 1 1
+ + . . .)
3 5 7
Nesse caso, devemos guardar no o valor mas o sinal da parcela anterior (para invert-lo) e o
denominador usado para clculo dessa parcela (ao qual devemos somar 2 a cada iterao):
sinal
= 1;
Em nosso ltimo exemplo, vamos denir uma funo para calcular um valor aproximado para
ex ,
para um dado
x,
usando a frmula:
while
i!
e o numerador
(em vez do
for),
xi ,
para ilustrao:
for
ou um comando
while
em
for
ou um comando
while
continue usado
continue usado
c1 :
for (c1 ; b; c2 ) c
c1 ; while (b) { c; c2 ; }
Outro comando de repetio disponvel em
o comando
forma:
do c; while (b);
do-while.
onde
um comando e
ao comando
while.
No caso do comando
45
10,
(b).
do-while,
no entanto, o comando
executado uma
int i = 1;
do { printf ("%d ",i );
i ++;
} while (i <= 10);
5.4.1 No-terminao
Pode ocorrer, em princpio, que a avaliao de certas expresses que contm smbolos denidos
recursivamente, assim como a execuo de certos comandos de repetio, no termine. Considere,
como um exemplo extremamente simples, a seguinte denio:
int
innito ()
{ return
innito ()
+ 1; }
int.
valor? A avaliao de uma chamada funo innito nunca termina, pois envolve, sempre, uma
nova chamada a essa funo. O valor representado por uma chamada a essa funo no , portanto,
nenhum valor inteiro. Em computao, qualquer tipo, predenido ou declarado em um programa,
em geral inclui um valor especial, que constitui um valor indenido do tipo em questo e que
representa expresses desse tipo cuja avaliao nunca termina ou provoca a ocorrncia de um erro
(como, por exemplo, uma diviso por zero).
Muitas vezes, um programa no termina devido aplicao de argumentos a funes cujo
domnio no engloba todos os valores do tipo da funo. Essas funes so comumente chamadas,
em computao, de parciais . Por exemplo, a denio de fat , dada anteriormente, especica que
essa funo recebe como argumento um nmero inteiro e retorna tambm um nmero inteiro. Mas
note que, para qualquer n
< 0,
claro, ser modicada de modo a indicar a ocorrncia de um erro quando o argumento negativo.
Considere agora a seguinte denio de uma funo const1 que retorna sempre
1,
para
qualquer argumento:
int
const1
(int
x)
{ return 1; }
A avaliao da expresso:
maioria das linguagens de programao, a avaliao dos argumentos de uma funo feita antes
do incio da execuo do corpo da funo.
46
Recurso e Iterao
A soluo de qualquer problema que envolva a realizao de uma ou mais operaes repetidas
vezes pode ser expressa, no paradigma de programao imperativo, por meio de um comando de
repetio ou usando funes com denies recursivas.
A escolha de um ou outro mtodo, recursivo ou iterativo, muitas vezes uma questo de estilo,
mas diversos aspectos podem inuir na deciso de escolher um ou outro mtodo, principalmente
a clareza ou facilidade de entendimento ou de convencimento ou demonstrao da correo, e a
ecincia do cdigo gerado.
Vamos dar nesta seo uma introduo a aspectos relativos a um entendimento mais preciso e
detalhado sobre o comportamento de programas e sobre como convencer (a si prprio e a outros)
e demonstrar a correo de programas.
convencimento de que um programa se comporta como esperado (em particular no caso de programas imperativos, que envolvem mudanas de estado) so obtidos informalmente. Estes devem ser
baseados no entanto em argumentao mais precisa e detalhada, como as apresentadas a seguir.
Comeamos com denies recursivas (seo 5.5.1) e depois abordamos programas que envolvem
mudanas de estado, com o uso de comandos de repetio e de atribuio (seo 5.5.2).
Devemos notar que o material desta seo constitui apenas um material bsico sobre o assunto
e, como tal:
desconsidera aspectos que envolvem uso de ponteiros e valores de tipo unio (union em
C),
que tornam possvel a alterao de uma varivel sem uso do nome desta varivel;
considera que expresses no tm efeito colateral. Trechos de programas com expresses que
tm efeito colateral podem ser transformados sem grande diculdade em trechos que primeiro
usam comandos para provocar o efeito colateral e modicar o valor armazenado em variveis
e em seguida usar as variveis (com os valores modicados).
fatr1 (n)
= n!.
Prova : O lema envolve consiste de fato em duas propriedades, que vamos chamar de
P1
P2 :
n I, n 0,
47
int
n!
como:
n! =
A prova de
P1
1
n (n 1)!
n,
se
n=0
caso contrrio
Caso base
P1 includa
(n = 0): Nesse
caso, temos:
fatr (0)
Para obter
(3),
=1
= 0!
P1 (n + 1),
para
(def. de fatr )
(def. de
0!)
n 0, n + 1 I):
= (n + 1) * fatr (n)
= (n + 1) * (n!)
= (n + 1) (n!)
= (n+1)!
+ 1)
(def. de fatr ,
n + 1 > 0)
(hip. de induo)
(hip.:
implementa
(1)
(2)
(def. de !)
(3)
(4)
tiplicao usada em
C ( *)
Em
implementaes que usam 32 bits para armazenamento de nmeros inteiros, essa suposio no
vlida (ocorre overow ) para
n 17.
P2 ,
n, i
f:
1. A condio
(n 0) (i n + 1) f = (i 1)!
deve ser verdadeira, no incio da execuo de uma chamada funo.
Uma condio que deve ser verdadeira no incio da execuo de um comando chamada de
pr-condio .
Analogamente, uma condio que verdadeira no nal da execuo de um comando, se a
pr-condio for verdadeira, chamada de ps-condio .
O programa deve ser feito de modo a garantir que a pr-condio seja verdadeira na primeira
chamada funo. No caso de fatIter , por exemplo, deve ser garantido sempre que
n > 0,
i0
ni+1
sempre no-negativa, se o for na primeira chamada funo, e decresce em cada chamada
recursiva funo.
Tal expresso, que decrescente mas permanece no-negativa, se for no-negativa na primeira iterao ou chamada recursiva de uma funo, chamada de uma expresso variante .
Entenda-se expresso no-negativa decrescente quando se falar de uma expresso variante.
A existncia de uma expresso variante garante que uma funo recursiva terminar, caso
tal expresso seja no-negativa na primeira chamada funo.
As duas condies acima garantem que, quando
i > n,
temos que
i = n + 1 e,
portanto,
f = n!.
48
Recurso e Iterao
{p} c {q}
onde
um comando e
proposicionais). A assero
chamada pr-condio e
A pr-condio especica o que deve ser vlido no estado anterior, e a ps-condio o que deve
ser vlido no estado posterior, execuo do comando.
Mais precisamente, dizemos que:
um estado em que
em um estado em que
Ou seja, correo total inclui a condio de que o comando termina, ao contrrio da correo
parcial.
Vamos mostrar a seguir que a denio iterativa fat dada na seo 5.3 (copiada abaixo) computa
o fatorial do argumento fornecido.
int).
*= i;
I,
onde
n!,
n I 0.
while
equi-
uma expresso
{p b} c {p}
{p b = e} c {e < }
p (e 0)
{p} while b do c {p (b)}
inteira e uma varivel nova, que
no ocorre em
p, b, e
c.
a premissa
O propsito de
Prova : . . .
49
{p} c {q}
5.5.4 Exemplos
...
while.
Soluo : Esse comando pode ser denido recursivamente pela seguinte equao:
while (
Obs.: O smbolo
= if (
) { c ; while (
comando de atribuio.
2. Dena uma funo mult2 que use a mesma tcnica empregada na denio de exp2 . Ou
seja, use diviso por 2 caso o segundo operando seja par, para obter uma implementao da
Soluo :
3. D uma denio recursiva para uma funo pgr que espelhe o processo iterativo de pg . Em
outras palavras, dena recursivamente uma funo que, dados um nmero inteiro
nmero inteiro no-negativo
n,
e um
n
X
xi
i=0
obtendo cada termo do somatrio a partir do termo anterior (pela multiplicao desse termo
anterior por x ) e passando como argumento, em cada chamada recursiva, o termo e o somatrio obtidos anteriormente.
Escreva um programa que leia repetidamente pares de valores inteiros
de
Pn
i
i=0 x ,
n,
at que o valor
Soluo :
4 Exemplos
do uso desse algoritmo so encontrados em um dos documentos matemticos mais antigos que se
conhece, escrito por um escrivo egpcio (A'h-mose), por volta de 1700 a.C.
50
Recurso e Iterao
(int x, int n ) {
return pgIter (x ,n ,1,1,1);
pgr
int main () {
int x,n;
while (1) {
scanf ("%d %d",&x , &n );
if (n <= 0) break;
printf ("%d",pgr (x,n ));
}
}
4. D uma denio para funo exp2 , denida na Figura 5.2, usando um comando de repetio,
em vez de recurso.
Soluo :
trivial (no diretamente ligado denio da funo) para atualizao do valor de variveis
no corpo do comando de repetio.
5. Dena uma funo para calcular o mximo divisor comum de dois nmeros inteiros positivos.
Soluo :
mdc (a, b)
a
mdc (b, a%b)
se
b=0
caso contrrio
% usado acima como em Java, ou seja, a%b representa o resto da diviso inteira
b (a e b so nmeros inteiros). O algoritmo original de Euclides (escrito no famoso
Elementos , por volta do ano 3 a.C.) usava mdc (b, a b) em vez de mdc (b, a%b), na
O operador
de
livro
por
51
mdc
% b; };
6. Dena uma funo calc que receba como argumentos um caractere, que indica uma operao
aritmtica ('+',
'-', '*'
'/'),
2.0
e calc
6.0.
switch,
deve
deve retornar
switch
case
case
...
case
}
switch
tem a forma:
( e) {
e1 : c1 ;
e2 : c2 ;
en :
cn ;
switch pode ser visto como uma seqncia de comandos de seleo if, cada um
switch.
O signicado de um comando switch o seguinte: a expresso e avaliada e executado
o primeiro comando ci , na ordem c1 , . . . , cn , para o qual o valor fornecido por e igual ao
valor de ei (caso tal comando exista), sendo tambm executados todos os comandos seguintes
(ci+1 , . . . , cn ), se existirem, nessa ordem.
O comando
A execuo de qualquer desses comandos pode ser nalizada, e geralmente deve ser, por meio
de um comando
break.
break
return, que termima a execuo
Supe-se tambm, na funo op denida abaixo, que o caractere passado como argumento
para op sempre igual a
ou
double op (char
switch (c ) {
case '+' :
case '*' :
case '-' :
case '/' :
}
}
'/'.
c,
{
{
{
{
double
return
return
return
return
a
a
a
a
a,
+
*
/
double b ) {
b;
}
}
b; }
b ; }-
b;
52
Recurso e Iterao
Se o valor de
ei ,
para qualquer
Se
ei , para i n, um
default pode ser usado no
O caso
i = 1, . . . , n,
para algum
ei ,
para
lugar de
case ei ,
default), o
i = 1, . . . , n, seja
comando
expresses
ci ,
para
i = 1, . . . , n).
hoje em geral reconhecida como um ponto fraco do projeto da linguagem Java (tendo sido
herdado da linguagem C).
A expresso
e,
no comando
switch,
e1 ,
switch
break
break
switch
7. Escreva uma denio para a funo raizq , que calcula a raiz quadrada de um dado valor
com erro de aproximao menor que
0.0001.
um nmero
tal que
y 2 = x.
x,
por exemplo, 2, a sua raiz quadrada um nmero que teria que ser representado com innitos
algarismos na sua parte decimal, no sendo possvel obter essa representao em um tempo
nito. Desse modo, o clculo desses valores feito a seguir, com um erro de aproximao
0.0001.
por |x| o valor
o valor
0.0001.
Denotando
y0
absoluto de
x,
o valor
a ser
|y 2 x| < e
Para denir a funo raizq, vamos usar o mtodo de aproximaes sucessivas de Newton.
Para a raiz quadrada, o mtodo de Newton especica que, se
yi
x,
x=2
y0 = 2.
Ento:
y1 = (2 + 2/2)/2
= 1.5
y2 = (1.5 + 2/1.5)/2
= 1.4167
y3 = (1.4167 + 2/1.4167)/2 = 1.4142157 . . .
Repetindo esse processo, podemos obter aproximaes para a raiz quadrada de 2 com qualquer preciso desejada (sujeitas, claro, s limitaes da representao de nmeros do computador). A implementao da funo raizq pode ser feita usando um comando de repetio,
como mostrado na Figura 5.3.
53
const double
= 0.0001;
x)
y
{
melhore (y ,x );
e;
x)
possvel, e consigam transferir 1 disco de uma torre para outra em 1 segundo, quanto tempo
decorreria (em segundos) desde a criao at o m do mundo?
Soluo : Uma soluo recursiva para o problema baseada na idia ilustrada na Figura 5.5.
Nessa soluo, supe-se, como hiptese indutiva, que se sabe como transferir
n1
discos de
uma torre para outra (sem colocar um disco em cima de outro menor); o caso base consiste
em transferir um disco de uma torre para outra vazia. O nmero total de movimentaes de
f (1) = 1
f (n) = 2 f (n 1) + 1
f (n)
requerimento de que um disco nunca pode ser colocado sobre outro de dimetro menor. Para
perceber isso, basta notar que, para mover um nico disco
torre
B,
d,
digamos, da torre
para a torre
1, 844674 1019
para a
C.
f (64).
Um resultado
A denio de
para
denido, por essa relao, em termos de seus predecessores). A primeira equao na denio
de
Podemos procurar obter uma frmula que dene diretamente, de forma no-recursiva, o valor
54
Recurso e Iterao
de
f (n),
f (n),
para cada
n:
f (1) = 1
f (2) = 2 f (1) + 1 = 2 1 + 1 = 2 + 1
f (3) = 2 f (2) + 1 = 2(2 + 1) + 1 = 22 + 2 + 1
f (4) = 2 f (3) + 1 = 2(22 + 2 + 1) + 1 = 23 + 22 + 2 + 1
...
f (n) = 2 f (n 1) + 1 = 2n1 + 2n2 + . . . + 2 + 1
f (n) = 2n 1
Pn1
i
n
i=0 2 = 2 1). O leitor com interesse em
matemtica pode provar (usando induo sobre n) que, para todo n, a denio recursiva de
f de fato satisfaz a equao f (n) = 2n 1.
Podemos observar que
(pois
9. O problema descrito a seguir foi introduzido em 1202 por Fibonacci tambm conhecido
como Leonardo de Pisa, e considerado como o maior matemtico europeu da Idade Mdia:
Escreva um programa para solucionar esse problema, imprimindo o nmero de coelhos existentes no nal do ano.
k;
k1
igual
k
k 2 (pois esse exatamente o nmero
k ).
55
fib(n)
da
fib(0) = 0
fib(1) = 1
fib(n) = fib(n 1) + fib(n 2)
se
n>1
int
}
main
() {
int b (int n ) {
if (n ==0) return 0;
else if (n ==1) return 1;
else return b (n -1) + b (n -2);
}
O nmero de pares de coelhos no nal do dcimo segundo ms, b (12), igual a 144 (ou
seja, o nmero de coelhos igual a 288).
A funo b denido no programa acima bastante ineciente, pois repete muitos clculos,
devido s chamadas recursivas a b (n -1) e b (n -2).
envolve calcular b (2) duas vezes. O mtodo a seguir claramente mais eciente, podendo
ser usado para o mesmo efeito, no programa acima, por meio da chamada b (12,0,1):
Por questo de ecincia, o teste de igualdade com zero foi retirado, supondo-se ento que o
argumento de b deve ser um inteiro positivo.
As chamadas a b usam r1 e r como acumuladores, comportando-se como mostrado a seguir:
b (n ,
a
1 chamada
a
2 chamada
0, 1)
1, 1)
b (n -1,
...
ltima chamada
b (1, r1 , r )
b (0)
b (1)
= 0
= 1
b (n -1)
r1
b (1)
b (2)
= 1
= 1
b (n )
A denio recursiva anterior de b simula o mesmo processo iterativo do comando de repetio mostrado a seguir:
int b (int n ) {
int r1 = 0, r = 1, t , i ;
for (i =2; i <=n ; i ++) {
t = r1 ; r1 = r ; r = r + t ; }
return r ;
}
56
Recurso e Iterao
int main () {
int n , m , col = 1;
printf ("Impressao de valores de 1 a n em notacao unaria, sem multiplos de m\n");
printf ("Digite n e m: ");
scanf ("%d %d",&n, &m);
continue
10. Os comandos
execuo de um comando
uma forma de saltar determinados casos em um comando de repetio, fazendo com que o
controle passe para a iterao seguinte.
O exemplo da Figura 5.6 imprime a representao unria (usando o smbolo |) de todos os
nmeros inteiros de
O resultado da execuo de
Os comandos
break
Exemplo_continue 20 5
continue
m > 1.
continue
switch
break,
continue.
Analogamente, um comando
break
algumas situaes, mais fcil (ou mais conveniente do que outras alternativas). Em alguns
casos, pode ser mais fcil testar uma condio internamente ao comando de repetio e usar
o comando
break,
repetio.
O uso do comando
break
repetidamente, um valor inteiro positivo e imprimir, para cada inteiro lido, seu fatorial. Se
for lido um valor negativo, a execuo do programa deve terminar.
11. Esse exerccio ilustra o uso de entrada de dados at que uma condio ocorra ou at que se
chegue ao nal dos dados de entrada. O caractere
Control-d
dos dados de entrada, em uma entrada de dados interativa no sistema operacional Linux e,
no sistema operacional Windows,
Return).
Control-z
Enter
(ou
A funo scanf retorna o nmero de variveis lidas, e pode ser usado para detectar m dos
dados de entrada a serem lidos (isto , se no existe mais nenhum valor na entrada de dados
a ser lido). O exemplo a seguir l vrios inteiros do dispositivo de entrada padro e imprima
a soma de todos os inteiros lidos. O programa termina quando no h mais valores a serem
lidos.
57
fatx
*= i;
int main () {
int v ;
while (1) {
printf ("Digite um valor inteiro: ");
scanf ("if (v < 0) break;
printf ("Fatorial de %d = }
return SYSTEM_SUCCESS ;
}
break
continue
58
Recurso e Iterao
O programa a seguir funciona de modo semelhante, mas l vrios inteiros positivos do dispositivo de entrada padro e termina a execuo quando quando no h mais valores a serem
lidos ou quando um valor negativo ou zero for lido.
12. Escreva um programa que leia, do dispositivo de entrada padro, vrios valores inteiros,
positivos ou no, e imprima, no dispositivo de sada padro, os dois maiores valores lidos.
A entrada termina com indicao de m dos dados de entrada (em entrada interativa,
Control-z
seguido de
Enter
no Windows, ou
Control-d
no Linux).
Soluo : So usadas duas variveis inteiras max1 e max2 para armazenar os dois maiores
valores lidos, e elas so atualizadas adequadamente, se necessrio, aps a leitura de cada
inteiro. O valor inicial atribudo a essas variveis o valor INT_MIN , menor inteiro armazenvel em uma varivel de tipo
int.
esse valor e ser, caso for maior, atribudo varivel. INT_MIN denido em limits.h.
O valor retornado por scanf usado para vericar m dos dados de entrada (scanf retorna
-1
59
13. Escreva um programa que leia, do dispositivo de entrada padro, um texto qualquer, caractere
a caractere e imprima, no dispositivo de sada padro, i) o nmero de caracteres, ii) o nmero
de palavras, e iii) o nmero de linhas do texto.
Considere que uma palavra uma sequncia de um ou mais caracteres que comea com
qualquer caractere que no um delimitador de palavras. Um delimitador de palavras um
caractere espao (branco, i.e.
A entrada termina com indicao de m dos dados de entrada (em entrada interativa,
Control-z
seguido de
Enter
no Windows, ou
Control-d
no Linux).
%c
o valor retornado por scanf para vericar m dos dados de entrada (scanf retorna
-1
para
C,
'a'
'z'
ou entre
'A'
'Z'.
Para contar palavras, usado uma varivel (fora ) que indica se o caractere corrente, que
est sendo lido, est fora ou dentro de uma palavra. O nmero de palavras (armazanado na
varivel palavras ) incrementado quando se est fora de uma palavra e um caractere no
delimitador de palavras lido (como especicado no enunciado, um delimitador de palavras
considerado como sendo um dos caracteres espao, m-de-linha ou tab).
60
Recurso e Iterao
fora =1;
14. Esse um exerccio baseado no problema PAR (Par ou mpar) , obtido de:
http://br.spoj.pl/problems/PAR
H uma modicao motivada pelo fato de que no vamos usar ainda leitura de cadeias de
caracteres, e por isso os nomes dos jogadores correspondentes a escolha "par"e "mpar"so
substitudos respectivamente por "Par"e "Impar". O problema descrito a seguir.
O problema consiste em determinar, para cada jogada de partidas do jogo Par ou mpar , o
vencedor da jogada.
A entrada representa uma sequncia de dados referentes a partidas de Par ou mpar .
primeira linha de cada partida contm um inteiro
partida.
As
a5
n,
0 B 5).
que representam o
n = 0.
A sada deve conter para cada partida, uma linha no formato Partida i, onde
i o nmero da
3
2
3
1
2
1
2
0
4
5
0
5
3
61
Partida 1
Par
Par
Impar
Partida 2
Par
Impar
Soluo : O programa abaixo dene e usa a funo processaPartida para separar o processamento (clculo e impresso) de valores de cada partida, e a funo par , que determina se
um dado valor par ou no. O nmero de cada partida armazenado em uma varivel, que
tem valor inicial igual a 1 e incrementada aps o processamento de cada partida.
O programa usa tambm o recurso de denir a assinatura (ou interface, ou cabealho) de cada
funo denida, para usar (chamar) a funo antes de deni-la. Na denio da interface o
nome dos parmetros opcional, e omitido no programa abaixo.
15. Nesse exerccio vamos apresentar uma soluo para o problema RUMO9S (Rumo aos 9s) ,
obtido de
http://br.spoj.pl/problems/RUMO9s/
A soluo apresentada no usa arranjo nem cadeia de caracteres (abordados no prximo
captulo), para ler, armazenar e imprimir os valores de entrada. Em vez disso, caracteres so
lidos um a um (nmeros no podem ser lidos e armazenados como valores inteiros porque
62
Recurso e Iterao
podem ter at 1000 dgitos decimais, e portanto no poder ser armazenadas como valores de
tipo
int
ou
long int).
Um nmero inteiro mltiplo de nove se e somente se a soma dos seus dgitos mltiplo de
9. Chama-se grau-9 de um nmero inteiro
n0
se
n = 9, 0
se
o valor igual a:
n < 9;
n > 9.
Escreva um programa que, dado uma sequncia de inteiros positivos, imprime se cada um
deles mltiplo de nove e, em caso armativo, seu grau-9.
A entrada, no dispositivo de
entrada padro, contm uma sequncia de inteiros positivos, um em cada linha, e termina
com o valor
0.
Exemplo:
Entrada:
999
27
9
998
0
Sada:
Soluo : A soluo usa a funo isdigit para testar se um dado caractere um dgito (i.e. em
C,
'0'
'9').
'0',
5.7 Exerccios
63
somaDigs (n/10));
grau9n );
5.7 Exerccios
1. Escreva trs denies de funo, chamadas somaIter , somaRec e soma , tais que, dados dois
nmeros inteiros positivos
b,
retorne o valor
a + b.
usar apenas as operaes mais simples de incrementar 1 e decrementar 1 (devem supor que as
operaes de adicionar e de subtrair mais de uma unidade no so disponveis). A primeira
denio deve usar um comando de repetio, e a segunda denio deve ser recursiva. A
terceira denio deve usar o operador
de adio.
Inclua essas trs denies em um programa de teste, e dena um programa de teste que
leia vrios pares de valores
cada par de valores
resultado retornado pela execuo das trs denies no igual, o programa deve terminar
64
Recurso e Iterao
a,b
da execuo foi diferente, assim como o resultado retornado por cada denio, junto com o
nome da funo que retornou cada resultado.
2. Escreva uma denio da funo numdiv que, dados dois nmeros inteiros positivos, retorna
o nmero de vezes que o primeiro pode ser dividido exatamente pelo segundo.
0.
a,b
Exemplos:
e imprima, para
cada par lido, o nmero de vezes que o primeiro pode ser dividido pelo segundo, usando a
funo denida acima. A leitura deve terminar quando um dos valores lidos for menor ou
igual a zero.
3. O nmero de combinaes de
objetos
elementos denotado
n
p , dado pela frmula:
n(n 1) . . . (n p + 1)
p!
43
2!
= 6 (se representamos
{1,2}, {1,3}, {1,4}, {2,3}, {2,4} e {3,4}).
p, calcule o nmero de combinaes de n objetos p a p.
n!
p! (n p)!
No entanto, note que uma implementao baseada diretamente nessa ltima seria menos
eciente do que uma implementao baseada diretamente na primeira, uma vez que o nmero
de operaes de multiplicao necessrias para o clculo seria maior nesse ltimo caso.
n, p e imprima,
p. A leitura deve
objetos
4. Escreva uma funo para calcular qual seria o saldo de sua conta de poupana depois de 5
anos, se voc depositou
1000
6%
ao ano.
5. Generalize a questo anterior, de maneira que se possa especicar quaisquer valores inteiros
como capital inicial, taxa de juros e prazo desejados.
Escreva um programa que leia, repetidamente, trs valores inteiros positivos
c, j , t
que
1
1
1
(c)
1
(b)
(d)
(e)
n,
calcule:
Pn
2
i=1 i
+ 32 +
24 +
Pn
i
i=0 ( i!
5
3
3
9
7
4 + ...
4
5
16 + 25
...
i
(i+1)! )
244668...
335577...
Cada somatrio deve ser implementado usando i) um comando de repetio e ii) uma funo
recursiva.
Escreva um programa que leia repetidamente pares de valores inteiros
cada par lido, o resultado de chamar a
argumento
ou quando
k -sima
n, k
e imprima, para
n0
5.7 Exerccios
65
7. Escreva funes para calcular um valor aproximado do seno e cosseno de um ngulo dado em
radianos, usando as seguintes frmulas:
sen (x)
=x
x3
3!
x5
5!
...
cos (x)
=1
x2
2!
x4
4!
...
no somatrio.
A denio no deve ser feita calculando o fatorial e a exponencial a cada parcela, mas sim
de modo que o valor do numerador e do denominador de cada parcela sejam obtidos a partir
dos valores respectivos da parcela anterior.
Escreva um programa que leia, do dispositivo de entrada padro, vrios nmeros de ponto
utuante que representam valores de ngulos em graus, e, para cada valor, imprima o seno e
o cosseno desse valor, usando as funes denidas acima e funes para converter graus em
radianos. A entrada deve terminar quando um valor negativo ou nulo for lido.
8. Faa um programa que leia uma sequncia de valores inteiros diferentes de zero, separados
por espaos ou linhas, e imprima os valores pares dessa sequncia. Um valor par se o resto
da diviso desse valor por 2 igual a zero. A entrada termina quando um valor igual a zero
for lido.
10
10
12
14
16
18
20
20
30
40
50
60
70
80
90
100
...
10
n.
*
***
*****
*******
*********
***********
*************
*
***
*****
*******
*********
***********
*************
***********
*********
*******
*****
***
*
n.
66
Recurso e Iterao
12. Dena uma funo que converta o valor de uma temperatura dada em graus Fahrenheit para
o valor correspondente em graus centgrados (ou Celsius). A converso dada pela frmula:
5 (TF 32)
9
TC =
Use a funo denida acima como parte de um programa que receba como argumentos o
valor de uma temperatura inicial, o valor de uma temperatura nal e um passo
(valor de
graus Fahrenheit.
13. Os nmeros mostrados na tabela a seguir formam a parte inicial do chamado tringulo de
Pascal (nome dado em homenagem a Blaise Pascal (16231662), que escreveu um inuente
tratado sobre esses nmeros). A tabela contm os valores das combinaes de
p,
0
1
10
10
15
20
15
21
35
35
21
28
56
70
56
28
36
84
126
126
84
36
10
10
45
120
210
252
210
120
45
10
n
2
p.
n
elementos,
n
0
1
n
1
n
4
n
5
n
6
n
7
n
8
n
9
n
10
As entradas em branco nessa tabela tm, de fato, valor igual a zero, tendo sido deixadas em
branco para evidenciar o tringulo formado pelas demais entradas da tabela.
Escreva um programa para imprimir o tringulo de Pascal, usando o fato de que
n
p+1
=
n
p
(n p)
p+1
n
n!
=
p
p ! (n p)!
14. Escreva um programa que leia quatro valores inteiros positivos nA, nB , tA e tB representando respectivamente as populaes atuais de dois pases A e B e as taxas de crescimento
anual dessas populaes e determine o nmero de anos necessrios para que a populao
do pas A ultrapasse a de B , supondo que as taxas de crescimento dessas populaes no
variam e que nA
<
nB e tA
>
tB .
15. Escreva um programa que leia, do dispositivo de entrada padro, um texto qualquer, caractere
a caractere e imprima, no dispositivo de sada padro, i) o nmero de vogais, ii) o nmero
de consoantes e iii) o nmero de outros caracteres diferentes de vogais e consoantes presentes
em palavras: considere que estes so todos os demais caracteres que no sejam espao, mde-linha ('\n') ou tab (caractere de tabulao, i.e.
'\t').
A entrada termina com indicao de m dos dados de entrada (em entrada interativa,
Control-z
seguido de
Enter
no Windows, ou
%c
Control-d
no Linux).
-1
Dena e use funo que retorna verdadeiro se e somente se o caractere passado como argumento uma letra; para deni-la, teste se tal caractere est entre
'Z'.
'a'
'z'
ou entre
'A'
5.7 Exerccios
67
<
nB
BIT
0).
disponvel em:
http://br.spoj.pl/problems/BIT/
O enunciado apresentado, de forma resumida, a seguir.
O problema consiste em escrever um programa para calcular e imprimir, para cada valor
inteiro positivo lido, quantas notas de 50, 10, 5 e 1 reais so necessias para para totalizar
esse valor, de modo a minimizar a quantidade de notas.
A entrada composta de vrios conjuntos de teste.
v,
v = 0.
Para cada conjunto de teste da entrada seu programa deve produzir trs linhas na sada.
A primeira linha deve conter um identicador do conjunto de teste, no formato
onde
"Teste n",
Na
segunda linha devem aparecer quatro inteiros, que representam o resultado encontrado pelo
seu programa: o primeiro inteiro indica o nmero de notas de 50 reais, o segundo o nmero
de notas de 10 reais, o terceiro o nmero de notas de 5 reais e o quarto o nmero de notas
de 1 real. A terceira linha deve ser deixada em branco.
Por exemplo, para a entrada:
1
72
0
A sada deve ser:
Teste 1
0 0 0 1
Teste 2
1 2 0 2
18. Resolva o problema
ALADES
disponvel em:
http://br.spoj.pl/problems/ALADES/
O enunciado apresentado, de forma resumida, a seguir.
O problema consiste em escrever um programa que, dados valores de hora e minutos corrente
e hora e minutos de um alarme, determinar o nmero de minutos entre os dois valores.
A entrada contm vrios casos de teste. Cada caso de teste descrito em uma linha, contendo
contm apenas quatro zeros, separados por espaos em branco. Os dados devem ser lidos da
entrada padro.
Para cada caso de teste da entrada, deve ser impressa uma linha, no dispositivo de sada
padro, contendo um nmero inteiro que indica o nmero de minutos entre os dois horrios.
Por exemplo, para a entrada:
68
Recurso e Iterao
1 5 3
23 59
21 33
0 0 0
5
0 34
21 10
0
120
35
1417
Captulo 6
C,
encadeadas, formadas com o uso de registros com ponteiros, so abordadas na seo 6.5.
Arranjos e cadeias so estruturas de dados homogneas, devido ao fato de que os componentes
tm que ser todos de um mesmo tipo, enquanto estruturas de dados encadeadas e registros em geral
so estruturas de dados heterogneas, que podem envolver componentes de vrios tipos, diferentes
entre si.
6.1 Arranjos
Arranjos so estruturas de dados muito usadas em programas. Um arranjo uma forma de
representar uma funo nita (funo de domnio nito que em geral vista como uma tabela
ou uma seqncia nita de valores com a caracterstica de que o acesso aos seus componentes
podem ser feitos de modo eciente. Esta seo aborda a denio e uso de arranjos na linguagem
C.
Um arranjo uma estrutura de dados formada por um certo nmero nito de componentes
(tambm chamados de posies do arranjo) de um mesmo tipo, sendo cada componente identicado
por um ndice .
Um arranjo tem um tamanho , que o nmero de componentes do arranjo. A uma varivel de
do arranjo.
Se
int
n,
C:
A linguagem
v.
operao de indexao (uso de um valor como ndice) de um arranjo, deva existir uma vericao
de que esse ndice um ndice vlido. A linguagem simplesmente deixa a responsabilidade para o
programador. Se o ndice estiver fora dos limites vlidos em uma indexao, uma rea de memria
distinta da rea alocada para o arranjo ser usada, ou o programa interrompido, com uma
mensagem de que um erro ocorreu devido a um acesso ilegal a uma rea de memria que no pode
ser usada pelo processo corrente.
O erro devido a um
acesso ilegal a uma rea de memria no reservada ao processo corrente provoca a emisso da
mensagem segmentation fault , e a interrupo da execuo do processo corrente. O motivo de no
existir vericao de que um ndice de um arranjo est ou no entre os limites desse arranjo ,
obviamente, ecincia (i.e. evitar gasto de tempo de execuo). O programador deve estar ciente
disso e atento de modo a evitar erros (i.e. evitar o uso de ndices fora dos limites vlidos em
indexaes de arranjos).
A ecincia que existe no acesso a componentes de um arranjo se deve ao fato de que arranjos
so geralmente armazenados em posies contguas da memria de um computador, e o acesso
i-sima
posio feito diretamente, sem necessidade de acesso a outras posies. Isso espelha o
70
i-simo
i.
de tipo arranjo em
a declarao de arranjos dentro de funes com tamanho que conhecido apenas dinamicamente,
mas em geral uma varivel de tipo arranjo tem um valor conhecido estaticamente (em tempo de
compilao) ou um parmetro de uma funo, sendo o tamanho nesse caso igual ao tamanho
do argumento, especicado no instante da chamada funo. Usaremos, para criao de arranjos
com tamanho conhecido apenas dinamicamente, a declarao de um ponteiro. Isso ser explicado
mais detalhadamente na seo 6.3.2.
O tamanho de um arranjo no faz parte do seu tipo (em geral, esse tamanho no conhecido
estaticamente), mas no podendo ser modicado. Considere os seguintes exemplos:
progbint ai [3];
char ac [4];
As declaraes acima criam as variveis ai e ac .
int.
ao de 4 variveis de tipo
char.
apenas que malloc aloca uma rea de memria na rea de memria dinmica do processo
corrente, chamada em ingls de heap que ser usada tipicamente por meio da operao de
indexao do arranjo. Considere os seguintes comandos:
int *pi ;
char *pc ;
pi = malloc (3 * sizeof(int));
pc = malloc (4 * sizeof(char));
A chamada malloc (3*sizeof(int)) alloca uma rea de memria de tamanho
sendo
sizeof(int)
4*(sizeof(char)),
valor de tipo char.
3*(sizeof(int)),
int. Si-
* sizeof(char))
sizeof(char) o tamanho
int.
char.
Note que, no caso da declarao de variveis com um tipo que explicitamente indicado como
sendo um tipo arranjo, para o qual o tamanho indicado explicitamente (como no exemplo anterior
das variveis ai e ac ), o arranjo no alocado na rea dinmica mas na rea de pilha da funo
6.1 Arranjos
71
/************************************************************
* L n, depois n inteiros do dispositivo de entrada padro *
* e imprime os n inteiros lidos em ordem inversa.
*
***********************************************************/
#include
stdio .h ;
int main () {
int *arr , i=0, n;
scanf ("%d", &n);
arr = malloc (n * sizeof(int));
for (i=0; i<n; i++) scanf ("%d", &arr [i]);
for (i; i>=0; i) printf ("%d ", arr [i]);
}
for
na qual a declarao ocorre (no caso, na rea de memria alocada quando a execuo da funo
main iniciada).
O tamanho de uma rea de memria pode ser obtido em
sizeof.
A palavra reservada
sizeof
sizeof
o tamanho
em bytes do tipo ou expresso usada como argumento (tamanho do tipo ou tamanho do tipo da
expresso, respectivamente). No caso de uso de um tipo, ele deve ser colocado entre parnteses, mas
quando uma expresso usada, ela pode seguir
sizeof
sizeof(3 * sizeof(int)).
a declarao:
int a[5];
declara uma varivel
a de tipo arranjo, mas o tipoa int ocorre antes e a indicao de que esse tipo
int ocorre aps o nome da varivel.
Isso feito com o mero intuito de permitir declaraes um pouco mais sucintas, como a seguinte,
que cria uma varivel b de tipo
int
int b,
int:
a [5];
n,
em seguida
i3 , i2 , i1 ,
3,
i1 , i2
i3 ,
o programa deve
O programa da Figura 6.1 ilustra a operao bsica de percorrer um arranjo para realizao de
alguma operao sobre os valores armazenados no arranjo. O programa declara o tipo da varivel
int.
int,
alocaco feita na rea de memria dinmica pela funo malloc , que retorna um endereo para a
rea de memria alocada. No entanto, a operao de indexao de arranjos funciona normalmente
tambm no caso de variveis ou valores de tipo ponteiro.
arranjos e ponteiros em
72
Para
evitar isso, h duas opes: i) no usar um arranjo, mas uma estrutura de dados encadeada, como
descrito na seo 6.5, ou ii) adotar um certo valor como mximo para o nmero de valores a serem
digitados (de modo a alocar um arranjo com tamanho igual a esse nmero mximo). Essa opo
tem as desvantagens de que um nmero mximo pode no ser conhecido estaticamente ou ser
difcil de ser determinado, e o uso de um valor mximo pode levar a alocao desnecessria de rea
signicativa de memria, que no ser usada (ou seja, o mximo pode ser um valor muito maior
do que o de fato necessrio).
Para percorrer um arranjo, usado tipicamente um comando
apropriado para o uso de uma varivel que controla a tarefa de percorrer um arranjo: iniciao
do valor da varivel usada para indexar o arranjo, teste para vericar se seu valor ainda um
ndice vlido do arranjo, e atualizao do valor armazenado na varivel.
int.
os componentes de um arranjo, passado como argumento, com um valor, tambm passado como
argumento, e ii) testar igualdade de arranjos, passados como argumentos da funo.
A primeira operao uma funo com efeito colateral. Isso signica que ela no uma funo
que tem como domnio e contra-domnio os tipos anotados na denio da funo, mas precisa,
para poder ser considerada como funo, que o domnio e contra-domnio abranjam (alm dos
parmetros explicitamente indicados na denio da funo) tambm uma forma de representao
do estado da computao. O estado da computao pode ser representado na forma de uma funo
que associa variveis a valores armazenados nessas variveis.
Nas duas funes acima, preenche e iguais , o tamanho do arranjo (nmero de posies alocadas)
um parmetro da funo.
sizeof
de
com argumento que um arranjo alocado dinamicamente: esta funo, anteriormente denio
do padro
C-99,
compilao.
Note que o uso de
==
6.1 Arranjos
73
Figura 6.3: Exemplo de uso de funo que testa igualdade entre arranjos
O programa da Figura 6.3 ilustra o uso da funo iguais denida acima, escrevendo um pro-
primeiros dos
n-simo
2 timesn
mais um, o
Aps a execuo desse trecho de programa, a representa um arranjo com quatro componentes,
sendo cada componente um arranjo com trs componentes. Tal arranjo algumas vezes chamado
de uma matriz , no caso uma matriz 4 por 3. Um arranjo de arranjos tambm chamado de arranjo
multidimensional .
Um arranjo pode ter como componentes arranjos de tamanhos diferentes, alocados dinamicamente, como ilustra o exemplo a seguir.
int **a ;
= malloc(2 * sizeof(int*));
...
a [0] = malloc(10 * sizeof(int));
...
a [1] = malloc(40 * sizeof(int));
...
a
74
alocados dinamicamente, sendo que o primeiro deles, a [0], tem 10 componentes, enquanto o
C,
'' e '',
todos
NULL
(ponteiro nulo).
n)
e as
notas desse
Soluo : A soluo dene uma funo calcNotas que recebe um arranjo com as notas de
cada aluno em cada tarefa, e retorna um arranjo com as notas nais de cada aluno. Em
C,
float
contidos no arranjo.
Na funo main , um arranjo de notas de cada aluno em cada avaliao preenchido com
valores lidos, o mtodo calcNotas chamado para clculo das notas nais, e as notas nais
calculadas, assim como a mdia, calculada por chamada funo media , so impressas.
As notas de cada aluno so representadas em
6.2 Exerccios
75
numAlunos ;
i++)
return
notasFinais ;
malloc (n*sizeof(int*));
calcNotas (notas,n,k );
6.2 Exerccios
1. Considere nessa questo que um amigo seu dono de
pediu sua ajuda para fazer o seguinte programa em
C.
Ele tem dados armazenados sobre o nmero de vendas de automveis vendidos em cada loja.
No importa qual automvel, ele est interessado apenas no nmero de unidades vendidas.
Escreva um programa, para ajudar seu amigo, que leia, do dispositivo de entrada padro, o
valor de
v1 ,
...,
76
n,
nas quais o nmero de unidades vendidas foi maior ou igual mdia de unidades vendidas
em suas lojas.
n n de valores inteiros,
n,
um quadrado mgico.
Um quadrado mgico uma matriz quadrada na qual a soma dos nmeros em cada linha,
coluna e diagonal igual.
n,
k,
de
n,
n, a 2
n-sima
divisveis por
1, etc., at a
1a
para os quais
para os
n 1.
valores inteiros,
4 12 13 15 16 17
Para essa entrada, a sada deve ser como a seguir:
Valores
Valores
Valores
Valores
divisiveis por 4: 12 16
com resto da divisao por 4 igual a 1: 13 17
com resto da divisao por 4 igual a 2:
com resto da divisao por 4 igual a 3: 15
j (diferente
j1
da linha anterior.
n = 5 no Tringulo
de Pascal (pgina 66) 10. Ele igual a 6+4: 6 o valor na mesma coluna da linha anterior
(correspondente a
n = 4),
n = 4).
7. Escreva um programa que leia, repetidamente, do dispositivo de entrada padro, os seguintes
valores, nesta ordem:
6.3 Ponteiros
77
inteiros positivos
v1 ,
...,
n,
vn ,
i, j , k .
i + p k j.
de sada padro.
Por exemplo, para a entrada:
10 11 25 33 40 50 69 73 85 96 101 3 2 7 0
a sada deve ser:
33 50 73
Isso ocorre porque o primeiro valor impresso
e o seguinte e ltimo
v3 (i = 3),
o seguinte
v5 (j = 2, 5 = i + j ),
v7 (k = 7 = i + 2 j ).
8. Escreva um programa que leia, do dispositivo de entrada padro, um texto qualquer, caractere
a caractere, e imprima, no dispositivo de sada padro, i) o nmero de palavras que tm um
gnero, masculino ou feminino, ii) o nmero de palavras do gnero masculino, e iii) o nmero
de palavras do gnero feminino.
Voc pode considerar, para simplicar o problema, que:
'o' ou se a
'O' ou "Os".
Analogamente, uma palavra tm gnero feminino se seu ltimo caractere for a letra 'a'
ou se a penltima letra for 'a' e a ltima letra for 's', ou se a palavra igual a 'O'
ou "Os".
Uma palavra tm gnero masculino se seu ltimo caractere for a letra
'o'
%c
's',
ou se a palavra igual a
-1
Uma
o valor
0 representa falso
10. Estenda o exerccio 8 para imprimir tambm o nmero total de palavras do texto.
6.3 Ponteiros
Ponteiros so representaes de endereos na memria do computador.
Eles constituem um
78
parte das vezes ser substitudo por uso de um estilo de programao baseado em abstraes mais
prximas do domnio do problema e no da implementao de uma soluo do problema em um
computador, abstraes essas tanto de dados quanto de denio de funes sobre esses dados.
O uso de ponteiros deve ser feito com cuidado, para evitar erros em tempo de execuo que
podem ser difceis de entender e de corrigir.
Uma varivel um lugar da memria ao qual foi dado um nome (o nome da varivel). Toda
varivel tem um endereo, que o endereo do lugar da memria que foi alocado para a varivel. Um
ponteiro um endereo (da memria), ou um tipo (de valores que so ponteiros para variveis de
um determinado tipo; por exemplo, o tipo
para variveis de tipo
int;
int *
dizemos apenas:
int).
contexto deixar claro, usamos tambm ponteiro para denotar varivel que contm um endereo.
Um tipo ponteiro indicado pelo caractere
int *p;
p e tipo int *, ou seja, ponteiro para int.
* considerado em um comando de declarao de variveis em C como qualicador
int *p, q ;
declara um ponteiro
e uma varivel
de tipo
int,
e no dois ponteiros.
&,
&
*,
e da funo malloc .
Por exemplo, a
sequncia de comandos:
int *p, q ;
p = &q ;
p como uma varivel de tipo int *, q como uma varivel de tipo int e armazena o endereo
p.
O operador * um operador chamado de derreferenciao: aplicado a um ponteiro p, o
resultado a varivel apontada por p (se usado como um valor, o resultado o valor contido na
varivel apontada por p).
O uso de * em uma declarao signica declarao de um ponteiro; o uso de * precedendo um
declara
de
em
a e b de tipo int.
Para fazer isso precisamos passar para uma funo troca o endereo das variveis,
i.e. devemos chamar troca (&a,&b), onde a funo troca denida como a seguir:
b,
programa provavelmente termine com um erro devido a tentativa de acesso a endereo invlido de
memria.
Note tambm que a funo scanf modica o valor de uma varivel, e por isso que o endereo
da varivell que deve ser passado como argumento de scanf.
Ocorre um erro durante a execuo de um programa quando um ponteiro derreferenciado e
o ponteiro representa um endereo que no est no conjunto de endereos vlidos que o programa
pode usar.
79
segmentao.
O endereo
ponteiro nulo, que no endereo de nenhuma varivel. em geral tambm usado em inicializaes de variveis de tipo ponteiro para as quais no se sabe o valor no instante da declarao.
C,
Sendo p um ponteiro para valot qualquer, p+1 representa o endereo seguinte ao endereo denotado por p e,
p-1 representa o endereo anterior ao endereo denotado por p.
res de um tipo
analogamente,
Com isso, possvel realizar operaes aritmticas quaisquer com um ponteiro e um inteiro.
Essas operaes aritmticas so realizadas de modo a levar em conta o tamanho do tipo do valor
denotado por um ponteiro: somar o inteiro 1 a um ponteiro signica somar uma unidade ao ponteiro
igual ao tamanho do tipo de variveis apontadas por esse ponteiro.
Por exemplo, um valor inteiro ocupa, em muitas implementaes, 4 bytes (32 bits).
implementaes, se
do tipo
*int
Nessas
int), p+1
p.
C, o nome de uma varivel de tipo arranjo pode ser usado como um ponteiro para a primeiro
posio do arranjo, com a diferena que o valor dessa varivel no pode ser modicado (a varivel
de tipo arranjo corresponde uma varivel de tipo ponteiro declarada com o atributo
const).
int a[10];
um arranjo de 10 posies alocado e o nome
desse arranjo. Ou seja, o nome
%a[0],
no
i uma expresso qualquer de tipo int, a expresso a[i] denota o mesmo que (a+i) ou
a, i posies depois da 0-sima posio. Se usada em um contexto
requer um valor, essa expresso derreferenciada, fornecendo o valor *(a+i). Portanto, em
Sendo
ponteiro.
Assim, quando um arranjo
&a[0]
f,
apenas o endereo
passado.
C,
'\0'
aspas duplas.
Por exemplo:
'\0',
80
deve levar em conta de que toda varivel que uma cadeia de caracteres deve ter um tamanho xo.
Para ler uma cadeia de caracteres, necessrio primeiro alocar espao um tamanho mximo
para armazenar os caracteres que vo ser lidos. No entanto, no caso de passagem de parmetros
para a funo main (veja seo
tamanho suciente para armazenar os caracteres passados como parmetros para a funo main ).
O uso de cadeias de caracteres em
Assinatura
int
strlen (char
Signicado
*s )
'\0'
tere
ractere
no
se as cadeias so iguais,
O uso do atributo
char*,
ou
char[],
==,
C,
podem ocorrer erros difceis de serem detectados se no for seguida a conveno de que
<
menor do que o s2. A comparao entre caracteres feita pelo valor da representao no cdigo
ASCII. Por exemplo:
"ab"
menor que
"abc"
e que
"ac",
e maior que
"aa"
"a".
Assinatura
Signicado
Converte cadeia de caracteres para valor de tipo
Converte cadeia de caracteres para valor de tipo
Converte cadeia de caracteres para valor de tipo
int
float
long
81
char
char
char
char
char
*s1
*s2
*s3
*s4
*s5
=
=
=
=
=
"1234";
"12.34";
"1234";
"123quatro";
"xpto1234";
int i;
float f ;
i
f
i
i
i
Note que:
0.
v1 , ..., vn )
onde formato um literal de tipo cadeia de caracteres de controle da operao de escrita na cadeia
de caracteres str e
v1 ,...,vn
sprintf no pode ser usada quando se deseja o valor da cadeia de caracteres correspondente a
um inteiro (pois sprintf um comando, no retorna nenhum valor). Quando um valor desejado,
uma funo pode ser denida pelo programador, ou pode ser usada a funo itoa , disponvel em
grande parte das implementaes da biblioteca
stdlib,
char*
char*
str,
int
base )
itoa converte valor para uma cadeia de caracteres, terminada com o caractere
base base , armazena essa cadeia em str , e retorna str .
Se a base for 10 e valor for negativo, a cadeia resultante precedida do sinal
NULL,
)-).
usando a
Em qualquer
str deve ser um arranjo com um tamanho grande o suciente para conter a cadeia.
main
A funo main pode receber como argumento vrias cadeias de caracteres, separadas entre si
por espaos ou outros caracteres delimitadores de palavras (como tab, i.e.
'\ t').
O interpretador
82
"abc xy 123"
e coloque cada sequncia de caracteres que est separada da seguinte por um ou mais delimitadores
em uma posio de um arranjo, e passe como argumento para o mtodo main do programa (prog)
o valor 3 que igual ao tamanho do arranjo (nmero de cadeias de caracteres) e esse arranjo.
Assim, o arranjo passado contm
"123"
"abc"
na varivel de ndice
0, "xy"
na varivel de ndice
na varivel de ndice 2.
n,
nesta cadeia.
Por exemplo, para a entrada:
10
112223a
a sada deve ser:
1
2
3
a
aparece
aparece
aparece
aparece
2
3
1
1
vezes
vezes
vez
vez
A ordem de impresso dos caracteres e sua frequncia no importante, mas cada caractere
deve aparecer, com sua frequncia de ocorrncia, apenas uma vez na sada, e somente se essa
frequncia for diferente de zero.
Soluo : Cada caractere representado no cdigo ASCII por um valor inteiro compreendido
entre
0 e 127.
malloc (max
* sizeof(char));
contChar [],
int
tamanho_str )
O uso do atributo
83
nas por questo de legibilidade, para indicar que a cadeia de caracteres str no modicada
no corpo da funo.
Um exemplo de denio de uma funo main que usa a funo contFreqChar mostrada a
seguir. Os valores de entrada so lidos, a funo contFreqChar chamada e a frequncia de
cada caractere que ocorre na cadeia de caracteres especicada na entrada impressa.
int main () {
int tam ;
scanf ("%d",&tam );
char *s = malloc (tam * sizeof(char));
scanf ("%s",s);
printf ("Na cadeia de caracteres %s\n",s);
int max = 128; int *contChar = malloc (max * sizeof(int));
int i,freq ;
for (i=0; i<max ; i++) contChar [i] = 0;
contFreqChar (s,contChar,tam );
for (i=0; i<max ; i++)
if (contChar [i] = 0) {
freq = contChar [i];
printf ("%c aparece %d %s\n",(char)i,freq,freq ==1?"vez":"vezes");
}
}
2. Escreva um programa para determinar a letra ou algarismo que ocorre com maior freqncia
em uma cadeia de caracteres dada, com um tamanho mximo previamente fornecido, e
imprimir esse algarismo no dispositivo de sada padro.
Soluo : Um caractere alfanumrico um caractere que pode ser um algarismo ou uma letra.
A soluo consiste em, inicialmente, determinar a freqncia de ocorrncia de cada caractere
alfanumrico, de maneira anloga do exerccio anterior. Ou seja, a soluo armazena cria
arranjos com componentes correspondentes a cada caractere alfanumrico. Cada componente
contm a frequncia de ocorrncia do caractere alfanumrico correspondente. Em seguida, o
ndice do componente de maior valor (isto , maior frequncia) desse arranjo determinado e
o caractere alfanumrico correspondente a esse ndice impresso. Vamos usar trs arranjos,
um arranjo para dgitos com ndices de
'0',
obtido por
d -
representao do caractere
'0'.
'a'
'A'.
84
letraMinusc (char
letraMaiusc (char
contFreqAlfaNums (const
int
tamDigs,
contDigLets [],
int i; char c;
for (i=0; i<tam ; i++) {
c = s[i];
if (isdigit (c)) contDigLets [c - '0']++;
else if (letraMinusc (c)) contDigLets [tamDigs + (c - 'a')]++;
else if (letraMaiusc (c)) contDigLets [tamDigs + tamLets + (c - 'A')]++;
}
%c\n",str,
A funo maisFreq recebe como argumento uma cadeia de caracteres, em que cada caractere
representa um algarismo, e retorna o algarismo mais freqente nessa cadeia. Quando existir
mais de um algarismo com a maior freqncia de ocorrncia, o mtodo retorna, dentre esses,
aquele que ocorre primeiro na cadeia. Por exemplo, maisFreq ("005552") retorna
'1'.
'5',
3. Escreva um programa para resolver o exerccio 15, pgina 61, considerando a condio de
que inteiros podem ter at 1000 dgitos decimais.
Soluo : Usamos uma cadeia de caracteres de at 1001 dgitos para armazenar inteiros que
85
'\0'
soma dos dgitos de um inteiro de at 1000 dgitos sempre pode ser armazenada em um valor
de tipo
int.
grau9
int main () {
const int numDigs = 1001;
char v [numDigs ];
while (1) {
scanf ("%s", &v );
int i=0; while (i < numDigs && v [i] == '0') i++;
if (i < numDigs && v [i]=='\0') break; // Termina se inteiro lido igual a zero
int
= grau9 (v );
is%s a multiple of 9", v, grau9v ==0 ?
if (grau9v ==0) printf ("\n");
else printf (" and has 9-degree %d\n",grau9v );
grau9v
printf ("%s
"not":
);
}
return 0;
6.4.5 Exerccios
1. Escreva uma funo inverte que estenda o Exerccio 5 da seo 3.2 para qualquer cadeia de
caracteres
o tamanho
deve ler, antes de cada cadeia de caracteres, um valor que, deve-se supor, maior que o
tamanho da cadeia.
2. Dena uma funo decPraBin que receba um nmero inteiro no-negativo como argumento
e retorne uma cadeia de caracteres que igual representao desse nmero em notao
binria.
86
8,
"1000".
Para calcular o tamanho da cadeia de caracteres a ser alocada, dena e use uma funo
m + 1 tal
n pode ser dividido
3
4
por 2 at que o quociente da diviso seja zero. Por exemplo, 2 8 < 2 , e 4 o nmero de
caracteres da cadeia "1000", necessrios para representao de 8 na base 2.
numDiv2 que, ao receber um nmero inteiro positivo
m
m+1
que
n<2
n,
deve ser alocada uma cadeia de caracteres de tamanho tam +2, onde
tam o resultado de numDiv2 (n), para conter, alm dos caracteres necessrios para re-
presentao de
na base 2, o caractere
'\0'
(usado em
caracteres).
Escreva um programa que leia vrios nmeros inteiros positivos do dispositivo de entrada
padro e imprima, para cada inteiro lido, a sua representao em notao binria, usando a
funo denida no item anterior (o programa que contm a funo main deve conter tambm
a denio das funes denidas acima).
A execuo deve terminar quando um inteiro negativo ou zero for lido.
3. Dena uma funo que receba como argumento um nmero inteiro no-negativo b, em notao
binria, e retorne o valor inteiro (de tipo
int)
1000,
8.
como um valor inteiro e supor que o valor lido pode ser arma-
10.
resto da diviso de
igual a
10)
int,
101
por
10;
e repita o processo.
Escreva um programa que leia, do dispositivo de entrada padro, vrias cadeias de caracteres
que representam nmeros inteiros positivos em notao binria, e imprima, para cada valor
lido, a sua representao em notao decimal, usando a funo denida acima (o programa
que contm a funo main deve conter tambm a denio da funo denida acima).
A execuo deve terminar com o m dos dados de entrada.
t,
s de tamanho menor que t e, em seguida, vrias cadeias
de caracteres s1 , . . . , sn , tambm com tamanho menor que t, e imprima, para cada cadeia
si , para i entre 1 e n, uma mensagem que indica se s contm si ou no. A entrada deve
4. Escreva um programa que leia, do dispositivo de entrada padro, um valor inteiro positivo
em seguida uma cadeia de caracteres
terminar com o m dos dados de entrada, isto , quando m-de-arquivo for detectado; em
entrada interativa, quando scanf retornar
-1,
1000
abcdefghijklmnopqrstuvwxyz123456789
nopqr
789
xya
abc
A sada deve ser uma mensagem como a seguir:
nopqr Sim
789 Sim
xya Nao
abc Sim
6.5 Registros
87
'\0'.
n,
n,
s2
s1
s2 ,
ambas com
s1 .
100
abci adefghiabaf
A sada deve ser:
defghf
6.5 Registros
Um registro (ou, como chamado em
C,
(10,'*') um par,
10, e um segundo componente, '*'. Um par um elemento
produto cartesiano de dois conjuntos o par (10,'*') um elemento do produto cartesiano
conjunto dos valores inteiros pelo conjunto dos valores de tipo char.
Naturalmente, alm de pares, tambm possvel formar triplas, qudruplas, quntuplas etc.
usualmente chamadas de tuplas que so elementos de produtos cartesianos generalizados, ou
seja, elementos de um produto de vrios conjuntos.
Em linguagens de programao (como
{
representa, em
C,
= 10,
= '*'}
tem rtulo y . Nesse exemplo, o valor do componente separado do rtulo pelo smbolo =. O
registro
{y = '*',
= 10}
{x = 10,
= '*'}.
Ou
valores dos campos, que a ordem em que os campos aparecem na denio do tipo registro, e s
podem ser usados em declaraes de variveis, como veremos no exemplo a seguir.
Uma declarao de um tipo registro consiste de uma sequncia de campos, cada um dos quais
com um tipo e um nome. Por exemplo:
88
struct contaBancaria {
int numero ;
char *idCorrentista ;
float saldo ;
};
Em
C,
struct
struct
contaBancaria
conta;
O tipo contaBancaria , assim como a varivel conta , tm trs campos ou componentes: conta-
char*
float.
int.
Analogamente, conta.idCorrentista
Esses componentes denotam (podem ser usados ou modicados como) uma varivel comum do
tipo do campo.
Valores de tipo registro podem ser construdos em
de tipo registro, de modo semelhante ao que ocorre no caso de arranjos. Um valor de tipo registro
especica valores a cada um dos campos do registro, entre chaves, como mostrado no exemplo a
seguir.
O exemplo seguinte ilustra uma declarao de uma varivel do tipo contaBancaria , denido
acima, especicando um valor inicial para a varivel:
struct
contaBancaria
A atribuio de um valor de tipo registro a outro copia, como esperado, o valor de todos os
campos do registro. Considere o seguinte exemplo:
Ponto
{ int x; int y ; } ;
int main () {
struct Ponto p = {1,2}, q ;
q = p;
q .x = 2;
printf ("p.x = %d\nq.x = %d\n", p.x, q .x);
}
p.x = 1
q.x = 2
6.5 Registros
89
{
p, q ;
main ()
Ponto
contaBancaria ;
ContaBancaria
*, mas existe em C a possibilidade de usar o operador ->, que alm da derreferenciao faz tambm
acesso a um campo de um registro. Por exemplo:
que contm um campo que uma ponteiro que pode ser nulo ou um ponteiro para um
T.
struct ListaInt {
int val ;
struct ListaInt *prox ;
};
int
90
Listas encadeadas so estruturas de dados exveis, pois no requerem tamanho mximo, como
arranjos. Elas podem crescer e decrescer de tamanho medida que dados vo sendo inseridos e
removidos.
A desvantagem, em relao ao uso de arranjos, que o acesso a um componente da estrutura
de dados requer um tempo que depende da posio desse componente na estrutura: o acesso a
cada componente depende de acesso a cada um dos componentes anteriores a ele na lista.
rvores binrias podem ser formadas de modo similar. Por exemplo, uma rvore binria com
nodos que contm campos de tipo
int
struct ArvBinInt {
int val ;
struct ArvBinInt *esq ;
struct ArvBinInt *dir ;
};
O seguinte exemplo ilustra o uso de uma lista encadeada para evitar a restrio de se ter que
especicar um nmero mximo de valores, necessrio para uso de arranjo. Considere o problema do
Exerccio Resolvido 1, da seo 6.4.4, que prope que um texto qualquer seja lido e seja impressa a
frequncia de todos os caracteres que ocorrem no texto. Considere que o problema no especica
o tamanho do texto. A soluo a seguir usa uma lista encadeada de caracteres para armazenar o
texto, em vez de uma cadeia de caracteres.
Em casos como esse, pode ser mais adequado usar um arranjo exvel, com um tamanho mximo
que pode ser aumentado, testando, antes de cada insero de um novo valor no arranjo, se esse
tamanho mximo foi atingido. Se o tamanho mximo for atingido, um novo arranjo alocado com
um tamanho maior (por exemplo, o dobro do tamanho anterior), o arranjo antigo copiado para
o novo, e o novo arranjo passa a ser usado, no lugar do antigo. Arranjos exveis so estruturas de
dados bastante usadas em programas escritos em linguagems como, por exemplo,
Java
C++.
Soluo :
91
->
(*ponteiro ).campo .
n,
onato;
(b)
nome do time
i;
si ,
onde
si
t1
t2 : t1
marcou
v1
t1 v1 t2 v2 , que indicam o
t2 marcou v2 gols; os
gols e
3
1
2
3
1
1
2
America
Atletico
Cruzeiro
1 2 2
2 3 3
1 3 1
Isso porque o
com o
Atletico, Cruzeiro
92
Soluo: A soluo apresentada usa arranjos para armazenar nomes de times e para armazenar pontos acumulados em partidas. Esses arranjos so indexados com o nmero do time
menos 1 (porque os nmeros de time variam entre 1 e
inicial igual a
0).
e arranjos em
sempre tm ndice
de pontos) medida em que tal maior nmero de pontos calculado. A lista de vencedores
chamda de maiores inicialmente nula. Para cada time, do primeiro ao ltimo, se o
nmero de pontos maior do que o maior calculado at cada instante desta iteraco, o maior
atualizado, seno, se o nmero de pontos for igual, este inserido na lista de maiores.
93
Maiores * prox ;
};
int main () {
int n, num ;
scanf ("%d", &n);
char** times = malloc (n * sizeof(char*));
int i; const int tamMaxNomeTime = 31; // 31 devido a terminacao com '\0'
for (i=0; i<n; i++) {
scanf ("%d", &num );
times [num -1] = malloc (tamMaxNomeTime *sizeof(char));
scanf ("%s", times [num -1]);
}
int
*pontos ;
= malloc (n * sizeof(int));
for (i=0; i<n; i++) pontos [i] = 0;
while (1) {
numValLidos = scanf ("%d%d%d%d",&num1, &gols1, &num2, &gols2 );
if (numValLidos != 4) break;
if (gols1 >gols2 ) pontos [num1 -1] += 3; else
if (gols2 >gols1 ) pontos [num2 -1] += 3;
else { pontos [num1 -1]++; pontos [num2 -1]++; }
}
pontos
Maiores * maiores
= NULL;
int maior = 0;
for (i=0; i<n; i++)
if (pontos [i] > maior ) {
maiores = malloc (sizeof(Maiores ));
maiores ->num = i;
maiores ->prox = NULL;
maior = pontos [i];
}
else if (pontos [i] == maior ) { // novo elemento em maiores
Maiores * novo = malloc (sizeof(Maiores ));
novo ->prox = maiores ;
novo ->num = i;
maiores = novo ;
}
printf ("%s", times [maiores ->num ]);
maiores = maiores ->prox ;
while (maiores !=NULL) {
printf (", %s",times [maiores ->num ]);
maiores = maiores -> prox ;
}
printf ("\n");
return 0;
3. Escreva um programa que leia uma sequncia de valores inteiros quaisquer e imprima esses
94
valores em ordem no-decrescente (cada valor seguinte maior ou igual ao anterior). Valores
iguais devem aparecer tantas vezes quantas existirem na entrada.
Por exemplo, considere a entrada:
4 3 1 5 5 2 3
A sada deve ser:
1 2 3 3 4 5 5
Soluo: Vamos denir e usar uma funo para ordenao de valores conhecida como ordenao por seleo . O algoritmo simplesmente seleciona a cada iterao o maior elemento (a
menos de igualdade) e insere o valor selecionado no incio de uma lista
no nal a lista
l de valores ordenados;
estar ordenada (no nal o menor elemento ser inserido no incio da lista).
6.7 Exerccios
1. Escreva um programa que leia um valor inteiro positivo
os
n,
n, e imprima
n ltimos caracteres de s, armazenando para isso a cadeia s como uma uma lista encadeada
de caracteres onde um apontador usado para apontar para o caractere anterior da cadeia.
2. Escreva um programa que leia um valor inteiro positivo
de valores inteiros diferentes de zero, cada valor lido separado do seguinte por um ou mais
espaos ou linhas, e imprima
por
a
n,
n-sima
1a
divisveis
1, etc., at
n 1.
A entrada termina quando um valor igual a zero for lido. A ordem dos valores impressos em
cada linha no relevante.
Use um arranjo de
de valores inteiros.
Exemplo: Considere a entrada:
4 12 13 15 16 17
Para essa entrada, a sada deve ser como a seguir:
Alm de as-
Captulo 7
Exerccios
Este captulo descreve a soluo de diversos exerccios, que mostram como usar e decidir quando
usar os diversos comandos e estruturas de dados abordados neste livro.
Os enunciados dos exerccios so obtidos da pgina Web
http://br.spoj.pl/problems/.
http://br.spoj.pl/)
C.
7.1 ENCOTEL
Considere que uma representao alfanumrica de um nmero de telefone uma sequncia de
caracteres tal que cada caractere pode ser: uma letra maiscula (de
dgito
9,
Z),
um hifen (-) ou um
abaixo.
Letras
ABC
DEF
GHI
JKL
MNO
PQRS
TUV
WXYZ
Nmero
2
3
4
5
6
7
8
9
Escreva um programa que leia vrias linhas, cada linha contendo uma tal representaco alfanumrica de nmero de telefone, e imprima uma sequncia de representaes para os nmeros de
telefone, novamente uma em cada linha, que substitua letras maisculas por dgitos de acordo com
a tabela mostrada.
Considere que cada representaco alfanumrica possui entre 1 e 30 caracteres.
terminada por m de arquivo (EOF).
Por exemplo, para a entrada:
1-HOME-SWEET-HOME
MY-MISERABLE-JOB
A sada deve ser:
1-4663-79338-4663
69-647372253-562
A entrada
96
Exerccios
A soluo mostrada abaixo usa um arranjo que armazenada, para cada letra maiscula, seu
menos um.
Essa soluo evita escrever um programa, relativamente ineciente e mais longo, que testa, aps
a leitura de cada caractere, se o caractere uma letra pertencente a um grupo especco de letras
na tabela mostrada, para impresso do dgito correspondente a esse grupo de letras na tabela.
7.2 PAPRIMAS
x Um nmero primo um nmero que possui somente dois divisores: ele mesmo e o nmero 1.
Exemplos de nmeros primos so: 1, 2, 3, 5, 17, 101 e 10007.
Neste problema voc deve ler um conjunto de palavras, onde cada palavra composta somente
por letras no intervalo
a-z
A-Z .
z,
b
B
vale 1, a letra
vale 52.
Voc deve escrever um programa para determinar se uma palavra uma palavra prima ou no.
Uma palavra uma palavra prima se a soma de suas letras um nmero primo.
7.2 PAPRIMAS
97
Entrada : A entrada consiste de um conjunto de palavras. Cada palavra est sozinha em uma
linha e possui
letras, onde
1 L 20.
Sada : Para cada palavra voc imprimir: It is a prime word., se a soma das letras da palavra
um nmero primo, caso contrrio voc deve imprimir It is not a prime word..
encontrar m-de-arquvo, e imprime mensagem indicando se cada palavra lida uma palavra prima
ou no. O tamanho de cada palavra restrito a um tamanho mximo de 20 caracteres.
A funo primo verica se um dado nmero
mentada de diversos modos. A Figura 7.1 usa o mtodo simples de divises sucessivas, por todos
os nmeros menores que
n.
n,
outros algoritmos existentes. Os programas mostrados a seguir usam o algoritmo conhecido como
http://en.wikipedia.org/wiki/Prime_number#Verifying_primality
98
const int
Exerccios
int main () {
char palavra [max ];
while (ler (palavra ))
printf ("It is%s a prime word.\n", prima (palavra ) ? "" : " not");
}
int minusc (char let ) { return (let >= 'a' && let <= 'z'); }
int valor (char let ) {
return (minusc (let ) ? let -'a'+1
: let -'A'+('z'-'a'+1)+1);
}
int prima (char* palavra ) {
int i, somaLet =0;
for (i=0; i < max && palavra [i] != '\0'; i++)
somaLet += valor (palavra [i]);
return primo (somaLet );
}
int primo (int n) {
if (n%2 == 0) return 0;
int k = 3, sqrtn = sqrt ((double)n);
// Se existir divisor prprio de n, tem que existir divisor prprio menor que n.
while (k <= sqrtn ) {
if (n%k == 0) return 0;
k += 2;
}
return 1;
}
int ler (char* palavra ) {
// Retorna verdadeiro sse leitura com sucesso.
return (scanf ("%s",palavra ) == 1);
}
7.2 PAPRIMAS
99
Uma soluo que usa um teste de primalidade baseado no algoritmo conhecido como crivo de
Crivo de Eratstenes
int main () {
const int m = max *(2*('z'-'a'+1));
// Primalidade deve ser testada para valores menores ou iguais a m
char palavra [max ]; int *primos = listaDePrimos (m);
while (ler (palavra ))
printf ("It is%s a prime word.\n", prima (palavra,primos,m) ? "" : " not");
}
int minusc (char let ) { . . . como na Figura 7.1 . . . }
int valor (char let ) { . . . como na Figura 7.1 . . . }
int* listaDePrimos (int m) {
int p=2, m2 =m+2, nums [m2 ], *primos = malloc (m),
// nums [0],nums [1] no usados (por simplicidade, i.e.
// para que ndice de nums corresponda a nmero entre 2 e m);
i,j ,k ;
for (i=2,j =0; i<m2 ; i++,j ++) { nums [i]=0; primos [j ] = 0; }
j = 0;
do {
// marca mltiplos de p
for (i=p; i<m2 ; i+=p) nums [i] = 1;
// procura prximo valor no marcado a partir de j
for (k=p+1; k<m2 ; k++) if (!nums [k]) break;
p = k ; // p o prximo primo
primos [j ] = p;
j ++;
} while (p<m2 );
return primos ;
}
int primo (int n, int* primos, int m) {
int i;
for (i=0; i<m; i++)
if (primos [i] >= n) return (primos [i]==n);
else if (primos [i] == 0) return 0;
return 0;
}
int ler (char* palavra ) { . . . como na Figura 7.1 . . .
int prima (char* palavra, int* primos, int m) {
int i, somaLet =0;
for (i=0; i < max && palavra [i] != '\0'; i++)
somaLet += valor (palavra [i]);
return primo (somaLet,primos,m);
}
O algoritmo do Crivo de Eratstenes , inventado por Eratstenes em 350 A.C., cria uma lista
de todos os primos menores que um valor mximo
m.
100
Exerccios
valor mximo, que pode ser denido como vinte vezes o valor mximo possvel para uma eletra
(uma vez que podem ocorrer no mximo 20 letras em uma palavra). O algoritmo de Eratstenes
consiste no seguinte:
1. Criar lista
2. Atribuir, inicialmente, 2 a
m.
p.
remover de
em seguida, fazer
todos os mltiplos de
a partir de
p:
p;
p,
em l, ainda no removido.
e, para vericar se um
primo, percorre esse arranjo usando uma pesquisa sequencial (de componente a
struct ListaETamanho {
int* lista ;
int tam ;
};
typedef struct ListaETamanho
ListaETamanho ;
(int m) {
int p=2, m2 =m+2, nums [m2 ], *primos = malloc (m),
i ,j ,k ;
for (i=2,j =0; i<m2 ; i++,j ++) { nums [i]=0; primos [j ] = 0; }
j = 0;
do {
for (i=p; i<m2 ; i+=p) nums [i] = 1;
for (k=p+1; k<m2 ; k++) if (!nums [k ]) break;
p = k ; // p o prximo primo
primos [j ] = p;
j ++;
}
while (p<m2 );
ListaETamanho l;
l.lista = primos ;
l.tam = j ;
return l;
ListaETamanho listaDePrimos
}
int primo (int n, ListaETamanho primos ) {
int linf =0, lsup =primos.tam -1, meio = (linf+lsup)/2;
while (linf <lsup -1) {
if ((primos.lista )[meio ] > n) { lsup = meio ; meio = (linf +lsup )/2;} else
if ((primos.lista )[meio ] < n) { linf = meio ; meio = (linf +lsup )/2;} else
return 1;
} return ((primos.lista )[linf ]== n || (primos.lista )[lsup ]==n);
}
O algoritmo de pesquisa binria compara o elemento que est sendo procurado com o valor
que est na metade do arranjo ordenado, permitindo assim que a busca prossiga ou na metade
inferior ou na superior do arranjo, conforme o elemento a ser procurado seja menor ou maior,
7.3 ENERGIA
101
respectivamente, do que o valor que est na metade do arranjo. Se o elemento a ser procurado
igual ao elemento na metade, ento, claro, a busca termina com sucesso.
So mostradas apenas as funes modicadas, que so listaDePrimos e primo . A funo lista-
DePrimos modicada apenas para retornar, alm do arranjo contendo os primos, o nmero de
primos de fato armazenado nesse arranjo. A funo primo percorre esse arranjo usando pesquisa
binria.
7.3 ENERGIA
7.4 CIRCUITO
7.5 POLEPOS
Referncias Bibliogrcas
104
REFERNCIAS BIBLIOGRFICAS
Apndice A
C.
necessidade de homogeneizao no ensino de disciplinas introdutrias de programao de computadores nos cursos de vrias universidades (por exemplo, nas disciplinas de Algoritmos e Estruturas
de Dados I do Departamento de Cincia da Computao da Universidade Federal de Minas Gerais). O uso da linguagem
para cursos como os de Engenharia Eltrica e Engenharia de Controle e Automao, por se tratar
de linguagem adequada chamada programao de sistemas , na qual se faz acesso direto a dispositivos e recursos de hardware. Para tais sistemas, a programao na linguagem
C adequada pois
a linguagem permite acesso direto aos dispositivos e recursos de hardware, e portanto bibliotecas
e programas que fazem tais acessos diretos ao hardware podem ser mais facilmente encontrados e
usados. Para outros cursos, o uso da linguagem
uma preocupao central com ecincia, e possibilidade de acesso direto a reas de memria, o que
leva, principalmente, a duas consequncias indesejveis do ponto de vista de um aprendizado em
programao:
1. Ausncia de vericao dos chamados erros de tipo.
valores em contextos inadequados, ou seja, em contextos nos quais no faz sentido usar tais
valores, e portanto nos quais tais valores no deveriam ser usados.
Grande parte do desenvolvimento das linguagens de programao nos dias atuais relacionado ao objetivo de tornar as linguagens cada vez mais seguras, no sentido de possibilitar a
deteo de um nmero cada vez maior de erros de tipo, e ao mesmo tempo dando exibilidade
ao programador, de modo que ele no tenha que especicar ou mesmo se preocupar com a
especicao de tipos em seus programas, e procurando manter o algoritmo que permite essa
deteo de erros simples e eciente.
NO ENTENDI O SEGUINTE ITEM (ANOLAN)
2. Mecanismos adequados na linguagem para suporte a abstraes, conceitos e construes
comumente usados em programas. Exemplos de tais mecanismos so:
Tipos algbricos: tipos que permitem representar disjuno (ou ) entre tipos e estruturas de dados, de modo seguro e simples.
Polimorsmo: tanto de valores (estruturas de dados) que podem ser instanciados para
quaisquer tipos, mantendo a mesma forma, quanto de funes que realizam operaes
sobre tais estruturas de dados, que funcionam do mesmo modo, independentemente da
instncia sobre a qual realizam a operao.
106
Pelo segundo, se oferecem sees especiais que abordam temas mais complexos, destinados aos
estudantes que procurem maior aprofundamento nos contedos lecionados.
Apndice B
Tipos bsicos em C
B.1 Nmeros
A rea de memria reservada para armazenar um dado valor em um computador tem um tamanho xo, por questes de custo e ecincia. Um valor de tipo
nos computadores atuais, em uma poro de memria com tamanho de 32 ou 64 bits, assim como
um nmero de ponto utuante em
C,
um valor de tipo
float
ou
double.
Tambm por questes de ecincia (isto , para minimizar tempo ou espao consumidos),
existem qualicadores que podem ser usados para aumentar ou restringir os conjuntos de valores
numricos inteiros e de nmeros de ponto utuante que podem ser armazenados ou representados
Cada implementao da linguagem pode usar um tamanho que julgar apropriado. As nicas
condies impostas so as seguintes. Elas usam a funo
sizeof,
predenida em
C,
que retorna o
short
o valor
short.
10,
de tipo
int,
= 10;
convertido, onde
short
feita a converso, sendo descartados os bits mais esquerda (mais signicativos) restantes.
108
Tipos bsicos em C
Nmeros inteiros podem tambm ser representados nos sistemas de numerao hexadecimal e
at
f,
ou
at
F,
respectivamente. Um numeral
7).
Nmeros de ponto utuante so nmeros representados com uma parte inteira (mantissa) e
outra parte fracionria, como, por exemplo:
2.0
3.1415
1.5e-3
7.16e1
Um ponto decimal usado para separar a parte inteira (mantissa) da parte fracionria.
expoente na base
10
-).
e,
E,
ou
Um
seguida de
ou
F,
como em
2e2f
4.f
0f
2.71828e+4f
double:
2e2
.5f
do suxo, ou
4.
.5
0.0
1e-9d
int
constitui,
C,
valor que causou a ocorrncia de overow no pode ser representado no espao reservado para que
ele seja armazenado, o programa usa ento um outro valor (incorreto). Quando ocorre overow ,
por exemplo, na adio de dois nmeros inteiros positivos, o resultado um nmero negativo. O
inverso tambm verdadeiro: quando ocorre overow na adio de dois nmeros inteiros negativos,
o resultado um nmero positivo.
B.2 Caracteres
Valores do tipo
char,
tais como letras, algarismos etc., e caracteres de controle, usados para indicar m de arquivo,
mudana de linha, tabulao etc.
Cada caractere representado, em um computador, por um determinado valor (binrio).
associao entre esses valores e os caracteres correspondentes constitui o que se chama de cdigo .
O cdigo usado para representao de caracteres em
Standard Code for Information Interchange). O cdigo ASCII baseado no uso de 8 bits para
cada caractere.
Caracteres visveis so escritos em
Por exemplo:
etc. preciso notar que, por exemplo, o caractere '3' diferente do numeral inteiro
representa um smbolo, enquanto o segundo representa um nmero inteiro.
Caracteres de controle e os caracteres
'
'\n'
'\t'
'\
'\\'
'
\
B.2 Caracteres
109
Um valor do tipo
char
converso de tipo implcita, tal como no caso de converses entre dois valores inteiros de tipos
diferentes (como, por exemplo,
short
int).
ao seu cdigo ASCII (isto , ao valor associado a esse caractere no cdigo ASCII).
Valores de tipo
do tipo
short,
char
char
, portanto, diferente
que inclui valores positivos e negativos. Converses entre esses tipos, e converses
C:
minusc_maiusc
tem como resultado o valor dado por
('b')
que igual a
'A' + 1,
ou seja,
'B'.
Como mencionado na seo B.2, caracteres podem ser expressos tambm por meio do valor da
sua representao no cdigo ASCII. Por exemplo, o caractere chamado nulo , que representado
com o valor
0,
'\x0000'
Nessa notao, o valor associado ao caractere no cdigo ASCII (cdigo ASCII do caractere)
escrito na base hexadecimal (usando os algarismos hexadecimais
minscula.
F,
110
Tipos bsicos em C
Apndice C
Programas e Bibliotecas
Um programa en
uma dessas funes, de nome main , a funo que inicia a execuo do programa. A denio de
uma funo de nome main deve sempre estar presente, para que uma sequncia de denies de
funes forme um programa
C.
A assinatura ou interface de uma funo uma denio de uma funo que omite o corpo
(sequncia de comandos que executada quando a funo chamada) da funo, mas especica o
nome, o tipo de cada argumento e do resultado da funo.
Em uma assinatura, os nomes dos argumentos so opcionais (mas os tipos so necessrios).
A assinatura da funo main de um programa
int
deve ser:
main (void)
ou
int
char*
argv [])
A primeira assinatura especica que a funo main no tem parmetros e o tipo do resultado
int.
Esse valor usado para especicar, para o sistema operacional, que a funo foi
executada normalmente, sem causar nenhum erro (nesse caso, o valor zero retornado), ou para
especicar que a execuo da funo provocou a ocorrncia de algum erro (nesse caso, um valor
diferente de zero retornado). Como o sistema operacional pode usar uma conveno diferente
para indicar a presena ou ausncia de erro, boa prtica usar as constantes EXIT_SUCCESS e
preprocessamento. Como mencionado na seo ??, Uma diretiva de preprocessamento comea com
o caractere
#,
e deve ser inserida na primeira coluna de uma linha. Uma diretiva de preproces-
samento deve comear sempre na primeira coluna de uma linha. Aps o caractere
no caso de um
.h,
entre os caracteres
.h
<
>,
o nome do arquivo deve ser inserido entre aspas duplas (como por exemplo em
sendo
A
vem o nome
"interface.h",
C, e a questo,
C.
bastante comum
stdio : contm funes para entrada e sada em dispositivos padro, como printf e scanf
(descritas na seo
??).
112
Programas e Bibliotecas
int
(de
char,
como:
'0'
'9'),
int
int
int
int
double
double
double
a base do logartmo
double
double
double
pow (double
a, double b):
retorna
ab (a
elevado a
b).
int
long
void
srand (unsigned
int):
rand ,
int
int
pseudo-aleatrios rand ,
double
int
int
EXIT_FAILURE : valor usado para indicar que ocorreu alguma falha na execuo
de um programa.
Na seo
compilao, cada uma armazenada em um arquivo, e como nomes denidos em uma unidade de
compilao so usados em outra unidade.
ndice Remissivo
= (atribuio), 19
!= (operador de desigualdade), 16
< (operador menor), 16
<= (operador menor que), 16
== (operador de igualdade), 15, 16, 19
> (operador maior), 16
>= (operador maior que), 16
! (operador lgico no), 16
& (operador bit-a-bit ), 17
& (operador lgico ), 16, 28
&& (operador lgico ), 16, 28
(operador bit-a-bit ou exclusivo), 17
| (operador bit-a-bit ou), 17
| (operador lgico ou), 16, 28
|| (operador lgico ou), 17, 28
somador completo, 8, 9
somador paralelo, 8, 9
cdigo
fonte, 5
objeto, 5
comando, 13
break,
continue,
26
44, 56
de atribuio, 13, 19
varivel alvo, 19
de escrita, 19
de leitura, 19
de repetio, 13, 3537
do-while, 44
for, 3738, 44, 72
while, 35, 44, 49
EXIT_FAILURE, 111
EXIT_SUCCESS, 111
itoa, 81
5152, 56
de seleo, 13,
if, 33
switch,
sprintf, 81
33
5152
algoritmo, 1
ecincia de, 39
Alocao dinmica de memria, 70, 71, 73
rtulo de, 52
return,
27, 38
ambiente de programao, 5
comentrio, 25
compilao, 5
arranjo, 6975
compilador, 5
ndice, 69
complemento de dois, 9
criao de, 71
computador
declarao de, 70
indexao, 69
tamanho, 69, 71
const, 80
continue (comando),
Converso
multidimensional, 73
44, 56
ASCII, 108
atribuio, veja comando de atribuio
80
para cadeia de caracteres, 81
bit, 2
boolean, 19
break (comando),
byte , 2
Crivo
de Eratstenes, 99
bytecodes , 5
Declarao
caractere, 108
Unicode, 108
char, 107,
108
80
declarao
de varivel,
19
denio
recursiva, 37
const),
114
NDICE REMISSIVO
depurador, 6
dispositivo de entrada, 3
dispositico de entrada padro, 26
Lgica Booleana, 7
conectivos, 7
dispositivo de sada, 3
dispositico de sada padro, 26
divisao
linguagem
Ada, 22
diviso inteira, 15
do-while (comando
double, 107108
de repetio), 44
C, 22
C++, 22
de alto nvel, 5
editor, 6
de baixo nvel, 5
de mquina, 3
de montagem, 4
ENCOTEL, 95
endereo de memria, 2
Eiel, 22
Eratstenes, 99
fonte, 5
funcional, 22, 23
Haskell, 22, 23
estilo, 23
imperativa, 14,
estruturas de dados, 69
Java, 22
heterogneas, 69
ML, 22, 23
homogneas, 69
Modula-2, 22
14
Modula-3, 22
Exemplos:
Exemplo_continue, 56
objeto, 5
ExemplosSelecaoMax3, 34
ExemplosSelecaoMax3, 34
Pascal, 22
Fibonacci, 55
Prolog, 22, 23
PrimeirosExemplos, 27
Torres de Hani, 52
Smalltalk, 22
long,
107
exponenciao, 39
ex
expresso, 17
com efeito colateral, 18, 19
condicional, 29
valor de, 18
memria, 2
mtodo
false,
chamada de, 28
19
montador, 4
fatorial, 41
m de arquivo, 56
float, 107108
for (comando de
nmeros de Fibonacci, 54
no-terminao, 45
funo, 26
notao
recursiva, 36
arbica, 6
funo
chamada de, 37
complemento de dois, 9
hexadecimal, 107
octal, 107
if (comando
int, 19, 107
de seleo),
33
Internet, 5, 23
interpretao, 5
interpretador, 5
iterao, veja comando iterativo
sinal-magnitude, 9
operao booleana, veja operao lgica
operao lgica, 7
operador
aritmtico, 1518
de comparao, veja operador relacional
Java, 22
precedncia de, 18
NDICE REMISSIVO
relacional, 15, 16
ordem de avaliao de expresses, 18
overow , 108
115
tipo
boolean, 19
char, 108
converso implcita de, 107
double,
palavra, 2
PAPRIMAS, 96
paradigma
esttico, 20
declarativo, 14
funcional, 22
imperativo, 14, 37
lgico, 22, 23
orientado por objetos, 22
107108
erro de, 20
float, 107108
int, 19, 107
long, 107
short, 107
Torres de Hani, 52
tringulo de Pascal, 66
true,
pilha, 38
polimorsmo, 23
19
tupla, 87
Unicode,
Palavra, 96
varivel,
Primalidade, 96
local, 38
procedimento, 26
tipo de, 19
processador, 2
von Neumann
programa, 1
arquitetura de, 2
fonte, 5
objeto, 5
while
27, 38
srie aritmtica, 42
srie geomtrica, 43
srie harmnica, 43
seno (clculo aproximado de), 65
107
sistema de numerao, 6
binrio, 6
converso de base, 6
decimal, 6
sistema operacional, 6
sizeof, 107
somatrio, 42
SPOJ, 95
stdio, 26
strcat, 80
strcmp, 80
strcpy, 80
strlen, 80
switch
19
global, 39
Nmero, 96
short,
14
declarao de,
Primo
return
108
unsigned, 107
Prima
(comando de repetio),
35, 44, 49