Problema: conversão de temperaturas
Podemos converter temperaturas na escala Fahrenheit para a escala Celsius da seguinte forma:
$$T_{Celsius} = \frac{5}{9} \left( T_{Fahrenheit} - 32\right)$$
Algoritmo
Input: limite inferior e limite superior.
Output: impressão da temperatura na escala Celsius para cada temperatura (número inteiro) no intervalo definido pelos limites dados como entrada.
- Inicia no limite inferior de temperatura na escala Fahrenheit.
fahr = inferior; - Enquanto temperatura não fôr superior ao limite superior:
while (fahr <= superior)- converte temperatura para escala Celsius;
celsius = 5 * (fahr-32) / 9; - escreve linha da tabela com temperaturas;
printf("%d\t%d\n", fahr, celsius); - aumenta valor de temperatura na escala Fahrenheit.
fahr = fahr + passo;
- converte temperatura para escala Celsius;
Implementação em C
#include <stdio.h>
/* Conversao Fahrenheit-Celsius */
int main ()
{
/* Declaracao de variaveis. */
int fahr, celsius;
int inferior, superior, passo;
/* Inicializacao de variaveis. */
inferior = 0;
superior = 300;
passo = 20;
/* Inicia no limite inferior de temperatura na escala Fahrenheit. */
fahr = inferior;
/* Enquanto temperatura nao for superior ao limite superior. */
while (fahr <= superior)
{
/* Converte temperatura para escala Celsius. */
celsius = 5 * (fahr-32) / 9;
/* Escreve linha da tabela com temperaturas. */
printf("%d\t%d\n", fahr, celsius);
/* Aumenta valor de temperatura na escala Fahrenheit. */
fahr = fahr + passo;
}
return 0;
}Notas sobre o código:
- podemos fazer comentários no código colocando-os entre
/*e*/; - temos de declarar todas as variáveis;
- devemos inicializar todas as variáveis, em particular aquelas cujo valor inicial é relevante no que se segue;
- utilizámos a estrutura de controlo
while, que permite definir ciclos; - a indentação ajuda a compreender a estrutura do programa, mas não indispensável;
- a função
printfpermite efectuar escrita formatada, notar a utilização de%dpara representar um inteiro decimal e o caracter tabulação\t; - podemos melhorar a formatação...
printf("%3d\t%6d\n", fahr, celsius);
NOTA: Evitar erros comuns na definição de ciclos:
while (i >= 0); i = i -1;
Cuidado com a colocação dos ;'s!
Problema: $0^o F$ são $-17,8^o C$ e não $-17^o C$!
Este problema ocorre devido à divisão inteira na instrução celsius = 5 * (fahr-32) / 9;. A divisão entre inteiros é a divisão inteira, o resultado é o quociente da divisão (número inteiro), e.g., o resultado de 5/9 é 0 e o resultado de 5/2 é 2.
Para resolver este problema podemos de utilizar o tipo float:
#include <stdio.h>
int main ()
{
float fahr, celsius;
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
fahr = inferior;
while (fahr <= superior) {
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + passo;
}
return 0;
}Definição de constantes
No exemplo anterior não precisamos de facto de tantas variáveis, uma vez que inferior, superior, e passo tomam sempre o mesmo valor. Logo, podemos reescrever da seguinte forma:
#include <stdio.h>
int main ()
{
float fahr, celsius;
int inferior, superior, passo;
fahr = 0;
while (fahr <= 300) {
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + 20;
}
return 0;
}Porém não é boa prática utilizarmos valores explícitos no código. Devemos antes utilizar constantes que podemos definir com a directiva #define. Desta forma podemos reescrever o exemplo da seguinte forma:
#include <stdio.h>
#define INFERIOR 0
#define SUPERIOR 300
#define PASSO 20
int main ()
{
float fahr, celsius;
int inferior, superior, passo;
fahr = INFERIOR;
while (fahr <= SUPERIOR) {
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + PASSO;
}
return 0;
}Nota: As directivas de preprocessamento como #include ou #define não têm ; no final.
Ciclos for
No exemplo anterior podemos utilizar o for em vez do while da seguinte forma:
#include <stdio.h>
#define INFERIOR 0
#define SUPERIOR 300
#define PASSO 20
int main ()
{
float fahr, celsius;
int inferior, superior, passo;
for (fahr = INFERIOR; fahr <= SUPERIOR; fahr = fahr + PASSO) {
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f\t%6.1f\n", fahr, celsius);
}
return 0;
}Notar a colocação das instruções de inicialização, de teste, e de incremento no for.
Leitura de valores do standard input
Nos exemplos anteriores escrevemos para o standard output com a função printf. Vamos agora ver como ler valores do standard input com a função scanf também definida em no ficheiro stdio.h:
#include <stdio.h>
/* Objectivo: vamos pedir um inteiro ao utilizador e devolver o
quadrado desse numero. */
int main ()
{
int x;
printf("Introduza um valor inteiro:\n");
scanf("%d", &x);
printf("O quadrado de %d é %d\n", x, x*x);
return 0;
}Neste exemplos indicamos com %d que o input dado pelo utilizador deve interpretado como um inteiro e guardado na variável x. A razão de colocarmos &x em vez apenas x tem a haver com facto de termos de passar a variável por referência e não por valor, como acontece normalmente. Mais tarde no decurso da disciplina vamos ver mais em detalhe a diferença de passar por valor e de passar por referência.
A função scanf é bastante flexível. Por exemplo, se quisermos ler dois inteiros basta utilizar o scanf da seguinte forma:
scanf("%d%d", &x, &y);
E para ler um float:
scanf("%f", &r);
Não esquecer, podemos sempre ver todos os detalhes a respeito desta função na sua man page, man 3 scanf.
Exemplo com leitura e escrita
Neste exemplo queremos ler uma lista de inteiros do standard input introduzidos pelo utilizador e mostrar esses valores no ecrã, ou seja, no standard output. O programa deve terminar quando ler um valor negativo.
Podemos pensar no seguinte algoritmo:
- Lê um inteiro e guarda-o numa variável
v.scanf("%d", &v); - Se v for válido:
while (v >= 0)- escreve o inteiro lido;
printf("%d\n", v); - lê próximo inteiro e guarda-o novamente na variável
v.scanf("%d", &v);
- escreve o inteiro lido;
Na implementação completa temos:
#include <stdio.h>
/* Copia inteiros do input para output */
int main ()
{
int v;
scanf("%d", &v);
while (v >= 0) {
printf("%d\n", v);
scanf("%d", &v);
}
return 0;
}Notar que neste exemplo utilizámos o operador >=, um dos operadores de comparação:
- operadores de comparação de igualdade:
==,!=; - operadores de comparação de desigualdades:
>,<,<=, e>=.
Comprimento de uma lista
Neste exemplo queremos ler uma lista de inteiros do standard input introduzidos pelo utilizador e, no final, mostrar o número de elementos na lista. O programa deve terminar quando ler um valor negativo.
Consideremos o seguinte algoritmo:
- Inicializa contador a
0.contador = 0; - Lê um inteiro.
scanf("%d", &v); - Enquanto conseguir ler um valor válido:
while (v >= 0)- incrementa contador;
++contador; - lê próximo inteiro;
scanf("%d", &v);
- incrementa contador;
- Escreve valor do contador.
printf("%ld\n", contador);
E a sua implementação em C:
#include <stdio.h>
/* Conta numero de elementos de lista de numeros positivos. */
int main ()
{
int v;
long contador;
contador = 0;
scanf("%d", &v);
while (v >= 0) {
++contador;
scanf("%d", &v);
}
printf("%ld\n", contador);
return 0;
}Neste caso a variável contador tem tipo long int, o que significa que temos garantidamente pelo menos 32 bits para guardar o inteiro. E, uma vez que esta variável é do tipo long int, na instrução printf("%ld\n", contador) temos de indicar esse facto com %ld.
A instrução ++contador introduz um novo operador, que é equivalente à instrução contador = contador+1. Para além deste operador, podemos utilizar outros operadores: contador++, --contador, e contador--. Ainda que todos tenham o comportamento esperado, existem alguns detalhes a ter em conta:
int a = 0, b = 0, c = 0; b = a++; /* Passamos a ter b=0 e a=1 */ c = ++a; /* Passamos a ter c=2 e a=2 */
E, no caso de um contador num ciclo:
int a = 0;
while (a++ <= 3) {
... /* O ciclo e' executado 4 vezes */
}
int a = 0;
while (++a <= 3) {
... /* O ciclo e' executado 3 vezes */
}Desta forma, a utilização dos operadores ++ e -- de forma prefixa ou sufixa pode influenciar a execução do programa.
No caso da contagem do número de elementos numa lista podemos também substituir o while por um for da seguinte forma:
#include <stdio.h>
/* Conta numero de elementos de lista de numeros positivos. */
int main ()
{
int v;
long contador;
scanf("%d", &v);
for (contador = 0; v >= 0; ++contador)
scanf("%d", &v);
printf("%ld\n", contador);
return 0;
}Notar novamente a colocação das instruções de inicialização, de teste, e de incremento no for.
E se quisermos utilizar um double em vez de um long int? Temos de fazer o seguinte:
#include <stdio.h>
/* Conta numero de elementos de lista de numeros positivos. */
int main ()
{
int v;
double contador;
scanf("%d", &v);
for (contador = 0; v >= 0; ++contador)
scanf("%d", &v);
printf("%.0f\n", contador);
return 0;
}Em que para além da alteração do tipo da variável foi necessário mudar a formatação no printf de forma a ter em conta o novo tipo da variável contador, em que utilizamos agora %.0f. Em geral podemos utilizar %f para representar variáveis do tipo float e double. Neste caso colocámos também .0 para que o número fosse escrito sem casa decimais.
Exemplo: contagem de aprovações e reprovações
Considere-se uma lista de inteiros que denota as notas dos alunos numa disciplina. Queremos ler uma lista de inteiros positivos introduzidos pelo utilizador e terminar quando for lido um número negativo. No final queremos mostrar o número de notas lidas, o número de aprovações, e o número de reprovações.
Algoritmo:
- Inicializa contador de notas e aprovações a
0.notas = aprovacoes = 0; - Lê nota.
scanf("%d", &v); - Enquanto conseguir ler uma nota válida:
while (v >= 0)- incrementa o contador de notas;
notas++; - se a nota lida é positiva,
if (v >= 10)- incrementa contador de aprovações;
aprovacoes++;
- incrementa contador de aprovações;
- lê nota seguinte.
scanf("%d", &v);
- incrementa o contador de notas;
- Escreve valor dos contadores.
printf(...);
Implementação:
#include <stdio.h>
/* Contagem de aprovacoes e reprovacoes de lista de notas. */
int main ()
{
int v, notas, aprovacoes;
notas = aprovacoes = 0;
scanf("%d", &v);
while (v >= 0)
{
notas++;
if (v >= 10)
aprovacoes++;
scanf("%d", &v);
}
printf("Total: %d, Aprovacoes: %d, Reprovacoes: %d\n",
notas, aprovacoes, notas-aprovacoes);
return 0;
}Neste exemplo a instrução notas = aprovacoes = 0 é equivalente a (notas = (aprovacoes = 0)) e ainda a notas = 0; aprovacoes = 0.
Exercícios:
- Modifique o programa anterior por forma a calcular também qual a maior nota presente na lista.
- Modifique o programa anterior por forma a calcular a média das notas positivas.
Linha de comandos
Nem sempre queremos estar a escrever o input na consola, em geral queremos passar como entrada o conteúdo de um ficheiro. Como é que podemos então passar o conteúdo de um ficheiro para um programa através do standard input?
Podemos redireccionar para o standard input:
$ ./myprogram < input.txt
E também podemos guardar o resultado do programa enviado para o standard output num ficheiro:
$ ./myprogram > output.txt
E podemos realizar ambas as operações em simultâneo:
$ ./myprogram < input.txt > output.txt