Você está na página 1de 36

ANSI C para quem tem pressa

Antnio Manuel de Sousa Barros (AMB)


amb@isep.ipp.pt
24 de Fevereiro de 2003
Contedo
1 Noes bsicas de sistemas informticos. 4
1.1 A histria da programao de computadores. . . . . . . . . . . . . . . 4
1.1.1 A linguagem mquina. . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 A linguagem assembly. . . . . . . . . . . . . . . . . . . . . . 5
1.1.3 As linguagens de alto nvel. . . . . . . . . . . . . . . . . . . 5
1.2 Os sistemas operativos. . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Compiladores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 Estrutura de um programa em C. 8
2.1 Directivas de pr-compilao. . . . . . . . . . . . . . . . . . . . . . 8
2.2 Declarao de variveis globais. . . . . . . . . . . . . . . . . . . . . 8
2.3 As funes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4 A funo main(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3 Estruturas de deciso e ciclos. 11
3.1 Estruturas de deciso. . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.1 if - ... - else - ... . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.2 switch... case... . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2 Ciclos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.1 Ciclos for(). . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.2 Ciclos while(). . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.3 Ciclos do-...-while(). . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4 Funes. 15
4.1 As partes de uma funo. . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.1 Cabealho ou Prottipo. . . . . . . . . . . . . . . . . . . . . 15
4.1.2 Corpo de uma funo. . . . . . . . . . . . . . . . . . . . . . 15
4.2 Funes sem parmetros. . . . . . . . . . . . . . . . . . . . . . . . . 15
4.3 Funes com parmetros. . . . . . . . . . . . . . . . . . . . . . . . . 16
4.3.1 Passagem de parmetros por valor. . . . . . . . . . . . . . . . 16
4.3.2 Passagem de parmetros por referncia. . . . . . . . . . . . . 17
5 Vectores. 18
5.1 Operaes com vectores. . . . . . . . . . . . . . . . . . . . . . . . . 18
5.1.1 Declarar um vector. . . . . . . . . . . . . . . . . . . . . . . . 18
5.1.2 Aceder aos elementos do vector. . . . . . . . . . . . . . . . . 18
1
6 Apontadores. 20
6.1 Aceder aos endereos de memria onde se encontram as variveis. . . 20
6.2 Variveis apontadores. . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.3 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
7 Apontadores e memria dinmica. 23
7.1 A necessidade de memria dinmica. . . . . . . . . . . . . . . . . . . 23
7.2 Manuseamento dinmico de memria em C. . . . . . . . . . . . . . . 23
7.2.1 Reserva dinmica de memria. . . . . . . . . . . . . . . . . . 23
7.2.2 Libertar memria dinmica. . . . . . . . . . . . . . . . . . . 24
7.2.3 Ajuste de memria dinmica. . . . . . . . . . . . . . . . . . 24
7.3 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8 Estruturas de dados. 26
8.1 Declarao de uma estrutura em C. . . . . . . . . . . . . . . . . . . . 26
8.2 Variveis do tipo estrutura. . . . . . . . . . . . . . . . . . . . . . . . 27
8.2.1 Declarao de variveis. . . . . . . . . . . . . . . . . . . . . 27
8.2.2 Utilizao das variveis. . . . . . . . . . . . . . . . . . . . . 27
8.3 Vectores de estruturas. . . . . . . . . . . . . . . . . . . . . . . . . . 27
8.3.1 Declarao de vectores. . . . . . . . . . . . . . . . . . . . . 27
8.3.2 Operao de vectores. . . . . . . . . . . . . . . . . . . . . . 28
8.4 Apontadores para estruturas. . . . . . . . . . . . . . . . . . . . . . . 28
8.4.1 Apontadores - declarao e utilizao. . . . . . . . . . . . . . 28
8.4.2 Atribuio dinmica de memria para uma estrutura. . . . . . 28
8.4.3 Operao dos contedos apontados. . . . . . . . . . . . . . . 28
8.5 Denir novos tipos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.6 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
9 Ficheiros. 30
9.1 Ficheiros de texto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
9.1.1 Abrir um cheiro de texto. . . . . . . . . . . . . . . . . . . . 30
9.1.2 Escrever para um cheiro de texto. . . . . . . . . . . . . . . . 30
9.1.3 Ler de um cheiro de texto. . . . . . . . . . . . . . . . . . . 31
9.1.4 Fechar um cheiro de texto. . . . . . . . . . . . . . . . . . . 31
9.2 Ficheiros binrios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
9.2.1 Abrir um cheiro de binrio. . . . . . . . . . . . . . . . . . . 32
9.2.2 Escrever para um cheiro binrio. . . . . . . . . . . . . . . . 32
9.2.3 Ler de um cheiro binrio. . . . . . . . . . . . . . . . . . . . 33
9.2.4 Fechar um cheiro binrio. . . . . . . . . . . . . . . . . . . . 33
9.3 Orientao e navegao num cheiro. . . . . . . . . . . . . . . . . . 33
9.3.1 O cheiro foi aberto correctamente? . . . . . . . . . . . . . . 33
9.3.2 Como que eu sei que cheguei ao mdo cheiro, quando estou
a ler? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
9.3.3 Estive a consultar o cheiro, mas agora queria realizar uma
nova consulta... a partir do incio do cheiro!... . . . . . . . . 34
9.4 Exerccios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2
Este pequeno apontamento serve para apresentar rapidamente as funcionalidades
bsicas da linguagem C. No entanto, muito ca por cobrir, devendo o interessado pro-
curar outras fontes para aprender esta linguagem poderosa. O meu livro preferido
The C Programming Language de Brian Kernighan e Dennis Ritchie (edio da
Prentice Hall). O manual do UNIX (comando man) um companheiro inseparvel
durante a escrita de um programa, pelo que outra fonte que vivamente recomendo.
3
Captulo 1
Noes bsicas de sistemas
informticos.
Durante a segunda metade do sculo XX, o papel dos sistemas informticos na soci-
edade teve um crescimento impressionante. Os computadores tm sido fundamentais
no desenvolvimento cientco e tecnolgico (e.g. explorao espacial, projecto do Ge-
noma Humano), mas tem tambm inuenciado a sociedade em geral (e.g. telecomuni-
caes, operaes bancrias, Internet).
Um computador uma mquina electrnica com memria, capaz de realizar vrios
clculos aritmticos e lgicos por segundo. Porm, para cada aplicao que se pretenda
que o computador realize, necessrio instru-lo sobre as tarefas que dever realizar
com os dados. A esta tarefa chama-se Programao.
Um programa uma sequncia de instrues que o computador deve realizar de
forma a processar os dados e obter os resultados correctamente.
1.1 A histria da programao de computadores.
1.1.1 A linguagem mquina.
O primeiro computador electrnico foi o ENIAC. Construdo nos EUA durante a II
Guerra Mundial e concludo em 1946, tinha por nalidade calcular rapidamente as ta-
belas de tiro para peas de artilharia e bombardeamentos. Era uma mquina enorme
construda por 18000 vlvulas e 1500 rels, ocupando vrias salas. A sua abilidade
era reduzida, dado que as vlvulas fundiam facilmente, devida potncia irradiada
por estes componentes. Os programas eram inseridos atravs de um leitor de cartes
perfurados (da IBM), sendo escritos directamente em cdigo-mquina (utilizando uni-
camente os dois nicos smbolos binrios zero e um). Adicionalmente, o ENIAC no
era capaz de armazenar os programas em memria, pelo que era necessrio congurar
um conjunto de interruptores e ligaes por cabos (trabalho realizado por seis tcnicas)
de acordo com o programa a ser executado. No entanto era capaz de calcular uma tra-
jectria de 60 segundos em apenas 30 segundos, em oposio s 20 horas tomadas por
um tcnico-matemtico com uma calculadora de secretria.
A linguagem mquina, sendo a nica que os computadores entendem, oferece gran-
des diculdades aos programadores:
longo tempo e grandes custos de aprendizagem;
4
mquinas diferentes entendem linguagens-mquina diferentes;
muito tempo despendido para escrever um programa;
depuramento e correco de programas simplesmente infernal.
Desta forma, fcil imaginar que a quantidade de programadores em todo o mundo era
extremamente reduzida, o que implicava um reduzido nmero de aplicao de compu-
tadores.
1.1.2 A linguagem assembly.
Nos nais da dcada de 1950 e durante a dcada de 1960, ocorreu uma procura macia
de poder de clculo devido aos seguinte factores:
explorao espacial (fomentado pela Guerra Fria);
desenvolvimento de armamento nuclear (tambm fomentado pela Guerra Fria);
gesto das grandes corporaes (IBM, General Motors, etc.).
A aplicao em mquinas de clculo do recm inventado transstor permitiu a cons-
truo de computadores mais veis (devido muito menor irradiao de calor), com-
pactas e rpidas.
Porm, o modelo de programao em linguagem-mquina, em que os progamas
eram picotados em cartes perfurados no podia dar resposta s crescentes solicitaes
do mercado. Os engenheiros pensaram ento numa linguagem de programao rudi-
mentar, em que o nvel de programao estaria muito prximo da linguagem-mquina,
mas cuja escrita e leitura por parte de humanos fosse razoavelmente simples. Surgiu
ento a linguagem assembly. O programa seria ento escrito pelos programadores em
linguagem assembly, sendo por m traduzido para linguagem mquina por um assem-
bler, que recorreria a uma tabela de traduo.
1.1.3 As linguagens de alto nvel.
O assembly permitiu aumentar o nmero de programadores e o desenvolvimento de
aplicaes para computadores. No entanto, no conseguia resolver satisfatoriamente
todos os problemas de construo de aplicaes:
embora facilitado, o depuramento de programas ainda era complicado;
era difcil "pegar" num programa escrito por outra pessoa;
o programador tinha que ter um bom conhecimento da arquitectura do computa-
dor.
Em 1957 surgiu a primeira linguagem de alto-nvel: o Fortran. A partir da, surgiram
outras linguagens de alto-nvel (e.g. ALGOL, BASIC, COBOL, FORTRAN, C), que
ofereciam aos programadores a possibilidade de escreverem programas em linguagens
prximas do ingls. Desta forma:
a aprendizagem de uma linguagem seria mais rpida;
o depuramento de programas era muito mais fcil;
5
o desenvolvimento de aplicaes poderia ser feito em equipas;
as aplicaes poderiam ser mais complexas.
Dado que o nvel de programao se situa muito acima da linguagem-mquina, a apli-
cao de simples tradutores como um assembler j no seria possvel. Surgiram en-
to os compiladores, aplicaes capazes de procurar erros de sintaxe e concepo nos
textos dos programas e transformar as instrues em linguagem quase-natural para lin-
guagem mquina. Uma nica instruo como
PRINT "Ol, tudo bem?"
em BASIC (ordenando o computador para imprimir uma frase no ecr), seria traduzida
em algumas dezenas de instrues em cdigo mquina.
1.2 Os sistemas operativos.
Um computador constitudo por um conjunto de dispositivos electrnicos (placa gr-
ca, impressora, teclado, disco, etc.). De computador para computador, normal en-
contrarmos placas grcas diferentes, discos de diferentes capacidades ou fabricantes,
pelo que seria muito difcil a um programador construir aplicaes (por exemplo, um
processador de texto) para uma mquina especca, e ter que rescrever o programa s
para que ele funcionasse num outro computador com uma placa grca diferente. Sur-
giu ento a necessidade de um sistema operativo, que oferecesse um servio de acesso
uniforme aos dispositivos fsicos para as aplicaes.
Com a existncia de um sistema operativo, uma aplicao como um editor de texto
s precisa de saber ordenar ao sistema operativo que quer que um dado documento seja
impresso: caber ao sistema operativo a funo de enviar para a impressora todos os
dados necessrios para a impresso (ver gura 1.1).
Figura 1.1: Camadas Aplicao / Sistema Operativo / Hardware.
O sistema operativo gere todas as actividades de um computador:
fornece o acesso aos dispositivos;
realiza o escalonamento das aplicaes;
assegura o correcto funcionamento das aplicaes.
O sistema operativo depende da arquitectura do computador, existindo para cada ar-
quitectura pelo menos um sistema operativo. Na tabela 1.1 so apresentados alguns
sistemas operativos para vrias arquitecturas:
6
Tabela 1.1: Arquitecturas e Sistemas Operativos.
Arquitecturas Sistemas operativos
Intel x86 Windows
UNIX (Linux, Free BSD, Solaris, etc)
BeOS
PowerPC (Mac) MacOS ver 7, 8, 9
MacOS X (UNIX)
HP HP-UX (UNIX)
SGI (Silicon Graphics) IRIX (UNIX)
SUN Solaris (UNIX)
1.3 Compiladores.
Tal como referido anteriormente, os compiladores transformam os textos dos progra-
mas (em linguagem de alto-nvel) em cdigo-mquina. Como o cdigo-mquina
produzido para utilizar os recursos oferecidos pelo sistema operativo, facilmente se
depreende que para cada sistema operativo dever existir um compilador.
Assumindo que se escreveu um programa em linguagem C. Se esse programa for
compilado para Windows, o cdigo-mquina gerado no ser inteligvel para o sistema
operativo Linux, nem para o MacOS. Para o programa ser executvel em vrios siste-
mas operativos, pois ento necessrio compil-lo para cada um dos sistemas. Num
futuro captulo, ser explicado o processo de compilao de um programa.
7
Captulo 2
Estrutura de um programa em
C.
2.1 Directivas de pr-compilao.
Nesta primeira fase, necessrio indicar ao compilador quais as bibliotecas de funes
que devem ser includas aquando da compilao, e denir os nomes e valores de cons-
tantes que sero utilizadas durante a escrita do programa. Um exemplo possvel para
este bloco seria o seguinte:
#include <stdio.h>
#include <math.h>
#define PI 3.14159265
As duas primeiras linhas indicam ao compilador que o programa utiliza funes que
se encontram denidas nos cheiros stdio.h (standard input/output) e math.h. Funes
tipicamente utilizadas so:
stdio.h - printf() e scanf() para sada e entrada de dados;
math.h - sin(), sqrt() e outras operaes matemticas.
A terceira linha de cdigo atribui ao nome PI o valor 3.14159265. Todas as referncias
PI ao longo do texto do programa sero substitudas por 3.14159265 antes da compila-
o.
2.2 Declarao de variveis globais.
Uma varivel que seja acessvel pelo mesmo nome em qualquer funo do programa
chamada global. A declarao de uma varivel global feita a seguir ao bloco de
directivas de pr-compilao.
Uma varivel declarada indicando o tipo de valores que poder conter seguido
do identicador (nome) da varivel. Atendendo ao seguinte exemplo de declarao de
variveis:
8
int contador = 0;
float cateto1, cateto2, hipotenusa;
A primeira linha declara a varivel contador para conter nmeros inteiros e inicializa-a
com o valor 0.
Na segunda linha, so declaradas as variveis cateto1, cateto2 e hipotenusa, para
conter nmeros com parte fraccionria.
2.3 As funes.
No ltimo bloco escreve-se o cdigo das funes (aquilo que realmente faz mexer o
programa). As funes so declaradas atravs do tipo do valor retornado, o identica-
dor da funo e a lista dos argumentos que a funo recebe.
No seguinte exemplo, teremos uma funo que calcula o comprimento da hipote-
nusa de um tringulo rectngulo, recebendo como argumentos os comprimentos dos
catetos:
float calculahipotenusa (float cat1, float cat2)
A funo chamada calculahipotenusa() devolve um resultado do tipo oat ( esquerda
do nome da funo), aceitando como argumentos dois valores do tipo oat, que sero
identicados dentro da funo pelos nomes cat1 e cat2.
A sequncia de instrues que a funo deve realizar encapsulada entre chavetas.
Em C, as chavetas so utilizadas para agrupar sequncias de instrues. Dentro do
grupo de instrues, existe um primeiro bloco em que so declaradas as variveis locais
funo e, nalmente, a sequncia de instrues. Continuando o exemplo, o cdigo da
funo poderia ser o seguinte:
{
float hip; /* Declarao da varivel local hip */
cat1 = cat1 * cat1; /* Eleva os catetos ao quadrado */
cat2 = cat2 * cat2;
hip = cat1 + cat2; /* Soma o quadrado dos catetos */
hip = sqtr(hip); /* e determina a raiz quadrada */
return(hip); /* Retorna o valor da variavel hip */
}
2.4 A funo main().
O programa, depois de compilado, comea a executar as instrues contidas numa
funo especial: a funo main(). Esta funo deve conter o algoritmo principal, e
chamar as funes necessrias execuo do algoritmo.
Tendo em conta os exemplos anteriores, poderamos escrever a seguinte funo
main():
9
main()
{
float c1, c2, hipotn; /* Declara as variveis locais */
/* Escreve no ecr a frase entre aspas */
printf("Clculo de hipotenusa...\n");
/* O utilizador introduz os comprimentos dos catetos */
printf("Introduza o comprimento de um dos catetos: ");
scanf("%f", &c1);
printf("Introduza o comprimento do outro cateto: ");
scanf("%f", &c2);
/* A hipotenusa calculada, chamando a */
/* funo calculahipotenusa() */
hipotn = calculahipotenusa(c1, c2);
printf("O comprimento da hipotenusa: %f\n", hipotn);
}
2.5 Exerccios.
1. Dados os valores de duas resistncias, pretende-se obter os valores das resistn-
cias equivalentes quando associadas em srie e em paralelo. Projecte o algoritmo
de um programa capaz de realizar esta tarefa.
10
Captulo 3
Estruturas de deciso e ciclos.
3.1 Estruturas de deciso.
As estruturas de deciso so teis sempre que se tem que optar por um conjunto de
operaes, dependendo de uma condio. A execuo do programa segue sempre em
frente (no confundir com os ciclos).
3.1.1 if - ... - else - ...
Quantas vezes no somos confrontados com situaes em que temos que tomar uma
deciso em funo de um conjunto de condies? Um caso que se aplica todos os
dias (excepto quando estamos de cama, doentes) quando temos que atravessar uma
estrada. Mentalmente, utilizamos o seguinte algoritmo:
SE (no passam carros nos prximos instantes)
ENTO Atravesso a rua
SENO Sigo at aos semforos.
A linguagem C, como foi criada por americanos, tem implementada esta estrutura de
deciso, mas em ingls... Para facilitar a vida ao programador, o ENTO omitido
(quando se avalia algo, de esperar que alguma aco possa ser despoletada). O SE-
NOe aces subsequentes so opcionais (nemsempre temos que fazer qualquer coisa,
caso o resultado da avaliao no nos interesse). O resultado este:
if ( condio lgica )
{
aces a tomar
}
else
{
aces alternativas a tomar
}
No seguinte exemplo, caso o saldo de um carto de telemvel seja inferior ao valor
de uma chamada, dever ser emitida uma mensagem a informar que a chamada no se
pode efectuar. Obviamente, se o saldo for maior, nada dever ocorrer.
11
if (saldo < compra)
{
printf("O saldo insuficiente para realizar a compra.\n");
printf("Por favor, efectue um carregamento do seu carto.\n");
}
No seguinte caso, avaliada a relao maior-igual-menor entre dois nmeros:
if (a > b)
printf("%d maior que %d.\n", a, b);
else
if (a < b)
printf("%d menor que %d.\n", a, b);
else
printf("So iguais.\n");
3.1.2 switch... case...
Quando o leque de aces a realizar depende do valor de uma varivel, podemos utilizar
a instruo switch(). Atendendo ao seguinte exemplo:
printf("Qual a operao que pretende efectuar? ");
operador = getch();
switch (operador) {
case +:
resultado = a + b;
break;
case -:
resultado = a - b;
break;
case *:
resultado = a * b;
break;
case /:
resultado = a / b;
break;
default:
printf("Operao no permitida!\n");
break;
}
Mediante o carcter teclado pelo utilizador, o programa ir realizar a operao preten-
dida. Para cada caso previsto, indicada a sequncia de instrues a realizar.
A palavra break termina a sequncia de instrues para cada opo.
A opo default realizada sempre que nenhuma das condies anteriores no
tenha sido satisfeita.
3.2 Ciclos.
As ciclos decorrem da necessidade de repetir a mesma sequncia de aces at que
determinada condio seja alcanada.
12
3.2.1 Ciclos for().
Os ciclos for() so utilizados quando as operaes de inicializao e incremento so
simples, normalmente utilizando uma varivel como contador do ciclo.
O mtodo de declarao de um ciclo for() o seguinte:
for(inicializao; condio; operao no fim de cada ciclo)
A inicializao uma operao realizada antes de se iniciar a actividade do ciclo. O
ciclo s executado enquanto o valor da condio for verdade. No nal de cada ciclo,
executada a instruo que se encontra no terceiro argumento.
O seguinte exemplo:
soma = 0;
for(contador = 1; contador < 5; contador++)
{
printf("Contador: %d\n", contador);
soma += contador;
}
printf("Somatrio: %d\n", soma);
produziria a sada:
Contador: 1
Contador: 2
Contador: 3
Contador: 4
Somatrio: 10
3.2.2 Ciclos while().
Os ciclos while() so realizados enquanto uma determinada condio vlida. Se a
condio partida for invlida, o ciclo no chega sequer a ser executado (o nmero
mnimo de execues do ciclo ZERO).
total = 0;
while(total < 50000)
{
scanf("%d", &custo);
total += custo;
}
O exemplo acima, permite introduzir custos enquanto o total de custos menor do que
50000. Note que este exemplo seria mais difcil de implementar com um ciclo for(), j
que a condio de incremento no to simples!
3.2.3 Ciclos do-...-while().
Os ciclos do ... while() asseguram que o conjunto de instrues dentro do ciclo exe-
cutado pelo menos UMA vez, isto porque a condio de execuo do ciclo avaliada
apenas no m.
13
do {
printf("Insira um nmero entre 0 e 20: ");
scanf("%d", &numero);
} while ( (numero < 0) && (numero > 20) );
3.3 Exerccios.
1. Dados dois valores, pretende-se saber se o primeiro maior, igual ou menor do
que o segundo. Construa uma hiptese possvel de resoluo deste problema.
2. Escreva um algoritmo que permita calcular o factorial de um nmero inteiro
(n!). Tenha em ateno de que no existem factoriais de nmeros negativos! Por
denio, 0! igual a 1 (um).
3. Num jogo, introduzido um nmero inteiro que dever ser adivinhado pelo jo-
gador, atravs de palpites. Para cada palpite, dever ser indicado ao jogador se
o nmero a adivinhar maior ou menor do que o palpite. Quando o jogador
nalmente adivinha o valor, dever ser indicado o nmero de palpites realizados.
14
Captulo 4
Funes.
Uma funo um conjunto de instrues, capaz de realizar uma determinada tarefa.
A grande vantagem de escrever funes num programa em C, podermos escrever
uma nica vez o conjunto de instrues (funo), e cham-la vrias vezes durante a
execuo do programa.
As funes podem receber valores e realizar processamento sobre esses valores,
retornando o resultado desse processamento.
4.1 As partes de uma funo.
4.1.1 Cabealho ou Prottipo.
Uma funo declarada no seu cabealho. O cabealho de uma funo contm os
seguintes elementos:
o tipo de valor que ser retornado pela funo (tipo do resultado);
o nome da funo;
uma lista de parmetros entre parntesis, que so recebidos pela funo.
4.1.2 Corpo de uma funo.
Aps o cabealho da funo, dever vir o corpo da funo. O corpo de uma funo o
conjunto de instrues que a funo dever realizar, delimitado por chavetas.
4.2 Funes sem parmetros.
As funes sem parmetros tm por funo realizar uma tarefa, independentemente de
quaisquer dados.
A seguinte funo escreve um menu de seleco no ecr. Imprimir estas quatro
linhas de texto no requer a recepo de quaisquer valores.
void mensagem ()
{
printf("\n\nEscolha a opo:\n");
15
printf("1 - Inserir\n");
printf("2 - Remover\n");
printf("3 - Sair\n\n");
}
4.3 Funes com parmetros.
Grande parte das funes processam dados que lhes so passados como parmetros.
Uma funo que calcule o comprimento de uma hipotenusa, ter que necessariamente
receber os valores dos comprimentos dos catetos.
H duas formas de passar parmetros:
por valor;
por referncia.
4.3.1 Passagem de parmetros por valor.
Neste caso, a funo recebe cpias dos valores que foram fornecidos aquando da cha-
mada da funo. Quaisquer alteraes dos valores das cpias no afectaro os valores
originais. Suponha o seguinte exemplo:
#include <math.h>
(...)
float hipotenusa (float cateto1, float cateto2)
{
float hipotenusa;
cateto1 = cateto1 * cateto1;
cateto2 = cateto2 * cateto2;
hipotenusa = cateto1 + cateto2;
hipotenusa = sqrt(hipotenusa);
return (hipotenusa);
}
(...)
main ()
{
float cat1 = 3.00;
float cat2 = 4.00;
float hip;
hip = hipotenusa(cat1, cat2);
(...)
}
Neste exemplo, as variaveis cateto1 e cateto2 da funo hipotenusa() recebem cpias
dos valores das variveis cat1 e cat2 e da funo main(). As operaes realizadas nas
16
variaveis cateto1 e cateto2 (dentro da funo hipotenusa) no afectam os valores das
variveis cat1 e cat2.
4.3.2 Passagem de parmetros por referncia.
Neste caso, a funo recebe a localizao em memria das variveis na chamada. Co-
nhecendo a localizao das variveis possvel altera os seus valores. Suponha o se-
guinte exemplo:
float troca (float *variavel1, float *variavel2)
{
float auxiliar;
auxiliar = *variavel1;
*variavel1 = *variavel2;
*variavel2 = auxiliar;
}
(...)
main ()
{
float a = 3.00;
float b = 4.00;
troca(&a, &b);
(...)
}
Repare que na chamada da funo troca() na funo main(), so passados os endereos
das variveis a e b, na forma &a e &b. No cabealho da funo troca(), as variaveis
variavel1 e variavel2 so apontadores (identicados pelo asterisco que os prexa na
declarao) para valores do tipo oat. Um apontador uma varivel que guarda um
endereo de memria. Nas linhas de instruo, o asterisco (*) indica que queremos
aceder ao contedo do endereo apontado:
variavel1 indica o endereo;
variavel1 indica o contedo no endereo.
Desta forma, a funo troca() realiza as seguintes aces:
1. a varivel auxiliar recebe o contedo do endereo apontado pela variavel1;
2. o contedo do endereo apontado pela variavel2 copiado para o contedo do
endereo apontado pela variavel1;
3. o valor da varivel auxiliar copiado para o contedo do endereo apontado pela
variavel2.
17
Captulo 5
Vectores.
5.1 Operaes com vectores.
Muitas vezes temos necessidade de operar com vrios elementos que representam a
mesma grandeza, e que se encontram relacionados: a posio de uma partcula ao
longo do tempo, os valores de resistncias elctricas num circuito...
Tomemos por um circuito elctrico que contm 10 resistncias. necessrio escre-
ver um programa que efectue uma srie de clculos utilizando os valores das resistn-
cias. Os valores das resistncias devero ser inseridos pelo utilizador.
Logo partida, confrontamo-nos com a necessidade de declarar 10 variveis, uma
para cada resistncia. A tarefa ainda se complica mais quando tivermos que repetir 10
vezes as instrues de insero dos valores das resistncias.
A utilizao de vectores permite facilitar (e bastante) a escrita de programas que
utilizem grandes quantidades de dados do mesmo tipo.
5.1.1 Declarar um vector.
A declarao de um vector semelhante de uma varivel. No entanto, teremos que
indicar (entre parntesis rectos) a dimenso do vector. Entenda-se por dimenso do
vector, o nmero de valores que o vector suporta.
main()
{
float resistencias[10];
(...)
}
No exemplo anterior, denido um vector chamado resistencia, com capacidade para
dez valores do tipo oat.
5.1.2 Aceder aos elementos do vector.
A forma de aceder aos elementos de um vector semelhante forma de aceder ao con-
tedo de uma varivel. No entanto, ser necessrio indicar qual o ndice do elemento
ao qual se pretende aceder. Considere um vector como uma rua, e o ndice como o
nmero de uma casa nessa rua.
18
O primeiro elemento do vector encontra-se no ndice zero. Desta forma, o ltimo
elemento encontra-se no ndice dimenso-1, em que dimenso dimenso do vector.
O seguinte exemplo demonstra alguns exemplos de utilizao dos vectores.
main()
{
float resist[10];
/* Insere 6 valores de resistncias para as */
/* posies de 0 a 5. */
for(i=0; i<6; i++)
{
printf("Insira o valor da resistncia R%d: ", i);
scanf("%f", &resist[i]);
}
resist[7] = (resist[0] + resist[1]) * 0.63;
(...)
}
19
Captulo 6
Apontadores.
6.1 Aceder aos endereos de memria onde se encon-
tram as variveis.
Em C, possvel determinar o endereo de memria em que uma varivel armazena os
seus valores, atravs dos apontadores. Consideremos, por exemplo, a seguinte deni-
o de uma vriavel:
int contador = 4;
O identicador da varivel - a palavra contador - aponta implicitamente para uma
posio em memria, onde se encontra armazenado o valor 4.
Endereo na memria Contedo Identicao da varivel
0x1F22E 4 contador
Quando utilizamos o identicador da varivel, acedemos ao seu contedo. Utili-
zando a seguinte expresso,
printf("O valor da variavel :%d.\n", contador);
obteramos o resultado
O valor da variavel : 4.
Caso seja necessrio aceder ao endereo de memria onde se guarda o valor da
varivel, utiliza-se o operador &:
printf("O endereo da variavel : %p.\n", &contador);
que resultaria na seguinte sada:
O endereo da variavel : 1F22E.
6.2 Variveis apontadores.
Por vezes, necessrio manipular directamente os endereos de memria.Uma varivel
pode ser denida para conter endereos de memria da seguinte forma:
20
int *apontador;
O operador * indica que a variavel apontador um apontador para uma posio de
memria onde se pretende armazenar - neste caso - um valor inteiro. Supondo o se-
guinte excerto de cdigo-fonte:
int valor = 7;
int *apontador;
/* A variavel apontador passa a apontar para
/* a posio de memria da varivel valor */
apontador = &valor;
printf("Endereo de valor: %p,\n", apontador);
printf("e actualmente contm o inteiro %d.\n", *apontador);
uma possvel sada seria a seguinte:
Endereo de valor: 10FF2,
e actualmente contm o inteiro 7.
Note que a prpria varivel apontador encontra-se num dado endereo de memria. A
tabela 6.1 resume os operadores de acesso a posies de memria:
Tabela 6.1: Signicados na notao de apontadores.
Expresso Signicado
&apontador Indica o endereo onde o contedo da varivel apontador
se encontra armazenado em memria.
apontador Indica um determinado endereo em memria onde supostamente
existe algum valor.
*apontador Indica o valor existente na posio de memria apontada
pela variavel apontador.
No seguinte caso, pretende-se que uma funo altere / actualize os valores das
variveis que so passadas como argumentos. Suponha que num programa se pretende
trocar os valores de duas variveis, chamando a funo troca.
troca(variavel1, variavel2);
Esta chamada da funo forneceria apenas os valores das variveis, sendo impossvel
funo actualizar os contedos das variaveis, dado que a funo desconhece os ende-
reos onde os valores se encontram. A funo tem que conhecer os endereos onde as
variveis armazenam os seus valores. Isso conseguido utilizando a seguinte chamada:
troca(&variavel1, &variavel2);
Desta forma, a funo recebe no os valores das variveis, mas sim os seus endereos.
O cdigo-fonte da funo poderia ser o seguinte:
troca(int *v1, int *v2)
{
int aux;
21
/* aux passa a ter o valor apontado por v1 */
aux = *v1;
/* aux passa a ter o valor apontado por v1 */
*v1 = *v2;
/* aux passa a ter o valor apontado por v1 */
*v2 = aux;
}
6.3 Exerccios.
1. Escreva um programa que dena uma varivel para conter valores inteiros, e
um apontador para inteiros. Ao apontador dever ser atribudo o endereo da
varivel. Para a varivel imprima as sua posio em memria e o seu valor. Para
o apontador, imprima a sua posio em memria, o seu valor e o valor na posio
de memria apontada.
2. Escreva uma funo que retorne um apontador para a 1
a
ocorrncia de um carc-
ter numa string ou o valor zero se o carcter no existir na string. A funo deve
ter como argumentos a string e o carcter a procurar.
22
Captulo 7
Apontadores e memria
dinmica.
7.1 A necessidade de memria dinmica.
Em vrias aplicaes, existe a necessidade de manipular estruturas de dados cuja di-
menso no inicialmente conhecida.
Suponha o caso em que se pretende conceber um programa que execute vrias
estatsticas sobre as idades dos alunos de uma turma. O nmero de alunos de uma
turma altamente varivel, o que levanta diculdades utilizao de vectores. Como
se deveria dimensionar o vector?
Uma dimenso razovel poderia ser insuciente para certas turmas.
Um vector muito grande estaria a desperdiar memria. Este factor crtico em
aplicaes que operam grandes quantidades de dados relativamente s capacida-
des da mquina.
A utilizao dinmica de memria permite adaptar as necessidades de memria ao
problema concreto.
7.2 Manuseamento dinmico de memria em C.
O C no oferece de raz o suporte para operaes de memria dinmica, sendo neces-
srio incluir a biblioteca standard do C: stdlib.h.
Nesta biblioteca, existem duas funes que oferecem as funcionalidades bsicas
para utilizao dinmica de memria: malloc() e free().
7.2.1 Reserva dinmica de memria.
A funo malloc() (memory allocation - trad. afectao de memria) reserva uma
poro de memria, retornando um apontador genrico (tipo void *) para o inicio da
poro reservada, ou o valor NULL no caso da reserva ser impossvel. A sua utilizao
representada no exemplo seguinte:
23
float *v;
int n;
printf("Quantos valores? ");
scanf("%d", n);
v = (float *) malloc(n * sizeof(float) );
Neste exemplo, reservada uma poro de memria capaz de guardar n nmeros reais
(oat), cando o apontador v a apontar para o endereo inicial dessa poro de me-
mria. O cast da funo malloc() - (oat *) - assegura que o apontador retornado
para o tipo especicado na declarao do apontador. Certos compiladores requerem
obrigatoriamente o cast.
Conselho: no altere o valor do apontador que recebeu o retorno da funo mal-
loc(). Desta forma poder sempre saber onde comea o bloco de memria dinmica
reservado. Utilize apontadores auxiliares para realizar operaes (leitura, escrita) den-
tro do bloco de memria.
7.2.2 Libertar memria dinmica.
Outra das vantagens da utilizao dinmica de memria a possibilidade de libertar
memria medida que deixa de ser precisa. A memria libertada utilizando a funo
free(). Supondo o exemplo da seco anterior, a poro de memria atribuda seria
libertada da seguinte forma:
free(v);
7.2.3 Ajuste de memria dinmica.
possvel alterar o tamanho do bloco de memria reservado, utilizando a funo re-
alloc(). Esta funo salvaguarda os valores anteriormente em memria, at ao limite
do novo tamanho (especialmente importante quando se reduz o tamanho do bloco de
memria). O seguinte exemplo ilustra a forma de utilizao desta funo.
int *a;
a = (int *) malloc( 10 * sizeof(int) );
(...)
a = (int *) realloc( a, 23 * sizeof(int) );
(...)
free(a);
A chamada da funo realloc() recebe como argumentos um apontador para o bloco
de memria previamente reservado com uma funo malloc() de forma a saber qual a
poro de memria a ser redimensionada, e o novo tamanho absoluto para o bloco de
memria.
24
7.3 Exerccios.
1. Leia uma sequncia de 10 nmeros do teclado usando apontadores em lugar de
ndices. Usando a mesma tcnica (apontadores) determine o maior e o menor
valor. Reserve memria dinmica em vez de declarar o vector de uma forma
esttica.
2. Ler uma sequncia de nmeros do teclado (sequncia terminada emzero).Escreva
no ecr os nmeros que esto acima da mdia. Utilize um vector dinmico para
armazenar os nmeros.
25
Captulo 8
Estruturas de dados.
Uma estrutura uma coleco de uma ou mais variveis, possivelmente de diferentes
tipos, agrupadas sob um nico nome para facilitar o seu manuseamento. As estruturas
permitem organizar dados complicados, porque permitem tratar um grupo de variveis
relacionadas como uma unidade, em vez de entidades separadas.
Como exemplos de estruturas teremos:
um aluno identicado pelo seu nmero e nome;
um ponto identicado pelas suas coordenadas cartesianas (x, y, z)...
Os componentes de uma estrutura (nmero e nome no caso do aluno) so chamados
campos.
8.1 Declarao de uma estrutura em C.
A declarao de uma estrutura em C iniciada pela palavra struct, seguida por uma
lista de declaraes entre chavetas. Uma possvel declarao de uma estrutura para
suportar informao relativa a um ponto seria:
struct ponto {
float x;
float y;
};
As estruturas declaradas podem ser utilizadas como tipos de campos de outras estru-
turas. Se pretendermos criar uma estrutura que dena um rectngulo a partir de dois
vrtices opostos, poderemos escrever:
struct rectangulo {
struct ponto p1;
struct ponto p2;
};
26
8.2 Variveis do tipo estrutura.
8.2.1 Declarao de variveis.
Aps a denio da estrutura, esta pode ser utilizada para declarar vriaveis. A decla-
rao das variveis no muito diferente do usual. Supondo que queremos declarar
variveis - r1 e r2 - para conter as posies de duas partculas, podemos escrever o
seguinte:
struct ponto r1, r2 = {1.5, 3.6};
As variveis so declaradas, sendo r2 inicializada com os valores:
x = 1.5;
y = 3.6;
8.2.2 Utilizao das variveis.
O campo de uma determinada estrutura pode ser acedido utilizando o operador .
(ponto).
/* Atribui o valor 2.3 ao campo x da varivel r1. */
r1.x = 2.3;
/* Atribui o valor guardado no campo y de r2 no campo y de r1. */
r1.y = r2.y;
Para alm da atribuio individual a cada um dos campos, ainda possvel igualar dois
registos rapidamente:
r1 = r2;
A expresso acima atribui a todos os campos de r1 os valores de todos os campos de
r2, criando uma cpia efectiva de r2 em r1.
8.3 Vectores de estruturas.
O C permite a declarao de vectores de estruturas. A sua declarao e utilizao
praticamente idntica aos vectores de tipo "simples".
8.3.1 Declarao de vectores.
A declarao de um vector para 10 elementos da estrutura ponto denida acima, teria
a seguinte forma:
struct ponto vp[10];
27
8.3.2 Operao de vectores.
Os campos dos diversos elementos de um vector so acedidos utilizando o operador .
(ponto).
vp[0].x = 2.3;
vp[0].y = 5.2;
vp[1].x = vp[0].x * 4;
vp[2] = vp[0];
8.4 Apontadores para estruturas.
As estruturas, como agrupamento de variveis que so, utilizam pores de mem-
ria que podem ser apontadas pelos apontadores. Vectores de estruturas em memria
dinmica podem igualmente ser criados, e operados com apontadores.
8.4.1 Apontadores - declarao e utilizao.
Um apontador para uma estrutura declarado da seguinte forma:
struct ponto *ap;
8.4.2 Atribuio dinmica de memria para uma estrutura.
Utilizando o apontador denido acima, podemos reservar memria para 5 pontos es-
crevendo a seguinte instruo:
ap = (struct ponto *) malloc( 5 * sizeof(struct ponto) );
O apontador ap ca a apontar para o incio de um bloco de memria suciente para
armazenar 5 elementos com a estrutura ponto.
A funo realloc() funciona de forma semelhante. A funo free() trivial.
8.4.3 Operao dos contedos apontados.
Os contedos apontados so acedidos utilizando o operador -> (hfen + maior que):
/* Atribui o valor 2.3 ao campo x no registo apontado por ap */
ap->x = 2.3;
/* Atribui o valor do campo y no registo apontado por ap *(
/* ao campo y do registo seguinte */
(ap+1)->y = ap->y;
Uma outra forma de aceder aos contedos apontados da seguinte forma:
/* Equivalente a ap->x = 2.3; */
*ap.x = 2.3;
/* Equivalente a (ap+1)->y = 4.33; */
*(ap+1).y = 4.33;
28
8.5 Denir novos tipos.
Em C, possvel denir novos nomes de tipos, utilizando o typedef.
typedef struct ponto pontocart;
(...)
pontocart p1, p2;
Aps a introduo typedef, o tipo struct ponto pode ser identicado simplesmente por
pontocart.
8.6 Exerccios.
1. Um projctil pode ser caracterizado pela sua posio e velocidade. Estas duas
grandezas so vectoriais, sendo compostas pelas componentes x e y. A partir da
sua posio inicial r0 = (r0x, r0y) e da sua velocidade inicial v0 = (v0x, v0y)
possvel determinar a sua posio-velocidade para qualquer instante a partir das
seguintes equaes:
x = x0 + v0x * t;
y = y0 + v0y * t - 5 * t^2
vx = v0x;
vy = v0y - 10 * t;
Pretende-se desenvolver um programa que a partir das condies iniciais de lan-
amento de um projctil se determine a posio e velocidade para qualquer ins-
tante (o instante inserido pelo utilizador). Na fase nal de desenvolvimento,
o programa dever aceitar a velocidade de lanamento na forma de mdulo e
inclinao em relao horizontal.
Sugesto: crie uma estrutura para conter a informao de umvector (cartesiano).
Crie depois uma outra estrutura onde os dados do projctil (vectores posio e
velocidade) recorram anterior estrutura.
2. Declare uma estrutura capaz de armazenar o nome, o nmero, o ano de entrada,
o curso e quantidade de cadeiras feitas. Dena um vector de 100 estruturas.
(a) Escreva uma funo para ler os valores para uma determinada estrutura do
vector.
(b) Para um determinado curso (a perguntar ao utilizador), o programa deve
responder quantos alunos zeram 10 ou menos cadeiras em mais de cinco
anos.
(c) Visualize no monitor todos os cursos inseridos sem repeties.
(d) O programa deve dizer qual o curso com melhor aproveitamento (curso
com maior mdia de cadeiras feitas por aluno).
29
Captulo 9
Ficheiros.
At ao momento, temos trabalhado apenas com memria. Infelizmente, sempre que
um programa terminado, os dados em memria so perdidos.
Uma forma de eliminar este inconveniente, consiste em guardar os dados em me-
mria secundria (disco).
Os dados em disco so armazenados em cheiros, unidades lgicas que agrupam
dados relacionados entre si.
9.1 Ficheiros de texto.
Tal como o nome indica, os cheiros de texto permitem armazenar informao na
forma de texto.
9.1.1 Abrir um cheiro de texto.
Antes de se realizar qualquer operao de leitura/escrita num cheiro, necessrio
abri-lo. Esta operao realizada utilizando a funo fopen().
FILE *fh; /* declarado um apontador para ficheiro. */
(...)
/* aberto o ficheiro agenda.txt para leitura. */
fh = fopen("agenda.txt", "r");
O primeiro parmetro da funo fopen() uma string, contendo o nome de um cheiro.
O segundo parmetro da funo fopen() uma string, que especica a forma como
se pretende aceder ao cheiro, conforme a tabela 9.1.
9.1.2 Escrever para um cheiro de texto.
As funes de escrita para um cheiro de texto so bastante semelhantes s funes de
escrita para o monitor. As diferenas situam-se nos nomes das funes (prexadas com
a letra f) e a indicao do apontador para o cheiro para o qual se pretende escrever.
30
Tabela 9.1: Modos de acesso a cheiros
Modo de acesso String Comentrio
Leitura "r" A leitura pode ser em qualquer ponto do cheiro.
A abertura do cheiro falha se o cheiro no existir.
Escrita "w" A escrita pode ser em qualquer ponto do cheiro.
Durante a abertura, se o cheiro j existir,
apagado para criar um novo.
Escrita "a" A escrita apenas pode ser no nal do cheiro.
Durante a abertura, caso o cheiro no exista,
criado um novo.
Leitura / Escrita "r+" A leitura pode ser em qualquer ponto do cheiro.
A escrita pode ser em qualquer ponto do cheiro.
Leitura / Escrita "w+" A leitura pode ser em qualquer ponto do cheiro.
A escrita pode ser em qualquer ponto do cheiro.
Leitura / Escrita "a+" A leitura pode ser em qualquer ponto do cheiro.
A escrita apenas pode ser no nal do cheiro.
fputs("Esta frase vai aparecer no ficheiro!\n", fh);
numero = 2;
fprintf(fh, "Linha %d\n", numero);
9.1.3 Ler de um cheiro de texto.
Tal como nas funes de escrita, as funes de leitura so semelhantes s funes de
entrada (geralmente do teclado). O prexo f caracterstico nestas funes, sendo
necessrio identicar o cheiro de onde se pretende ler, identicado pelo apontador de
cheiro.
char string[50];
int a, b;
(...)
/* L dois inteiro de uma linha de texto do ficheiro. */
fscanf(fh, "%d %d", &a, &b);
/* L para a variavel string 50 caracteres, no mximo. */
fgets(string, sizeof(string), fh);
9.1.4 Fechar um cheiro de texto.
Aps todas as operaes de leitura / escrita terem sido realizadas, dever-se- fechar
o cheiro, com a funo fclose(). Esta operao assegura que todos os dados cam
correctamente armazenados no cheiro.
fclose(fh);
31
9.2 Ficheiros binrios.
Os cheiros binrios armazenam os dados tal e qual como eles se encontram na mem-
ria. Um int representado num cheiro binrio tal como guardado na memria (em
formato mquina). Desta forma, espreitar para um cheiro binrio pode dar resultados
ininteligveis para ns, humanos.
9.2.1 Abrir um cheiro de binrio.
A abertura de um cheiro binrio realizada recorrendo igualmente funo fopen().
No entanto, no modo de utilizao do cheiro dever ser adicionada a letra b para
indicar que o cheiro binrio (nem todos os compiladores necessitam da incluso da
letra b).
FILE *fh; /* declarado um apontador para ficheiro. */
(...)
/* aberto o ficheiro binrio temperaturas.dat para leitura. */
fh = fopen("temperaturas.dat", "rb");
9.2.2 Escrever para um cheiro binrio.
As operaes de escrita para um cheiro de binrio devero ser realizadas com a funo
fwrite(). A funo fwrite() toma como argumentos:
o endereo do incio do bloco de memria a copiar para o cheiro;
o tamanho de cada elemento (registo / cha);
o nmero de elementos (registos / chas) a escrever;
o apontador para o cheiro para onde os dados devero ser escritos.
typedef struct {
char cidade[50];
short temperatura;
} registo;
(...)
registo ficha;
FILE *fh;
fh = fopen("temperaturas.dat", "ab");
printf("Insira o nome da cidade: ");
gets(ficha.cidade);
printf("Insira a temperatura da cidade: ");
scanf("%hd", &ficha.temperatura);
fwrite(&ficha, sizeof(registo), 1, fh);
32
(...)
A linha de cdigo que contm a funo fwrite() copia para o cheiro a poro de
memria identicada pela varivel cha.
9.2.3 Ler de um cheiro binrio.
A leitura de um cheiro binrio realizada utilizando a funo fread(). A funo
fread() toma como argumentos:
o endereo do incio do bloco de memria para onde se deve copiar os contedos
do cheiro;
o tamanho de cada elemento (registo / cha);
o nmero de elementos (registos / chas) a ler;
o apontador para o cheiro de onde os dados devero ser lidos.
typedef struct {
char cidade[50];
short temp;
} registo;
(...)
registo ficha;
FILE *fh;
fh = fopen("temperaturas.dat", "rb");
fread(&ficha, sizeof(registo), 1, fh);
printf("Cidade %s - Temp: %hd
o
C.\n", ficha.cidade, ficha.temp);
(...)
A linha de cdigo que contm a funo fread() copia do cheiro para a varivel cha
um registo composto por um nome de cidade e respectiva temperatura.
9.2.4 Fechar um cheiro binrio.
Aps todas as operaes de leitura / escrita terem sido realizadas, dever-se- fechar
o cheiro, com a funo fclose(). Esta operao assegura que todos os dados cam
correctamente armazenados no cheiro.
fclose(fh);
9.3 Orientao e navegao num cheiro.
9.3.1 O cheiro foi aberto correctamente?
A operao de abertura de um cheiro pode falhar por vrias razes, tais como:
33
tentar abrir para leitura um cheiro inexistente;
criar um cheiro num disco sem espao disponvel ou sem permisses de escrita
(e.g. CD-ROM)...
Desta forma, convm certicar de que no houve quaisquer problemas antes de se pro-
ceder a qualquer leitura ou escrita no cheiro. A funo fopen() retorna um apontador
nulo - NULL - quando falha. A seguinte rotina testa a abertura do cheiro, e no caso
de falha, aborta a execuo do programa.
if ( fh = fopen("ficheiro", "w+") == NULL) {
perror("fopen");
exit(0);
}
(...)
9.3.2 Como que eu sei que cheguei ao m do cheiro, quando
estou a ler?
Afuno fread() retorna o nmero de elementos efectivamente lidos do cheiro. Quando
se chega ao m do cheiro, a funo fread() no consegue ler mais elementos. A se-
guinte rotina detecta o m do cheiro.
if ( fh = fopen("ficheiro", "r") == NULL)
{
printf("ERRO: No foi possvel abrir o ficheiro!\n");
exit(0);
}
while( fread(&ficha, sizeof(registo), 1, fh) != 0 )
printf("Cidade %s - Temp %hd
o
C.\n", ficha.cidade, ficha.temp);
O ciclo while() realizado enquanto o nmero de elementos lidos for diferente de zero.
9.3.3 Estive a consultar o cheiro, mas agora queria realizar uma
nova consulta... a partir do incio do cheiro!...
Existe um cursor que aponta para o local no cheiro onde se dever realizar a prxima
escrita / leitura. Quando se abre o cheiro nos modos "r" e w, este cursor aponta para
o incio do cheiro; quando o cheiro aberto em modo a, o cursor colocado no
nal do cheiro.
Aps uma operao de leitura ou escrita, este cursor avana. Quando se realizam
leituras posteriores, so lidos os elementos seguintes. Esta funcionalidade facilita a
leitura sequencial de vrios elementos, mas no permite voltar atrs para ler elementos
anteriores.
Existe a funo rewind() que simplesmente coloca o cursor a apontar para o incio
do cheiro. Aceita como nico argumento o apontador para o cheiro que se pretende
"rebobinar".
rewind(fh);
34
Uma funo mais verstil a fseek() que capaz de colocar o cursor em qualquer ponto
do cheiro. A funo fseek() aceita como parmetros:
o apontador para o cheiro;
o "salto" (em nmero de bytes) a dar no cheiro, podendo ser um nmero o
positivo (salto para a frente); o negativo (salto para trs);
a posio a partir da qual se pretende dar o "salto" o SEEK_SET se for a partir
do incio do cheiro; o SEEK_CUR se for a partir da posio actual do cursor; o
SEEK_END se for a partir do nal do cheiro.
/* Tem o mesmo efeito de rewind(fh); */
fseek(fh, 0, SEEK_SET);
(...)
/* Coloca o cursor no final do ficheiro. */
fseek(fh, 0, SEEK_END);
9.4 Exerccios.
1. Escreva um programa que realize as seguintes operaes:
Deve escrever trs frases (inseridas pelo utilizador) num cheiro de texto.
Dever ler as frases escritas no cheiro referido na alnea anterior, e apresent-
las no ecr.
2. Pretende-se armazenar as temperaturas de vrias cidades de um determinado dia
numcheiro binrio. Onome do cheiro dever seguir o seguinte formato DDM-
MAAAA.dat, em que:
DD o dia;
MM o ms;
AAAA o ano. 2. Cada registo dever conter o nome da cidade e a respec-
tiva temperatura medida.
(a) Escreva um programa que dever guardar os registos das temperaturas re-
lativas a uma data inserida pelo utilizador, num cheiro binrio.
(b) Escreva um segundo programa que dever apresentar as temperaturas me-
didas num determinado dia, e calcular a mdia das temperaturas.
35

Você também pode gostar