Até agora só temos usado procedimentos como ferramenta de modularização do código, mas muitas vezes é útil chamar um procedimento que retorna alguma informação de volta para o código que o chamou. Esta é a diferença entre procedimentos e funções: as funções retornam algum valor. Desta forma, as funções em linguagem C são similares às funções da matemática: uma função como
f : Z → Z, f(x) = x2+ 2
tem um parâmetro x (um inteiro), e retorna um determinado valor que depende do parâmetro passado; por exemplo,
f(5) = 52+ 2 = 27 É fácil escrever a mesma função em linguagem C:
int f(int x) { // 1x
return x * x + 2; // 2x
x
1 Definição da função f. A definição começa com int f(...), significando que o tipo de
retorno da função é int.
x
2 A palavra-chave return determina o valor de retorno da função f, que será o resultado da
expressão x * x + 2.
A função f do exemplo faz o mesmo que a versão matemática: dado o valor do parâmetro x, retorna um valor que é igual a x ao quadrado, somado a dois. Note que é preciso especificar o tipo do valor que é retornado pela função e, por isso, toda função começa com o tipo de retorno antes do nome. Especificar os tipos dos parâmetros e o tipo do valor de retorno também é similar às funções na matemática, para as quais devemos especificar os conjuntos domínio e contra-domínio.
5.3.1
Funções, Procedimentos e o Tipovoid
Neste ponto pode surgir uma pergunta: se é preciso especificar o tipo do valor retornado por uma função antes do nome da função (por exemplo int f(...)), por que nos procedimentos usa-se a palavra-chave void?
A verdade é que, embora algumas linguagens de programação façam uma distinção entre procedi- mentos e funções, na linguagem C existem apenas funções. Como a diferença entre procedimentos e funções é apenas o fato de retornar ou não um valor, os procedimentos em C são considerados funções que retornam um valor vazio. É isso que significa o void no início da definição de um procedimento como imprime_separador, que vimos anteriormente; a rigor, imprime_separador é uma função, mas retorna um valor vazio, ou seja, nenhum valor. O tipo void na linguagem C é um tipo especial que denota a ausência de valores.
Como procedimentos em C são funções, também é possível usar return em procedimentos, mas apenas para terminar sua execução e retornar imediatamente. Isso às vezes é útil para terminar um procedimento em pontos diferentes do seu final. Também pode-se utilizar return ao final do pro- cedimento, mas este uso é supérfluo e não é recomendado.
O seguinte exemplo demonstra o uso do return em procedimentos. Continuando no tema relaci- onado ao cálculo de médias, queremos detectar se uma das notas entradas pelo usuário é uma nota inválida antes de fazer o cálculo da média. Neste caso, o programa deve apenas imprimir se algum valor negativo foi entrado pelo usuário. O procedimento possui_negativo será responsável por imprimir uma mensagem caso um dos valores seja negativo.
Código fonte
Uso de return em um procedimento
1 #include <stdio.h> 2
3 void possui_negativo(float n1, float n2, float n3) { 4 if (n1 < 0.0) {
5 printf("Numero negativo encontrado!\n");
6 return; // 1x
7 }
8
9 if (n2 < 0.0) {
10 printf("Numero negativo encontrado!\n");
11 return;
13
14 if (n3 < 0.0) {
15 printf("Numero negativo encontrado!\n");
16 return;
17 }
18
19 printf("Nenhum numero negativo encontrado\n"); // 2x
20 }
21
22 int main() {
23 float nota1, nota2, nota3; 24
25 printf("Entre as três notas, separadas por espacos: "); 26 scanf("%f %f %f", ¬a1, ¬a2, ¬a3);
27
28 possui_negativo(nota1, nota2, nota3); 29
30 printf("Media: %f\n", (nota1 + nota2 + nota3) / 3.0); 31
32 return 0;
33 }
x
1 Uso do return para sair prematuramente do procedimento.
x
2 Este comando de impressão será executado se nenhuma das condições testadas em
possui_negativo for verdade, ou seja, se nenhum dos valores dos parâmetros for nega- tivo.
Resultado de duas execuções do programa code/cap5/retorno_proc.c
Entre as três notas, separadas por espacos: 4.5 5.6 8.9 Nenhum numero negativo encontrado
Media: 6.333333
Entre as três notas, separadas por espacos: 4.5 -6.7 9.9 Numero negativo encontrado!
Media: 2.566667
O procedimento possui_negativo deve verificar se um dos três números passados como argu- mentos, mas basta achar um número entre eles para que o resultado possa ser impresso imediatamente e o procedimento pode retornar; por isso, usamos return assim que o primeiro valor negativo é en- contrado.
Esse exemplo ainda tem um problema: como pode ser visto nos exemplos de execução, mesmo que o usuário entre um valor negativo, a média aritmética das três notas ainda é impressa na tela (o usuário apenas é avisado que um dos valores foi negativo). Isso é uma indicação que seria melhor que possui_negativo fosse uma função, e que o programa principal verificasse o valor retornado e tomasse uma decisão. Se fizermos essas alterações ficamos com o seguinte programa:
Código fonte
1 #include <stdio.h> 2
3 int possui_negativo(float n1, float n2, float n3) { // 1x 4 if (n1 < 0.0 || n2 < 0.0 || n3 < 0.0) // 2x 5 return 1; // 3x 6 7 return 0; // 4x 8 } 9 10 int main() {
11 float nota1, nota2, nota3; 12
13 printf("Entre as três notas, separadas por espacos: "); 14 scanf("%f %f %f", ¬a1, ¬a2, ¬a3);
15
16 if (possui_negativo(nota1, nota2, nota3) == 1) // 5x
17 printf("Nao e’ possivel calcular a media, uma ou mais notas ←-
sao negativas\n");
18 else
19 printf("Media: %f\n", (nota1 + nota2 + nota3) / 3.0); 20
21 return 0;
22 }
x
1 A função possui_negativo agora retorna um inteiro de valor 1 caso um dos valores dos
parâmetros seja negativo, e 0 caso contrário (todos são positivos).
x
2 Teste para identificar se um ou mais dos parâmetros informados são negativos.
x
3 A função retorna 1 se um dos números passados para a função for negativo.
x
4 Caso nenhum dos números seja negativo, o controle passa para o comando return ao final da
função e o valor 0 é retornado para indicar que nenhum número negativo foi encontrado.
x
5 O programa principal verifica o valor de retorno da função possui_negativo e imprime
informações adequadas na tela para cada caso.
Resultado de duas execuções do programa code/cap5/retorno_func.c
Entre as três notas, separadas por espacos: 6.8 9.7 -2.3 Nao e’ possivel calcular a media, uma ou mais notas sao ←-
negativas
Entre as três notas, separadas por espacos: 6.8 9.7 7.2 Media: 7.900000
Como pode-se ver nos dois exemplos de execução do programa, a saída agora é mais adequada. Caso uma das notas informadas seja negativa, o programa não imprime um valor de média, apenas avisando o usuário do erro na entrada de dados. O código da função possui_negativo também foi simplificado pelo uso do operador lógico OU.
Como funções e procedimentos são tratados de maneira uniforme na linguagem C (e em muitas outras linguagens atuais), a partir de agora vamos usar o termo função tanto para funções como para procedimentos. Isso não deve gerar nenhuma confusão. Em caso de dúvida, basta olhar para a definição da função no código-fonte do programa; se a função for declarada com o tipo de retorno void, então é um procedimento.