Você está na página 1de 9

Captulo 2

Seguindo em frente
2.1 A biblioteca matematica
Diversas fun coes matematicas estao denidas em C. Algumas que usamos com freq uencia em aplicacoes
fsicas sao listadas abaixo. A variaveis x e y sao double, e os valores calculados sao double. Os angulos
para as funcoes trigonometricas devem ser expressos em radianos.
sin(x) seno de x
cos(x) cosseno de x
tan(x) tangente de x
asin(x) arco-seno de x, no intervalo [/2, /2], x [1, 1]
acos(x) arco-cosseno de x, no intervalo [0, ], x [1, 1]
atan(x) arco-tangente de x, no intervalo [/2, /2]
atan2(y,x) arco-tangente de y/x, no intervalo [, ]
sinh(x) seno hiperbolico de x
cosh(x) cosseno hiperbolico de x
tanh(x) tangente hiperbolica de x
exp(x) e
x
log(x) logartmo natural de x
log10(x) logartmo de x na base 10
pow(x,y) x
y
. Se x < 0, entao y deve ser inteiro. Se x= 0, y deve ser positivo.
sqrt(x)

x
ceil(x) O inteiro logo acima de x, mas escrito como um double
floor(x) O inteiro logo abaixo de x, mas escrito como um double
fabs(x) |x|
Um codigo que use alguma dessas funcoes precisa ter no seu incio a linha
#include <math.h>
O comando para a criacao do executavel deve ter no m dele -lm. Por exemplo, suponha que o arquivo com
o codigo se chama prog.c, e o executavel tera nome prog, o comando de compilacao seria
gcc -o prog prog.c -lm
2.2 Estruturas condicionais
Nos codigos que vimos ate agora, as instrucoes sao seguidas seq uencialmente usando os valores de variaveis
atuais a cada linha. Essa estrutura linear nao e adequada para a maioria das aplicacoes. Necessitamos de
mecanismos que provoquem bifurcacoes na excecucao, ou seja, que certos comandos so sejam executados se
determinadas condicoes forem satisfeitas. Tambem precisamos de uma forma de forcar a repeticao de grupos
de comandos. As diversas estruturas condicionais existentes na linguagem proveem esses mecanismos. O
funcionamento delas depende da avaliacao, como falsa ou verdadeira, de uma determinada armativa.
11
CAP

ITULO 2. SEGUINDO EM FRENTE 12


Operadores l ogicos e relacionais
Os operadores relacionais sao
> (maior) >= (maior ou igual) < (menor) <= (menor ou igual),
com a mesma precedencia, e
== (igual) != (diferente de),
com precedencia imediatamente abaixo. Os operadores relacionais tem precedencia abaixo dos aritmeticos,
assim a expressao x < y-1 e avaliada como x < (y-1).
Os operadores logicos sao
&& (e) || (ou).
Expressoes conectadas por && e || sao avaliadas da esquerda para a direita, e a avaliacao e interrompida
assim que seja possvel determinar se a expressao e falsa ou verdadeira. A precedencia de && e mais alta do
que a de ||, e ambos tem precedencia inferior a == e !=.
O operador unario ! e o operador de negacao. Uma expressao logica tem valor numerico 1 se for
verdadeira, e 0 se for falsa, assim o operador negacao opera trocando 0 por 1 e vice-versa.
A avalia cao de uma expressao e feita de acordo com a tabela abaixo, para cada par, seguindo as regras
de precedencia:
V && V = V
V && F = F
F && F = F
V || V = V
V || F = V
F || F = F
Controle de Fluxo com if
If
Em ingles if signica se, a ideia e condicionar a execucao de uma parte do codigo. Por exemplo, suponha
que, dado o valor de x, queremos calcular

x apenas se x for positivo. Escrevemos:
y = -1.0;
if(x > 0)
y = sqrt(x);
w = a*x;
.
.
.
ou
y = -1.0;
if(x > 0)y = sqrt(x);
w = a*x;
.
.
.
Se x for negativo, a atribuicao y=sqrt(x) nao sera feita, e y = -1.0. Se x for positivo, y tomara o valor
sqrt(x). Se desejamos que varios comandos sejam executados condicionalmente, usamos os delimitadores
de bloco, {}, assim
CAP

ITULO 2. SEGUINDO EM FRENTE 13


y = -1.0;
if(x > 0)
{
y = sqrt(x);
printf("x e positivo e sua raiz vale %f\n",y);
}
w = a*x;
.
.
.
if-else
O exemplo acima pode ser modicado para incluir mais uma possibilidade, como
if(x > 0)
y = sqrt(x);
else
y = sqrt(-x);
w = a*x;
.
.
.
else, signica se nao, ou caso contrario, em ingles. A atribuicao y = sqrt(-x) so sera feita se x for
negativo ou 0, e so sera percorrida durante a execucao nesse caso. Veja uma situacao bem diferente na
estrutura if-if abaixo.
if-if
Na estrutura
if (expressao 1)
comando 1
if (expressao 2)
comando 2
comando 1 e comando 2 podem ser blocos de comandos (cada um terminando com ;) delimitados por {}.
Nessa estrutura, o segundo teste e sempre realizado, mesmo que a primeira expressao seja verdadeira.
Nos exemplos acima, note que colocamos a parte interna da seq uencia if-else com recuo. Para o
compilador isso nao faz diferenca, o else e associado por default ao if mais proximo, mas para quem le ca
mais facil de entender o que esta acontecendo.
Else-if
Esta seq uencia e muito utilizada e serve para quando temos que escolher entre varias possibilidades. Sua
forma e
if (express~ao)
comando
else if (express~ao)
comando
else if (express~ao)
comando
else if (express~ao)
CAP

ITULO 2. SEGUINDO EM FRENTE 14


comando
else
comando
A ultima parte else e a opcao nenhuma das opcoes acima, e pode ser omitida, ou usada para vericar
erros de logica por exemplo, se camos em uma condicao impossvel.
Expressoes Condicionais
O operador ternario ? possibilita a substituicao de uma seq uencia if-else por uma unica expressao na
forma
expr
1
? expr
2
: expr
3
.
Aqui, expr
1
e calculada primeiro. Se retorna um valor nao-nulo ( o que acontece quando e verdadeira ),
entao a expr
2
e calculada e este passa a ser o valor da expressao condicional. Se expr
1
retorna um valor nulo
( se e falsa ), entao a expr
3
e calculada. Por exemplo, se queremos que z assuma o valor maximo entre a e
b, podemos escrever
z = (a > b) ? a : b;
Lacos for e while
Estas estruturas sao usadas para forcar a repeticao de um comando ou bloco de comandos. Vamos ver alguns
exemplos de uso. Suponha que queremos calcular o somatorio
s =
N

n=1
1
n
.
Podemos usar um for:
#include <stdio.h>
void main(void)
{
double s;
int n, N;
printf("De o numero de termos a serem somados:\n");
scanf("%d", &N);
s = 0.;
for(n = 1; n <= N ; n++){
s = s + 1./n; // ou s += 1./n;
printf("%d\t%lf\n", n, s);
}
printf(" soma calculada...\n");
}
Veja como funciona. Suponha que N = 10:
A variavel double s e inicializada com o valor s = 0.
A variavel int n e inicializada com o valor n = 1.
A expressao n <= N e avaliada, se for verdadeira, o bloco de comandos entre chaves e executado, senao,
o comando a seguir da chave de fechamento e executado.
Neste caso n = 1 e menor que 10, assim s tem seu valor aumentado de 1/n, e o valor atual de s e
mostrado na tela, junto com o valor de n.
O valor de n e incrementado de 1, pela aplicacao de ++, vale agora 2.
CAP

ITULO 2. SEGUINDO EM FRENTE 15


A expressao n <= N e avaliada, se for verdadeira, o bloco de comandos entre chaves e executado, senao,
o comando a seguir da chave de fechamento e executado.
Agora n = 2, ainda menor que 10, assim s tem seu valor aumentado de 1/n, e o valor atual de s e
mostrado na tela, junto com o valor de n.
O valor de n e incrementado de 1, pela aplicacao de ++, vale agora 3.
A expressao n <= N e avaliada, se for verdadeira, o bloco de comandos entre chaves e executado, senao,
os comando a seguir da chave de fechamento sao executados.
Etc, ate que o n = N, e o termo 1/N e adicionado. Agora, ao ter seu valor incrementado, n tera valor
11, e a expressao n <= N sera falsa pela primeira vez. O bloco nao e executado, a execucao passa para
o printf, e termina ao bater na chave nal do main.
Reescrevemos o programa usando o laco while agora.
#include <stdio.h>
void main(void)
{
double s;
int n, N;
printf("De o numero de termos a serem somados:);
scanf("%d", &N);
s = 0.;
n = 1;
while(n <= N){
s = s + 1./n; // ou s += 1./n;
printf("%d\t%lf\n", n, s);
n++;
}
printf(" soma calculada...\n");
}
Na primeira vez em que a condicao e falsa (aqui signica n>N), as linhas do bloco sao puladas, a execucao
segue imediatamente do m do bloco. Assim, deve-se vericar se a entrada no bloco esta garantida.
2.3 Manipulacao de arquivos
A entrada e sada de valores e feita sempre para arquivos. Algumas funcoes, como printf e scanf tem o
arquivo previamente denido, depedendo de como estamos executando nosso programa. Ate agora usamos
sempre a execucao interativa, neste caso, os arquivo default sao a tela para sada, e teclado para entrada. Se
executamos o programa de forma nao interativa, em geral e mais pratico ter a entrada e sada direcionadas
para arquivos.
Redirecionamento simples de I/O: O sistema operacional UNIX (e derivados) permite o redireciona-
mento de input e output de forma muito simples. Por exemplo, se queremos que a sada de um executavel
de nome prog1 seja escrita em um arquivo de nome dados.dat em vez de aparecer na tela, e so executar o
programa na forma:
./prog1 > dados.dat
O sinal > faz com que tudo o que apareceria na tela va para o arquivo especicado. Se o programa pedisse
dados para iniciar os calculos, poderamos tambem le-los de um arquivo de forma semelhante: executavel <
arquivo de entrada. Assim de uma forma geral:
executavel < arquivo de entrada > arquivo de sada
CAP

ITULO 2. SEGUINDO EM FRENTE 16


Lendo e escrevendo em arquivos
Uma situacao bastante comum e ter um programa que le valores de varios arquivos diferentes, realiza uma
serie de calculos, e escreve os resultados em varios outros arquivos. Para que isso seja possvel devemos ter
funcoes para ler e escrever referentes a cada um dos arquivos, e que o executavel tenha permissao para lidar
com os mesmos.
Na linguagem C, um arquivo e descrito por um objeto do tipo estrutura. Nao veremos estruturas neste
curso, mas podemos ter uma ideia. Por exemplo, imagine que um programa lida com uma serie de partculas
elpticas descritas pelo n umero de atomos contido nela (int N), posicao do seu centro (double x, y, z), e
pela razao de seus eixos (double K). Podemos trabalhar com cada uma dessas propriedades separadamente,
ou podemos agrupa-las denindo um objeto do tipo, por exemplo, ELIPSOIDE, que e uma estrutura for-
mada pelos elementos N,x,y,z,K. Os nomes dados `as estruturas sao convencionalmente escritos em letras
mai usculas. Uma estrutura do tipo FILE, que signica arquivo em ingles, deve incluir variaveis que descrevam
varias propriedades do arquivo tais como nome e tipo de acesso, e sua denicao esta no arquivo stdio.h.
Vamos ver um exemplo. Queremos escrever num arquivo de nome seno.dat uma tabela com 3 colunas,
a primeira com o valor de um arco em radianos, a segunda com o valor do arco em graus, e a terceira com
o valor de seu seno.
// seno.c //
#include <stdio.h>
#include <math.h>
void main(void)
{
double ar, ag, pi;
FILE *fp;
fp = fopen("seno.dat","w");
pi = 4.*atan(1.);
for(ar = 0; ar <= 2*pi ; ar = ar + 0.1)
{
ag = 180.*ar/pi;
fprintf(fp,"%.3lf\t%.3lf\t%.3lf\n",ar,ag,sin(ar));
}
fclose(fp);
}
Entao, fp e o ponteiro para uma estrutura do tipo FILE. A funcao fopen abre o arquivo com o nome
seno.dat, para escrever (o w e para write). Se o arquivo nao existe, e criado, se ja existe, seu conte udo
e descartado. O resultado da abertura do arquivo e a designacao de um endereco de memoria onde todos
os dados pertinentes ao arquivo sao guardados, e este e entao atribudo `a variavel fp. Finalmente, para
escrever no arquivo usamos a funcao fprintf, analoga `a printf, mas que tem como primeiro argumento
o endereco da estrutura tipo FILE que ir a receber os dados. O comando fclose termina a relacao com o
arquivo. De qualquer forma, o m da execucao causa o fechamento de todos os arquivos apontados. Cada
vez que o arquivo e aberto para leitura, ele e iniciado no seu primeiro caracter. Leituras consecutivas vao
percorrendo seq uencialmente o arquivo. Pode-se voltar ao incio do arquivo com o comando rewind(fp).
Suponhamos que quisessemos ler os valores de 100 arcos em radianos, de um arquivo arcos.dat, e assim
como no programa anteror, converte-los para graus, calcular seus senos e escrever o resultado num arquivo
seno.dat. Um codigo possvel e
#include <stdio.h>
#include <math.h>
#define N 100
void main(void)
{
double ar, ag, pi;
CAP

ITULO 2. SEGUINDO EM FRENTE 17


int i;
FILE *fpin, *fpout;
fpin = fopen("arcos.dat","r");
fpout = fopen("seno.dat","w");
pi = 4.*atan(1.);
for(i = 1; i <= N ; i++)
{
fscanf(fpin,"%lf",&ar);
ag = 180.*ar/pi;
fprintf(fpout,"%.3lf\t%.3lf\t%.3lf\n",ar,ag,sin(ar));
}
fclose(fpin);
fclose(fpout);
}
Nem sempre a abertura de um arquivo e bem sucedida. Por exemplo, voce pode estar solicitando o acesso
para leitura de um arquivo que nao existe. Esse e um erro muito comum, difcil de detectar, ja que nao e
apontado na compilacao. Quando fopen nao tem sucesso, o endereco de memoria retornado e NULL, uma
constante denida em stdio.h. Podemos usar isso entao, abrindo todos os arquivos com um mecanismo de
deteccao de erro da seguinte forma
if((fpin=fopen("arcos.dat","r"))== NULL)
{
fprintf(stderr,"nao pude abrir arcos.dat \n");
exit(1);
}
O arquivo stderr e o default para mensagens de erro de execucao. Se estamos excetutando de forma
interativa, e a propria tela. No caso de erro de abertura de arquivo, aparecera escrito a mensagem nao pude
abrir arcos.dat e a execucao terminara com codigo 1, devido `a chamada da funcao exit.
Exerccios
1. Nas porcoes de codigo indicadas, x e um n umero inteiro. Indique, em cada caso, o que aparecera escrito
na tela quando x tomar os valores 4, 2 e 1. Nao vale fazer o programa para testar. . .
(a)
if (x >2)
printf("a\n");
if (x % 2 == 0)
printf("b\n");
else
printf("c\n");
(b)
if (x > 2)
printf("a\n");
else if (x % 2 == 0)
printf("b\n");
else
printf("c\n");
(c)
if (x > 2)
printf("a\n");
if (x % 2 == 0)
printf("b\n");
if (x != 100)
printf("c\n");
(d)
if (x > 2)
printf("a\n");
else if (x % 2 == 0)
printf("b\n");
else if (x != 100)
printf("c\n");
(e)
if (x != 1)
if (x > 2)
printf("a\n");
else
printf("b\n");
(f)
if (x != 1){
if (x > 2)
printf("a\n");
}
else
printf("b\n");
2. Escreva um programa que calcule o fatorial de um n umero.
CAP

ITULO 2. SEGUINDO EM FRENTE 18


3. Escreva um programa que calcule o modulo e o angulo entre o vetor e o eixo x, dadas as componentes
v
x
e v
y
do vetor.
(a) Usando a funcao tan.
(b) Usando a funcao sin.
4. Reescreva os lacos abaixo, trocando while por for e vice versa.
(a)
int s = 1;
int N = 10;
while(N > 1){
s *= N;
N--;
}
(b)
int i, N = 50;
double x = 0, pi;
pi = 4.*atan(1.);
for(i = 1; i <= N; i++){
x += sin(i*PI/N);
printf("%g\n", x);
}
5. Seja y(x) = ax
2
+bx+c. Escreva o codigo de um programa que calcula as raizes x
r
de y(x), e as mostre
na tela, dados os valores dos coecientes a, b e c, que devem ser lidos pelo teclado. Seu programa deve:
recusar valores nulos de a, e discriminar os casos: raizes iguais, raizes reais diferentes, raizes complexas
diferentes. No ultimo caso, os valores de x
r
devem ser escritos como Re x
r1
+iIm x
r1
e Re x
r2
+iIm
x
r2
.
6. Escreva o codigo de um programa que leia do arquivo notas.dat as notas das duas provas parciais de
um grupo de N = 100 alunos, calcule a media, e escreva no arquivo medias.dat as notas das provas,
a media e as palavras APROVADO, FINAL e REPROVADO caso a media seja, maior ou igual a sete, maior
ou igual a tres e menor que sete, e menor que tres, respectivamente.
7. Inclua no programa acima o calculo do valor medio das medias, x
m
, e seu desvio padrao denidos
por
x
m
=
1
N
N

i=1
x
i
=

1
N
N

i=1
x
2
i

x
2
m
.
Os valores calculados sao escritos na tela.
8. Escreva um programa que some N termos de uma dada serie. O valor de N deve ser tal que

S
N+1
S
N
S
N

10
4
,
onde S
N
e a soma de N termos. Compare o valor calculado com o obtido diretamente pelo uso da
funcao, para os casos
(a)
sen(x) =

n=0
(1)
n
x
2n+1
(2n + 1)!
(b)
exp(x) =

n=0
x
n
n!
,
para |x| < 1.
Bibliograa
[1] Intel Coporporation. IA-32 Intel Architecture Software Developers Manual.
http://support.intel.com/design/Pentium4/documentation.htm, 2004.
[2] Winn L. Rosch. The Winn L. Rosch Hardware Bible (6th Edition). Que, 2003.
[3] http://computer.howstuworks.com/computer-memory.htm.
[4] http://arstechnica.com/paedia/r/ram guide/ram guide.part1-1.html.
23

Você também pode gostar