|
Aula 12: Programação Modular II:
Funções com entrada e saída
|
|
Traduzido por Ana Paula Costa
Na aula anterior (aula 11) vimos funções
que não aceitam parâmetros e não retornam valores.
Estas eram funções simples. Agora vamos ver funções
que aceitam parâmetros de entrada e funções que produzem
valores de retorno.
Parâmetros para passar para as funções
Nós podemos passar parâmetros para as funções.
As funções podem depois trabalhar com estes parâmetros.
Dentro da função, os parâmetros funcionam como variáveis
normais. Em C, os parâmetros que a função espera são
colocados depois do nome da função entre parêntesis.
Para uma função que não tem saída (ou por outras
palavras, que retorna o tipo void):
Uma funcção com entrada(input) (mas sem saída(output)):
void
nomedafunção(listadeparâmetros)
{
<declaração
de variáveis locais>
instruções;
} |
|
|
As variáveis na lista de parâmetros são declaradas
da mesma maneira que as variáveis normais de um programa ou função,
nomeadamente temos que especificar o tipo de cada parâmetro. Dentro
da função podemos utilizar o parâmetro como se fosse
uma variável normal. Podemos efectuar cálculos com ele, utilizá-lo
em condições, e até mesmo alterar o seu valor. Não
necessita de ser inicializado, porque a inicialização vem
do programa que faz a chamada à função.
Como um exemplo, o programa que se segue irá calcular e mostrar
o quadrado de uma variável x: De notar a forma como o parâmetro
r
é declarado e utilizado.
código do programa
#include <stdio.h>
void write_square(float r)
{
float y;
y = r*r;
printf("The square of %f is %f", r,
y);
}
void main()
{
float x;
x = 4;
write_square(x);
write_square(3.0);
} |
output
The square of 4.0 is 16.0
The square of 3.0 is 9.0 |
Como se pode ver no programa de cima, as funções com parâmetros
podem ser chamadas com uma variável, como é o caso em write_square(x),
ou com uma constante, como em write_square(3.0).
Outro exemplo, que utiliza dois parâmetros:
código do programa
#include <stdio.h>
void write_sum(int i1, i2)
/* write the sum of i1 and i2 */
{
int j;
j = i1+i2;
printf("The sum of %d and %d
is %d',
i1, i2, j);
}
void main()
{
int x, y;
x = 4;
y = 5;
write_sum(x, y);
write_sum(3, 4);
} |
output
The sum of 4 and 5 is 9
The sum of 3 and 4 is 7 |
De notar que temos que passar para a função o tipo de informação
que ela espera. Neste caso, a função espera por dois inteiros,
e então nós devemos passar-lhe dois inteiros (x e y).
Por fim, um exemplo com uma lista de parâmetros de vários
tipos. As variáveis a serem declaradas na lista de parâmetros
são separadas por uma vírgula (,).
código do programa
#include <stdio.h>
void write_N_times(float r, int n);
/* Will write n times the real r */
{
int i;
for (i= 1; i<=n; i++)
printf("%10.3f\n", r);
}
void main()
{
write_N_times(3.0, 4);
} |
output
3.000
3.000
3.000
3.000 |
Funções com saída (output)
As funções podem retornar um valor de saída. O tipo
do valor de retorno tem que ser especificado no momento da declaração
da função, antes do nome da função.
tipo nomedafunção(listadeparâmetros)
{
<listadevariáveis>
instruções;
} |
|
Funções com saída e com parâmetros
de entrada
|
Algures nas instruções temos que especificar o valor
de retorno. Fazemos isso com a palavra reservada return
Obviamente, o valor tem que ser do mesmo tipo que o tipo da declaração
da função.
De notar que a instrução return sai imediatamente da
função e as instruções que se encontrem depois
de return não serão executadas.
double square(double r)
/* will return the square
of of the parameter r */
{
r = r*r;
return (r);
}
No local onde a função será chamada, podemos atribuir
este valor a uma variável (do mesmo tipo do valor retornado pela
função!), por exemplo
y = square(3.0);
utilizá-lo como parte de uma expressão, por exemplo
y = 4.0 * square(3.0) + 1.0;
ou utilizá-lo noutra função, por exemplo
printf("%f", square(3.0));
Um exemplo completo:
código do programa
/* example with parameters */
#include <stdio.h>
double square(double r)
(* will return the square of of the
parameter r *)
{
r = r*r;
return(r);
}
void main()
{
double x, y;
x = 4.0;
y = square(x);
printf("The square of %f is %f\n",
x, y);
printf("The square of %f is %f\n",
3.0, square(3.0));
} |
output
The square of 4.0 is 16.0
The square of 3.0 is 9.0 |
O que está a acontecer com a instrução y
= square(x) é o seguinte:
-
O valor da expressão dentro de parêntesis é calculado.
Neste caso é simples. É o valor de x,
nomeadamente 4.0;
-
Este valor (4.0) é passado para a função square().
Dentro da função:
-
É criada uma variável temporária com nome r.
-
O valor passado para a função é atribuído a
essa variável r. Efectivamente
aconteceu uma instrução r=4.0.
-
r=r*r; O novo valor de r
é calculado. r agora tem o valor 16.0.
-
return(r); O valor da expressão
dentro de parêntesis (16) é passado
de volta à instrução que fez a chamada (y=square(x););
onde poderá ser utilizado.
-
Neste caso, o valor retornado (square(4.0) que é 16.0) será
atribuído a y. A instrução
y=square(x);
efectivamente transforma-se em y=16.0;
-
A linha seguinte (printf...) mostra
os valores das variáveis x e y. (De notar que o valor de x
se manteve inalterado e continua a ser 4.0. Mais tarde, na aula sobre
"passagem por valor / passagem por referência" iremos ver que não
é necessariamente assim.)
De notar que em C não temos que utilizar o valor que é
retornado pela função. Podemos, por exemplo escrever na nossa
função main()
square(3.0);
Esta construção é muito confusa e deve ser
evitada quando possível em programas estruturados; um valor retornado
por uma função deve, em princípio, ser utilizado na
parte que fez a chamada.
Porquê?
Agora a grande questão é "porquê?". Porquê escrever
funções se podemos fazer o mesmo com linhas de instruções
normais? De facto, as primeiras linguagens (por exemplo o BASIC) não
tinham a possibilidade de escrever funções e mesmo assim
podíamos escrever programas para resolver qualquer problema. Existem
no entanto três razões importantes que justificam a utilização
de módulos.
-
Com os módulos, devido ao facto de serem como caixas negras,
podemos distribuir as nossas tarefas de programação por várias
pessoas, ou grupos de pessoas, sem ter que haver muita comunicação
entre essas pessoas. Podemos dizer a alguém que necessitamos de
uma função que inverta uma matriz sem termos que dizer como
queremos que o faça. Temos que especificar apenas o tipo de parâmetros
a passar para a função.
-
Pela mesma razão, podemos facilmente copiar partes de outros programas
ou bibliotecas para servir os nossos propósitos (desde que se utilizem
apenas parâmetros e variáveis locais, como iremos ver mais
tarde). No caso ideal, nós apenas temos que fazer o "link" dessas
funções que iremos utilizar, com o nosso programa, sem saber
exactamente como elas funcionam. (Sabendo, claro, o que elas irão
fazer e como as chamar). Uma consequência interessante disto é
que podemos distribuir as nossas funções de uma forma pré-compilada,
de forma a que o código se mantenha seguro na nossa posse.
-
Com as funções o programa fica mais pequeno, mais eficiente
e mais legível, evitando-se repetições de código
e organizando-se o programa de forma mais lógica.
Teste Rápido:
Para testar os conhecimentos sobre o que aprendeu nesta aula, prima aqui
para fazer um teste on-line. De notar que este Não é
o formato que será utilizado no teste final!
Peter Stallinga. Universidade do Algarve, 8 November
2002