O objetivo dessa unidade é apresentar ao aluno o conceito de procedimentos e funções e sua utilização na linguagem C.
Para a melhor estruturação de programas, é comum utilizar o conceito de MODULARIZAÇÃO.
Modularizar um programa consiste em dividi-lo em partes que serão desenvolvidas em separado. Essas partes executam tarefas menores que depois serão acopladas para formar o programa. A cada uma dessas partes chamamos de subprograma.
Os subprogramas permitem uma melhor legibilidade e manutenibilidade do programa.
Em C modularizamos um programa através de Funções e Procedimentos.
Podemos dizer então que:
Funções e Procedimentos são blocos de código que podem ser nomeados e chamados a partir de um programa.
Uma função pode ser empregada para evitar repetição de código e assim facilitar a manutenção do código contido no programa.
Uma função pode necessitar de alguns dados para que possa realizar alguma ação baseada neles. Esses dados são chamados parâmetros da função. Além disso, a função pode retornar um certo valor, que é chamado valor de retorno. Os parâmetros (e seus tipos) devem ser especificados explicitamente, assim como o tipo do valor de retorno. A forma geral da definição de uma função é:
Para o nome da função e dos parâmetros valem as mesmas regras que foram dadas para os nomes de variáveis. Não podemos usar o mesmo nome para funções diferentes em um programa.
Todas as funções devem ser definidas antes da função main, ou deve ser feito o protótipo da função, que veremos mais adiante.
O código deve estar obrigatoriamente dentro das chaves e funciona como qualquer outro bloco.
Frequentemente, uma função faz algum tipo de processamento ou cálculo e precisa retornar o resultado desse procedimento. Em C, isso se chama valor de retorno e pode ser feito com a instrução return. Para poder retornar um valor, precisamos especificar seu tipo (char, int, float, double e variações). Para efetivamente retornar um valor, usamos a instrução return seguida do valor de retorno, que pode ou não vir entre parênteses. Um exemplo bem simples de função que retorna um valor inteiro:
O tipo de retorno, além dos tipos normais de variáveis (char, int, float, double e suas variações), pode ser o tipo especial void, que na verdade significa que não há valor de retorno. Um Procedimento é uma função que não retorna nada.
Como já foi dito, um parâmetro é um valor que é fornecido à função quando ela é chamada. É comum também chamar os parâmetros de argumentos, embora argumento esteja associado ao valor de um parâmetro.
Os parâmetros de uma função podem ser acessados da mesma maneira que variáveis locais. Eles, na verdade, funcionam exatamente como variáveis locais, e modificar um argumento não modifica o valor original no contexto da chamada de função, pois, ao dar um argumento numa chamada de função, ele é copiado como uma variável local da função. A única maneira de modificar o valor de um parâmetro é usar ponteiros, que serão introduzidos mais adiante.
Para declarar a presença de parâmetros, usamos uma lista de parâmetros entre parênteses, com os parâmetros separados por vírgulas. Cada declaração de parâmetro é feita de maneira semelhante à declaração de variáveis: a forma geral é tipo nome. Por exemplo:
Para especificar que a função não usa nenhum parâmetro, a lista de parâmetros deve conter apenas a palavra-chave void. No entanto, ela é frequentemente omitida nesses casos. Portanto, você poderia escrever qualquer uma destas duas linhas:
Note que os nomes dos parâmetros são usados apenas na própria função (para distinguir os argumentos); eles não têm nenhuma relação com as variáveis usadas para chamar a função.
Para executar uma função, fazemos uma chamada de função, que é uma instrução composta pelo nome da função, seguida pela lista de argumentos entre parênteses:
Os argumentos podem ser qualquer tipo de expressão: podem ser variáveis, valores constantes, expressões matemáticas ou até mesmo outras chamadas de função.
Lembre que você deve sempre dar o mesmo número de argumentos que a função pede. Além disso, embora algumas conversões de tipo sejam feitas automaticamente pelo compilador, você deve atender aos tipos de argumentos.
Note que o valor dos argumentos é copiado para a função, de maneira que as variáveis originais ficam inalteradas mesmo que na função tentemos alterá-las. A isso chamamos passagem de argumentos por valor (ao contrário de por referência). Veremos como modificar as variáveis originais na seção Ponteiros.
A própria chamada de função também é uma expressão cujo valor é o valor de retorno da função, bastando colocá-la no lado direito de um sinal de igual para guardar o valor numa variável. Por exemplo, se a função "quadrado" retorna o quadrado de um número inteiro, podemos fazer assim para calcular o quadrado de 11 na variável x:
Para definir uma função depois da função main é necessário se fazer o protótipo dessa função. Esse deve ser feito antes da função main. O protótipo nada mais é que definirmos o tipo de retorno, o nome da função e seus atributos, porém ao invés de colocarmos as chaves e os comandos do bloco, colocamos apenas ponto e vírgula. Vejamos um exemplo:
Vamos fazer um programa que imprima a seguinte saída na tela:
Primeiro vamos tentar fazer utilizando conceitos que já foram aprendidos. Então utilizaremos um laço para imprimir cada uma das linhas.
Observe que foi necessário repetir duas vezes o for para imprimir 3+ e duas vezes o for para imprimir 5+.
Agora vamos tentar melhorar essa resolução. Vamos resolver este mesmo problema utilizando funções:
Observe que:
Com o uso de funções, não é preciso repetir os comandos for. O que se repete são as chamadas das funções.
As funções são chamadas dentro do main.
O void serve para indicar que a função não tem parâmetro de saída
Ainda sim podemos melhorar nosso código, vamos utilizar parâmetros de entrada. Observe:
Os parâmetros passados no cabeçalho da função são:
O caractere ch será utilizado para determinar qual caractere será impresso e o inteiro n representa o número de linhas que serão impressas
Os argumentos são colocados na chamada da função
O primeiro parâmetro deverá ser do tipo char, portanto ele é compatível com o primeiro argumento ‘+’, já segundo parâmetro é do tipo int , portanto será compatível com o número 3.
Relembrando: Uma função que não retorna nada (void) é um procedimento. Logo, o exemplo acima é um procedimento
Fazer um programa para verificar se um dado número é par ou não. Para isso, utilize uma função com passagens de parâmetros.
Observe que:
É passada para a função int verifPar(int k) uma variável (k) do tipo inteiro com o valor que veio da função principal main (valor de num).
A função recebe esta variável, verifica se ela é par ou não e devolve ao programa principal o número 1 se k for par e o número zero se k for ímpar.
A função utiliza o comando return para devolver o valor. O tipo do valor devolvido é que define o tipo da função. Portanto, a função int verifPar(int k) é então uma função do tipo inteiro, porque o valor devolvido é inteiro.
São variáveis declaradas dentro de um subprograma. Elas só podem ser manipuladas dentro do subprograma que as declarou. Logo, elas não são visíveis em nenhuma outra parte do programa. Vejamos:
Observe que o valor da variável "a" foi alterado em mudaA(), mas esta alteração não foi repassada para o main.
Na realidade a variável "a" da função mudaA( ) NÃO é igual à variável "a" do main. O programa trabalha com as duas variáveis independentemente.
Com a variável local, duas funções diferentes, por exemplo f1 e f2 podem ter o mesmo nome de variável, para armazenar dados diferentes, pois neste caso quando a função f1 está sendo executada o valor da variável fica “oculto” em f2 e vice-versa.
São variáveis declaradas no início do programa principal (fora do corpo de qualquer função, inclusive da main). As variáveis globais podem ser manipuladas durante toda a execução do programa. Assim, qualquer alteração que se faça numa variável global refletirá em todas as funções do programa.
Deve-se tomar cuidado, pois ao se definir uma variável global, ela não poderá ser redeclarada em outra função do programa, porque isto acarreta em um erro de compilação
Observe que a variável "a" foi declarada no corpo do programa principal e não dentro da função mudaA, como no exemplo anterior, portanto ela é uma variável global.
O valor da variável a foi alterado em mudaA( ) e esta alteração foi passada para a variável a do main( ).
Em C existem várias funções que já estão programadas, como por exemplo a função sqrt(x ) que calcula a raiz quadrada de x, a função sin(x) que calcula o seno(x), etc.
Uma função pode ser responsável por fazer determinada tarefa e uma vez terminada esta tarefa, ela devolve, como resultado, apenas um valor. A devolução desse valor é feita através do comando return, seguido do valor a ser devolvido. Esse valor pode ser qualquer expressão válida na linguaguem.
Fazer um programa que solicite ao usuário dois números e apresente na tela o resultado da sua soma e do dobro de cada um deles. Utilize uma função para calcular a soma e outra para o dobro.
Exemplo de execução:
Note que não é sempre necessário passar o valor de retorno de uma função para uma variável, podemos imprimir esse valor simplesmente chamando a função dentro do comando PRINTF como no exemplo acima.