Esta aula introduz o conceito de função em linguagens de programação e dá exemplos utilizando a linguagem C.
Em exemplos anteriores utilizamos a função sqrt que está definida em math.h. A função sqrt é uma função que já está pré-definida. Quando fazemos programas também podemos definir as nossas próprias funções. Por exemplo, podemos fazer uma função abs para calcular o valor absoluto de um número. Depois de definida, podemos usar essa função tal e qual como usamos a função sqrt em exemplos anteriores. Exemplo:
#include <stdio.h> main() { float a; printf("Introduz um número: "); scanf("%f", &a ); printf("O valor absoluto de %f é %f\n", a, abs(a) ); }
O programa não funciona tal como está porque a linguagem C não conhece a função abs. No entanto, podemos definir a função abs do seguinte modo:
float abs( float x ) { if( x < 0 ) return -x; else return x; }Concentrem-se na primeira linha da definição da função abs:
float abs( float x )
O float que aparece antes da palavra abs e o float que aparece antes de x correspondem na Matemática ao contra-domínio e ao domínio da função (ver figura).
A função em si é uma espécie de caixa preta que recebe um valor real x e manda cá para fora um outro valor real que é o valor absoluto de x. Dentro da função propriamente dita, podemos utilizar quaisquer instruções da linguagem C. A instrução return serve para "mandar cá para fora" o valor da função e terminar a sua execução.
O programa completo ficaria assim:
#include <stdio.h> /* função para calcular o valor absoluto de um número */ float abs( float x ) { if( x < 0 ) return -x; else return x; } main() { float a; printf("Introduz um número: "); scanf("%f", &a ); printf("O valor absoluto de %f é %f\n", a, abs(a) ); }
O x que aparece na definição da função abs chama-se parâmetro formal. A variável a que aparece quando a função é chamada chama-se parâmetro actual. Na altura em que a função é chamada o parâmetro formal recebe uma cópia do valor do parâmetro actual (no exemplo, x recebe uma cópia do valor de a).
Imaginem que queriam calcular o valor da seguinte fórmula:
f = x! / a! (x-a)!
Numa das aulas passadas fizemos um programa que calculava o factorial de um número. O programa tinha um ciclo que varria os números de 1 a n e ia acumulando o produto dos respectivos números.
Para calcular a fórmula f = x! / a! (x-a)! , temos de calcular o factorial de 3 números. Podemos fazer 3 ciclos, um para cada factorial, mas isso é uma grande chatice porque os 3 ciclos fazem basicamente a mesma coisa.
Em vez de fazer isso, podemos definir a função factorial e depois é só chamar a função 3 vezes. Deste modo o programa fica muito mais simples e muito mais legível:
#include <stdio.h> /* função para calcular o factorial de um número */ int factorial( int n ) { int i,p; p = 1; for( i=2; i<=n; i++ ) p = p * i; return p; } main() { int f, x, a; ... f = factorial(x) / ( factorial(a) * factorial(x-a) ); ... }
Reparem na semelhança entre
f = factorial(x) / ( factorial(a) * factorial(x-a) )
e a notação matemática usual
f = x! / a! (x-a)!
As funções são uma espécie de mini-programas em que podemos declarar variáveis e usar quaisquer instruções da linguagem C. O segredo da programação é conseguir dividir um problema complexo em bocados mais pequenos. Cada bocado corresponde a um sub-problema que é mais simples de resolver. Por sua vez, cada sub-problema pode ser novamente dividido em bocados ainda mais pequenos, e assim sucessivamente.
A utilização de funções tem as seguintes vantagens:
#include <stdio.h> /* função para calcular o factorial de um número */ int factorial( int n ) { int i,p; p = 1; for( i=2; i<=n; i++ ) p = p * i; return p; } main() { int i,f; i = 3; f = factorial(6); printf("%d %d\n", i, f ); }
Ao ser executado o programa vai escrever o seguinte no ecrã:
3 720
O que quero mostrar com este exemplo é que a variável i que está definida em main não tem nada a ver com a variável i que está definida na função factorial. As variáveis definidas dentro de uma função só existem enquanto essa função estiver a ser executada. Outra coisa que é de salientar é que se o main tivesse a instrução printf("%d", p );, o compilador iria dar um erro, visto que o main não conhece p (a variável p que está definida na função factorial é invisível para o exterior da função).
É possível declarar variáveis que têm validade em todo o programa. Essas variáveis chamam-se variáveis globais, mas apenas iremos ver isso mais tarde.
Função para calcular o máximo de 2 números:
float max( float x, float y ) { if( x > y ) return x; else return y; }
Função para calcular o máximo de 3 números:
float max3( float x, float y, float z ) { return max( x, max(y,z) ); }
Programa que utiliza as funções max e max3:
#include <stdio.h> /* calcula o máximo de 2 números */ float max( float x, float y ) { if( x > y ) return x; else return y; } /* calcula o máximo de 3 números */ float max3( float x, float y, float z ) { return max( x, max(y,z) ); } main() { float a,b,c; a = -3; b = 4; c = 2; printf("O máximo de %f, %f, e %f é %f\n", a, b, c, max3(a,b,c) ); }
A função max3 está definida à custa da função max. Na altura em que o programa executa max3(a,b,c), os parâmetros formais x,y,z recebem cópias dos valores de a,b,c respectivamente. Se no main tivéssemos declarado variáveis x,y,z em vez de a,b,c, não iria haver problema nenhum e o programa funcionava exactamente do mesmo modo, isto é, os parâmetros formais x,y,z iriam recebem cópias dos valores das variáveis x,y,z do main.
O conceito de função na linguagem C é mais geral que o conceito de função em Matemática. Em C, é possível ter funções que não retornam nenhum valor (noutras linguagens de programação, tais como o Pascal e o Fortran, este tipo de função costuma ser chamado de procedimento ou rotina). O próximo exemplo ilustra uma função chamada atelogo que não retorna nenhum valor.
#include <stdio.h> /* escreve até logo n vezes */ atelogo( int n ) { int i; for( i=1; i<=n; i++ ) printf("Até logo\n"); } main() { int n; printf("Diz um número: "); scanf("%d", &n) atelogo( n ); }
O programa acima é um programa "imbecil" mas serve para ilustrar o conceito. Reparem que o main também é uma função. Estritamente falando, deveríamos colocar a palavra void na definição de uma função que não retorna nada.
#include <stdio.h> /* escreve até logo n vezes */ void atelogo( int n ) { int i; for( i=1; i<=n; i++ ) printf("Até logo\n"); } void main() { int n; printf("Diz um número: "); scanf("%d", &n) atelogo( n ); }
Em geral, os programas em C são constituídos por um conjunto de funções que comunicam entre si através dos parâmetros. Cada função costuma ter meia dúzia de linhas e faz uma tarefa específica.